From d0e9590bbdd3d5789a077711610cea7f64088e7d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 15 Jul 2006 05:15:15 +0000 Subject: [PATCH 0002/1664] stupid, moved up one dir --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4028 --- sourcepawn/compiler/{compiler-init => }/amx.h | 0 sourcepawn/compiler/{compiler-init => }/amxdbg.h | 0 sourcepawn/compiler/{compiler-init => }/libpawnc.c | 0 sourcepawn/compiler/{compiler-init => }/libpawnc.rc | 0 sourcepawn/compiler/{compiler-init => }/lstring.c | 0 sourcepawn/compiler/{compiler-init => }/lstring.h | 0 sourcepawn/compiler/{compiler-init => }/memfile.c | 0 sourcepawn/compiler/{compiler-init => }/memfile.h | 0 sourcepawn/compiler/{compiler-init => }/osdefs.h | 0 sourcepawn/compiler/{compiler-init => }/pawn.ico | Bin sourcepawn/compiler/{compiler-init => }/pawncc.c | 0 sourcepawn/compiler/{compiler-init => }/sc.h | 0 sourcepawn/compiler/{compiler-init => }/sc1.c | 0 sourcepawn/compiler/{compiler-init => }/sc2.c | 0 sourcepawn/compiler/{compiler-init => }/sc3.c | 0 sourcepawn/compiler/{compiler-init => }/sc4.c | 0 sourcepawn/compiler/{compiler-init => }/sc5.c | 0 sourcepawn/compiler/{compiler-init => }/sc5.scp | 0 sourcepawn/compiler/{compiler-init => }/sc6.c | 0 sourcepawn/compiler/{compiler-init => }/sc7.c | 0 sourcepawn/compiler/{compiler-init => }/sc7.scp | 0 sourcepawn/compiler/{compiler-init => }/scexpand.c | 0 sourcepawn/compiler/{compiler-init => }/sci18n.c | 0 sourcepawn/compiler/{compiler-init => }/sclist.c | 0 sourcepawn/compiler/{compiler-init => }/scmemfil.c | 0 sourcepawn/compiler/{compiler-init => }/scstate.c | 0 sourcepawn/compiler/{compiler-init => }/scvars.c | 0 sourcepawn/compiler/{compiler-init => }/sp_file.h | 0 sourcepawn/compiler/{compiler-init => }/spcomp.sln | 0 .../compiler/{compiler-init => }/spcomp.vcproj | 0 sourcepawn/compiler/{compiler-init => }/svnrev.h | 0 .../compiler/{compiler-init => }/zlib/adler32.c | 0 .../compiler/{compiler-init => }/zlib/compress.c | 0 .../compiler/{compiler-init => }/zlib/crc32.c | 0 .../compiler/{compiler-init => }/zlib/crc32.h | 0 .../compiler/{compiler-init => }/zlib/deflate.c | 0 .../compiler/{compiler-init => }/zlib/deflate.h | 0 sourcepawn/compiler/{compiler-init => }/zlib/gzio.c | 0 .../compiler/{compiler-init => }/zlib/infback.c | 0 .../compiler/{compiler-init => }/zlib/inffast.c | 0 .../compiler/{compiler-init => }/zlib/inffast.h | 0 .../compiler/{compiler-init => }/zlib/inffixed.h | 0 .../compiler/{compiler-init => }/zlib/inflate.c | 0 .../compiler/{compiler-init => }/zlib/inflate.h | 0 .../compiler/{compiler-init => }/zlib/inftrees.c | 0 .../compiler/{compiler-init => }/zlib/inftrees.h | 0 .../compiler/{compiler-init => }/zlib/trees.c | 0 .../compiler/{compiler-init => }/zlib/trees.h | 0 .../compiler/{compiler-init => }/zlib/uncompr.c | 0 .../compiler/{compiler-init => }/zlib/zconf.h | 0 sourcepawn/compiler/{compiler-init => }/zlib/zlib.h | 0 .../compiler/{compiler-init => }/zlib/zutil.c | 0 .../compiler/{compiler-init => }/zlib/zutil.h | 0 53 files changed, 0 insertions(+), 0 deletions(-) rename sourcepawn/compiler/{compiler-init => }/amx.h (100%) rename sourcepawn/compiler/{compiler-init => }/amxdbg.h (100%) rename sourcepawn/compiler/{compiler-init => }/libpawnc.c (100%) rename sourcepawn/compiler/{compiler-init => }/libpawnc.rc (100%) rename sourcepawn/compiler/{compiler-init => }/lstring.c (100%) rename sourcepawn/compiler/{compiler-init => }/lstring.h (100%) rename sourcepawn/compiler/{compiler-init => }/memfile.c (100%) rename sourcepawn/compiler/{compiler-init => }/memfile.h (100%) rename sourcepawn/compiler/{compiler-init => }/osdefs.h (100%) rename sourcepawn/compiler/{compiler-init => }/pawn.ico (100%) rename sourcepawn/compiler/{compiler-init => }/pawncc.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc.h (100%) rename sourcepawn/compiler/{compiler-init => }/sc1.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc2.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc3.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc4.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc5.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc5.scp (100%) rename sourcepawn/compiler/{compiler-init => }/sc6.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc7.c (100%) rename sourcepawn/compiler/{compiler-init => }/sc7.scp (100%) rename sourcepawn/compiler/{compiler-init => }/scexpand.c (100%) rename sourcepawn/compiler/{compiler-init => }/sci18n.c (100%) rename sourcepawn/compiler/{compiler-init => }/sclist.c (100%) rename sourcepawn/compiler/{compiler-init => }/scmemfil.c (100%) rename sourcepawn/compiler/{compiler-init => }/scstate.c (100%) rename sourcepawn/compiler/{compiler-init => }/scvars.c (100%) rename sourcepawn/compiler/{compiler-init => }/sp_file.h (100%) rename sourcepawn/compiler/{compiler-init => }/spcomp.sln (100%) rename sourcepawn/compiler/{compiler-init => }/spcomp.vcproj (100%) rename sourcepawn/compiler/{compiler-init => }/svnrev.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/adler32.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/compress.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/crc32.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/crc32.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/deflate.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/deflate.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/gzio.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/infback.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inffast.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inffast.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inffixed.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inflate.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inflate.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inftrees.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/inftrees.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/trees.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/trees.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/uncompr.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/zconf.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/zlib.h (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/zutil.c (100%) rename sourcepawn/compiler/{compiler-init => }/zlib/zutil.h (100%) diff --git a/sourcepawn/compiler/compiler-init/amx.h b/sourcepawn/compiler/amx.h similarity index 100% rename from sourcepawn/compiler/compiler-init/amx.h rename to sourcepawn/compiler/amx.h diff --git a/sourcepawn/compiler/compiler-init/amxdbg.h b/sourcepawn/compiler/amxdbg.h similarity index 100% rename from sourcepawn/compiler/compiler-init/amxdbg.h rename to sourcepawn/compiler/amxdbg.h diff --git a/sourcepawn/compiler/compiler-init/libpawnc.c b/sourcepawn/compiler/libpawnc.c similarity index 100% rename from sourcepawn/compiler/compiler-init/libpawnc.c rename to sourcepawn/compiler/libpawnc.c diff --git a/sourcepawn/compiler/compiler-init/libpawnc.rc b/sourcepawn/compiler/libpawnc.rc similarity index 100% rename from sourcepawn/compiler/compiler-init/libpawnc.rc rename to sourcepawn/compiler/libpawnc.rc diff --git a/sourcepawn/compiler/compiler-init/lstring.c b/sourcepawn/compiler/lstring.c similarity index 100% rename from sourcepawn/compiler/compiler-init/lstring.c rename to sourcepawn/compiler/lstring.c diff --git a/sourcepawn/compiler/compiler-init/lstring.h b/sourcepawn/compiler/lstring.h similarity index 100% rename from sourcepawn/compiler/compiler-init/lstring.h rename to sourcepawn/compiler/lstring.h diff --git a/sourcepawn/compiler/compiler-init/memfile.c b/sourcepawn/compiler/memfile.c similarity index 100% rename from sourcepawn/compiler/compiler-init/memfile.c rename to sourcepawn/compiler/memfile.c diff --git a/sourcepawn/compiler/compiler-init/memfile.h b/sourcepawn/compiler/memfile.h similarity index 100% rename from sourcepawn/compiler/compiler-init/memfile.h rename to sourcepawn/compiler/memfile.h diff --git a/sourcepawn/compiler/compiler-init/osdefs.h b/sourcepawn/compiler/osdefs.h similarity index 100% rename from sourcepawn/compiler/compiler-init/osdefs.h rename to sourcepawn/compiler/osdefs.h diff --git a/sourcepawn/compiler/compiler-init/pawn.ico b/sourcepawn/compiler/pawn.ico similarity index 100% rename from sourcepawn/compiler/compiler-init/pawn.ico rename to sourcepawn/compiler/pawn.ico diff --git a/sourcepawn/compiler/compiler-init/pawncc.c b/sourcepawn/compiler/pawncc.c similarity index 100% rename from sourcepawn/compiler/compiler-init/pawncc.c rename to sourcepawn/compiler/pawncc.c diff --git a/sourcepawn/compiler/compiler-init/sc.h b/sourcepawn/compiler/sc.h similarity index 100% rename from sourcepawn/compiler/compiler-init/sc.h rename to sourcepawn/compiler/sc.h diff --git a/sourcepawn/compiler/compiler-init/sc1.c b/sourcepawn/compiler/sc1.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc1.c rename to sourcepawn/compiler/sc1.c diff --git a/sourcepawn/compiler/compiler-init/sc2.c b/sourcepawn/compiler/sc2.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc2.c rename to sourcepawn/compiler/sc2.c diff --git a/sourcepawn/compiler/compiler-init/sc3.c b/sourcepawn/compiler/sc3.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc3.c rename to sourcepawn/compiler/sc3.c diff --git a/sourcepawn/compiler/compiler-init/sc4.c b/sourcepawn/compiler/sc4.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc4.c rename to sourcepawn/compiler/sc4.c diff --git a/sourcepawn/compiler/compiler-init/sc5.c b/sourcepawn/compiler/sc5.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc5.c rename to sourcepawn/compiler/sc5.c diff --git a/sourcepawn/compiler/compiler-init/sc5.scp b/sourcepawn/compiler/sc5.scp similarity index 100% rename from sourcepawn/compiler/compiler-init/sc5.scp rename to sourcepawn/compiler/sc5.scp diff --git a/sourcepawn/compiler/compiler-init/sc6.c b/sourcepawn/compiler/sc6.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc6.c rename to sourcepawn/compiler/sc6.c diff --git a/sourcepawn/compiler/compiler-init/sc7.c b/sourcepawn/compiler/sc7.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sc7.c rename to sourcepawn/compiler/sc7.c diff --git a/sourcepawn/compiler/compiler-init/sc7.scp b/sourcepawn/compiler/sc7.scp similarity index 100% rename from sourcepawn/compiler/compiler-init/sc7.scp rename to sourcepawn/compiler/sc7.scp diff --git a/sourcepawn/compiler/compiler-init/scexpand.c b/sourcepawn/compiler/scexpand.c similarity index 100% rename from sourcepawn/compiler/compiler-init/scexpand.c rename to sourcepawn/compiler/scexpand.c diff --git a/sourcepawn/compiler/compiler-init/sci18n.c b/sourcepawn/compiler/sci18n.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sci18n.c rename to sourcepawn/compiler/sci18n.c diff --git a/sourcepawn/compiler/compiler-init/sclist.c b/sourcepawn/compiler/sclist.c similarity index 100% rename from sourcepawn/compiler/compiler-init/sclist.c rename to sourcepawn/compiler/sclist.c diff --git a/sourcepawn/compiler/compiler-init/scmemfil.c b/sourcepawn/compiler/scmemfil.c similarity index 100% rename from sourcepawn/compiler/compiler-init/scmemfil.c rename to sourcepawn/compiler/scmemfil.c diff --git a/sourcepawn/compiler/compiler-init/scstate.c b/sourcepawn/compiler/scstate.c similarity index 100% rename from sourcepawn/compiler/compiler-init/scstate.c rename to sourcepawn/compiler/scstate.c diff --git a/sourcepawn/compiler/compiler-init/scvars.c b/sourcepawn/compiler/scvars.c similarity index 100% rename from sourcepawn/compiler/compiler-init/scvars.c rename to sourcepawn/compiler/scvars.c diff --git a/sourcepawn/compiler/compiler-init/sp_file.h b/sourcepawn/compiler/sp_file.h similarity index 100% rename from sourcepawn/compiler/compiler-init/sp_file.h rename to sourcepawn/compiler/sp_file.h diff --git a/sourcepawn/compiler/compiler-init/spcomp.sln b/sourcepawn/compiler/spcomp.sln similarity index 100% rename from sourcepawn/compiler/compiler-init/spcomp.sln rename to sourcepawn/compiler/spcomp.sln diff --git a/sourcepawn/compiler/compiler-init/spcomp.vcproj b/sourcepawn/compiler/spcomp.vcproj similarity index 100% rename from sourcepawn/compiler/compiler-init/spcomp.vcproj rename to sourcepawn/compiler/spcomp.vcproj diff --git a/sourcepawn/compiler/compiler-init/svnrev.h b/sourcepawn/compiler/svnrev.h similarity index 100% rename from sourcepawn/compiler/compiler-init/svnrev.h rename to sourcepawn/compiler/svnrev.h diff --git a/sourcepawn/compiler/compiler-init/zlib/adler32.c b/sourcepawn/compiler/zlib/adler32.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/adler32.c rename to sourcepawn/compiler/zlib/adler32.c diff --git a/sourcepawn/compiler/compiler-init/zlib/compress.c b/sourcepawn/compiler/zlib/compress.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/compress.c rename to sourcepawn/compiler/zlib/compress.c diff --git a/sourcepawn/compiler/compiler-init/zlib/crc32.c b/sourcepawn/compiler/zlib/crc32.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/crc32.c rename to sourcepawn/compiler/zlib/crc32.c diff --git a/sourcepawn/compiler/compiler-init/zlib/crc32.h b/sourcepawn/compiler/zlib/crc32.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/crc32.h rename to sourcepawn/compiler/zlib/crc32.h diff --git a/sourcepawn/compiler/compiler-init/zlib/deflate.c b/sourcepawn/compiler/zlib/deflate.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/deflate.c rename to sourcepawn/compiler/zlib/deflate.c diff --git a/sourcepawn/compiler/compiler-init/zlib/deflate.h b/sourcepawn/compiler/zlib/deflate.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/deflate.h rename to sourcepawn/compiler/zlib/deflate.h diff --git a/sourcepawn/compiler/compiler-init/zlib/gzio.c b/sourcepawn/compiler/zlib/gzio.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/gzio.c rename to sourcepawn/compiler/zlib/gzio.c diff --git a/sourcepawn/compiler/compiler-init/zlib/infback.c b/sourcepawn/compiler/zlib/infback.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/infback.c rename to sourcepawn/compiler/zlib/infback.c diff --git a/sourcepawn/compiler/compiler-init/zlib/inffast.c b/sourcepawn/compiler/zlib/inffast.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inffast.c rename to sourcepawn/compiler/zlib/inffast.c diff --git a/sourcepawn/compiler/compiler-init/zlib/inffast.h b/sourcepawn/compiler/zlib/inffast.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inffast.h rename to sourcepawn/compiler/zlib/inffast.h diff --git a/sourcepawn/compiler/compiler-init/zlib/inffixed.h b/sourcepawn/compiler/zlib/inffixed.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inffixed.h rename to sourcepawn/compiler/zlib/inffixed.h diff --git a/sourcepawn/compiler/compiler-init/zlib/inflate.c b/sourcepawn/compiler/zlib/inflate.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inflate.c rename to sourcepawn/compiler/zlib/inflate.c diff --git a/sourcepawn/compiler/compiler-init/zlib/inflate.h b/sourcepawn/compiler/zlib/inflate.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inflate.h rename to sourcepawn/compiler/zlib/inflate.h diff --git a/sourcepawn/compiler/compiler-init/zlib/inftrees.c b/sourcepawn/compiler/zlib/inftrees.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inftrees.c rename to sourcepawn/compiler/zlib/inftrees.c diff --git a/sourcepawn/compiler/compiler-init/zlib/inftrees.h b/sourcepawn/compiler/zlib/inftrees.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/inftrees.h rename to sourcepawn/compiler/zlib/inftrees.h diff --git a/sourcepawn/compiler/compiler-init/zlib/trees.c b/sourcepawn/compiler/zlib/trees.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/trees.c rename to sourcepawn/compiler/zlib/trees.c diff --git a/sourcepawn/compiler/compiler-init/zlib/trees.h b/sourcepawn/compiler/zlib/trees.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/trees.h rename to sourcepawn/compiler/zlib/trees.h diff --git a/sourcepawn/compiler/compiler-init/zlib/uncompr.c b/sourcepawn/compiler/zlib/uncompr.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/uncompr.c rename to sourcepawn/compiler/zlib/uncompr.c diff --git a/sourcepawn/compiler/compiler-init/zlib/zconf.h b/sourcepawn/compiler/zlib/zconf.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/zconf.h rename to sourcepawn/compiler/zlib/zconf.h diff --git a/sourcepawn/compiler/compiler-init/zlib/zlib.h b/sourcepawn/compiler/zlib/zlib.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/zlib.h rename to sourcepawn/compiler/zlib/zlib.h diff --git a/sourcepawn/compiler/compiler-init/zlib/zutil.c b/sourcepawn/compiler/zlib/zutil.c similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/zutil.c rename to sourcepawn/compiler/zlib/zutil.c diff --git a/sourcepawn/compiler/compiler-init/zlib/zutil.h b/sourcepawn/compiler/zlib/zutil.h similarity index 100% rename from sourcepawn/compiler/compiler-init/zlib/zutil.h rename to sourcepawn/compiler/zlib/zutil.h From b712d61b472e587a97c2f790ec49c13aaceedfe2 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 15 Jul 2006 19:23:07 +0000 Subject: [PATCH 0003/1664] improved error output for arrays using decl --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4032 --- sourcepawn/compiler/sc1.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 27ce05dc..0a8e88b3 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2339,8 +2339,11 @@ static cell initvector(int ident,int tag,cell size,int fillzero, } while (matchtoken(',')); /* do */ needtoken('}'); } else { - if (hadtoken && !autozero) + if (hadtoken && !autozero) { error(10); + lexclr(TRUE); /* drop the rest of the line */ + return 0; + } init(ident,&ctag,errorfound); if (!matchtag(tag,ctag,TRUE)) error(213); /* tagname mismatch */ From 66f7568ce72854bd661cdc80253d26b864ab92c9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 19 Jul 2006 00:53:26 +0000 Subject: [PATCH 0004/1664] added binary writer stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4033 --- sourcepawn/compiler/amx.h | 92 ++++++------ sourcepawn/compiler/pawncc.c | 193 ++++++++++--------------- sourcepawn/compiler/scmemfil.c | 15 -- sourcepawn/compiler/sp_file.c | 224 ++++++++++++++++++++++++++++++ sourcepawn/compiler/sp_file.h | 160 +++++++++------------ sourcepawn/compiler/spcomp.vcproj | 12 ++ 6 files changed, 419 insertions(+), 277 deletions(-) create mode 100644 sourcepawn/compiler/sp_file.c diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index ca25a0da..3d497a0f 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -206,9 +206,9 @@ typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX #endif #if defined __GNUC__ - #define PACKED __attribute__((packed)) + #define PACKEDENTRY __attribute__((packed)) #else - #define PACKED + #define PACKEDENTRY #endif #if !defined AMX_NO_ALIGN @@ -226,8 +226,8 @@ typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX #endif typedef struct tagAMX_NATIVE_INFO { - const char _FAR *name PACKED; - AMX_NATIVE func PACKED; + const char _FAR *name PACKEDENTRY; + AMX_NATIVE func PACKEDENTRY; } AMX_NATIVE_INFO; #define AMX_USERNUM 4 @@ -235,48 +235,48 @@ typedef struct tagAMX_NATIVE_INFO { #define sNAMEMAX 31 /* maximum name length of symbol name */ typedef struct tagAMX_FUNCSTUB { - ucell address PACKED; - char name[sEXPMAX+1] PACKED; + ucell address PACKEDENTRY; + char name[sEXPMAX+1] PACKEDENTRY; } AMX_FUNCSTUB; typedef struct tagFUNCSTUBNT { - ucell address PACKED; - uint32_t nameofs PACKED; + ucell address PACKEDENTRY; + uint32_t nameofs PACKEDENTRY; } AMX_FUNCSTUBNT; /* The AMX structure is the internal structure for many functions. Not all * fields are valid at all times; many fields are cached in local variables. */ typedef struct tagAMX { - unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */ - unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */ - AMX_CALLBACK callback PACKED; - AMX_DEBUG debug PACKED; /* debug callback */ + unsigned char _FAR *base PACKEDENTRY; /* points to the AMX header plus the code, optionally also the data */ + unsigned char _FAR *data PACKEDENTRY; /* points to separate data+stack+heap, may be NULL */ + AMX_CALLBACK callback PACKEDENTRY; + AMX_DEBUG debug PACKEDENTRY; /* debug callback */ /* for external functions a few registers must be accessible from the outside */ - cell cip PACKED; /* instruction pointer: relative to base + amxhdr->cod */ - cell frm PACKED; /* stack frame base: relative to base + amxhdr->dat */ - cell hea PACKED; /* top of the heap: relative to base + amxhdr->dat */ - cell hlw PACKED; /* bottom of the heap: relative to base + amxhdr->dat */ - cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */ - cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */ - int flags PACKED; /* current status, see amx_Flags() */ + cell cip PACKEDENTRY; /* instruction pointer: relative to base + amxhdr->cod */ + cell frm PACKEDENTRY; /* stack frame base: relative to base + amxhdr->dat */ + cell hea PACKEDENTRY; /* top of the heap: relative to base + amxhdr->dat */ + cell hlw PACKEDENTRY; /* bottom of the heap: relative to base + amxhdr->dat */ + cell stk PACKEDENTRY; /* stack pointer: relative to base + amxhdr->dat */ + cell stp PACKEDENTRY; /* top of the stack: relative to base + amxhdr->dat */ + int flags PACKEDENTRY; /* current status, see amx_Flags() */ /* user data */ - long usertags[AMX_USERNUM] PACKED; - void _FAR *userdata[AMX_USERNUM] PACKED; + long usertags[AMX_USERNUM] PACKEDENTRY; + void _FAR *userdata[AMX_USERNUM] PACKEDENTRY; /* native functions can raise an error */ - int error PACKED; + int error PACKEDENTRY; /* passing parameters requires a "count" field */ int paramcount; /* the sleep opcode needs to store the full AMX status */ - cell pri PACKED; - cell alt PACKED; - cell reset_stk PACKED; - cell reset_hea PACKED; - cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */ + cell pri PACKEDENTRY; + cell alt PACKEDENTRY; + cell reset_stk PACKEDENTRY; + cell reset_hea PACKEDENTRY; + cell sysreq_d PACKEDENTRY; /* relocated address/value for the SYSREQ.D opcode */ #if defined JIT /* support variables for the JIT */ - int reloc_size PACKED; /* required temporary buffer for relocations */ - long code_size PACKED; /* estimated memory footprint of the native code */ + int reloc_size PACKEDENTRY; /* required temporary buffer for relocations */ + long code_size PACKEDENTRY; /* estimated memory footprint of the native code */ #endif } AMX; @@ -284,23 +284,23 @@ typedef struct tagAMX { * structure is used internaly. */ typedef struct tagAMX_HEADER { - int32_t size PACKED; /* size of the "file" */ - uint16_t magic PACKED; /* signature */ - char file_version PACKED; /* file format version */ - char amx_version PACKED; /* required version of the AMX */ - int16_t flags PACKED; - int16_t defsize PACKED; /* size of a definition record */ - int32_t cod PACKED; /* initial value of COD - code block */ - int32_t dat PACKED; /* initial value of DAT - data block */ - int32_t hea PACKED; /* initial value of HEA - start of the heap */ - int32_t stp PACKED; /* initial value of STP - stack top */ - int32_t cip PACKED; /* initial value of CIP - the instruction pointer */ - int32_t publics PACKED; /* offset to the "public functions" table */ - int32_t natives PACKED; /* offset to the "native functions" table */ - int32_t libraries PACKED; /* offset to the table of libraries */ - int32_t pubvars PACKED; /* the "public variables" table */ - int32_t tags PACKED; /* the "public tagnames" table */ - int32_t nametable PACKED; /* name table */ + int32_t size PACKEDENTRY; /* size of the "file" */ + uint16_t magic PACKEDENTRY; /* signature */ + char file_version PACKEDENTRY; /* file format version */ + char amx_version PACKEDENTRY; /* required version of the AMX */ + int16_t flags PACKEDENTRY; + int16_t defsize PACKEDENTRY; /* size of a definition record */ + int32_t cod PACKEDENTRY; /* initial value of COD - code block */ + int32_t dat PACKEDENTRY; /* initial value of DAT - data block */ + int32_t hea PACKEDENTRY; /* initial value of HEA - start of the heap */ + int32_t stp PACKEDENTRY; /* initial value of STP - stack top */ + int32_t cip PACKEDENTRY; /* initial value of CIP - the instruction pointer */ + int32_t publics PACKEDENTRY; /* offset to the "public functions" table */ + int32_t natives PACKEDENTRY; /* offset to the "native functions" table */ + int32_t libraries PACKEDENTRY; /* offset to the table of libraries */ + int32_t pubvars PACKEDENTRY; /* the "public variables" table */ + int32_t tags PACKEDENTRY; /* the "public tagnames" table */ + int32_t nametable PACKEDENTRY; /* name table */ } AMX_HEADER; #if PAWN_CELL_SIZE==16 diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index 2db16e1f..8da3e2e6 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -8,11 +8,27 @@ #include "osdefs.h" #include "zlib/zlib.h" -#define NUM_SECTIONS 6 +enum FileSections +{ + FS_Code, /* required */ + FS_Data, /* required */ + FS_Publics, + FS_Pubvars, + FS_Natives, + FS_Nametable, /* required */ + FS_DbgFile, + FS_DbgSymbol, + FS_DbgLine, + FS_DbgTags, + FS_DbgAutomaton, + FS_DbgState, + /* --- */ + FS_Number, +}; int pc_printf(const char *message,...); int pc_compile(int argc, char **argv); -void sfwrite(const void *buf, size_t size, size_t count, FILE *fp); +void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf); memfile_t *bin_file = NULL; jmp_buf brkout; @@ -21,17 +37,11 @@ int main(int argc, char *argv[]) { if (pc_compile(argc,argv) == 0) { - FILE *fp; AMX_HEADER *hdr; - sp_file_hdr_t shdr; - uint32_t curoffs = 0; - uint32_t lastsection = 0; int err; - uint8_t i8; uint32_t i; - const char *tables[NUM_SECTIONS] = {".code", ".data", ".publics", ".pubvars", ".natives", ".names"}; - uint32_t offsets[NUM_SECTIONS] = {0,0,0,0,0,0}; - sp_file_section_t sh; + sp_file_t *spf; + uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0}; if (bin_file == NULL) { @@ -39,13 +49,12 @@ int main(int argc, char *argv[]) } hdr = (AMX_HEADER *)bin_file->base; - shdr.version = SPFILE_VERSION; - shdr.magic = SPFILE_MAGIC; - if ((fp=fopen(bin_file->name, "wb")) == NULL) + if ((spf=spfw_create(bin_file->name, NULL)) == NULL) { - pc_printf("Error writing to file: %s", bin_file->name); - return 1; + pc_printf("Error creating binary file!\n"); + memfile_destroy(bin_file); + return 0; } if ((err=setjmp(brkout))!=0) @@ -53,48 +62,34 @@ int main(int argc, char *argv[]) goto write_error; } - shdr.sections = NUM_SECTIONS; - shdr.stringtab = sizeof(shdr) + (sizeof(sp_file_section_t) * shdr.sections); + spfw_add_section(spf, ".code"); + spfw_add_section(spf, ".data"); - /** - * write the header - * unwritten values: - * imagesize - */ - sfwrite(&shdr, sizeof(shdr), 1, fp); - - curoffs = shdr.stringtab; - - /** - * write the sections - * unwritten values: - * dataoffs - * size - */ - for (i8=0; i8natives - hdr->publics) / hdr->defsize; + if (sections[FS_Publics]) { - /* set name offset to next in string table */ - sh.nameoffs = curoffs - shdr.stringtab; - /* save offset to this section */ - offsets[i8] = (uint32_t)ftell(fp) + sizeof(sh.nameoffs); - /* update `end of file` offset */ - curoffs += strlen(tables[i8]) + 1; - sfwrite(&sh, sizeof(sh), 1, fp); + spfw_add_section(spf, ".publics"); + } + sections[FS_Pubvars] = (hdr->tags - hdr->pubvars) / hdr->defsize; + if (sections[FS_Pubvars]) + { + spfw_add_section(spf, ".pubvars"); + } + sections[FS_Natives] = (hdr->libraries - hdr->natives) / hdr->defsize; + if (sections[FS_Natives]) + { + spfw_add_section(spf, ".natives"); } - /** write the string table */ - for (i8=0; i8natives - hdr->publics) / hdr->defsize; + uint32_t publics = sections[FS_Publics]; pbtbl = (sp_file_publics_t *)malloc(sizeof(sp_file_publics_t) * publics); stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->publics); @@ -423,25 +404,18 @@ int main(int argc, char *argv[]) } if (publics) { - sfwrite(pbtbl, sizeof(sp_file_publics_t), publics, fp); + sfwrite(pbtbl, sizeof(sp_file_publics_t), publics, spf); } free(pbtbl); - /* backtrack and write section's header info */ - curoffs = ftell(fp); - fseek(fp, offsets[2], SEEK_SET); - sfwrite(&lastsection, sizeof(uint32_t), 1, fp); - publics *= sizeof(sp_file_publics_t); - sfwrite(&publics, sizeof(uint32_t), 1, fp); - fseek(fp, curoffs, SEEK_SET); - lastsection = curoffs; + spfw_next_section(spf); } - if (strcmp(tables[3], ".pubvars") == 0) + if (sections[FS_Pubvars]) { sp_file_pubvars_t *pbvars; AMX_FUNCSTUBNT *stub; - uint32_t pubvars = (hdr->tags - hdr->pubvars) / hdr->defsize; + uint32_t pubvars = sections[FS_Pubvars]; pbvars = (sp_file_pubvars_t *)malloc(sizeof(sp_file_pubvars_t) * pubvars); stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->pubvars); @@ -455,21 +429,13 @@ int main(int argc, char *argv[]) } if (pubvars) { - sfwrite(pbvars, sizeof(sp_file_pubvars_t), pubvars, fp); + sfwrite(pbvars, sizeof(sp_file_pubvars_t), pubvars, spf); } free(pbvars); - - /* backtrack and write section's header info */ - curoffs = ftell(fp); - fseek(fp, offsets[3], SEEK_SET); - sfwrite(&lastsection, sizeof(uint32_t), 1, fp); - pubvars *= sizeof(sp_file_pubvars_t); - sfwrite(&pubvars, sizeof(uint32_t), 1, fp); - fseek(fp, curoffs, SEEK_SET); - lastsection = curoffs; + spfw_next_section(spf); } - if (strcmp(tables[4], ".natives") == 0) + if (sections[FS_Natives]) { sp_file_natives_t *nvtbl; AMX_FUNCSTUBNT *stub; @@ -486,21 +452,13 @@ int main(int argc, char *argv[]) } if (natives) { - sfwrite(nvtbl, sizeof(sp_file_natives_t), natives, fp); + sfwrite(nvtbl, sizeof(sp_file_natives_t), natives, spf); } free(nvtbl); - - /* backtrack and write header */ - curoffs = ftell(fp); - fseek(fp, offsets[4], SEEK_SET); - sfwrite(&lastsection, sizeof(uint32_t), 1, fp); - natives *= sizeof(sp_file_natives_t); - sfwrite(&natives, sizeof(uint32_t), 1, fp); - fseek(fp, curoffs, SEEK_SET); - lastsection = curoffs; + spfw_next_section(spf); } - if (strcmp(tables[5], ".names") == 0) + if (sections[FS_Nametable]) { unsigned char *base; uint32_t namelen; @@ -512,25 +470,18 @@ int main(int argc, char *argv[]) * this may clip at most an extra three bytes in! */ namelen = hdr->cod - hdr->nametable; - sfwrite(base, namelen, 1, fp); - - /* backtrack and write header */ - curoffs = ftell(fp); - fseek(fp, offsets[5], SEEK_SET); - sfwrite(&lastsection, sizeof(uint32_t), 1, fp); - sfwrite(&namelen, sizeof(uint32_t), 1, fp); - fseek(fp, curoffs, SEEK_SET); - lastsection = curoffs; + sfwrite(base, namelen, 1, spf); + spfw_next_section(spf); } - fclose(fp); + spfw_finalize_all(spf); + spfw_destroy(spf); return 0; write_error: pc_printf("Error writing to file: %s", bin_file->name); unlink(bin_file->name); - fclose(fp); memfile_destroy(bin_file); bin_file = NULL; @@ -541,9 +492,9 @@ write_error: return 1; } -void sfwrite(const void *buf, size_t size, size_t count, FILE *fp) +void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf) { - if (fwrite(buf, size, count, fp) != count) + if (spf->funcs.fnWrite(buf, size, count, spf->handle) != count) { longjmp(brkout, 1); } diff --git a/sourcepawn/compiler/scmemfil.c b/sourcepawn/compiler/scmemfil.c index 73a76c63..4924e71d 100644 --- a/sourcepawn/compiler/scmemfil.c +++ b/sourcepawn/compiler/scmemfil.c @@ -31,26 +31,11 @@ #include #include "memfile.h" -#if defined FORTIFY - #include -#endif - - -#define BUFFERSIZE 512u - -/* For every block, except the first: - * buffer points to a block that is BUFFERSIZE long that holds the data - * bufpos is the "used size" of the block - * For the first block: - * buffer points to the "file name" - * bufpos is the current "file pointer" - */ typedef memfile_t MEMFILE; #define tMEMFILE 1 #include "sc.h" - MEMFILE *mfcreate(char *filename) { return memfile_creat(filename, 4096); diff --git a/sourcepawn/compiler/sp_file.c b/sourcepawn/compiler/sp_file.c new file mode 100644 index 00000000..21f2980e --- /dev/null +++ b/sourcepawn/compiler/sp_file.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include "sp_file.h" + +void *fp_open(const char *name); +void fp_close(void *handle); +size_t fp_write(const void *buf, size_t size, size_t count, void *handle); +size_t fp_read(void *buf, size_t size, size_t count, void *handle); +size_t fp_getpos(void *handle); +int fp_setpos(void *handle, size_t pos); + +sp_writefuncs_t cstd_funcs = +{ + fp_open, + fp_close, + fp_write, + fp_read, + fp_getpos, + fp_setpos +}; + +sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs) +{ + sp_file_t file; + sp_file_t *pFile; + + if (!optfuncs) + { + optfuncs = &cstd_funcs; + } + + file.handle = optfuncs->fnOpen(name); + if (!file.handle) + { + return NULL; + } + + pFile = (sp_file_t *)malloc(sizeof(sp_file_t)); + + pFile->handle = file.handle; + memcpy(&pFile->funcs, optfuncs, sizeof(sp_writefuncs_t)); + pFile->curoffs = 0; + pFile->header.magic = SPFILE_MAGIC; + pFile->header.sections = 0; + pFile->header.stringtab = 0; + pFile->header.version = SPFILE_VERSION; + pFile->header.imagesize = 0; + pFile->lastsection = 0; + pFile->offsets = NULL; + pFile->sections = NULL; + pFile->state = -1; + pFile->nametab = NULL; + pFile->nametab_idx = 0; + + return pFile; +} + +void spfw_destroy(sp_file_t *spf) +{ + free(spf->sections); + free(spf->nametab); + free(spf->offsets); + spf->funcs.fnClose(spf->handle); + free(spf); +} + +uint8_t spfw_add_section(sp_file_t *spf, const char *name) +{ + size_t namelen; + uint8_t s; + if (spf->state != -1) + { + return 0; + } + + namelen = strlen(name) + 1; + + if (spf->header.sections == 0) + { + /** allocate for first section */ + spf->sections = (sp_file_section_t *)malloc(sizeof(sp_file_section_t)); + spf->offsets = (size_t *)malloc(sizeof(size_t)); + spf->nametab = (char *)malloc(namelen); + } else { + uint16_t num = spf->header.sections + 1; + spf->sections = (sp_file_section_t *)realloc(spf->sections, sizeof(sp_file_section_t) * num); + spf->offsets = (size_t *)realloc(spf->offsets, sizeof(size_t) * num); + spf->nametab = (char *)realloc(spf->nametab, spf->nametab_idx + namelen); + } + + s = spf->header.sections; + + spf->sections[s].nameoffs = spf->nametab_idx; + /** + * "fix" offset will be the second uint2 slot, which is after the previous sections after the header. + */ + spf->offsets[s] = sizeof(spf->header) + (sizeof(sp_file_section_t) * spf->header.sections) + sizeof(uint32_t); + strcpy(&spf->nametab[spf->nametab_idx], name); + spf->nametab_idx += namelen; + + return ++spf->header.sections; +} + +int spfw_finalize_header(sp_file_t *spf) +{ + uint32_t size; + if (spf->state != -1) + { + return -1; + } + + size = sizeof(sp_file_section_t) * spf->header.sections; + + spf->header.stringtab = sizeof(spf->header) + size; + if (spf->funcs.fnWrite(&spf->header, sizeof(spf->header), 1, spf->handle) != 1) + { + return -1; + } + if (spf->funcs.fnWrite(spf->sections, sizeof(sp_file_section_t), spf->header.sections, spf->handle) != + spf->header.sections) + { + return -1; + } + if (spf->funcs.fnWrite(spf->nametab, sizeof(char), spf->nametab_idx, spf->handle) != spf->nametab_idx) + { + return -1; + } + spf->curoffs = spf->funcs.fnGetPos(spf->handle); + spf->lastsection = spf->curoffs; + spf->state++; + + return 0; +} + +int spfw_next_section(sp_file_t *spf) +{ + uint8_t s; + uint32_t rest[2]; + + if (spf->state < 0 || spf->state > spf->header.sections) + { + return -1; + } + + if (spf->state == (int)spf->header.sections) + { + return 0; + } + + s = (uint8_t)spf->state; + + spf->curoffs = spf->funcs.fnGetPos(spf->handle); + spf->funcs.fnSetPos(spf->handle, spf->offsets[s]); + + rest[0] = spf->lastsection; + rest[1] = spf->curoffs - spf->lastsection; + if (spf->funcs.fnWrite(rest, sizeof(uint32_t), 2, spf->handle) != 2) + { + return -1; + } + + spf->funcs.fnSetPos(spf->handle, spf->curoffs); + spf->lastsection = spf->curoffs; + + spf->state++; + + return 1; +} + +int spfw_finalize_all(sp_file_t *spf) +{ + uint8_t offs; + + if (spf->state < spf->header.sections) + { + return -1; + } + + offs = offsetof(sp_file_hdr_t, imagesize); + spf->header.imagesize = spf->funcs.fnGetPos(spf->handle); + spf->funcs.fnSetPos(spf->handle, offs); + spf->funcs.fnWrite(&spf->header.imagesize, sizeof(uint32_t), 1, spf->handle); + spf->funcs.fnSetPos(spf->handle, spf->header.imagesize); + + return 1; +} + +/** + * Default file operations... + * Based on C standard library calls. + */ + +void *fp_open(const char *name) +{ + return fopen(name, "wb"); +} + +void fp_close(void *handle) +{ + fclose((FILE *)handle); +} + +size_t fp_write(const void *buf, size_t size, size_t count, void *handle) +{ + return fwrite(buf, size, count, (FILE *)handle); +} + +size_t fp_read(void *buf, size_t size, size_t count, void *handle) +{ + return fread(buf, size, count, (FILE *)handle); +} + +size_t fp_getpos(void *handle) +{ + return (size_t)ftell((FILE *)handle); +} + +int fp_setpos(void *handle, size_t pos) +{ + return fseek((FILE *)handle, (long)pos, SEEK_SET); +} + + diff --git a/sourcepawn/compiler/sp_file.h b/sourcepawn/compiler/sp_file.h index b0aeb2c3..41ff70a9 100644 --- a/sourcepawn/compiler/sp_file.h +++ b/sourcepawn/compiler/sp_file.h @@ -1,110 +1,80 @@ #ifndef _INCLUDE_SPFILE_H #define _INCLUDE_SPFILE_H -#include -#if defined __GNUC__ || defined HAVE_STDINT_ -#include -#else - #if !defined HAVE_STDINT_H - typedef unsigned __int64 uint64_t; - typedef __int64 int64_t; - typedef unsigned __int32 uint32_t; - typedef __int32 int32_t; - typedef unsigned __int16 uint16_t; - typedef __int16 int16_t; - typedef unsigned __int8 uint8_t; - typedef __int8 int8_t; - #define HAVE_STDINT_H - #endif -#endif +#include "sp_file_headers.h" -#define SPFILE_MAGIC 0xDEADC0D3 -#define SPFILE_VERSION 0x0100 - -//:TODO: better compiler/nix support -#if defined __linux__ - #pragma pack(1) /* structures must be packed (byte-aligned) */ -#else - #pragma pack(push) - #pragma pack(1) /* structures must be packed (byte-aligned) */ -#endif - -typedef struct sp_file_section_s +/** + * Used for overwriting writing routines. + */ +typedef struct sp_writefuncs_s { - uint32_t nameoffs; /* rel offset into global string table */ - uint32_t dataoffs; - uint32_t size; -} sp_file_section_t; + void *(*fnOpen)(const char *); /* filename, returns handle */ + void (*fnClose)(void *); /* handle */ + /* buffer, size, count, handle, returns count written */ + size_t (*fnWrite)(const void *, size_t, size_t, void *); + /* buffer, size, count, handle, returns count read */ + size_t (*fnRead)(void *, size_t, size_t, void *); + /* returns current position from start */ + size_t (*fnGetPos)(void *); + /* sets current position from start, return 0 for success, nonzero for error */ + int (*fnSetPos)(void *, size_t); +} sp_writefuncs_t; -typedef struct sp_file_hdr_s +typedef struct sp_file_s { - uint32_t magic; - uint16_t version; - uint32_t imagesize; - uint8_t sections; - uint32_t stringtab; -} sp_file_hdr_t; + sp_file_hdr_t header; + sp_file_section_t *sections; + size_t *offsets; + sp_writefuncs_t funcs; + size_t lastsection; + size_t curoffs; + void *handle; + int state; + char *nametab; + size_t nametab_idx; +} sp_file_t; -typedef enum -{ - SP_FILE_NONE = 0, - SP_FILE_DEBUG = 1, -} sp_file_flags_t; +/** + * Creates a new SourcePawn binary file. + * You may optionally specify alternative writing functions. + */ +sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs); -/* section is ".code" */ -typedef struct sp_file_code_s -{ - uint32_t codesize; /* codesize in bytes */ - uint8_t cellsize; /* cellsize in bytes */ - uint8_t codeversion; /* version of opcodes supported */ - uint16_t flags; /* flags */ - uint32_t main; /* address to "main" if any */ - uint32_t disksize; /* disksize in bytes */ - uint32_t compression; /* compression */ - uint32_t code; /* rel offset to code */ -} sp_file_code_t; +/** + * Closes file handle and frees memory. + */ +void spfw_destroy(sp_file_t *spf); -#define SPFILE_COMPRESSION_NONE 0 -#define SPFILE_COMPRESSION_GZ 1 +/** + * Adds a section name to the header. + * Only valid BEFORE finalization. + * Returns the number of sections, or 0 on failure. + */ +uint8_t spfw_add_section(sp_file_t *spf, const char *name); -/* section is .data */ -typedef struct sp_file_data_s -{ - uint32_t datasize; /* size of data section in memory */ - uint32_t memsize; /* total mem required (includes data) */ - uint32_t disksize; /* size of data on disk (compressed) */ - uint8_t compression; /* compression */ - uint32_t data; /* file offset to data (helper) */ -} sp_file_data_t; +/** + * Finalizes the section header. + * This means no more sections can be added after this call. + * Also, aligns the writer to the first section. + * Returns 0 on success, nonzero on error. + */ +int spfw_finalize_header(sp_file_t *spf); -/* section is .publics */ -typedef struct sp_file_publics_s -{ - uint32_t address; /* address rel to code section */ - uint32_t name; /* index into nametable */ -} sp_file_publics_t; +/** + * Finalizes the current section and advances to the next. + * In order for this to be accurate, the file pointer must + * reside at the end before calling this, because the size + * is calculated by differencing with the last known offset. + * Returns 1 if there are more sections left, 0 otherwise. + * Returns -1 if the file state is wrong. + */ +int spfw_next_section(sp_file_t *spf); -/* section is .natives */ -typedef struct sp_file_natives_s -{ - uint32_t name; /* name of native at index */ -} sp_file_natives_t; - -/* section is .pubvars */ -typedef struct sp_file_pubvars_s -{ - uint32_t address; /* address rel to dat section */ - uint32_t name; /* index into nametable */ -} sp_file_pubvars_t; - -#if defined __linux__ - #pragma pack() /* reset default packing */ -#else - #pragma pack(pop) /* reset previous packing */ -#endif - - -/* section is .names */ -typedef char * sp_file_nametab_t; +/** + * Finalizes all sections. + * Cannot be called until all sections are used. + * Must be called with the file pointer at the end. + */ +int spfw_finalize_all(sp_file_t *spf); #endif //_INCLUDE_SPFILE_H diff --git a/sourcepawn/compiler/spcomp.vcproj b/sourcepawn/compiler/spcomp.vcproj index db52d001..44d6c891 100644 --- a/sourcepawn/compiler/spcomp.vcproj +++ b/sourcepawn/compiler/spcomp.vcproj @@ -250,6 +250,10 @@ RelativePath=".\scvars.c" > + + + + @@ -280,6 +288,10 @@ RelativePath=".\sp_file.h" > + + From 5414f803a809c34e9a506dc2a69da63cdc452eb2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 19 Jul 2006 00:53:57 +0000 Subject: [PATCH 0005/1664] didn't notice this guy because of the stupid icons not showing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4034 --- sourcepawn/compiler/sp_file_headers.h | 110 ++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 sourcepawn/compiler/sp_file_headers.h diff --git a/sourcepawn/compiler/sp_file_headers.h b/sourcepawn/compiler/sp_file_headers.h new file mode 100644 index 00000000..bb60aee8 --- /dev/null +++ b/sourcepawn/compiler/sp_file_headers.h @@ -0,0 +1,110 @@ +#ifndef _INCLUDE_SPFILE_HEADERS_H +#define _INCLUDE_SPFILE_HEADERS_H + +#include +#if defined __GNUC__ || defined HAVE_STDINT_ +#include +#else + #if !defined HAVE_STDINT_H + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned __int16 uint16_t; + typedef __int16 int16_t; + typedef unsigned __int8 uint8_t; + typedef __int8 int8_t; + #define HAVE_STDINT_H + #endif +#endif + +#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ +#define SPFILE_VERSION 0x0100 + +//:TODO: better compiler/nix support +#if defined __linux__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#endif + +typedef struct sp_file_section_s +{ + uint32_t nameoffs; /* rel offset into global string table */ + uint32_t dataoffs; + uint32_t size; +} sp_file_section_t; + +typedef struct sp_file_hdr_s +{ + uint32_t magic; + uint16_t version; + uint32_t imagesize; + uint8_t sections; + uint32_t stringtab; +} sp_file_hdr_t; + +typedef enum +{ + SP_FILE_NONE = 0, + SP_FILE_DEBUG = 1, +} sp_file_flags_t; + +/* section is ".code" */ +typedef struct sp_file_code_s +{ + uint32_t codesize; /* codesize in bytes */ + uint8_t cellsize; /* cellsize in bytes */ + uint8_t codeversion; /* version of opcodes supported */ + uint16_t flags; /* flags */ + uint32_t main; /* address to "main" if any */ + uint32_t disksize; /* disksize in bytes */ + uint8_t compression; /* compression */ + uint32_t code; /* rel offset to code */ +} sp_file_code_t; + +#define SPFILE_COMPRESSION_NONE 0 +#define SPFILE_COMPRESSION_GZ 1 + +/* section is .data */ +typedef struct sp_file_data_s +{ + uint32_t datasize; /* size of data section in memory */ + uint32_t memsize; /* total mem required (includes data) */ + uint32_t disksize; /* size of data on disk (compressed) */ + uint8_t compression; /* compression */ + uint32_t data; /* file offset to data (helper) */ +} sp_file_data_t; + +/* section is .publics */ +typedef struct sp_file_publics_s +{ + uint32_t address; /* address rel to code section */ + uint32_t name; /* index into nametable */ +} sp_file_publics_t; + +/* section is .natives */ +typedef struct sp_file_natives_s +{ + uint32_t name; /* name of native at index */ +} sp_file_natives_t; + +/* section is .pubvars */ +typedef struct sp_file_pubvars_s +{ + uint32_t address; /* address rel to dat section */ + uint32_t name; /* index into nametable */ +} sp_file_pubvars_t; + +#if defined __linux__ + #pragma pack() /* reset default packing */ +#else + #pragma pack(pop) /* reset previous packing */ +#endif + + +/* section is .names */ +typedef char * sp_file_nametab_t; + +#endif //_INCLUDE_SPFILE_HEADERS_H From 95351749a6ebea0102f29ebbd6c8fc728daf534a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 19 Jul 2006 09:58:18 +0000 Subject: [PATCH 0006/1664] added debug information output revised file format to make compression global --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4035 --- sourcepawn/compiler/amx.h | 94 +++++----- sourcepawn/compiler/amxdbg.h | 104 +++++------ sourcepawn/compiler/memfile.c | 13 +- sourcepawn/compiler/memfile.h | 34 +++- sourcepawn/compiler/pawncc.c | 254 +++++++++++++++++++++----- sourcepawn/compiler/sp_file.c | 80 ++++++-- sourcepawn/compiler/sp_file.h | 1 + sourcepawn/compiler/sp_file_headers.h | 66 +++++-- 8 files changed, 471 insertions(+), 175 deletions(-) diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 3d497a0f..6ba09a92 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -205,12 +205,6 @@ typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX #define AMX_NO_ALIGN #endif -#if defined __GNUC__ - #define PACKEDENTRY __attribute__((packed)) -#else - #define PACKEDENTRY -#endif - #if !defined AMX_NO_ALIGN #if defined LINUX || defined __FreeBSD__ #pragma pack(1) /* structures must be packed (byte-aligned) */ @@ -226,8 +220,8 @@ typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX #endif typedef struct tagAMX_NATIVE_INFO { - const char _FAR *name PACKEDENTRY; - AMX_NATIVE func PACKEDENTRY; + const char _FAR *name; + AMX_NATIVE func; } AMX_NATIVE_INFO; #define AMX_USERNUM 4 @@ -235,48 +229,48 @@ typedef struct tagAMX_NATIVE_INFO { #define sNAMEMAX 31 /* maximum name length of symbol name */ typedef struct tagAMX_FUNCSTUB { - ucell address PACKEDENTRY; - char name[sEXPMAX+1] PACKEDENTRY; + ucell address; + char name[sEXPMAX+1]; } AMX_FUNCSTUB; typedef struct tagFUNCSTUBNT { - ucell address PACKEDENTRY; - uint32_t nameofs PACKEDENTRY; + ucell address; + uint32_t nameofs; } AMX_FUNCSTUBNT; /* The AMX structure is the internal structure for many functions. Not all * fields are valid at all times; many fields are cached in local variables. */ typedef struct tagAMX { - unsigned char _FAR *base PACKEDENTRY; /* points to the AMX header plus the code, optionally also the data */ - unsigned char _FAR *data PACKEDENTRY; /* points to separate data+stack+heap, may be NULL */ - AMX_CALLBACK callback PACKEDENTRY; - AMX_DEBUG debug PACKEDENTRY; /* debug callback */ + unsigned char _FAR *base; /* points to the AMX header plus the code, optionally also the data */ + unsigned char _FAR *data; /* points to separate data+stack+heap, may be NULL */ + AMX_CALLBACK callback; + AMX_DEBUG debug ; /* debug callback */ /* for external functions a few registers must be accessible from the outside */ - cell cip PACKEDENTRY; /* instruction pointer: relative to base + amxhdr->cod */ - cell frm PACKEDENTRY; /* stack frame base: relative to base + amxhdr->dat */ - cell hea PACKEDENTRY; /* top of the heap: relative to base + amxhdr->dat */ - cell hlw PACKEDENTRY; /* bottom of the heap: relative to base + amxhdr->dat */ - cell stk PACKEDENTRY; /* stack pointer: relative to base + amxhdr->dat */ - cell stp PACKEDENTRY; /* top of the stack: relative to base + amxhdr->dat */ - int flags PACKEDENTRY; /* current status, see amx_Flags() */ + cell cip ; /* instruction pointer: relative to base + amxhdr->cod */ + cell frm ; /* stack frame base: relative to base + amxhdr->dat */ + cell hea ; /* top of the heap: relative to base + amxhdr->dat */ + cell hlw ; /* bottom of the heap: relative to base + amxhdr->dat */ + cell stk ; /* stack pointer: relative to base + amxhdr->dat */ + cell stp ; /* top of the stack: relative to base + amxhdr->dat */ + int flags ; /* current status, see amx_Flags() */ /* user data */ - long usertags[AMX_USERNUM] PACKEDENTRY; - void _FAR *userdata[AMX_USERNUM] PACKEDENTRY; + long usertags[AMX_USERNUM] ; + void _FAR *userdata[AMX_USERNUM] ; /* native functions can raise an error */ - int error PACKEDENTRY; + int error ; /* passing parameters requires a "count" field */ int paramcount; /* the sleep opcode needs to store the full AMX status */ - cell pri PACKEDENTRY; - cell alt PACKEDENTRY; - cell reset_stk PACKEDENTRY; - cell reset_hea PACKEDENTRY; - cell sysreq_d PACKEDENTRY; /* relocated address/value for the SYSREQ.D opcode */ + cell pri ; + cell alt ; + cell reset_stk ; + cell reset_hea ; + cell sysreq_d ; /* relocated address/value for the SYSREQ.D opcode */ #if defined JIT /* support variables for the JIT */ - int reloc_size PACKEDENTRY; /* required temporary buffer for relocations */ - long code_size PACKEDENTRY; /* estimated memory footprint of the native code */ + int reloc_size ; /* required temporary buffer for relocations */ + long code_size ; /* estimated memory footprint of the native code */ #endif } AMX; @@ -284,23 +278,23 @@ typedef struct tagAMX { * structure is used internaly. */ typedef struct tagAMX_HEADER { - int32_t size PACKEDENTRY; /* size of the "file" */ - uint16_t magic PACKEDENTRY; /* signature */ - char file_version PACKEDENTRY; /* file format version */ - char amx_version PACKEDENTRY; /* required version of the AMX */ - int16_t flags PACKEDENTRY; - int16_t defsize PACKEDENTRY; /* size of a definition record */ - int32_t cod PACKEDENTRY; /* initial value of COD - code block */ - int32_t dat PACKEDENTRY; /* initial value of DAT - data block */ - int32_t hea PACKEDENTRY; /* initial value of HEA - start of the heap */ - int32_t stp PACKEDENTRY; /* initial value of STP - stack top */ - int32_t cip PACKEDENTRY; /* initial value of CIP - the instruction pointer */ - int32_t publics PACKEDENTRY; /* offset to the "public functions" table */ - int32_t natives PACKEDENTRY; /* offset to the "native functions" table */ - int32_t libraries PACKEDENTRY; /* offset to the table of libraries */ - int32_t pubvars PACKEDENTRY; /* the "public variables" table */ - int32_t tags PACKEDENTRY; /* the "public tagnames" table */ - int32_t nametable PACKEDENTRY; /* name table */ + int32_t size ; /* size of the "file" */ + uint16_t magic ; /* signature */ + char file_version ; /* file format version */ + char amx_version ; /* required version of the AMX */ + int16_t flags ; + int16_t defsize ; /* size of a definition record */ + int32_t cod ; /* initial value of COD - code block */ + int32_t dat ; /* initial value of DAT - data block */ + int32_t hea ; /* initial value of HEA - start of the heap */ + int32_t stp ; /* initial value of STP - stack top */ + int32_t cip ; /* initial value of CIP - the instruction pointer */ + int32_t publics ; /* offset to the "public functions" table */ + int32_t natives ; /* offset to the "native functions" table */ + int32_t libraries ; /* offset to the table of libraries */ + int32_t pubvars ; /* the "public variables" table */ + int32_t tags ; /* the "public tagnames" table */ + int32_t nametable ; /* name table */ } AMX_HEADER; #if PAWN_CELL_SIZE==16 diff --git a/sourcepawn/compiler/amxdbg.h b/sourcepawn/compiler/amxdbg.h index acc4d1b3..4fc3c1c1 100644 --- a/sourcepawn/compiler/amxdbg.h +++ b/sourcepawn/compiler/amxdbg.h @@ -42,12 +42,6 @@ extern "C" { #define AMX_NO_ALIGN #endif -#if defined __GNUC__ - #define PACKED __attribute__((packed)) -#else - #define PACKED -#endif - #if !defined AMX_NO_ALIGN #if defined LINUX || defined __FreeBSD__ #pragma pack(1) /* structures must be packed (byte-aligned) */ @@ -63,72 +57,72 @@ extern "C" { #endif typedef struct tagAMX_DBG_HDR { - int32_t size PACKED; /* size of the debug information chunk */ - uint16_t magic PACKED; /* signature, must be 0xf1ef */ - char file_version PACKED; /* file format version */ - char amx_version PACKED; /* required version of the AMX */ - int16_t flags PACKED; /* currently unused */ - int16_t files PACKED; /* number of entries in the "file" table */ - int16_t lines PACKED; /* number of entries in the "line" table */ - int16_t symbols PACKED; /* number of entries in the "symbol" table */ - int16_t tags PACKED; /* number of entries in the "tag" table */ - int16_t automatons PACKED; /* number of entries in the "automaton" table */ - int16_t states PACKED; /* number of entries in the "state" table */ -} PACKED AMX_DBG_HDR; + int32_t size ; /* size of the debug information chunk */ + uint16_t magic ; /* signature, must be 0xf1ef */ + char file_version ; /* file format version */ + char amx_version ; /* required version of the AMX */ + int16_t flags ; /* currently unused */ + int16_t files ; /* number of entries in the "file" table */ + int16_t lines ; /* number of entries in the "line" table */ + int16_t symbols ; /* number of entries in the "symbol" table */ + int16_t tags ; /* number of entries in the "tag" table */ + int16_t automatons ; /* number of entries in the "automaton" table */ + int16_t states ; /* number of entries in the "state" table */ +} AMX_DBG_HDR; #define AMX_DBG_MAGIC 0xf1ef typedef struct tagAMX_DBG_FILE { - ucell address PACKED; /* address in the code segment where generated code (for this file) starts */ - const char name[1] PACKED; /* ASCII string, zero-terminated */ -} PACKED AMX_DBG_FILE; + ucell address ; /* address in the code segment where generated code (for this file) starts */ + const char name[1] ; /* ASCII string, zero-terminated */ +} AMX_DBG_FILE; typedef struct tagAMX_DBG_LINE { - ucell address PACKED; /* address in the code segment where generated code (for this line) starts */ - int32_t line PACKED; /* line number */ -} PACKED AMX_DBG_LINE; + ucell address ; /* address in the code segment where generated code (for this line) starts */ + int32_t line ; /* line number */ +} AMX_DBG_LINE; typedef struct tagAMX_DBG_SYMBOL { - ucell address PACKED; /* address in the data segment or relative to the frame */ - int16_t tag PACKED; /* tag for the symbol */ - ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */ - ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */ - char ident PACKED; /* kind of symbol (function/variable) */ - char vclass PACKED; /* class of symbol (global/local) */ - int16_t dim PACKED; /* number of dimensions */ - const char name[1] PACKED; /* ASCII string, zero-terminated */ -} PACKED AMX_DBG_SYMBOL; + ucell address ; /* address in the data segment or relative to the frame */ + int16_t tag ; /* tag for the symbol */ + ucell codestart ; /* address in the code segment from which this symbol is valid (in scope) */ + ucell codeend ; /* address in the code segment until which this symbol is valid (in scope) */ + char ident ; /* kind of symbol (function/variable) */ + char vclass ; /* class of symbol (global/local) */ + int16_t dim ; /* number of dimensions */ + const char name[1] ; /* ASCII string, zero-terminated */ +} AMX_DBG_SYMBOL; typedef struct tagAMX_DBG_SYMDIM { - int16_t tag PACKED; /* tag for the array dimension */ - ucell size PACKED; /* size of the array dimension */ -} PACKED AMX_DBG_SYMDIM; + int16_t tag ; /* tag for the array dimension */ + ucell size ; /* size of the array dimension */ +} AMX_DBG_SYMDIM; typedef struct tagAMX_DBG_TAG { - int16_t tag PACKED; /* tag id */ - const char name[1] PACKED; /* ASCII string, zero-terminated */ -} PACKED AMX_DBG_TAG; + int16_t tag ; /* tag id */ + const char name[1] ; /* ASCII string, zero-terminated */ +} AMX_DBG_TAG; typedef struct tagAMX_DBG_MACHINE { - int16_t automaton PACKED; /* automaton id */ - ucell address PACKED; /* address of state variable */ - const char name[1] PACKED; /* ASCII string, zero-terminated */ -} PACKED AMX_DBG_MACHINE; + int16_t automaton ; /* automaton id */ + ucell address ; /* address of state variable */ + const char name[1] ; /* ASCII string, zero-terminated */ +} AMX_DBG_MACHINE; typedef struct tagAMX_DBG_STATE { - int16_t state PACKED; /* state id */ - int16_t automaton PACKED; /* automaton id */ - const char name[1] PACKED; /* ASCII string, zero-terminated */ -} PACKED AMX_DBG_STATE; + int16_t state ; /* state id */ + int16_t automaton ; /* automaton id */ + const char name[1] ; /* ASCII string, zero-terminated */ +} AMX_DBG_STATE; typedef struct tagAMX_DBG { - AMX_DBG_HDR *hdr PACKED; /* points to the AMX_DBG header */ - AMX_DBG_FILE **filetbl PACKED; - AMX_DBG_LINE *linetbl PACKED; - AMX_DBG_SYMBOL **symboltbl PACKED; - AMX_DBG_TAG **tagtbl PACKED; - AMX_DBG_MACHINE **automatontbl PACKED; - AMX_DBG_STATE **statetbl PACKED; -} PACKED AMX_DBG; + AMX_DBG_HDR *hdr ; /* points to the AMX_DBG header */ + AMX_DBG_FILE **filetbl ; + AMX_DBG_LINE *linetbl ; + AMX_DBG_SYMBOL **symboltbl ; + AMX_DBG_TAG **tagtbl ; + AMX_DBG_MACHINE **automatontbl ; + AMX_DBG_STATE **statetbl ; +} AMX_DBG; #if !defined iVARIABLE #define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ diff --git a/sourcepawn/compiler/memfile.c b/sourcepawn/compiler/memfile.c index 2047f710..bc572e7f 100644 --- a/sourcepawn/compiler/memfile.c +++ b/sourcepawn/compiler/memfile.c @@ -28,6 +28,11 @@ memfile_t *memfile_creat(const char *name, size_t init) void memfile_destroy(memfile_t *mf) { + if (!mf) + { + return; + } + if (!mf->_static) { free(mf->name); @@ -69,7 +74,7 @@ size_t memfile_read(memfile_t *mf, void *buffer, size_t maxsize) return maxsize; } -int memfile_write(memfile_t *mf, void *buffer, size_t size) +int memfile_write(memfile_t *mf, const void *buffer, size_t size) { if (mf->offs + size > mf->size) { @@ -103,3 +108,9 @@ int memfile_write(memfile_t *mf, void *buffer, size_t size) return 1; } + +void memfile_reset(memfile_t *mf) +{ + mf->usedoffs = 0; + mf->offs = 0; +} diff --git a/sourcepawn/compiler/memfile.h b/sourcepawn/compiler/memfile.h index f5222a9e..7f953f20 100644 --- a/sourcepawn/compiler/memfile.h +++ b/sourcepawn/compiler/memfile.h @@ -13,11 +13,43 @@ typedef struct memfile_s int _static; } memfile_t; +/** + * Creates a new memory file + * init is the initial size in bytes + */ memfile_t *memfile_creat(const char *name, size_t init); + +/** + * Frees the memory associated. + */ void memfile_destroy(memfile_t *mf); + +/** + * Seeks to a given offset (always from start) + */ void memfile_seek(memfile_t *mf, long seek); -int memfile_write(memfile_t *mf, void *buffer, size_t size); + +/** + * Writes to a memory buffer (expands as necessary). + * Returns 1 on success, 0 on failure. + */ +int memfile_write(memfile_t *mf, const void *buffer, size_t size); + +/** + * Reads a number of bytes from a memory buffer. + * Returns the number of bytes read until the end was hit. + */ size_t memfile_read(memfile_t *mf, void *buffer, size_t maxsize); + +/** + * Returns the current position from the start. + */ long memfile_tell(memfile_t *mf); +/** + * Resets all the states of the memory buffer. + * (does not actually free or zero memory) + */ +void memfile_reset(memfile_t *mf); + #endif //_INCLUDE_MEMFILE_H diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index 8da3e2e6..d8073e2d 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -5,6 +5,7 @@ #include "memfile.h" #include "sp_file.h" #include "amx.h" +#include "amxdbg.h" #include "osdefs.h" #include "zlib/zlib.h" @@ -22,6 +23,7 @@ enum FileSections FS_DbgTags, FS_DbgAutomaton, FS_DbgState, + FS_DbgStrings, /* --- */ FS_Number, }; @@ -38,10 +40,14 @@ int main(int argc, char *argv[]) if (pc_compile(argc,argv) == 0) { AMX_HEADER *hdr; + AMX_DBG_HDR *dbg = NULL; int err; uint32_t i; sp_file_t *spf; + memfile_t *dbgtab = NULL; + unsigned char *dbgptr = NULL; uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0}; + FILE *fp; if (bin_file == NULL) { @@ -83,6 +89,35 @@ int main(int argc, char *argv[]) spfw_add_section(spf, ".names"); + if (hdr->flags & AMX_FLAG_DEBUG) + { + dbg = (AMX_DBG_HDR *)((unsigned char *)hdr + hdr->size); + if (dbg->magic != AMX_DBG_MAGIC) + { + pc_printf("Error reading AMX_DBG_HDR, debug data will not be written."); + } else { + dbgtab = memfile_creat("", 512); + dbgptr = (unsigned char *)dbg + sizeof(AMX_DBG_HDR); + if (dbg->files) + { + spfw_add_section(spf, ".dbg.files"); + sections[FS_DbgFile] = dbg->files; + } + if (dbg->lines) + { + spfw_add_section(spf, ".dbg.lines"); + sections[FS_DbgLine] = dbg->lines; + } + if (dbg->symbols) + { + spfw_add_section(spf, ".dbg.symbols"); + sections[FS_DbgSymbol] = dbg->symbols; + } + sections[FS_DbgStrings] = 1; + spfw_add_section(spf, ".dbg.strings"); + } + } + spfw_finalize_header(spf); /** @@ -324,8 +359,6 @@ int main(int argc, char *argv[]) } } cod.codesize = (uint32_t)(tptr - tbase); - cod.disksize = cod.codesize; - cod.compression = SPFILE_COMPRESSION_NONE; sfwrite(&cod, sizeof(cod), 1, spf); sfwrite(tbase, cod.codesize, 1, spf); free(tbase); @@ -336,51 +369,19 @@ int main(int argc, char *argv[]) if (sections[FS_Data]) { sp_file_data_t dat; - unsigned char *dbase; - Bytef *cmp_dbase; - uLong disksize; - int err; + unsigned char *dbase = (unsigned char *)hdr + hdr->dat; dat.datasize = hdr->hea - hdr->dat; dat.memsize = hdr->stp; dat.data = sizeof(dat); - dat.compression = SPFILE_COMPRESSION_GZ; + + /* write header */ + sfwrite(&dat, sizeof(dat), 1, spf); if (dat.datasize) { - dat.disksize = (uint32_t)compressBound((uLong)dat.datasize); - - dbase = (unsigned char *)hdr + hdr->dat; - cmp_dbase = (Bytef *)malloc(dat.disksize); - - /* compress */ - err = compress2(cmp_dbase, &disksize, (Bytef *)dbase, (uLong)dat.datasize, Z_BEST_COMPRESSION); - - if (err != Z_OK) - { - pc_printf("Failed to compress DAT section with error: %d\n", err); - pc_printf("Defaulting to no compression.\n"); - dat.compression = SPFILE_COMPRESSION_NONE; - dat.disksize = dat.datasize; - - /* write header */ - sfwrite(&dat, sizeof(dat), 1, spf); - /* write data */ - sfwrite(&dbase, dat.datasize, 1, spf); - } else { - dat.disksize = (uint32_t)disksize; - - /* write header */ - sfwrite(&dat, sizeof(dat), 1, spf); - /* write data */ - sfwrite(cmp_dbase, dat.disksize, 1, spf); - } - - free(cmp_dbase); - } else { - /* should be 0 */ - dat.disksize = dat.datasize; - sfwrite(&dat, sizeof(dat), 1, spf); + /* write data */ + sfwrite(dbase, dat.datasize, 1, spf); } spfw_next_section(spf); @@ -474,17 +475,186 @@ int main(int argc, char *argv[]) spfw_next_section(spf); } + if (hdr->flags & AMX_FLAG_DEBUG) + { + if (sections[FS_DbgFile]) + { + uint32_t idx; + sp_fdbg_file_t dbgfile; + AMX_DBG_FILE *_ptr; + uint32_t len; + for (idx=0; idxname); + /* store */ + dbgfile.addr = _ptr->address; + dbgfile.name = (uint32_t)memfile_tell(dbgtab); + sfwrite(&dbgfile, sizeof(sp_fdbg_file_t), 1, spf); + /* write to tab, then move to next */ + memfile_write(dbgtab, _ptr->name, len + 1); + dbgptr += sizeof(AMX_DBG_FILE) + len; + } + spfw_next_section(spf); + } + + if (sections[FS_DbgLine]) + { + uint32_t idx; + AMX_DBG_LINE *line; + sp_fdbg_line_t dbgline; + for (idx=0; idxaddress; + dbgline.line = (uint32_t)line->line; + sfwrite(&dbgline, sizeof(sp_fdbg_line_t), 1, spf); + /* move to next */ + dbgptr += sizeof(AMX_DBG_LINE); + } + spfw_next_section(spf); + } + + if (sections[FS_DbgSymbol]) + { + uint32_t idx; + uint32_t dnum; + AMX_DBG_SYMBOL *sym; + AMX_DBG_SYMDIM *dim; + sp_fdbg_symbol_t dbgsym; + sp_fdbg_arraydim_t dbgdim; + uint32_t len; + + for (idx=0; idxaddress; + dbgsym.tagid = sym->tag; + dbgsym.codestart = (uint32_t)sym->codestart; + dbgsym.codeend = (uint32_t)sym->codeend; + dbgsym.dimcount = (uint16_t)sym->dim; + dbgsym.vclass = (uint8_t)sym->vclass; + dbgsym.ident = (uint8_t)sym->ident; + dbgsym.name = (uint32_t)memfile_tell(dbgtab); + sfwrite(&dbgsym, sizeof(sp_fdbg_symbol_t), 1, spf); + /* write to tab */ + len = strlen(sym->name); + memfile_write(dbgtab, sym->name, len + 1); + /* move to next */ + dbgptr += sizeof(AMX_DBG_SYMBOL) + len; + /* look for any dimensions */ + for (dnum=0; dnumsize; + dbgdim.tagid = dim->tag; + sfwrite(&dbgdim, sizeof(sp_fdbg_arraydim_t), 1, spf); + /* move to next */ + dbgptr += sizeof(AMX_DBG_SYMDIM); + } + } + spfw_next_section(spf); + } + + if (sections[FS_DbgStrings]) + { + sfwrite(dbgtab->base, sizeof(char), dbgtab->usedoffs, spf); + spfw_next_section(spf); + } + } + spfw_finalize_all(spf); + + /** + * do compression + * new block for scoping only + */ + if (1) + { + memfile_t *pOrig = (memfile_t *)spf->handle; + sp_file_hdr_t *pHdr; + unsigned char *proper; + size_t size; + Bytef *zcmp; + uLong disksize; + int err = Z_OK; + + /* reuse this memory block! */ + memfile_reset(bin_file); + + /* copy tip of header */ + memfile_write(bin_file, pOrig->base, sizeof(sp_file_hdr_t)); + + /* get pointer to header */ + pHdr = (sp_file_hdr_t *)bin_file->base; + + /* copy the rest of the header */ + memfile_write(bin_file, + (unsigned char *)pOrig->base + sizeof(sp_file_hdr_t), + pHdr->dataoffs - sizeof(sp_file_hdr_t)); + + size = pHdr->imagesize - pHdr->dataoffs; + proper = (unsigned char *)pOrig->base + pHdr->dataoffs; + + /* get initial size estimate */ + pHdr->disksize = (uint32_t)compressBound(pHdr->imagesize); + zcmp = (Bytef *)malloc(pHdr->disksize); + + if ((err=compress2(zcmp, + &disksize, + (Bytef *)proper, + (uLong)size, + Z_BEST_COMPRESSION)) + != Z_OK) + { + free(zcmp); + pc_printf("Unable to compress (Z): error %d", err); + pc_printf("Falling back to no compression."); + memfile_write(bin_file, + proper, + size); + } else { + pHdr->disksize = (uint32_t)disksize; + pHdr->compression = SPFILE_COMPRESSION_GZ; + memfile_write(bin_file, + (unsigned char *)zcmp, + pHdr->disksize); + free(zcmp); + } + } + spfw_destroy(spf); + memfile_destroy(dbgtab); + + /** + * write file + */ + if ((fp=fopen(bin_file->name, "wb")) != NULL) + { + fwrite(bin_file->base, bin_file->usedoffs, 1, fp); + fclose(fp); + } else { + pc_printf("Unable to open %s for writing!", bin_file->name); + } + + memfile_destroy(bin_file); return 0; write_error: pc_printf("Error writing to file: %s", bin_file->name); + + spfw_destroy(spf); unlink(bin_file->name); - memfile_destroy(bin_file); - bin_file = NULL; + memfile_destroy(dbgtab); return 1; } diff --git a/sourcepawn/compiler/sp_file.c b/sourcepawn/compiler/sp_file.c index 21f2980e..a83d290d 100644 --- a/sourcepawn/compiler/sp_file.c +++ b/sourcepawn/compiler/sp_file.c @@ -2,22 +2,23 @@ #include #include #include "sp_file.h" +#include "memfile.h" -void *fp_open(const char *name); -void fp_close(void *handle); -size_t fp_write(const void *buf, size_t size, size_t count, void *handle); -size_t fp_read(void *buf, size_t size, size_t count, void *handle); -size_t fp_getpos(void *handle); -int fp_setpos(void *handle, size_t pos); +void *mf_open(const char *name); +void mf_close(void *handle); +size_t mf_write(const void *buf, size_t size, size_t count, void *handle); +size_t mf_read(void *buf, size_t size, size_t count, void *handle); +size_t mf_getpos(void *handle); +int mf_setpos(void *handle, size_t pos); sp_writefuncs_t cstd_funcs = { - fp_open, - fp_close, - fp_write, - fp_read, - fp_getpos, - fp_setpos + mf_open, + mf_close, + mf_write, + mf_read, + mf_getpos, + mf_setpos }; sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs) @@ -46,6 +47,9 @@ sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs) pFile->header.stringtab = 0; pFile->header.version = SPFILE_VERSION; pFile->header.imagesize = 0; + pFile->header.disksize = 0; + pFile->header.compression = SPFILE_COMPRESSION_NONE; + pFile->header.dataoffs = 0; pFile->lastsection = 0; pFile->offsets = NULL; pFile->sections = NULL; @@ -113,6 +117,7 @@ int spfw_finalize_header(sp_file_t *spf) size = sizeof(sp_file_section_t) * spf->header.sections; spf->header.stringtab = sizeof(spf->header) + size; + spf->header.dataoffs = spf->header.stringtab + spf->nametab_idx; if (spf->funcs.fnWrite(&spf->header, sizeof(spf->header), 1, spf->handle) != 1) { return -1; @@ -178,6 +183,7 @@ int spfw_finalize_all(sp_file_t *spf) } offs = offsetof(sp_file_hdr_t, imagesize); + spf->header.disksize = spf->funcs.fnGetPos(spf->handle); spf->header.imagesize = spf->funcs.fnGetPos(spf->handle); spf->funcs.fnSetPos(spf->handle, offs); spf->funcs.fnWrite(&spf->header.imagesize, sizeof(uint32_t), 1, spf->handle); @@ -186,6 +192,53 @@ int spfw_finalize_all(sp_file_t *spf) return 1; } +/** + * More memory file operations + */ + +void *mf_open(const char *name) +{ + return memfile_creat(name, 1024); +} + +void mf_close(void *handle) +{ + memfile_destroy((memfile_t *)handle); +} + +size_t mf_write(const void *buf, size_t size, size_t count, void *handle) +{ + if (!count) + { + return 0; + } + + if (memfile_write((memfile_t *)handle, buf, size*count)) + { + return count; + } + + return 0; +} + +size_t mf_read(void *buf, size_t size, size_t count, void *handle) +{ + return memfile_read((memfile_t *)handle, buf, size*count) / count; +} + +size_t mf_getpos(void *handle) +{ + return (long)memfile_tell((memfile_t *)handle); +} + +int mf_setpos(void *handle, size_t pos) +{ + memfile_seek((memfile_t *)handle, (long)pos); + return 1; +} + + +#if UNUSED_FOR_NOW /** * Default file operations... * Based on C standard library calls. @@ -220,5 +273,4 @@ int fp_setpos(void *handle, size_t pos) { return fseek((FILE *)handle, (long)pos, SEEK_SET); } - - +#endif diff --git a/sourcepawn/compiler/sp_file.h b/sourcepawn/compiler/sp_file.h index 41ff70a9..f2d39786 100644 --- a/sourcepawn/compiler/sp_file.h +++ b/sourcepawn/compiler/sp_file.h @@ -74,6 +74,7 @@ int spfw_next_section(sp_file_t *spf); * Finalizes all sections. * Cannot be called until all sections are used. * Must be called with the file pointer at the end. + * Also does compression! */ int spfw_finalize_all(sp_file_t *spf); diff --git a/sourcepawn/compiler/sp_file_headers.h b/sourcepawn/compiler/sp_file_headers.h index bb60aee8..b83fff38 100644 --- a/sourcepawn/compiler/sp_file_headers.h +++ b/sourcepawn/compiler/sp_file_headers.h @@ -29,6 +29,9 @@ #pragma pack(1) /* structures must be packed (byte-aligned) */ #endif +#define SPFILE_COMPRESSION_NONE 0 +#define SPFILE_COMPRESSION_GZ 1 + typedef struct sp_file_section_s { uint32_t nameoffs; /* rel offset into global string table */ @@ -36,13 +39,21 @@ typedef struct sp_file_section_s uint32_t size; } sp_file_section_t; +/** + * If compression is 0, then + * disksize may be 0 to mean that + * only the imagesize is needed. + */ typedef struct sp_file_hdr_s { - uint32_t magic; - uint16_t version; - uint32_t imagesize; - uint8_t sections; - uint32_t stringtab; + uint32_t magic; /* magic number */ + uint16_t version; /* version code */ + uint8_t compression;/* compression algorithm */ + uint32_t disksize; /* size on disk */ + uint32_t imagesize; /* size in memory */ + uint8_t sections; /* number of sections */ + uint32_t stringtab; /* offset to string table */ + uint32_t dataoffs; /* offset to file proper (any compression starts here) */ } sp_file_hdr_t; typedef enum @@ -59,21 +70,14 @@ typedef struct sp_file_code_s uint8_t codeversion; /* version of opcodes supported */ uint16_t flags; /* flags */ uint32_t main; /* address to "main" if any */ - uint32_t disksize; /* disksize in bytes */ - uint8_t compression; /* compression */ uint32_t code; /* rel offset to code */ } sp_file_code_t; -#define SPFILE_COMPRESSION_NONE 0 -#define SPFILE_COMPRESSION_GZ 1 - /* section is .data */ typedef struct sp_file_data_s { uint32_t datasize; /* size of data section in memory */ uint32_t memsize; /* total mem required (includes data) */ - uint32_t disksize; /* size of data on disk (compressed) */ - uint8_t compression; /* compression */ uint32_t data; /* file offset to data (helper) */ } sp_file_data_t; @@ -103,6 +107,44 @@ typedef struct sp_file_pubvars_s #pragma pack(pop) /* reset previous packing */ #endif +/** + * Debug information structures + */ +typedef struct sp_fdbg_file_s +{ + uint32_t addr; /* address into code */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_file_t; + +typedef struct sp_fdbg_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line number */ +} sp_fdbg_line_t; + +#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ +#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */ +#define SP_SYM_ARRAY 3 +#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */ +#define SP_SYM_FUNCTION 9 + +typedef struct sp_fdbg_symbol_s +{ + int32_t addr; /* address rel to DAT or stack frame */ + int16_t tagid; /* tag id */ + uint32_t codestart; /* start scope validity in code */ + uint32_t codeend; /* end scope validity in code */ + uint8_t ident; /* variable type */ + uint8_t vclass; /* scope class (local vs global) */ + uint16_t dimcount; /* dimension count (for arrays) */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_symbol_t; + +typedef struct sp_fdbg_arraydim_s +{ + int16_t tagid; /* tag id */ + uint32_t size; /* size of dimension */ +} sp_fdbg_arraydim_t; /* section is .names */ typedef char * sp_file_nametab_t; From 2c4d8924696dd5e74ee64b67d5db0483542ba96d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 28 Jul 2006 05:34:12 +0000 Subject: [PATCH 0007/1664] reorganized this a tad --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4037 --- sourcepawn/compiler/{ => msvc8}/spcomp.sln | 0 sourcepawn/compiler/{ => msvc8}/spcomp.vcproj | 122 ++++++++---------- .../{compiler => include}/sp_file_headers.h | 0 3 files changed, 56 insertions(+), 66 deletions(-) rename sourcepawn/compiler/{ => msvc8}/spcomp.sln (100%) rename sourcepawn/compiler/{ => msvc8}/spcomp.vcproj (69%) rename sourcepawn/{compiler => include}/sp_file_headers.h (100%) diff --git a/sourcepawn/compiler/spcomp.sln b/sourcepawn/compiler/msvc8/spcomp.sln similarity index 100% rename from sourcepawn/compiler/spcomp.sln rename to sourcepawn/compiler/msvc8/spcomp.sln diff --git a/sourcepawn/compiler/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj similarity index 69% rename from sourcepawn/compiler/spcomp.vcproj rename to sourcepawn/compiler/msvc8/spcomp.vcproj index 44d6c891..491bacf5 100644 --- a/sourcepawn/compiler/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -40,6 +40,7 @@ - - - - - + + @@ -261,39 +255,35 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - @@ -303,15 +293,15 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > @@ -322,51 +312,51 @@ Name="Source Files" > @@ -374,43 +364,43 @@ Name="Header Files" > diff --git a/sourcepawn/compiler/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h similarity index 100% rename from sourcepawn/compiler/sp_file_headers.h rename to sourcepawn/include/sp_file_headers.h From 8f0e90ee294981fd67e0fa3a30513c93c78f9b89 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 29 Jul 2006 21:02:28 +0000 Subject: [PATCH 0008/1664] initial import of API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4038 --- sourcepawn/include/sp_vm_types.h | 202 ++++ sourcepawn/vm/msvc8/vm.sln | 20 + sourcepawn/vm/msvc8/vm.vcproj | 305 ++++++ sourcepawn/vm/sp_vm.h | 273 +++++ sourcepawn/vm/zlib/adler32.c | 149 +++ sourcepawn/vm/zlib/compress.c | 79 ++ sourcepawn/vm/zlib/crc32.c | 423 ++++++++ sourcepawn/vm/zlib/crc32.h | 441 ++++++++ sourcepawn/vm/zlib/deflate.c | 1736 ++++++++++++++++++++++++++++++ sourcepawn/vm/zlib/deflate.h | 331 ++++++ sourcepawn/vm/zlib/gzio.c | 1026 ++++++++++++++++++ sourcepawn/vm/zlib/infback.c | 623 +++++++++++ sourcepawn/vm/zlib/inffast.c | 318 ++++++ sourcepawn/vm/zlib/inffast.h | 11 + sourcepawn/vm/zlib/inffixed.h | 94 ++ sourcepawn/vm/zlib/inflate.c | 1368 +++++++++++++++++++++++ sourcepawn/vm/zlib/inflate.h | 115 ++ sourcepawn/vm/zlib/inftrees.c | 329 ++++++ sourcepawn/vm/zlib/inftrees.h | 55 + sourcepawn/vm/zlib/trees.c | 1219 +++++++++++++++++++++ sourcepawn/vm/zlib/trees.h | 128 +++ sourcepawn/vm/zlib/uncompr.c | 61 ++ sourcepawn/vm/zlib/zconf.h | 281 +++++ sourcepawn/vm/zlib/zlib.h | 1357 +++++++++++++++++++++++ sourcepawn/vm/zlib/zutil.c | 318 ++++++ sourcepawn/vm/zlib/zutil.h | 269 +++++ 26 files changed, 11531 insertions(+) create mode 100644 sourcepawn/include/sp_vm_types.h create mode 100644 sourcepawn/vm/msvc8/vm.sln create mode 100644 sourcepawn/vm/msvc8/vm.vcproj create mode 100644 sourcepawn/vm/sp_vm.h create mode 100644 sourcepawn/vm/zlib/adler32.c create mode 100644 sourcepawn/vm/zlib/compress.c create mode 100644 sourcepawn/vm/zlib/crc32.c create mode 100644 sourcepawn/vm/zlib/crc32.h create mode 100644 sourcepawn/vm/zlib/deflate.c create mode 100644 sourcepawn/vm/zlib/deflate.h create mode 100644 sourcepawn/vm/zlib/gzio.c create mode 100644 sourcepawn/vm/zlib/infback.c create mode 100644 sourcepawn/vm/zlib/inffast.c create mode 100644 sourcepawn/vm/zlib/inffast.h create mode 100644 sourcepawn/vm/zlib/inffixed.h create mode 100644 sourcepawn/vm/zlib/inflate.c create mode 100644 sourcepawn/vm/zlib/inflate.h create mode 100644 sourcepawn/vm/zlib/inftrees.c create mode 100644 sourcepawn/vm/zlib/inftrees.h create mode 100644 sourcepawn/vm/zlib/trees.c create mode 100644 sourcepawn/vm/zlib/trees.h create mode 100644 sourcepawn/vm/zlib/uncompr.c create mode 100644 sourcepawn/vm/zlib/zconf.h create mode 100644 sourcepawn/vm/zlib/zlib.h create mode 100644 sourcepawn/vm/zlib/zutil.c create mode 100644 sourcepawn/vm/zlib/zutil.h diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h new file mode 100644 index 00000000..e89ea89e --- /dev/null +++ b/sourcepawn/include/sp_vm_types.h @@ -0,0 +1,202 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H +#define _INCLUDE_SOURCEPAWN_VM_TYPES_H + +#include "sp_file_headers.h" + +typedef uint32_t ucell_t; +typedef int32_t cell_t; + +/** + * Error codes + */ +#define SP_ERR_NONE 0 +#define SP_ERR_FILE_FORMAT 1 /* File format unrecognized */ +#define SP_ERR_DECOMPRESSOR 2 /* A decompressor was not found */ + +/********************************************** + *** The following structures are reference structures. + *** They are not essential to the API, but are used + *** to hold the backend database format of the plugin + *** binary. + **********************************************/ + +/** + * Information about the core plugin tables. + * These may or may not be present! + */ +typedef struct sp_plugin_infotab_t +{ + const char *stringbase; /* base of string table */ + uint32_t publics_num; /* number of publics */ + sp_file_publics_t *publics; /* public table */ + uint32_t natives_num; /* number of natives */ + sp_file_natives_t *natives; /* native table */ + uint32_t pubvars_num; /* number of pubvars */ + sp_file_pubvars_t *pubvars; /* pubvars table */ +} sp_plugin_infotab_s; + +/** + * Information about the plugin's debug tables. + * These are all present if one is present. + */ +typedef struct sp_plugin_debug_t +{ + const char *stringbase; /* base of string table */ + uint32_t files_num; /* number of files */ + sp_fdbg_file_t *files; /* files table */ + uint32_t lines_num; /* number of lines */ + sp_fdbg_line_t *lines; /* lines table */ + uint32_t syms_num; /* number of symbols */ + sp_fdbg_symbol_t *symbols; /* symbol table */ +} sp_plugin_debug_s; + +#define SP_FA_SELF_EXTERNAL (1<<0) +#define SP_FA_BASE_EXTERNAL (1<<1) + +/** + * The rebased, in-memory format of a plugin. + * This differs from the on-disk structure to ensure + * that the format is properly read. + */ +typedef struct sp_plugin_t +{ + uint8_t *base; /* base of memory */ + uint8_t *pcode; /* p-code */ + uint32_t pcode_size; /* size of p-code */ + uint8_t *data; /* data size */ + uint32_t data_size; /* size of data */ + uint32_t memory; /* required memory */ + uint16_t flags; /* code flags */ + uint32_t allocflags; /* allocation flags */ + sp_plugin_infotab_t *info; /* base info table */ + sp_plugin_debug_t *debug; /* debug info table */ +} sp_plugin_s; + +struct sp_context_s; +typedef int (*SPVM_NATIVE_FUNC)(sp_context_s *, cell_t *); + +/********************************************** + *** The following structures are bound to the VM/JIT. + *** Changing them will result in necessary recompilation. + **********************************************/ + +/** + * Offsets and names to a public function. + * By default, these point back to the string table + * in the sp_plugin_infotab_t structure. + */ +typedef struct sp_public_t +{ + uint32_t offs; /* code offset */ + const char *name; /* name */ +} sp_publics_s; + +/** + * Offsets and names to public variables. + * The offset is relocated and the name by default + * points back to the sp_plugin_infotab_t structure. + */ +typedef struct sp_pubvar_t +{ + cell_t *offs; /* pointer to data */ + const char *name; /* name */ +} sp_pubvar_t + +#define SP_NATIVE_NONE (0) /* Native is not yet found */ +#define SP_NATIVE_OKAY (1) /* Native has been added */ +#define SP_NATIVE_PENDING (2) /* Native is marked as usable but replaceable */ + +/** + * Native lookup table, by default names + * point back to the sp_plugin_infotab_t structure. + * A native is NULL if unit + */ +typedef struct sp_native_t +{ + SPVM_NATIVE_FUNC pfn; /* function pointer */ + const char * name; /* name of function */ + uint32_t status; /* status flags */ +} sp_native_t; + +/** + * Debug file table + */ +typedef struct sp_debug_file_s +{ + uint32_t addr; /* address into code */ + const char * name; /* name of file */ +} sp_debug_file_t; + +/** + * Note that line is missing. It is not necessary since + * this can be retrieved from the base plugin info. + */ +typedef struct sp_debug_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line no. */ +} sp_debug_line_t; + +typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; + +/** + * The majority of this struct is already located in the parent + * block. Thus, only the relocated portions are required. + */ +typedef struct sp_debug_symbol_s +{ + uint32_t codestart; /* relocated code address */ + uint32_t codeend; /* relocated code end address */ + const char * name; /* relocated name */ + sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */ + sp_fdbg_symbol_t *sym; /* pointer to original symbol */ +} sp_debug_symbol_t; + +/** + * Executes a Context. + * @sp_context_s - Execution Context + * @uint32_t - Offset from code pointer + * @res - return value of function + * @return - error code (0=none) + */ +typedef int (*SPVM_EXEC)(struct sp_context_s *, + uint32_t, + cell_t *res); + +#define SP_CONTEXT_DEBUG (1<<0) /* in debug mode */ +#define SP_CONTEXT_INHERIT_MEMORY (1<<1) /* inherits memory pointers */ +#define SP_CONTEXT_INHERIT_CODE (1<<2) /* inherits code pointers */ + +/** + * This is the heart of the VM. It contains all of the runtime + * information about a plugin context. + * It is split into three sections. + */ +typedef struct sp_context_s +{ + /* parent information */ + void *base; /* base of generated code and memory */ + sp_plugin_t *plugin; /* pointer back to parent information */ + struct sp_context_s *parent; /* pointer to parent context */ + uint32_t flags; /* context flags */ + /* execution specific data */ + SPVM_EXEC exec; /* execution base */ + cell_t pri; /* PRI register */ + cell_t alt; /* ALT register */ + cell_t *data; /* data chunk */ + cell_t *heap; /* pointer after data for start of heap */ + cell_t *sp; /* stack pointer */ + ucell_t memory; /* total memory size; */ + int32_t err; /* error code */ + uint32_t pushcount; /* push count */ + /* context rebased database */ + sp_public_t *publics /* public functions table */ + sp_pubvar_t *pubvars; /* public variables table */ + sp_native_t *natives; /* natives table */ + sp_debug_file_t *files; /* files */ + sp_debug_line_t *lines; /* lines */ + sp_debug_symbol_t *symbols; /* symbols */ +} sp_context_t; + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H + diff --git a/sourcepawn/vm/msvc8/vm.sln b/sourcepawn/vm/msvc8/vm.sln new file mode 100644 index 00000000..d9b51a02 --- /dev/null +++ b/sourcepawn/vm/msvc8/vm.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vm", "vm.vcproj", "{1B84D3AE-5938-401E-AD85-84D22A823BDA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Debug|Win32.Build.0 = Debug|Win32 + {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Release|Win32.ActiveCfg = Release|Win32 + {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj new file mode 100644 index 00000000..add70b61 --- /dev/null +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h new file mode 100644 index 00000000..51ea5d8c --- /dev/null +++ b/sourcepawn/vm/sp_vm.h @@ -0,0 +1,273 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_H_ +#define _INCLUDE_SOURCEPAWN_VM_H_ + +#include "sp_vm_types.h" + +/***************** + ** Note that all functions return a non-zero error code on failure + * unless otherwise noted. + * All input pointers must be valid unless otherwise noted as optional. + * All local address are guaranteed to be positive. However, they are stored + * as signed integers, because they must logically fit inside a cell. + */ + +typedef struct sp_nativeinfo_s +{ + const char *name; + SPVM_NATIVE_FUNC func; +} sp_nativeinfo_t; + +/** + * Loads a named file from a file pointer. + * Using this means base memory will be allocated by the VM. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ +sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err); + +/** + * Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ +sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); + +/** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ +int SP_FreeFromMemory(sp_plugin_t *plugin); + +/** + * Allocs memory on the secondary stack of a plugin. + * Note that although called a heap, it is in fact a stack. + * + * @param ctx Context pointer. + * @param cells Number of cells to allocate. + * @param local_adddr Will be filled with data offset to heap. + * @param phys_addr Physical address to heap memory. + */ +int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr); + +/** + * Pops a heap address off the heap stack. Use this to free memory allocated with + * SP_HeapAlloc(). + * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations + * with this native should be performed in precisely the REVERSE order. + */ +int SP_HeapPop(sp_context_t *ctx, cell_t local_addr); + +/** + * Releases a heap address using a different method than SP_HeapPop(). + * This allows you to release in any order. However, if you allocate N + * objects, release only some of them, then begin allocating again, + * you cannot go back and starting freeing the originals. + * In other words, for each chain of allocations, if you start deallocating, + * then allocating more in a chain, you must only deallocate from the current + * allocation chain. This is basically SP_HeapPop() except on a larger scale. + */ +int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr); + +/** + * Finds a native by name. + * + * @param ctx Context pointer. + * @param name Name of native. + * @param index Optionally filled with native index number. + */ +int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index); + +/** + * Gets native info by index. + * + * @param ctx Context pointer. + * @param index Index number of native. + * @param native Optionally filled with pointer to native structure. + */ +int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native); + +/** + * Gets the number of natives. + * + * @param ctx Context pointer. + * @param num Filled with the number of natives. + */ +int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num); + +/** + * Finds a public function by name. + * + * @param ctx Context pointer. + * @param name Name of public + * @param index Optionally filled with public index number. + */ +int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index); + + +/** + * Gets public function info by index. + * + * @param ctx Context pointer. + * @param index Public function index number. + * @param pblic Optionally filled with pointer to public structure. + */ +int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic); + +/** + * Gets the number of public functions. + * + * @param ctx Context pointer. + * @param num Filled with the number of public functions. + */ +int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num); + +/** + * Gets public variable info by index. + * @param ctx Context pointer. + * @param index Public variable index number. + * @param pubvar Optionally filled with pointer to pubvar structure. + */ +int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar); + +/** + * Finds a public variable by name. + * + * @param ctx Context pointer. + * @param name Name of pubvar + * @param index Optionally filled with pubvar index number. + * @param local_addr Optionally filled with local address offset. + * @param phys_addr Optionally filled with relocated physical address. + */ +int SP_FindPubvarByName(sp_context_t *ctx, + const char *name, + uint32_t *index, + cell_t *local_addr, + cell_t **phys_addr); + +/** + * Round-about method of converting a plugin reference to a physical address + * + * @param ctx Context pointer. + * @param local_addr Local address in plugin. + * @param phys_addr Optionally filled with relocated physical address. + */ +int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr); + +/** + * Convers a local address to a physical string. + * Note that SourcePawn does not support packed strings, as such this function is + * 'cell to char' only. + * + * @param ctx Context pointer. + * @param local_addr Local address in plugin. + * @param chars Optionally filled with the number of characters written. + * @param buffer Destination output buffer. + * @param maxlength Maximum length of output buffer, including null terminator. + */ +int SP_LocalToString(sp_context_t *ctx, + cell_t local_addr, + int *chars, + char *buffer, + size_t maxlength); + +/** + * Pushes a cell onto the stack. Increases the parameter count by one. + * + * @param ctx Context pointer. + * @param value Cell value. + */ +int SP_PushCell(sp_context_t *ctx, cell_t value); + +/** + * Pushes an array of cells onto the stack. Increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling SP_Execute(). + * + * @param ctx Context pointer. + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ +int SP_PushCellArray(sp_context_t *ctx, + cell_t *local_addr, + cell_t **phys_addr, + cell_t array[], + unsigned int numcells); + +/** + * Pushes a string onto the stack (by reference) and increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling SP_Execute(). + * + * @param ctx Context pointer. + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ +int SP_PushString(sp_context_t *ctx, + cell_t *local_addr, + cell_t **phys_addr, + const char *string); + +/** + * Individually pushes each cell of an array of cells onto the stack. Increases the + * parameter count by the number of cells pushed. + * + * @param ctx Context pointer. + * @param array Array of cells to read from. + * @param numcells Number of cells to read. + */ +int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells); + +/** + * Binds a list of native names and their function pointers to a context. + * If num is 0, the list is read until an entry with a NULL name is reached. + * All natives are assigned a status of SP_NATIVE_OKAY by default. + * If overwrite is non-zero, already registered arrays will be overwritten. + * + * @param ctx Context pointer. + * @param natives Array of natives. + * @param num Number of natives in array. + */ +int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite); + +/** + * Binds a single native. Overwrites any existing bind. + * + * @param ctx Context pointer. + * @param native Pointer to native. + * @param status Status value to set (should be SP_NATIVE_OKAY). + */ +int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status); + +/** + * Binds a single native to any non-registered native. + * Status is automatically set to pending. + * + * @param ctx Context pointer. + */ +int SP_BindNativeToAny(sp_context_t *ctx, sp_nativeinfo_t *native); + +/** + * Executes a public function in a context. + * The parameter count is set to zero during execution. + * All context-specific variables that are modified are saved before execution, + * thus allowing nested calls to SP_Execute(). + * + * @param ctx Context pointer. + * @param idx Public function index number. + * @param result Optional pointer to store return value. + */ +int SP_Execute(sp_context_t *ctx, uint32_t idx, cell_t *result); + + +#endif //_INCLUDE_SOURCEPAWN_VM_H_ diff --git a/sourcepawn/vm/zlib/adler32.c b/sourcepawn/vm/zlib/adler32.c new file mode 100644 index 00000000..f201d670 --- /dev/null +++ b/sourcepawn/vm/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/sourcepawn/vm/zlib/compress.c b/sourcepawn/vm/zlib/compress.c new file mode 100644 index 00000000..d37e84f5 --- /dev/null +++ b/sourcepawn/vm/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/sourcepawn/vm/zlib/crc32.c b/sourcepawn/vm/zlib/crc32.c new file mode 100644 index 00000000..32814c20 --- /dev/null +++ b/sourcepawn/vm/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/sourcepawn/vm/zlib/crc32.h b/sourcepawn/vm/zlib/crc32.h new file mode 100644 index 00000000..5de49bc9 --- /dev/null +++ b/sourcepawn/vm/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/sourcepawn/vm/zlib/deflate.c b/sourcepawn/vm/zlib/deflate.c new file mode 100644 index 00000000..529f716b --- /dev/null +++ b/sourcepawn/vm/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/sourcepawn/vm/zlib/deflate.h b/sourcepawn/vm/zlib/deflate.h new file mode 100644 index 00000000..222c53e0 --- /dev/null +++ b/sourcepawn/vm/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/sourcepawn/vm/zlib/gzio.c b/sourcepawn/vm/zlib/gzio.c new file mode 100644 index 00000000..5e20a4aa --- /dev/null +++ b/sourcepawn/vm/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/sourcepawn/vm/zlib/infback.c b/sourcepawn/vm/zlib/infback.c new file mode 100644 index 00000000..1e03e1ba --- /dev/null +++ b/sourcepawn/vm/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/sourcepawn/vm/zlib/inffast.c b/sourcepawn/vm/zlib/inffast.c new file mode 100644 index 00000000..fa31cad9 --- /dev/null +++ b/sourcepawn/vm/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/sourcepawn/vm/zlib/inffast.h b/sourcepawn/vm/zlib/inffast.h new file mode 100644 index 00000000..614fa787 --- /dev/null +++ b/sourcepawn/vm/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/sourcepawn/vm/zlib/inffixed.h b/sourcepawn/vm/zlib/inffixed.h new file mode 100644 index 00000000..423d5c5b --- /dev/null +++ b/sourcepawn/vm/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/sourcepawn/vm/zlib/inflate.c b/sourcepawn/vm/zlib/inflate.c new file mode 100644 index 00000000..33ea9029 --- /dev/null +++ b/sourcepawn/vm/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/sourcepawn/vm/zlib/inflate.h b/sourcepawn/vm/zlib/inflate.h new file mode 100644 index 00000000..fbbc8714 --- /dev/null +++ b/sourcepawn/vm/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/sourcepawn/vm/zlib/inftrees.c b/sourcepawn/vm/zlib/inftrees.c new file mode 100644 index 00000000..38ded81c --- /dev/null +++ b/sourcepawn/vm/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/sourcepawn/vm/zlib/inftrees.h b/sourcepawn/vm/zlib/inftrees.h new file mode 100644 index 00000000..dc0fd567 --- /dev/null +++ b/sourcepawn/vm/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/sourcepawn/vm/zlib/trees.c b/sourcepawn/vm/zlib/trees.c new file mode 100644 index 00000000..7a048028 --- /dev/null +++ b/sourcepawn/vm/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/sourcepawn/vm/zlib/trees.h b/sourcepawn/vm/zlib/trees.h new file mode 100644 index 00000000..1ca868b8 --- /dev/null +++ b/sourcepawn/vm/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/sourcepawn/vm/zlib/uncompr.c b/sourcepawn/vm/zlib/uncompr.c new file mode 100644 index 00000000..ad6db0a6 --- /dev/null +++ b/sourcepawn/vm/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/sourcepawn/vm/zlib/zconf.h b/sourcepawn/vm/zlib/zconf.h new file mode 100644 index 00000000..59b5e7a6 --- /dev/null +++ b/sourcepawn/vm/zlib/zconf.h @@ -0,0 +1,281 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/sourcepawn/vm/zlib/zlib.h b/sourcepawn/vm/zlib/zlib.h new file mode 100644 index 00000000..62d0e467 --- /dev/null +++ b/sourcepawn/vm/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/sourcepawn/vm/zlib/zutil.c b/sourcepawn/vm/zlib/zutil.c new file mode 100644 index 00000000..0f4bd787 --- /dev/null +++ b/sourcepawn/vm/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/sourcepawn/vm/zlib/zutil.h b/sourcepawn/vm/zlib/zutil.h new file mode 100644 index 00000000..0ba6e020 --- /dev/null +++ b/sourcepawn/vm/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ From 2f47baee55a0f6f0f87ecfdca5a95f42c40dd4d1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 29 Jul 2006 23:29:52 +0000 Subject: [PATCH 0009/1664] fixed headers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4039 --- sourcepawn/include/sp_vm_types.h | 26 +++++++++++++------------- sourcepawn/vm/msvc8/vm.vcproj | 5 +++++ sourcepawn/vm/sp_vm.h | 1 + 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index e89ea89e..52019b07 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -24,7 +24,7 @@ typedef int32_t cell_t; * Information about the core plugin tables. * These may or may not be present! */ -typedef struct sp_plugin_infotab_t +typedef struct sp_plugin_infotab_s { const char *stringbase; /* base of string table */ uint32_t publics_num; /* number of publics */ @@ -33,13 +33,13 @@ typedef struct sp_plugin_infotab_t sp_file_natives_t *natives; /* native table */ uint32_t pubvars_num; /* number of pubvars */ sp_file_pubvars_t *pubvars; /* pubvars table */ -} sp_plugin_infotab_s; +} sp_plugin_infotab_t; /** * Information about the plugin's debug tables. * These are all present if one is present. */ -typedef struct sp_plugin_debug_t +typedef struct sp_plugin_debug_s { const char *stringbase; /* base of string table */ uint32_t files_num; /* number of files */ @@ -48,7 +48,7 @@ typedef struct sp_plugin_debug_t sp_fdbg_line_t *lines; /* lines table */ uint32_t syms_num; /* number of symbols */ sp_fdbg_symbol_t *symbols; /* symbol table */ -} sp_plugin_debug_s; +} sp_plugin_debug_t; #define SP_FA_SELF_EXTERNAL (1<<0) #define SP_FA_BASE_EXTERNAL (1<<1) @@ -58,7 +58,7 @@ typedef struct sp_plugin_debug_t * This differs from the on-disk structure to ensure * that the format is properly read. */ -typedef struct sp_plugin_t +typedef struct sp_plugin_s { uint8_t *base; /* base of memory */ uint8_t *pcode; /* p-code */ @@ -70,10 +70,10 @@ typedef struct sp_plugin_t uint32_t allocflags; /* allocation flags */ sp_plugin_infotab_t *info; /* base info table */ sp_plugin_debug_t *debug; /* debug info table */ -} sp_plugin_s; +} sp_plugin_t; struct sp_context_s; -typedef int (*SPVM_NATIVE_FUNC)(sp_context_s *, cell_t *); +typedef int (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); /********************************************** *** The following structures are bound to the VM/JIT. @@ -85,22 +85,22 @@ typedef int (*SPVM_NATIVE_FUNC)(sp_context_s *, cell_t *); * By default, these point back to the string table * in the sp_plugin_infotab_t structure. */ -typedef struct sp_public_t +typedef struct sp_public_s { uint32_t offs; /* code offset */ const char *name; /* name */ -} sp_publics_s; +} sp_public_t; /** * Offsets and names to public variables. * The offset is relocated and the name by default * points back to the sp_plugin_infotab_t structure. */ -typedef struct sp_pubvar_t +typedef struct sp_pubvar_s { cell_t *offs; /* pointer to data */ const char *name; /* name */ -} sp_pubvar_t +} sp_pubvar_t; #define SP_NATIVE_NONE (0) /* Native is not yet found */ #define SP_NATIVE_OKAY (1) /* Native has been added */ @@ -111,7 +111,7 @@ typedef struct sp_pubvar_t * point back to the sp_plugin_infotab_t structure. * A native is NULL if unit */ -typedef struct sp_native_t +typedef struct sp_native_s { SPVM_NATIVE_FUNC pfn; /* function pointer */ const char * name; /* name of function */ @@ -190,7 +190,7 @@ typedef struct sp_context_s int32_t err; /* error code */ uint32_t pushcount; /* push count */ /* context rebased database */ - sp_public_t *publics /* public functions table */ + sp_public_t *publics; /* public functions table */ sp_pubvar_t *pubvars; /* public variables table */ sp_native_t *natives; /* natives table */ sp_debug_file_t *files; /* files */ diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index add70b61..c7aaedd7 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -40,6 +40,7 @@ + + #include "sp_vm_types.h" /***************** From 166a2b8a438b742bad236ee0acd4caf62dfa4835 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 30 Jul 2006 04:53:06 +0000 Subject: [PATCH 0010/1664] fixed bug where disk size was written without the header included --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4040 --- sourcepawn/compiler/pawncc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index d8073e2d..1727e5c2 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -584,6 +584,7 @@ int main(int argc, char *argv[]) size_t size; Bytef *zcmp; uLong disksize; + size_t header_size; int err = Z_OK; /* reuse this memory block! */ @@ -600,8 +601,9 @@ int main(int argc, char *argv[]) (unsigned char *)pOrig->base + sizeof(sp_file_hdr_t), pHdr->dataoffs - sizeof(sp_file_hdr_t)); - size = pHdr->imagesize - pHdr->dataoffs; - proper = (unsigned char *)pOrig->base + pHdr->dataoffs; + header_size = pHdr->dataoffs; + size = pHdr->imagesize - header_size; + proper = (unsigned char *)pOrig->base + header_size; /* get initial size estimate */ pHdr->disksize = (uint32_t)compressBound(pHdr->imagesize); @@ -621,11 +623,11 @@ int main(int argc, char *argv[]) proper, size); } else { - pHdr->disksize = (uint32_t)disksize; + pHdr->disksize = (uint32_t)disksize + header_size; pHdr->compression = SPFILE_COMPRESSION_GZ; memfile_write(bin_file, (unsigned char *)zcmp, - pHdr->disksize); + disksize); free(zcmp); } } From e03ab1e6d4cce8737c70a6e016434c21d0ceb59d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 30 Jul 2006 04:53:53 +0000 Subject: [PATCH 0011/1664] something changed here --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4041 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 4 ++++ sourcepawn/include/sp_file_headers.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index 491bacf5..08d373a6 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -282,6 +282,10 @@ RelativePath="..\sp_file.h" > + + diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h index b83fff38..c7bd81ae 100644 --- a/sourcepawn/include/sp_file_headers.h +++ b/sourcepawn/include/sp_file_headers.h @@ -52,7 +52,7 @@ typedef struct sp_file_hdr_s uint32_t disksize; /* size on disk */ uint32_t imagesize; /* size in memory */ uint8_t sections; /* number of sections */ - uint32_t stringtab; /* offset to string table */ + uint32_t stringtab; /* offset to string table aa*/ uint32_t dataoffs; /* offset to file proper (any compression starts here) */ } sp_file_hdr_t; From 83ae061c6e8ba1636333dbfe4224ca66e8c1edaf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 31 Jul 2006 18:59:17 +0000 Subject: [PATCH 0012/1664] begin implementing some helpers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4042 --- sourcepawn/include/sp_file_headers.h | 2 +- sourcepawn/include/sp_vm_types.h | 10 ++- sourcepawn/vm/msvc8/vm.vcproj | 6 +- sourcepawn/vm/sp_vm.c | 107 +++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 sourcepawn/vm/sp_vm.c diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h index c7bd81ae..b83fff38 100644 --- a/sourcepawn/include/sp_file_headers.h +++ b/sourcepawn/include/sp_file_headers.h @@ -52,7 +52,7 @@ typedef struct sp_file_hdr_s uint32_t disksize; /* size on disk */ uint32_t imagesize; /* size in memory */ uint8_t sections; /* number of sections */ - uint32_t stringtab; /* offset to string table aa*/ + uint32_t stringtab; /* offset to string table */ uint32_t dataoffs; /* offset to file proper (any compression starts here) */ } sp_file_hdr_t; diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 52019b07..9569b924 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -12,6 +12,9 @@ typedef int32_t cell_t; #define SP_ERR_NONE 0 #define SP_ERR_FILE_FORMAT 1 /* File format unrecognized */ #define SP_ERR_DECOMPRESSOR 2 /* A decompressor was not found */ +#define SP_ERR_HEAPLOW 3 /* Not enough space left on the heap */ +#define SP_ERR_PARAM 4 /* Invalid parameter */ +#define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ /********************************************** *** The following structures are reference structures. @@ -183,9 +186,10 @@ typedef struct sp_context_s SPVM_EXEC exec; /* execution base */ cell_t pri; /* PRI register */ cell_t alt; /* ALT register */ - cell_t *data; /* data chunk */ - cell_t *heap; /* pointer after data for start of heap */ - cell_t *sp; /* stack pointer */ + uint8_t *data; /* data chunk */ + cell_t heapbase; /* heap base */ + cell_t hp; /* heap pointer */ + cell_t sp; /* stack pointer */ ucell_t memory; /* total memory size; */ int32_t err; /* error code */ uint32_t pushcount; /* push count */ diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index c7aaedd7..66fe7b10 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -41,13 +41,13 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\include" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" - Detect64BitPortabilityProblems="true" + Detect64BitPortabilityProblems="false" DebugInformationFormat="4" /> diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c new file mode 100644 index 00000000..2c668530 --- /dev/null +++ b/sourcepawn/vm/sp_vm.c @@ -0,0 +1,107 @@ +#include +#include +#include "sp_vm.h" + +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) + +int main() +{ + /** temporary testing area */ + sp_context_t ctx; + cell_t l, *p; + + ctx.data = (uint8_t *)malloc(50000); + ctx.memory = 50000; + ctx.heapbase = 200; + ctx.hp = ctx.heapbase; + ctx.sp = 45000; + + assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); + assert(SP_HeapPop(&ctx, l) == SP_ERR_NONE); + assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); + assert(SP_HeapRelease(&ctx, 4) == SP_ERR_INVALID_ADDRESS); + assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); + assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); + + return 0; +} + +int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr) +{ + cell_t *addr; + ucell_t realmem; + +#if 0 + if (cells > CELLBOUNDMAX) + { + return SP_ERR_PARAM; + } +#else + assert(cells < CELLBOUNDMAX); +#endif + + realmem = cells * sizeof(cell_t); + + /** + * Check if the space between the heap and stack is sufficient. + */ + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) + { + return SP_ERR_HEAPLOW; + } + + addr = (cell_t *)(ctx->data + ctx->hp); + /* store size of allocation in cells */ + *addr = (cell_t)cells; + addr++; + ctx->hp += sizeof(cell_t); + + *local_addr = ctx->hp; + + if (phys_addr) + { + *phys_addr = addr; + } + + ctx->hp += realmem; + + return SP_ERR_NONE; +} + +int SP_HeapPop(sp_context_t *ctx, cell_t local_addr) +{ + cell_t cellcount; + cell_t *addr; + + /* check the bounds of this address */ + local_addr -= sizeof(cell_t); + if (local_addr < ctx->heapbase || local_addr >= ctx->sp) + { + return SP_ERR_INVALID_ADDRESS; + } + + addr = (cell_t *)(ctx->data + local_addr); + cellcount = (*addr) * sizeof(cell_t); + /* check if this memory count looks valid */ + if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) + { + return SP_ERR_INVALID_ADDRESS; + } + + ctx->hp = local_addr; + + return SP_ERR_NONE; +} + +int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) +{ + if (local_addr < ctx->heapbase) + { + return SP_ERR_INVALID_ADDRESS; + } + + ctx->hp = local_addr - sizeof(cell_t); + + return SP_ERR_NONE; +} From dec86a9b2b13cacc2bade41fe1eef0212ba8984a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 31 Jul 2006 19:12:23 +0000 Subject: [PATCH 0013/1664] to preserve cips, pre-compression of code is removed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4043 --- sourcepawn/compiler/pawncc.c | 223 +---------------------------------- 1 file changed, 3 insertions(+), 220 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index 1727e5c2..43030f13 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -127,15 +127,11 @@ int main(int argc, char *argv[]) if (sections[FS_Code]) { sp_file_code_t cod; - cell cip; unsigned char *cbase; - uint8_t *tbase, *tptr; - cell real_codesize; - uint8_t op; cod.cellsize = sizeof(cell); - cod.codesize = 0; + cod.codesize = hdr->dat - hdr->cod; cod.codeversion = hdr->amx_version; cod.flags = 0; if (hdr->flags & AMX_FLAG_DEBUG) @@ -145,223 +141,10 @@ int main(int argc, char *argv[]) cod.code = sizeof(cod); cod.main = hdr->cip; - /* write the code in our newer format */ + /* write the code */ cbase = (unsigned char *)hdr + hdr->cod; - real_codesize = hdr->dat - hdr->cod; - tbase = (uint8_t *)malloc(real_codesize); - tptr = tbase; - for (cip = 0; cip < real_codesize;) - { -#define DBGPARAM(v) ( (v)=*(cell *)(cbase+(int)cip), cip+=sizeof(cell) ) - op=(uint8_t) *(ucell *)(cbase+(int)cip); - cip += sizeof(cell); - *tptr++ = op; - switch (op) - { - case OP_PUSH5_C: /* instructions with 5 parameters */ - case OP_PUSH5: - case OP_PUSH5_S: - case OP_PUSH5_ADR: - { - memcpy(tptr, cbase+(int)cip, sizeof(cell)*5); - cip += sizeof(cell)*5; - tptr += sizeof(cell)*5; - break; - } - case OP_PUSH4_C: /* instructions with 4 parameters */ - case OP_PUSH4: - case OP_PUSH4_S: - case OP_PUSH4_ADR: - { - memcpy(tptr, cbase+(int)cip, sizeof(cell)*4); - cip += sizeof(cell)*4; - tptr += sizeof(cell)*4; - break; - } - case OP_PUSH3_C: /* instructions with 3 parameters */ - case OP_PUSH3: - case OP_PUSH3_S: - case OP_PUSH3_ADR: - { - memcpy(tptr, cbase+(int)cip, sizeof(cell)*3); - cip += sizeof(cell)*3; - tptr += sizeof(cell)*3; - break; - } - case OP_PUSH2_C: /* instructions with 2 parameters */ - case OP_PUSH2: - case OP_PUSH2_S: - case OP_PUSH2_ADR: - case OP_LOAD_BOTH: - case OP_LOAD_S_BOTH: - case OP_CONST: - case OP_CONST_S: - case OP_SYSREQ_N: - { - memcpy(tptr, cbase+(int)cip, sizeof(cell)*2); - cip += sizeof(cell)*2; - tptr += sizeof(cell)*2; - break; - } - case OP_LOAD_PRI: /* instructions with 1 parameter */ - case OP_LOAD_ALT: - case OP_LOAD_S_PRI: - case OP_LOAD_S_ALT: - case OP_LREF_PRI: - case OP_LREF_ALT: - case OP_LREF_S_PRI: - case OP_LREF_S_ALT: - case OP_LODB_I: - case OP_CONST_PRI: - case OP_CONST_ALT: - case OP_ADDR_PRI: - case OP_ADDR_ALT: - case OP_STOR_PRI: - case OP_STOR_ALT: - case OP_STOR_S_PRI: - case OP_STOR_S_ALT: - case OP_SREF_PRI: - case OP_SREF_ALT: - case OP_SREF_S_PRI: - case OP_SREF_S_ALT: - case OP_STRB_I: - case OP_LIDX_B: - case OP_IDXADDR_B: - case OP_ALIGN_PRI: - case OP_ALIGN_ALT: - case OP_LCTRL: - case OP_SCTRL: - case OP_PUSH_R: - case OP_PUSH_C: - case OP_PUSH: - case OP_PUSH_S: - case OP_STACK: - case OP_HEAP: - case OP_JREL: - case OP_SHL_C_PRI: - case OP_SHL_C_ALT: - case OP_SHR_C_PRI: - case OP_SHR_C_ALT: - case OP_ADD_C: - case OP_SMUL_C: - case OP_ZERO: - case OP_ZERO_S: - case OP_EQ_C_PRI: - case OP_EQ_C_ALT: - case OP_INC: - case OP_INC_S: - case OP_DEC: - case OP_DEC_S: - case OP_MOVS: - case OP_CMPS: - case OP_FILL: - case OP_HALT: - case OP_BOUNDS: - case OP_PUSH_ADR: - case OP_CALL: /* opcodes that need relocation */ - case OP_JUMP: - case OP_JZER: - case OP_JNZ: - case OP_JEQ: - case OP_JNEQ: - case OP_JLESS: - case OP_JLEQ: - case OP_JGRTR: - case OP_JGEQ: - case OP_JSLESS: - case OP_JSLEQ: - case OP_JSGRTR: - case OP_JSGEQ: - case OP_SWITCH: - case OP_SYSREQ_C: - { - *(cell *)tptr = *(cell *)(cbase + (int)cip); - cip += sizeof(cell); - tptr += sizeof(cell); - break; - } - case OP_LOAD_I: /* instructions without parameters */ - case OP_STOR_I: - case OP_LIDX: - case OP_IDXADDR: - case OP_MOVE_PRI: - case OP_MOVE_ALT: - case OP_XCHG: - case OP_PUSH_PRI: - case OP_PUSH_ALT: - case OP_POP_PRI: - case OP_POP_ALT: - case OP_PROC: - case OP_RET: - case OP_RETN: - case OP_CALL_PRI: - case OP_SHL: - case OP_SHR: - case OP_SSHR: - case OP_SMUL: - case OP_SDIV: - case OP_SDIV_ALT: - case OP_UMUL: - case OP_UDIV: - case OP_UDIV_ALT: - case OP_ADD: - case OP_SUB: - case OP_SUB_ALT: - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_NOT: - case OP_NEG: - case OP_INVERT: - case OP_ZERO_PRI: - case OP_ZERO_ALT: - case OP_SIGN_PRI: - case OP_SIGN_ALT: - case OP_EQ: - case OP_NEQ: - case OP_LESS: - case OP_LEQ: - case OP_GRTR: - case OP_GEQ: - case OP_SLESS: - case OP_SLEQ: - case OP_SGRTR: - case OP_SGEQ: - case OP_INC_PRI: - case OP_INC_ALT: - case OP_INC_I: - case OP_DEC_PRI: - case OP_DEC_ALT: - case OP_DEC_I: - case OP_SYSREQ_PRI: - case OP_JUMP_PRI: - case OP_SWAP_PRI: - case OP_SWAP_ALT: - case OP_NOP: - case OP_BREAK: - break; - case OP_CASETBL: - { - cell num; - DBGPARAM(*(cell *)tptr); - num = *(cell *)tptr; - tptr += sizeof(cell); - memcpy(tptr, cbase+(int)cip, (2*num+1)*sizeof(cell)); - tptr += (2*num+1) * sizeof(cell); - cip += (2*num+1) * sizeof(cell); - break; - } - default: - { - assert(0); - } -#undef DBGPARAM - } - } - cod.codesize = (uint32_t)(tptr - tbase); sfwrite(&cod, sizeof(cod), 1, spf); - sfwrite(tbase, cod.codesize, 1, spf); - free(tbase); + sfwrite(cbase, cod.codesize, 1, spf); spfw_next_section(spf); } From 8bdd9c20d33c6adea4b9e7c12dbbaab3f9c7e302 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 31 Jul 2006 19:18:09 +0000 Subject: [PATCH 0014/1664] upped version # --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4044 --- sourcepawn/include/sp_file_headers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h index b83fff38..9ccf4bb9 100644 --- a/sourcepawn/include/sp_file_headers.h +++ b/sourcepawn/include/sp_file_headers.h @@ -19,7 +19,8 @@ #endif #define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ -#define SPFILE_VERSION 0x0100 +//#define SPFILE_VERSION 0x0100 +#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */ //:TODO: better compiler/nix support #if defined __linux__ From 0ac9fcea2d966814e07aa426c84ac7bb9925abb6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 31 Jul 2006 21:42:02 +0000 Subject: [PATCH 0015/1664] new error type --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4045 --- sourcepawn/include/sp_vm_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 9569b924..c4a8d815 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -15,6 +15,7 @@ typedef int32_t cell_t; #define SP_ERR_HEAPLOW 3 /* Not enough space left on the heap */ #define SP_ERR_PARAM 4 /* Invalid parameter */ #define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ +#define SP_ERR_NOT_FOUND 6 /* File not found */ /********************************************** *** The following structures are reference structures. From a97a3cddb9ca46b520cbd88dda3cba04cfff3777 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 1 Aug 2006 00:21:00 +0000 Subject: [PATCH 0016/1664] reader implementation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4046 --- sourcepawn/vm/sp_reader.c | 211 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 sourcepawn/vm/sp_reader.c diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c new file mode 100644 index 00000000..f61b63d6 --- /dev/null +++ b/sourcepawn/vm/sp_reader.c @@ -0,0 +1,211 @@ +#include +#include +#include "sp_vm.h" +#include "zlib/zlib.h" + +sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err) +{ + char *nameptr; + uint8_t sectnum = 0; + + sp_plugin_infotab_t *info = (sp_plugin_infotab_t *)malloc(sizeof(sp_plugin_infotab_t)); + sp_plugin_debug_t *dbg = (sp_plugin_debug_t *)malloc(sizeof(sp_plugin_debug_t)); + + sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t)); + + memset(plugin, 0, sizeof(sp_plugin_t)); + memset(info, 0, sizeof(sp_plugin_infotab_t)); + memset(dbg, 0, sizeof(sp_plugin_debug_t)); + + plugin->base = base; + plugin->info = info; + plugin->debug = dbg; + + while (sectnum < hdr->sections) + { + nameptr = base + hdr->stringtab + secptr->nameoffs; + + if (!(plugin->pcode) && !strcmp(nameptr, ".code")) + { + sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs); + plugin->pcode = base + secptr->dataoffs + cod->code; + plugin->pcode_size = cod->codesize; + plugin->flags = cod->flags; + } + else if (!(plugin->data) && !strcmp(nameptr, ".data")) + { + sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs); + plugin->data = base + secptr->dataoffs + dat->data; + plugin->data_size = dat->datasize; + plugin->memory = dat->memsize; + } + else if (!(plugin->info->stringbase) && !strcmp(nameptr, ".names")) + { + plugin->info->stringbase = base + secptr->dataoffs; + } + else if (!(plugin->info->publics) && !strcmp(nameptr, ".publics")) + { + plugin->info->publics_num = secptr->size / sizeof(sp_file_publics_t); + plugin->info->publics = (sp_file_publics_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info->pubvars) && !strcmp(nameptr, ".pubvars")) + { + plugin->info->pubvars_num = secptr->size / sizeof(sp_file_pubvars_t); + plugin->info->pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info->natives) && !strcmp(nameptr, ".natives")) + { + plugin->info->natives_num = secptr->size / sizeof(sp_file_natives_t); + plugin->info->natives = (sp_file_natives_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug->files) && !strcmp(nameptr, ".dbg.files")) + { + plugin->debug->files_num = secptr->size / sizeof(sp_fdbg_file_t); + plugin->debug->files = (sp_fdbg_file_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug->stringbase) && !strcmp(nameptr, ".dbg.strings")) + { + plugin->debug->stringbase = base + secptr->dataoffs; + } + else if (!(plugin->debug->lines) && !strcmp(nameptr, ".dbg.lines")) + { + plugin->debug->lines_num = secptr->size / sizeof(sp_fdbg_line_t); + plugin->debug->lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug->symbols) && !strcmp(nameptr, ".dbg.symbols")) + { + plugin->debug->syms_num = secptr->size / sizeof(sp_fdbg_symbol_t); + plugin->debug->symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); + } + secptr++; + sectnum++; + } + + if (!(plugin->pcode) || !(plugin->data) || !(plugin->info->stringbase)) + goto return_error; + + if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug->files) || !(plugin->debug->lines) || !(plugin->debug->symbols))) + goto return_error; + + return plugin; + +return_error: + free(dbg); + free(info); + + if (err) + *err = SP_ERR_FILE_FORMAT; + + return NULL; +} + +sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err) +{ + sp_file_hdr_t hdr; + sp_plugin_t *plugin; + uint8_t *base; + int z_result; + int error; + + if (!fp) + { + error = SP_ERR_NOT_FOUND; + goto return_error; + } + + /* Rewind for safety */ + rewind(fp); + fread(&hdr, sizeof(sp_file_hdr_t), 1, fp); + + if (hdr.magic != SPFILE_MAGIC) + { + error = SP_ERR_FILE_FORMAT; + goto return_error; + } + + switch (hdr.compression) + { + case SPFILE_COMPRESSION_GZ: + { + uint32_t uncompsize = hdr.imagesize - hdr.dataoffs; + uint32_t compsize = hdr.disksize - hdr.dataoffs; + uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t); + uLongf destlen = uncompsize; + + char *tempbuf = (char *)malloc(compsize); + void *uncompdata = malloc(uncompsize); + void *sectheader = malloc(sectsize); + + fread(sectheader, sectsize, 1, fp); + fread(tempbuf, compsize, 1, fp); + + z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize); + free(tempbuf); + if (z_result != Z_OK) + { + free(sectheader); + free(uncompdata); + error = SP_ERR_DECOMPRESSOR; + goto return_error; + } + + base = (uint8_t *)malloc(hdr.imagesize); + memcpy(base, &hdr, sizeof(sp_file_hdr_t)); + memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize); + free(sectheader); + memcpy(base + hdr.dataoffs, uncompdata, uncompsize); + free(uncompdata); + break; + } + case SPFILE_COMPRESSION_NONE: + { + base = (uint8_t *)malloc(hdr.imagesize); + rewind(fp); + fread(base, hdr.imagesize, 1, fp); + break; + } + default: + { + error = SP_ERR_DECOMPRESSOR; + goto return_error; + } + } + + plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); + if (!_ReadPlugin(&hdr, base, plugin, err)) + { + free(plugin); + free(base); + return NULL; + } + + return plugin; + +return_error: + if (err) + *err = error; + return NULL; +} + +sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) +{ + sp_file_hdr_t hdr; + uint8_t noptr = 0; + + memcpy(&hdr, base, sizeof(sp_file_hdr_t)); + + if (!plugin) + { + plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); + noptr = 1; + } + + if (!_ReadPlugin(&hdr, base, plugin, err)) + { + if (noptr) + free(plugin); + return NULL; + } + + return plugin; +} From ba55eab9f51ecd097fd25a8e0477793f5b88c07c Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 1 Aug 2006 01:14:54 +0000 Subject: [PATCH 0017/1664] find native by name --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4047 --- sourcepawn/vm/sp_vm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index 2c668530..b9651fb4 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -1,4 +1,5 @@ #include +#include #include #include "sp_vm.h" @@ -105,3 +106,19 @@ int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) return SP_ERR_NONE; } + +int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) +{ + uint32_t i; + + for (i = 0; i < ctx->plugin->info->natives_num; i++) + { + if (!strcmp(name, ctx->natives[i].name)) + { + if (index) + *index = i; + return SP_ERR_NONE; + } + } + return SP_ERR_NOT_FOUND; +} \ No newline at end of file From 1ac897a9b1e5502403f108461914cac6f426e3fc Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 1 Aug 2006 10:15:01 +0000 Subject: [PATCH 0018/1664] changed comment --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4048 --- sourcepawn/include/sp_vm_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index c4a8d815..345b6159 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -15,7 +15,7 @@ typedef int32_t cell_t; #define SP_ERR_HEAPLOW 3 /* Not enough space left on the heap */ #define SP_ERR_PARAM 4 /* Invalid parameter */ #define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ -#define SP_ERR_NOT_FOUND 6 /* File not found */ +#define SP_ERR_NOT_FOUND 6 /* The object in question was not found */ /********************************************** *** The following structures are reference structures. From 119939590d4216d968befd7039a3fe2e7dfc8f45 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 1 Aug 2006 12:00:49 +0000 Subject: [PATCH 0019/1664] little fix --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4049 --- sourcepawn/vm/sp_reader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c index f61b63d6..92f8b9a3 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_reader.c @@ -87,6 +87,9 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug->files) || !(plugin->debug->lines) || !(plugin->debug->symbols))) goto return_error; + if (err) + *err = SP_ERR_NONE; + return plugin; return_error: From a9b3da5904d7e1f53accdb930a5d5fca00580380 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Aug 2006 19:49:33 +0000 Subject: [PATCH 0020/1664] fixed a bug with stub offsets being calculated wrong --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4050 --- sourcepawn/compiler/pawncc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index 43030f13..a64ac5aa 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -174,17 +174,19 @@ int main(int argc, char *argv[]) { sp_file_publics_t *pbtbl; AMX_FUNCSTUBNT *stub; + unsigned char *stubptr; uint32_t publics = sections[FS_Publics]; pbtbl = (sp_file_publics_t *)malloc(sizeof(sp_file_publics_t) * publics); - stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->publics); + stubptr = (unsigned char *)hdr + hdr->publics; for (i=0; iaddress; pbtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t)); - stub += hdr->defsize; + stubptr += hdr->defsize; } if (publics) { @@ -199,17 +201,19 @@ int main(int argc, char *argv[]) { sp_file_pubvars_t *pbvars; AMX_FUNCSTUBNT *stub; + unsigned char *stubptr; uint32_t pubvars = sections[FS_Pubvars]; pbvars = (sp_file_pubvars_t *)malloc(sizeof(sp_file_pubvars_t) * pubvars); - stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->pubvars); + stubptr = (unsigned char *)hdr + hdr->pubvars; for (i=0; iaddress; pbvars[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t)); - stub += hdr->defsize; + stubptr += hdr->defsize; } if (pubvars) { @@ -223,16 +227,18 @@ int main(int argc, char *argv[]) { sp_file_natives_t *nvtbl; AMX_FUNCSTUBNT *stub; + unsigned char *stubptr; uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize; nvtbl = (sp_file_natives_t *)malloc(sizeof(sp_file_natives_t) * natives); - stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->natives); + stubptr = (unsigned char *)hdr + hdr->natives; for (i=0; inameofs - (hdr->nametable + sizeof(uint16_t)); - stub += hdr->defsize; + stubptr += hdr->defsize; } if (natives) { From c23a23fb344a9ca75041b0b18f90c82de55fbb09 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Aug 2006 23:17:13 +0000 Subject: [PATCH 0021/1664] Added new .dbg.info section to the compiler for helping counting --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4051 --- sourcepawn/compiler/pawncc.c | 14 ++++++++++++++ sourcepawn/include/sp_file_headers.h | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index a64ac5aa..f9839590 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -24,6 +24,7 @@ enum FileSections FS_DbgAutomaton, FS_DbgState, FS_DbgStrings, + FS_DbgInfo, /* --- */ FS_Number, }; @@ -113,7 +114,9 @@ int main(int argc, char *argv[]) spfw_add_section(spf, ".dbg.symbols"); sections[FS_DbgSymbol] = dbg->symbols; } + sections[FS_DbgInfo] = 1; sections[FS_DbgStrings] = 1; + spfw_add_section(spf, ".dbg.info"); spfw_add_section(spf, ".dbg.strings"); } } @@ -266,6 +269,10 @@ int main(int argc, char *argv[]) if (hdr->flags & AMX_FLAG_DEBUG) { + sp_fdbg_info_t info; + + memset(&info, 0, sizeof(sp_fdbg_info_t)); + if (sections[FS_DbgFile]) { uint32_t idx; @@ -284,6 +291,7 @@ int main(int argc, char *argv[]) /* write to tab, then move to next */ memfile_write(dbgtab, _ptr->name, len + 1); dbgptr += sizeof(AMX_DBG_FILE) + len; + info.num_files++; } spfw_next_section(spf); } @@ -303,6 +311,7 @@ int main(int argc, char *argv[]) sfwrite(&dbgline, sizeof(sp_fdbg_line_t), 1, spf); /* move to next */ dbgptr += sizeof(AMX_DBG_LINE); + info.num_lines++; } spfw_next_section(spf); } @@ -337,6 +346,7 @@ int main(int argc, char *argv[]) /* move to next */ dbgptr += sizeof(AMX_DBG_SYMBOL) + len; /* look for any dimensions */ + info.num_syms++; for (dnum=0; dnumbase, sizeof(char), dbgtab->usedoffs, spf); diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h index 9ccf4bb9..a390a653 100644 --- a/sourcepawn/include/sp_file_headers.h +++ b/sourcepawn/include/sp_file_headers.h @@ -108,6 +108,14 @@ typedef struct sp_file_pubvars_s #pragma pack(pop) /* reset previous packing */ #endif +typedef struct sp_fdbg_info_s +{ + uint32_t num_files; /* number of files */ + uint32_t num_lines; /* number of lines */ + uint32_t num_syms; /* number of symbols */ + uint32_t num_arrays; /* number of symbols which are arrays */ +} sp_fdbg_info_t; + /** * Debug information structures */ From 3696dade013c19d3fbd0a3d6a780542d09ca6f82 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 1 Aug 2006 23:40:32 +0000 Subject: [PATCH 0022/1664] new error code updated reader for new section added 2 new functs to VM API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4052 --- sourcepawn/include/sp_vm_types.h | 1 + sourcepawn/vm/sp_reader.c | 35 ++++++++++++++++++-------------- sourcepawn/vm/sp_vm.h | 19 +++++++++++------ 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 345b6159..82212ab5 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -16,6 +16,7 @@ typedef int32_t cell_t; #define SP_ERR_PARAM 4 /* Invalid parameter */ #define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ #define SP_ERR_NOT_FOUND 6 /* The object in question was not found */ +#define SP_ERR_INDEX 7 /* Invalid index parameter */ /********************************************** *** The following structures are reference structures. diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c index 92f8b9a3..a9f5e092 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_reader.c @@ -39,10 +39,6 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, plugin->data_size = dat->datasize; plugin->memory = dat->memsize; } - else if (!(plugin->info->stringbase) && !strcmp(nameptr, ".names")) - { - plugin->info->stringbase = base + secptr->dataoffs; - } else if (!(plugin->info->publics) && !strcmp(nameptr, ".publics")) { plugin->info->publics_num = secptr->size / sizeof(sp_file_publics_t); @@ -58,25 +54,34 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, plugin->info->natives_num = secptr->size / sizeof(sp_file_natives_t); plugin->info->natives = (sp_file_natives_t *)(base + secptr->dataoffs); } + else if (!(plugin->info->stringbase) && !strcmp(nameptr, ".names")) + { + plugin->info->stringbase = base + secptr->dataoffs; + } else if (!(plugin->debug->files) && !strcmp(nameptr, ".dbg.files")) { - plugin->debug->files_num = secptr->size / sizeof(sp_fdbg_file_t); plugin->debug->files = (sp_fdbg_file_t *)(base + secptr->dataoffs); } + else if (!(plugin->debug->lines) && !strcmp(nameptr, ".dbg.lines")) + { + plugin->debug->lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug->symbols) && !strcmp(nameptr, ".dbg.symbols")) + { + plugin->debug->symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug->lines_num) && !strcmp(nameptr, ".dbg.info")) + { + sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs); + plugin->debug->files_num = inf->num_files; + plugin->debug->lines_num = inf->num_lines; + plugin->debug->syms_num = inf->num_syms; + } else if (!(plugin->debug->stringbase) && !strcmp(nameptr, ".dbg.strings")) { plugin->debug->stringbase = base + secptr->dataoffs; } - else if (!(plugin->debug->lines) && !strcmp(nameptr, ".dbg.lines")) - { - plugin->debug->lines_num = secptr->size / sizeof(sp_fdbg_line_t); - plugin->debug->lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); - } - else if (!(plugin->debug->symbols) && !strcmp(nameptr, ".dbg.symbols")) - { - plugin->debug->syms_num = secptr->size / sizeof(sp_fdbg_symbol_t); - plugin->debug->symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); - } + secptr++; sectnum++; } diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index 657e33d1..e8a3ae68 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -146,11 +146,18 @@ int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar) * @param local_addr Optionally filled with local address offset. * @param phys_addr Optionally filled with relocated physical address. */ -int SP_FindPubvarByName(sp_context_t *ctx, - const char *name, - uint32_t *index, - cell_t *local_addr, - cell_t **phys_addr); +int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index); + +//:TODO: fill in the info of this function, hi +int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr); + +/** +* Gets the number of public variables. +* +* @param ctx Context pointer. +* @param num Filled with the number of public variables. +*/ +int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num); /** * Round-about method of converting a plugin reference to a physical address @@ -162,7 +169,7 @@ int SP_FindPubvarByName(sp_context_t *ctx, int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr); /** - * Convers a local address to a physical string. + * Converts a local address to a physical string. * Note that SourcePawn does not support packed strings, as such this function is * 'cell to char' only. * From e0abed88d5082735e2ee5b960a2e675810daac27 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 Aug 2006 17:30:12 +0000 Subject: [PATCH 0023/1664] flattened this structure out --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4053 --- sourcepawn/include/sp_vm_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 82212ab5..ee0663e8 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -73,8 +73,8 @@ typedef struct sp_plugin_s uint32_t memory; /* required memory */ uint16_t flags; /* code flags */ uint32_t allocflags; /* allocation flags */ - sp_plugin_infotab_t *info; /* base info table */ - sp_plugin_debug_t *debug; /* debug info table */ + sp_plugin_infotab_t info; /* base info table */ + sp_plugin_debug_t debug; /* debug info table */ } sp_plugin_t; struct sp_context_s; From fc5b0f37a07a7439b083f247cd9c0c31a292cd16 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 2 Aug 2006 20:00:44 +0000 Subject: [PATCH 0024/1664] updated reader for latest structs more API functs, with bin search whoa :O --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4054 --- sourcepawn/vm/sp_reader.c | 61 +++++++---------- sourcepawn/vm/sp_vm.c | 135 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 156 insertions(+), 40 deletions(-) diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c index a9f5e092..504cf69c 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_reader.c @@ -7,19 +7,11 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, { char *nameptr; uint8_t sectnum = 0; - - sp_plugin_infotab_t *info = (sp_plugin_infotab_t *)malloc(sizeof(sp_plugin_infotab_t)); - sp_plugin_debug_t *dbg = (sp_plugin_debug_t *)malloc(sizeof(sp_plugin_debug_t)); - sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t)); memset(plugin, 0, sizeof(sp_plugin_t)); - memset(info, 0, sizeof(sp_plugin_infotab_t)); - memset(dbg, 0, sizeof(sp_plugin_debug_t)); plugin->base = base; - plugin->info = info; - plugin->debug = dbg; while (sectnum < hdr->sections) { @@ -39,57 +31,57 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, plugin->data_size = dat->datasize; plugin->memory = dat->memsize; } - else if (!(plugin->info->publics) && !strcmp(nameptr, ".publics")) + else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics")) { - plugin->info->publics_num = secptr->size / sizeof(sp_file_publics_t); - plugin->info->publics = (sp_file_publics_t *)(base + secptr->dataoffs); + plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t); + plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs); } - else if (!(plugin->info->pubvars) && !strcmp(nameptr, ".pubvars")) + else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars")) { - plugin->info->pubvars_num = secptr->size / sizeof(sp_file_pubvars_t); - plugin->info->pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); + plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t); + plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); } - else if (!(plugin->info->natives) && !strcmp(nameptr, ".natives")) + else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives")) { - plugin->info->natives_num = secptr->size / sizeof(sp_file_natives_t); - plugin->info->natives = (sp_file_natives_t *)(base + secptr->dataoffs); + plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t); + plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs); } - else if (!(plugin->info->stringbase) && !strcmp(nameptr, ".names")) + else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) { - plugin->info->stringbase = base + secptr->dataoffs; + plugin->info.stringbase = base + secptr->dataoffs; } - else if (!(plugin->debug->files) && !strcmp(nameptr, ".dbg.files")) + else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files")) { - plugin->debug->files = (sp_fdbg_file_t *)(base + secptr->dataoffs); + plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs); } - else if (!(plugin->debug->lines) && !strcmp(nameptr, ".dbg.lines")) + else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines")) { - plugin->debug->lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); + plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); } - else if (!(plugin->debug->symbols) && !strcmp(nameptr, ".dbg.symbols")) + else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols")) { - plugin->debug->symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); + plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); } - else if (!(plugin->debug->lines_num) && !strcmp(nameptr, ".dbg.info")) + else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info")) { sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs); - plugin->debug->files_num = inf->num_files; - plugin->debug->lines_num = inf->num_lines; - plugin->debug->syms_num = inf->num_syms; + plugin->debug.files_num = inf->num_files; + plugin->debug.lines_num = inf->num_lines; + plugin->debug.syms_num = inf->num_syms; } - else if (!(plugin->debug->stringbase) && !strcmp(nameptr, ".dbg.strings")) + else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) { - plugin->debug->stringbase = base + secptr->dataoffs; + plugin->debug.stringbase = base + secptr->dataoffs; } secptr++; sectnum++; } - if (!(plugin->pcode) || !(plugin->data) || !(plugin->info->stringbase)) + if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase)) goto return_error; - if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug->files) || !(plugin->debug->lines) || !(plugin->debug->symbols))) + if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) goto return_error; if (err) @@ -98,9 +90,6 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, return plugin; return_error: - free(dbg); - free(info); - if (err) *err = SP_ERR_FILE_FORMAT; diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index b9651fb4..d1c720e5 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -109,16 +109,143 @@ int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t i; + uint32_t mid, low, high, diff; - for (i = 0; i < ctx->plugin->info->natives_num; i++) + high = ctx->plugin->info.natives_num - 1; + low = 0; + + while (low <= high) { - if (!strcmp(name, ctx->natives[i].name)) + mid = (low + high) / 2; + diff = strcmp(ctx->natives[mid].name, name); + if (diff == 0) { if (index) - *index = i; + *index = mid; return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; } } + return SP_ERR_NOT_FOUND; +} + +int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native) +{ + if (index >= ctx->plugin->info.natives_num) + return SP_ERR_INDEX; + + if (native) + *native = &(ctx->natives[index]); + + return SP_ERR_NONE; +} + +int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num) +{ + *num = ctx->plugin->info.natives_num; + + return SP_ERR_NONE; +} + +int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) +{ + uint32_t mid, low, high, diff; + + high = ctx->plugin->info.publics_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->publics[mid].name, name); + if (diff == 0) + { + if (index) + *index = mid; + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic) +{ + if (index >= ctx->plugin->info.publics_num) + return SP_ERR_INDEX; + + if (pblic) + *pblic = &(ctx->publics[index]); + + return SP_ERR_NONE; +} + +int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num) +{ + *num = ctx->plugin->info.publics_num; + + return SP_ERR_NONE; +} + +int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar) +{ + if (index >= ctx->plugin->info.pubvars_num) + return SP_ERR_INDEX; + + if (pubvar) + *pubvar = &(ctx->pubvars[index]); + + return SP_ERR_NONE; +} + +int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) +{ + uint32_t mid, low, high, diff; + + high = ctx->plugin->info.pubvars_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->pubvars[mid].name, name); + if (diff == 0) + { + if (index) + *index = mid; + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr) +{ + if (index >= ctx->plugin->info.pubvars_num) + return SP_ERR_INDEX; + + *local_addr = ctx->plugin->info.pubvars[index].address; + *phys_addr = ctx->pubvars[index].offs; + + return SP_ERR_NONE; +} + +int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num) +{ + *num = ctx->plugin->info.pubvars_num; + + return SP_ERR_NONE; } \ No newline at end of file From ec8dec1049638734861d7c2d2f2644dae64017de Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 3 Aug 2006 20:58:38 +0000 Subject: [PATCH 0025/1664] bind native stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4055 --- sourcepawn/vm/sp_vm.c | 55 +++++++++++++++++++++++++++++++++++++++++++ sourcepawn/vm/sp_vm.h | 6 +++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index d1c720e5..b795ed06 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -247,5 +247,60 @@ int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num) { *num = ctx->plugin->info.pubvars_num; + return SP_ERR_NONE; +} + +int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite) +{ + uint32_t i, j, max; + + max = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status == SP_NATIVE_OKAY && !overwrite) + continue; + + for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) + { + ctx->natives[i].pfn = natives[j].func; + ctx->natives[i].status = SP_NATIVE_OKAY; + } + } + } + + return SP_ERR_NONE; +} + +int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status) +{ + uint32_t index, err; + + if ((err = SP_FindNativeByName(ctx, native->name, &index)) != SP_ERR_NONE) + return err; + + ctx->natives[index].pfn = native->func; + ctx->natives[index].status = status; + + return SP_ERR_NONE; +} + +int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native) +{ + uint32_t nativesnum, i; + + nativesnum = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status != SP_NATIVE_OKAY) + { + ctx->natives[i].pfn = native; + ctx->natives[i].status = SP_NATIVE_PENDING; + } + } + return SP_ERR_NONE; } \ No newline at end of file diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index e8a3ae68..bba01c79 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -240,7 +240,7 @@ int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcel * Binds a list of native names and their function pointers to a context. * If num is 0, the list is read until an entry with a NULL name is reached. * All natives are assigned a status of SP_NATIVE_OKAY by default. - * If overwrite is non-zero, already registered arrays will be overwritten. + * If overwrite is non-zero, already registered natives will be overwritten. * * @param ctx Context pointer. * @param natives Array of natives. @@ -250,6 +250,8 @@ int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num /** * Binds a single native. Overwrites any existing bind. + * If the context does not contain the native that will be binded the function will return + * with a SP_ERR_NOT_FOUND error. * * @param ctx Context pointer. * @param native Pointer to native. @@ -263,7 +265,7 @@ int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status); * * @param ctx Context pointer. */ -int SP_BindNativeToAny(sp_context_t *ctx, sp_nativeinfo_t *native); +int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native); /** * Executes a public function in a context. From b051f32ab610e4749e66aef5d2ad70bc66c13654 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 3 Aug 2006 23:42:50 +0000 Subject: [PATCH 0026/1664] =?UTF-8?q?mo=C3=96=C3=B6re=20stuff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4056 --- sourcepawn/vm/sp_vm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index b795ed06..b1ec091c 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -258,7 +258,7 @@ int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num for (i=0; inatives[i].status == SP_NATIVE_OKAY && !overwrite) + if ((ctx->natives[i].status == SP_NATIVE_OKAY) && !overwrite) continue; for (j=0; (natives[j].name) && (!num || j= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + return SP_ERR_INVALID_ADDRESS; + + if (phys_addr) + *phys_addr = (cell_t *)(ctx->data + local_addr); + return SP_ERR_NONE; } \ No newline at end of file From 4a324feac0bd8168f6962b0030e94e326778ce56 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 4 Aug 2006 03:41:50 +0000 Subject: [PATCH 0027/1664] Corrected the most annoying spelling mistake ever: depricated -> deprecated --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4057 --- sourcepawn/compiler/sc.h | 4 ++-- sourcepawn/compiler/sc1.c | 16 ++++++++-------- sourcepawn/compiler/sc2.c | 8 ++++---- sourcepawn/compiler/sc3.c | 4 ++-- sourcepawn/compiler/sc5.scp | 2 +- sourcepawn/compiler/scvars.c | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index b4a367a8..4f839169 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -218,7 +218,7 @@ typedef struct s_symbol { */ #define uRETNONE 0x10 -#define flgDEPRICATED 0x01 /* symbol is depricated (avoid use) */ +#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */ #define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */ #define uSIZEOF 0x80 /* set in the "hasdefault" field of the arginfo struct */ @@ -790,7 +790,7 @@ SC_VDECL int sc_rationaltag; /* tag for rational numbers */ SC_VDECL int rational_digits; /* number of fractional digits */ SC_VDECL int sc_allowproccall;/* allow/detect tagnames in lex() */ SC_VDECL short sc_is_utf8; /* is this source file in UTF-8 encoding */ -SC_VDECL char *pc_depricate; /* if non-NULL, mark next declaration as depricated */ +SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecated */ SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 0a8e88b3..bd4ea550 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -612,7 +612,7 @@ static void resetglobals(void) pc_addlibtable=TRUE; /* by default, add a "library table" to the output file */ sc_alignnext=FALSE; pc_docexpr=FALSE; - pc_depricate=NULL; + pc_deprecate=NULL; sc_curstates=0; pc_memflags=0; } @@ -2741,19 +2741,19 @@ SC_FUNC symbol *fetchfunc(char *name,int tag) /* set the required stack size to zero (only for non-native functions) */ sym->x.stacksize=1; /* 1 for PROC opcode */ } /* if */ - if (pc_depricate!=NULL) { + if (pc_deprecate!=NULL) { assert(sym!=NULL); - sym->flags|=flgDEPRICATED; + sym->flags|=flgDEPRECATED; if (sc_status==statWRITE) { if (sym->documentation!=NULL) { free(sym->documentation); sym->documentation=NULL; } /* if */ - sym->documentation=pc_depricate; + sym->documentation=pc_deprecate; } else { - free(pc_depricate); + free(pc_deprecate); } /* if */ - pc_depricate=NULL; + pc_deprecate=NULL; } /* if */ return sym; @@ -3273,9 +3273,9 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc cidx=code_idx; glbdecl=glb_declared; } /* if */ - if ((sym->flags & flgDEPRICATED)!=0) { + if ((sym->flags & flgDEPRECATED)!=0) { char *ptr= (sym->documentation!=NULL) ? sym->documentation : ""; - error(234,symbolname,ptr); /* depricated (probably a public function) */ + error(234,symbolname,ptr); /* deprecated (probably a public function) */ } /* if */ begcseg(); sym->usage|=uDEFINE; /* set the definition flag */ diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 2cf9c1af..859ec30f 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1046,12 +1046,12 @@ static int command(void) error(27); /* invalid character constant */ sc_ctrlchar=(char)val; } /* if */ - } else if (strcmp(str,"depricated")==0) { + } else if (strcmp(str,"deprecated")==0) { while (*lptr<=' ' && *lptr!='\0') lptr++; - pc_depricate=(char*)malloc(strlen((char*)lptr)+1); - if (pc_depricate!=NULL) - strcpy(pc_depricate,(char*)lptr); + pc_deprecate=(char*)malloc(strlen((char*)lptr)+1); + if (pc_deprecate!=NULL) + strcpy(pc_deprecate,(char*)lptr); lptr=(unsigned char*)strchr((char*)lptr,'\0'); /* skip to end (ignore "extra characters on line") */ } else if (strcmp(str,"dynamic")==0) { preproc_expr(&pc_stksize,NULL); diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index ddb0acc3..9c5df24c 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1944,9 +1944,9 @@ static int nesting=0; #endif sc_allowproccall=FALSE; /* parameters may not use procedure call syntax */ - if ((sym->flags & flgDEPRICATED)!=0) { + if ((sym->flags & flgDEPRECATED)!=0) { char *ptr= (sym->documentation!=NULL) ? sym->documentation : ""; - error(234,sym->name,ptr); /* depricated (probably a native function) */ + error(234,sym->name,ptr); /* deprecated (probably a native function) */ } /* if */ /* run through the arguments */ diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index 5fef861a..25e4baa2 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -299,7 +299,7 @@ static char *warnmsg[] = { /*231*/ "state specification on forward declaration is ignored\n", /*232*/ "output file is written, but with compact encoding disabled\n", /*233*/ "state variable \"%s\" shadows a global variable\n", -/*234*/ "function is depricated (symbol \"%s\") %s\n", +/*234*/ "function is deprecated (symbol \"%s\") %s\n", /*235*/ "public function lacks forward declaration (symbol \"%s\")\n", /*236*/ "unknown parameter in substitution (incorrect #define pattern)\n" #else diff --git a/sourcepawn/compiler/scvars.c b/sourcepawn/compiler/scvars.c index 6a1365f8..3efef129 100644 --- a/sourcepawn/compiler/scvars.c +++ b/sourcepawn/compiler/scvars.c @@ -86,7 +86,7 @@ SC_VDEFINE int sc_rationaltag=0; /* tag for rational numbers */ SC_VDEFINE int rational_digits=0; /* number of fractional digits */ SC_VDEFINE int sc_allowproccall=0; /* allow/detect tagnames in lex() */ SC_VDEFINE short sc_is_utf8=FALSE; /* is this source file in UTF-8 encoding */ -SC_VDEFINE char *pc_depricate=NULL;/* if non-null, mark next declaration as depricated */ +SC_VDEFINE char *pc_deprecate=NULL;/* if non-null, mark next declaration as deprecated */ SC_VDEFINE int sc_curstates=0; /* ID of the current state list */ SC_VDEFINE int pc_optimize=sOPTIMIZE_NOMACRO; /* (peephole) optimization level */ SC_VDEFINE int pc_memflags=0; /* special flags for the stack/heap usage */ From 84ec7c87133172e141ed00dd86a0911852f5db5c Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 Aug 2006 19:09:41 +0000 Subject: [PATCH 0028/1664] push functions and some little fixes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4058 --- sourcepawn/vm/sp_reader.c | 12 +++++ sourcepawn/vm/sp_vm.c | 102 +++++++++++++++++++++++++++++++++++--- sourcepawn/vm/sp_vm.h | 5 +- 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c index 504cf69c..a0014c15 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_reader.c @@ -79,19 +79,27 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, } if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase)) + { goto return_error; + } if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) + { goto return_error; + } if (err) + { *err = SP_ERR_NONE; + } return plugin; return_error: if (err) + { *err = SP_ERR_FILE_FORMAT; + } return NULL; } @@ -180,7 +188,9 @@ sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err) return_error: if (err) + { *err = error; + } return NULL; } @@ -200,7 +210,9 @@ sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) if (!_ReadPlugin(&hdr, base, plugin, err)) { if (noptr) + { free(plugin); + } return NULL; } diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index b1ec091c..60b7d627 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -24,6 +24,7 @@ int main() assert(SP_HeapRelease(&ctx, 4) == SP_ERR_INVALID_ADDRESS); assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); + assert(SP_PushCell(&ctx, 1337) == SP_ERR_NONE); return 0; } @@ -109,7 +110,8 @@ int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high, diff; + uint32_t mid, low, high; + int diff; high = ctx->plugin->info.natives_num - 1; low = 0; @@ -121,7 +123,9 @@ int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) if (diff == 0) { if (index) + { *index = mid; + } return SP_ERR_NONE; } else if (diff < 0) { low = mid + 1; @@ -136,10 +140,14 @@ int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native) { if (index >= ctx->plugin->info.natives_num) + { return SP_ERR_INDEX; + } if (native) + { *native = &(ctx->natives[index]); + } return SP_ERR_NONE; } @@ -153,7 +161,8 @@ int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num) int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high, diff; + uint32_t mid, low, high; + int diff; high = ctx->plugin->info.publics_num - 1; low = 0; @@ -165,7 +174,9 @@ int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) if (diff == 0) { if (index) + { *index = mid; + } return SP_ERR_NONE; } else if (diff < 0) { low = mid + 1; @@ -180,10 +191,14 @@ int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic) { if (index >= ctx->plugin->info.publics_num) + { return SP_ERR_INDEX; + } if (pblic) + { *pblic = &(ctx->publics[index]); + } return SP_ERR_NONE; } @@ -198,17 +213,22 @@ int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num) int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar) { if (index >= ctx->plugin->info.pubvars_num) + { return SP_ERR_INDEX; + } if (pubvar) + { *pubvar = &(ctx->pubvars[index]); + } return SP_ERR_NONE; } int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high, diff; + uint32_t mid, low, high; + int diff; high = ctx->plugin->info.pubvars_num - 1; low = 0; @@ -220,7 +240,9 @@ int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) if (diff == 0) { if (index) + { *index = mid; + } return SP_ERR_NONE; } else if (diff < 0) { low = mid + 1; @@ -235,7 +257,9 @@ int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr) { if (index >= ctx->plugin->info.pubvars_num) + { return SP_ERR_INDEX; + } *local_addr = ctx->plugin->info.pubvars[index].address; *phys_addr = ctx->pubvars[index].offs; @@ -259,7 +283,9 @@ int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) + { continue; + } for (j=0; (natives[j].name) && (!num || jname, &index)) != SP_ERR_NONE) + { return err; + } ctx->natives[index].pfn = native->func; ctx->natives[index].status = status; @@ -308,10 +337,71 @@ int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native) int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr) { if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { return SP_ERR_INVALID_ADDRESS; - + } + if (phys_addr) + { *phys_addr = (cell_t *)(ctx->data + local_addr); + } return SP_ERR_NONE; -} \ No newline at end of file +} + +int SP_PushCell(sp_context_t *ctx, cell_t value) +{ + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) + { + return SP_ERR_HEAPLOW; + } + + ctx->sp -= sizeof(cell_t); + *(cell_t *)(ctx->data + ctx->sp) = value; + ctx->pushcount++; + + return SP_ERR_NONE; +} + +int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells) +{ + unsigned int i; + int err; + + for (i=0; isp += i * sizeof(cell_t); + ctx->pushcount -= i; + return err; + } + } + + return SP_ERR_NONE; +} + +int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) +{ + cell_t *ph_addr; + int err; + + if ((err = SP_HeapAlloc(ctx, numcells, local_addr, &ph_addr)) != SP_ERR_NONE) + { + return err; + } + + memcpy(ph_addr, array, numcells * sizeof(cell_t)); + if (phys_addr) + { + *phys_addr = ph_addr; + } + + if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE) + { + SP_HeapRelease(ctx, *local_addr); + return err; + } + + return SP_ERR_NONE; +} diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index bba01c79..69fec20d 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -8,6 +8,7 @@ ** Note that all functions return a non-zero error code on failure * unless otherwise noted. * All input pointers must be valid unless otherwise noted as optional. + * All output pointers on failure are undefined. * All local address are guaranteed to be positive. However, they are stored * as signed integers, because they must logically fit inside a cell. */ @@ -195,6 +196,7 @@ int SP_PushCell(sp_context_t *ctx, cell_t value); /** * Pushes an array of cells onto the stack. Increases the parameter count by one. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. * Note that this does not release the heap, so you should release it after * calling SP_Execute(). * @@ -229,6 +231,7 @@ int SP_PushString(sp_context_t *ctx, /** * Individually pushes each cell of an array of cells onto the stack. Increases the * parameter count by the number of cells pushed. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. * * @param ctx Context pointer. * @param array Array of cells to read from. @@ -260,7 +263,7 @@ int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status); /** - * Binds a single native to any non-registered native. + * Binds a single native to any non-registered or pending native. * Status is automatically set to pending. * * @param ctx Context pointer. From 2665d13475a68937fc7fc86e78b29f6cf0c8fd6d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 6 Aug 2006 02:16:03 +0000 Subject: [PATCH 0029/1664] string functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4059 --- sourcepawn/vm/sp_vm.c | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index 60b7d627..69a356fe 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -11,6 +11,10 @@ int main() /** temporary testing area */ sp_context_t ctx; cell_t l, *p; + cell_t arr1[] = {1,3,3,7}; + cell_t arr2[] = {123,1234,12345,123456}; + const char *str = "hat hat"; + char buf[20]; ctx.data = (uint8_t *)malloc(50000); ctx.memory = 50000; @@ -25,6 +29,12 @@ int main() assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); assert(SP_PushCell(&ctx, 1337) == SP_ERR_NONE); + assert(SP_PushCellArray(&ctx, &l, &p, arr1, 4) == SP_ERR_NONE); + assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); + assert(SP_PushCellsFromArray(&ctx, arr2, 4) == SP_ERR_NONE); + assert(SP_PushString(&ctx, &l, &p, str) == SP_ERR_NONE); + assert(SP_LocalToString(&ctx, l, NULL, buf, 20) == SP_ERR_NONE); + assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); return 0; } @@ -405,3 +415,67 @@ int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, return SP_ERR_NONE; } + +int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buffer, size_t maxlength) +{ + size_t len = 0; + cell_t *src; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { + return SP_ERR_INVALID_ADDRESS; + } + + src = (cell_t *)(ctx->data + local_addr); + while ((*src != '\0') && (len < maxlength)) + { + buffer[len++] = (char)*src++; + } + + if (len >= maxlength) + { + len = maxlength - 1; + } + if (len >= 0) + { + buffer[len] = '\0'; + } + + if (chars) + { + *chars = len; + } + + return SP_ERR_NONE; +} + +int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, const char *string) +{ + cell_t *ph_addr; + int err; + unsigned int i, numcells = strlen(string); + + if ((err = SP_HeapAlloc(ctx, numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE) + { + return err; + } + + for (i=0; i Date: Sun, 6 Aug 2006 18:37:14 +0000 Subject: [PATCH 0030/1664] added core debug api added missing setstring function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4060 --- sourcepawn/include/sp_vm_types.h | 9 ++++++++- sourcepawn/vm/msvc8/vm.vcproj | 4 ++++ sourcepawn/vm/sp_vm.c | 1 + sourcepawn/vm/sp_vm.h | 13 +++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index ee0663e8..fa8aed3e 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -168,6 +168,11 @@ typedef int (*SPVM_EXEC)(struct sp_context_s *, uint32_t, cell_t *res); +/** + * Breaks into a debugger + */ +typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *); + #define SP_CONTEXT_DEBUG (1<<0) /* in debug mode */ #define SP_CONTEXT_INHERIT_MEMORY (1<<1) /* inherits memory pointers */ #define SP_CONTEXT_INHERIT_CODE (1<<2) /* inherits code pointers */ @@ -179,11 +184,13 @@ typedef int (*SPVM_EXEC)(struct sp_context_s *, */ typedef struct sp_context_s { - /* parent information */ + /* general/parent information */ void *base; /* base of generated code and memory */ sp_plugin_t *plugin; /* pointer back to parent information */ struct sp_context_s *parent; /* pointer to parent context */ uint32_t flags; /* context flags */ + SPVM_DEBUGBREAK dbreak; /* debug break function */ + void *user; /* user specific pointer */ /* execution specific data */ SPVM_EXEC exec; /* execution base */ cell_t pri; /* PRI register */ diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 66fe7b10..2516a305 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -193,6 +193,10 @@ RelativePath="..\sp_vm.h" > + + diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index 69a356fe..3e7ac7a3 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "sp_vm.h" #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index 69fec20d..1128bc04 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -186,6 +186,19 @@ int SP_LocalToString(sp_context_t *ctx, char *buffer, size_t maxlength); +/** + * Converts a physical string to a local address. + * Note that SourcePawn does not support packed strings. + * @param ctx Context pointer + * @param local_addr Local address in plugin. + * @param chars Number of chars to write, including NULL terminator. + * @param source Source string to copy. + */ +int SP_StringToLocal(sp_context_t *ctx, + cell_t local_addr, + size_t chars, + const char *source); + /** * Pushes a cell onto the stack. Increases the parameter count by one. * From 03587a329e5e3055c076237566c709876f25195a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 Aug 2006 18:38:00 +0000 Subject: [PATCH 0031/1664] added debug api fo' real --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4061 --- sourcepawn/vm/sp_vm_debug.h | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 sourcepawn/vm/sp_vm_debug.h diff --git a/sourcepawn/vm/sp_vm_debug.h b/sourcepawn/vm/sp_vm_debug.h new file mode 100644 index 00000000..901f955c --- /dev/null +++ b/sourcepawn/vm/sp_vm_debug.h @@ -0,0 +1,52 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_DEBUG_H +#define _INCLUDE_SOURCEPAWN_VM_DEBUG_H + +/***************** + ** Note that all functions return a non-zero error code on failure + * unless otherwise noted. + * All input pointers must be valid unless otherwise noted as optional. + * All output pointers on failure are undefined. + * All local address are guaranteed to be positive. However, they are stored + * as signed integers, because they must logically fit inside a cell. + */ + +/** + * Given a code pointer, finds the file it is associated with. + * + * @param ctx Context pointer. + * @param addr Code address offset. + * @param filename Pointer to store filename pointer in. + */ +int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename); + +/** + * Given a code pointer, finds the function it is associated with. + * + * @param ctx Context pointer. + * @param addr Code address offset. + * @param name Pointer to store function name pointer in. + */ +int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name); + +/** + * Given a code pointer, finds the line it is associated with. + * + * @param ctx Context pointer. + * @param addr Code address offset. + * @param line Pointer to store line number in. + */ +int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line); + +/** + * Installs a debug break and returns the old one, if any. + * + * @param ctx Context pointer. + * @param newpfn New function pointer. + * @param oldpfn Pointer to retrieve old function pointer. + */ +int SP_DbgInstallBreak(sp_context_t *ctx, + SPVM_DEBUGBREAK newpfn, + SPVM_DEBUGBREAK *oldpfn); + + +#endif //_INCLUDE_SOURCEPAWN_VM_DEBUG_H From 1f51cdbbb340243032aa0c15f28c6071c01a9487 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 6 Aug 2006 23:08:02 +0000 Subject: [PATCH 0032/1664] debug API implementation added SetString --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4062 --- sourcepawn/vm/sp_vm.c | 46 +++++++++++++++---- sourcepawn/vm/sp_vm_debug.c | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 sourcepawn/vm/sp_vm_debug.c diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index 3e7ac7a3..d2896f5b 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -403,10 +403,6 @@ int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, } memcpy(ph_addr, array, numcells * sizeof(cell_t)); - if (phys_addr) - { - *phys_addr = ph_addr; - } if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE) { @@ -414,6 +410,11 @@ int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, return err; } + if (phys_addr) + { + *phys_addr = ph_addr; + } + return SP_ERR_NONE; } @@ -467,16 +468,43 @@ int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, con } ph_addr[numcells] = '\0'; - if (phys_addr) - { - *phys_addr = ph_addr; - } - if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE) { SP_HeapRelease(ctx, *local_addr); return err; } + if (phys_addr) + { + *phys_addr = ph_addr; + } + + return SP_ERR_NONE; +} + +int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const char *source) +{ + cell_t *dest; + size_t i, len; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { + return SP_ERR_INVALID_ADDRESS; + } + + len = strlen(source); + dest = (cell_t *)(ctx->data + local_addr); + + if (len >= chars) + { + len = chars - 1; + } + + for (i=0; iplugin->debug.files_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = ctx->files[mid].addr - addr; + if (diff == 0) + { + *filename = ctx->files[mid].name; + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name) +{ + uint32_t iter, max = ctx->plugin->debug.syms_num; + + for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) + && (ctx->symbols[iter].codestart <= addr) + && (ctx->symbols[iter].codeend > addr)) + { + break; + } + } + + if (iter >= max) + { + return SP_ERR_NOT_FOUND; + } + + *name = ctx->symbols[iter].name; + + return SP_ERR_NONE; +} + +int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line) +{ + uint32_t mid, low, high; + int diff; + + high = ctx->plugin->debug.lines_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = ctx->lines[mid].addr - addr; + if (diff == 0) + { + *line = ctx->lines[mid].line; + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int SP_DbgInstallBreak(sp_context_t *ctx, SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) +{ + if (ctx->dbreak) + *oldpfn = ctx->dbreak; + + ctx->dbreak = newpfn; + + return SP_ERR_NONE; +} From 9743c00e2fab47aba79cb4fbf80dba780f8603e0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 Aug 2006 23:31:08 +0000 Subject: [PATCH 0033/1664] the bridge function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4063 --- sourcepawn/vm/sp_vm.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index 1128bc04..40cb9d1e 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -295,5 +295,25 @@ int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native); */ int SP_Execute(sp_context_t *ctx, uint32_t idx, cell_t *result); +/** + * Creates a base context. The context is not bound to any JIT, and thus + * thus inherits the parent code pointer of the file structure. It does, + * however, have relocated info+debug tables (even though the code address + * do not need to be relocated). + * It is guaranteed to have a newly allocated and copied memory layout + * of the data, heap and stack, and thus relevant address in the info/debug + * tables must be relocated. + * + * @param plugin Plugin file structure to build a context form. + * @param ctx Pointer to store newly created context pointer. + */ +int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx); + +/** + * Frees a base context. + * + * @param ctx Context pointer. + */ +int SP_FreeBaseContext(sp_context_t *ctx); #endif //_INCLUDE_SOURCEPAWN_VM_H_ From 4c18f4686071c37b9dc069cde4d2c7972265370a Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 7 Aug 2006 22:40:43 +0000 Subject: [PATCH 0034/1664] changed flags added 2 more error types --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4064 --- sourcepawn/include/sp_file_headers.h | 6 +----- sourcepawn/include/sp_vm_types.h | 9 +++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h index a390a653..ec2ffaa3 100644 --- a/sourcepawn/include/sp_file_headers.h +++ b/sourcepawn/include/sp_file_headers.h @@ -57,11 +57,7 @@ typedef struct sp_file_hdr_s uint32_t dataoffs; /* offset to file proper (any compression starts here) */ } sp_file_hdr_t; -typedef enum -{ - SP_FILE_NONE = 0, - SP_FILE_DEBUG = 1, -} sp_file_flags_t; +#define SP_FLAG_DEBUG (1<<0) /* section is ".code" */ typedef struct sp_file_code_s diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index fa8aed3e..f3f9c618 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -17,11 +17,13 @@ typedef int32_t cell_t; #define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ #define SP_ERR_NOT_FOUND 6 /* The object in question was not found */ #define SP_ERR_INDEX 7 /* Invalid index parameter */ +#define SP_ERR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ +#define SP_ERR_STACKERR 9 /* Stack/Heap collision */ /********************************************** *** The following structures are reference structures. *** They are not essential to the API, but are used - *** to hold the backend database format of the plugin + *** to hold the back end database format of the plugin *** binary. **********************************************/ @@ -78,7 +80,7 @@ typedef struct sp_plugin_s } sp_plugin_t; struct sp_context_s; -typedef int (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); +typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); /********************************************** *** The following structures are bound to the VM/JIT. @@ -210,6 +212,5 @@ typedef struct sp_context_s sp_debug_line_t *lines; /* lines */ sp_debug_symbol_t *symbols; /* symbols */ } sp_context_t; - -#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H +#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H From 063baa9e7109ee20edcbbb2982078c80d7a0792d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 7 Aug 2006 22:48:07 +0000 Subject: [PATCH 0035/1664] implemented teh bridge function little type fix in bsearch fixed debug flag checking added SP_NoExecNative() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4065 --- sourcepawn/vm/sp_reader.c | 2 +- sourcepawn/vm/sp_vm.c | 164 +++++++++++++++++++++++++++++++++--- sourcepawn/vm/sp_vm.h | 5 +- sourcepawn/vm/sp_vm_debug.c | 8 +- 4 files changed, 160 insertions(+), 19 deletions(-) diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_reader.c index a0014c15..7f6b17c6 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_reader.c @@ -83,7 +83,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, goto return_error; } - if ((plugin->flags == SP_FILE_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) + if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) { goto return_error; } diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index d2896f5b..6a2b0a1b 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -121,8 +121,8 @@ int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high; - int diff; + int diff, high, low; + uint32_t mid; high = ctx->plugin->info.natives_num - 1; low = 0; @@ -172,8 +172,8 @@ int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num) int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high; - int diff; + int diff, high, low; + uint32_t mid; high = ctx->plugin->info.publics_num - 1; low = 0; @@ -238,8 +238,8 @@ int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar) int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) { - uint32_t mid, low, high; - int diff; + int diff, high, low; + uint32_t mid; high = ctx->plugin->info.pubvars_num - 1; low = 0; @@ -364,7 +364,7 @@ int SP_PushCell(sp_context_t *ctx, cell_t value) { if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) { - return SP_ERR_HEAPLOW; + return SP_ERR_STACKERR; } ctx->sp -= sizeof(cell_t); @@ -383,7 +383,7 @@ int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcel { if ((err = SP_PushCell(ctx, array[i])) != SP_ERR_NONE) { - ctx->sp += i * sizeof(cell_t); + ctx->sp += (cell_t)(i * sizeof(cell_t)); ctx->pushcount -= i; return err; } @@ -420,7 +420,7 @@ int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buffer, size_t maxlength) { - size_t len = 0; + int len = 0; cell_t *src; if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) @@ -429,12 +429,12 @@ int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buf } src = (cell_t *)(ctx->data + local_addr); - while ((*src != '\0') && (len < maxlength)) + while ((*src != '\0') && ((size_t)len < maxlength)) { buffer[len++] = (char)*src++; } - if (len >= maxlength) + if ((size_t)len >= maxlength) { len = maxlength - 1; } @@ -485,7 +485,7 @@ int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, con int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const char *source) { cell_t *dest; - size_t i, len; + int i, len; if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) { @@ -495,7 +495,7 @@ int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const c len = strlen(source); dest = (cell_t *)(ctx->data + local_addr); - if (len >= chars) + if ((size_t)len >= chars) { len = chars - 1; } @@ -508,3 +508,141 @@ int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const c return SP_ERR_NONE; } + +int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx) +{ + uint32_t iter, max; + uint8_t *dat, *cursor; + const char *strbase; + sp_fdbg_symbol_t *sym; + sp_fdbg_arraydim_t *arr; + sp_context_t *context = *ctx; + + context = (sp_context_t *)malloc(sizeof(sp_context_t)); + memset(context, 0, sizeof(sp_context_t)); + + context->base = plugin->base; + context->plugin = plugin; + context->flags = plugin->flags; + + context->data = (uint8_t *)malloc(plugin->memory); + memcpy(context->data, plugin->data, plugin->data_size); + context->memory = plugin->memory; + context->heapbase = (cell_t)(plugin->data_size); + + strbase = plugin->info.stringbase; + + if (max = plugin->info.publics_num) + { + context->publics = (sp_public_t *)malloc(sizeof(sp_public_t) * max); + for (iter=0; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; + context->publics[iter].offs = plugin->info.publics[iter].address; + } + } + + if (max = plugin->info.pubvars_num) + { + dat = plugin->data; + context->pubvars = (sp_pubvar_t *)malloc(sizeof(sp_pubvar_t) * max); + for (iter=0; iterpubvars[iter].name = strbase + plugin->info.pubvars[iter].name; + context->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); + } + } + + if (max = plugin->info.natives_num) + { + context->natives = (sp_native_t *)malloc(sizeof(sp_native_t) * max); + for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; + context->natives[iter].pfn = SP_NoExecNative; + context->natives[iter].status = SP_NATIVE_NONE; + } + } + + strbase = plugin->debug.stringbase; + + if (plugin->flags & SP_FLAG_DEBUG) + { + max = plugin->debug.files_num; + context->files = (sp_debug_file_t *)malloc(sizeof(sp_debug_file_t) * max); + for (iter=0; iterfiles[iter].addr = plugin->debug.files[iter].addr; + context->files[iter].name = strbase + plugin->debug.files[iter].name; + } + + max = plugin->debug.lines_num; + context->lines = (sp_debug_line_t *)malloc(sizeof(sp_debug_line_t) * max); + for (iter=0; iterlines[iter].addr = plugin->debug.lines[iter].addr; + context->lines[iter].line = plugin->debug.lines[iter].line; + } + + cursor = (uint8_t *)(plugin->debug.symbols); + max = plugin->debug.syms_num; + context->symbols = (sp_debug_symbol_t *)malloc(sizeof(sp_debug_symbol_t) * max); + for (iter=0; itersymbols[iter].codestart = sym->codestart; + context->symbols[iter].codeend = sym->codeend; + context->symbols[iter].name = strbase + sym->name; + context->symbols[iter].sym = sym; + + if (sym->dimcount > 0) + { + cursor += sizeof(sp_fdbg_symbol_t); + arr = (sp_fdbg_arraydim_t *)cursor; + context->symbols[iter].dims = arr; + cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; + continue; + } + + context->symbols[iter].dims = NULL; + cursor += sizeof(sp_fdbg_symbol_t); + } + } + + *ctx = context; + return SP_ERR_NONE; +} + +int SP_FreeBaseContext(sp_context_t *ctx) +{ + if (ctx->flags & SP_FLAG_DEBUG) + { + free(ctx->symbols); + free(ctx->lines); + free(ctx->files); + } + if (ctx->plugin->info.natives) + { + free(ctx->natives); + } + if (ctx->plugin->info.pubvars_num) + { + free(ctx->pubvars); + } + if (ctx->plugin->info.publics_num) + { + free(ctx->publics); + } + free(ctx->data); + free(ctx); + + return SP_ERR_NONE; +} + +cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params) +{ + ctx->err = SP_ERR_NATIVE_PENDING; + + return 0; +} \ No newline at end of file diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h index 40cb9d1e..8ed41cb2 100644 --- a/sourcepawn/vm/sp_vm.h +++ b/sourcepawn/vm/sp_vm.h @@ -297,7 +297,7 @@ int SP_Execute(sp_context_t *ctx, uint32_t idx, cell_t *result); /** * Creates a base context. The context is not bound to any JIT, and thus - * thus inherits the parent code pointer of the file structure. It does, + * inherits the parent code pointer of the file structure. It does, * however, have relocated info+debug tables (even though the code address * do not need to be relocated). * It is guaranteed to have a newly allocated and copied memory layout @@ -316,4 +316,7 @@ int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx); */ int SP_FreeBaseContext(sp_context_t *ctx); +//:TODO: fill in this +cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params); + #endif //_INCLUDE_SOURCEPAWN_VM_H_ diff --git a/sourcepawn/vm/sp_vm_debug.c b/sourcepawn/vm/sp_vm_debug.c index f3fc80e9..f97812ae 100644 --- a/sourcepawn/vm/sp_vm_debug.c +++ b/sourcepawn/vm/sp_vm_debug.c @@ -3,8 +3,8 @@ int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename) { - uint32_t mid, low, high; - int diff; + int diff, high, low; + uint32_t mid; high = ctx->plugin->debug.files_num - 1; low = 0; @@ -53,8 +53,8 @@ int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name) int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line) { - uint32_t mid, low, high; - int diff; + int diff, high, low; + uint32_t mid; high = ctx->plugin->debug.lines_num - 1; low = 0; From b8d6dddea5dfdcefad896c639b5d34a34e5c6723 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 19 Aug 2006 20:52:42 +0000 Subject: [PATCH 0036/1664] fixed bsearch in debug API as its a lower bound one --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4066 --- sourcepawn/vm/sp_vm.c | 8 ++--- sourcepawn/vm/sp_vm_debug.c | 62 ++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c index 6a2b0a1b..303b92c3 100644 --- a/sourcepawn/vm/sp_vm.c +++ b/sourcepawn/vm/sp_vm.c @@ -7,10 +7,10 @@ #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) #define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) -int main() +/*int main() { /** temporary testing area */ - sp_context_t ctx; + /*sp_context_t ctx; cell_t l, *p; cell_t arr1[] = {1,3,3,7}; cell_t arr2[] = {123,1234,12345,123456}; @@ -38,7 +38,7 @@ int main() assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); return 0; -} +}*/ int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr) { @@ -516,7 +516,7 @@ int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx) const char *strbase; sp_fdbg_symbol_t *sym; sp_fdbg_arraydim_t *arr; - sp_context_t *context = *ctx; + sp_context_t *context; context = (sp_context_t *)malloc(sizeof(sp_context_t)); memset(context, 0, sizeof(sp_context_t)); diff --git a/sourcepawn/vm/sp_vm_debug.c b/sourcepawn/vm/sp_vm_debug.c index f97812ae..862af16d 100644 --- a/sourcepawn/vm/sp_vm_debug.c +++ b/sourcepawn/vm/sp_vm_debug.c @@ -1,30 +1,34 @@ #include "sp_vm.h" #include "sp_vm_debug.h" +#define USHR(x) ((unsigned int)(x)>>1) + int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename) { - int diff, high, low; - uint32_t mid; + int high, low, mid; - high = ctx->plugin->debug.files_num - 1; - low = 0; + high = ctx->plugin->debug.files_num; + low = -1; - while (low <= high) + while (high - low > 1) { - mid = (low + high) / 2; - diff = ctx->files[mid].addr - addr; - if (diff == 0) + mid = USHR(low + high); + if (ctx->files[mid].addr <= addr) { - *filename = ctx->files[mid].name; - return SP_ERR_NONE; - } else if (diff < 0) { - low = mid + 1; + low = mid; } else { - high = mid - 1; + high = mid; } } - return SP_ERR_NOT_FOUND; + if (low == -1) + { + return SP_ERR_NOT_FOUND; + } + + *filename = ctx->files[low].name; + + return SP_ERR_NONE; } int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name) @@ -53,28 +57,30 @@ int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name) int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line) { - int diff, high, low; - uint32_t mid; + int high, low, mid; - high = ctx->plugin->debug.lines_num - 1; - low = 0; + high = ctx->plugin->debug.lines_num; + low = -1; - while (low <= high) + while (high - low > 1) { - mid = (low + high) / 2; - diff = ctx->lines[mid].addr - addr; - if (diff == 0) + mid = USHR(low + high); + if (ctx->lines[mid].addr <= addr) { - *line = ctx->lines[mid].line; - return SP_ERR_NONE; - } else if (diff < 0) { - low = mid + 1; + low = mid; } else { - high = mid - 1; + high = mid; } } - return SP_ERR_NOT_FOUND; + if (low == -1) + { + return SP_ERR_NOT_FOUND; + } + + *line = ctx->lines[low].line; + + return SP_ERR_NONE; } int SP_DbgInstallBreak(sp_context_t *ctx, SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) From d792a19e4ae7c0fdd310306af3f2be6874883308 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 28 Aug 2006 15:22:02 +0000 Subject: [PATCH 0037/1664] updated compiler to 3.2.3636 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4067 --- sourcepawn/compiler/amx.h | 4 +- sourcepawn/compiler/amxdbg.h | 2 +- sourcepawn/compiler/libpawnc.c | 2 +- sourcepawn/compiler/pawncc.c | 2 +- sourcepawn/compiler/sc.h | 124 +++++++++-------- sourcepawn/compiler/sc1.c | 244 ++++++++++++++++++++++----------- sourcepawn/compiler/sc2.c | 28 +++- sourcepawn/compiler/sc3.c | 27 +++- sourcepawn/compiler/sc4.c | 10 +- sourcepawn/compiler/sc5.scp | 186 ++++++++++++------------- sourcepawn/compiler/sc6.c | 7 +- sourcepawn/compiler/sci18n.c | 2 +- sourcepawn/compiler/sclist.c | 6 +- sourcepawn/compiler/scmemfil.c | 11 +- sourcepawn/compiler/scvars.c | 2 +- sourcepawn/compiler/svnrev.h | 10 +- 16 files changed, 397 insertions(+), 270 deletions(-) diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 6ba09a92..3c473a77 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: amx.h 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id: amx.h 3633 2006-08-11 16:20:18Z thiadmer $ */ #ifndef AMX_H_INCLUDED @@ -266,6 +266,7 @@ typedef struct tagAMX { cell alt ; cell reset_stk ; cell reset_hea ; + /* extra fields for increased performance */ cell sysreq_d ; /* relocated address/value for the SYSREQ.D opcode */ #if defined JIT /* support variables for the JIT */ @@ -341,6 +342,7 @@ enum { #define AMX_FLAG_COMPACT 0x04 /* compact encoding */ #define AMX_FLAG_SLEEP 0x08 /* script uses the sleep instruction (possible re-entry or power-down mode) */ #define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no BREAK opcodes */ +#define AMX_FLAG_SYSREQN 0x800 /* script new (optimized) version of SYSREQ opcode */ #define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */ #define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */ #define AMX_FLAG_BROWSE 0x4000 /* busy browsing */ diff --git a/sourcepawn/compiler/amxdbg.h b/sourcepawn/compiler/amxdbg.h index 4fc3c1c1..606b4806 100644 --- a/sourcepawn/compiler/amxdbg.h +++ b/sourcepawn/compiler/amxdbg.h @@ -21,7 +21,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: amxdbg.h 3519 2006-02-17 17:57:04Z thiadmer $ + * Version: $Id: amxdbg.h 3612 2006-07-22 09:59:46Z thiadmer $ */ #ifndef AMXDBG_H_INCLUDED diff --git a/sourcepawn/compiler/libpawnc.c b/sourcepawn/compiler/libpawnc.c index c2aa9f27..ddf84261 100644 --- a/sourcepawn/compiler/libpawnc.c +++ b/sourcepawn/compiler/libpawnc.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: libsc.c 3114 2005-03-17 14:48:29Z thiadmer $ + * Version: $Id: libpawnc.c 3612 2006-07-22 09:59:46Z thiadmer $ */ #include #include diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index f9839590..ff78485c 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -139,7 +139,7 @@ int main(int argc, char *argv[]) cod.flags = 0; if (hdr->flags & AMX_FLAG_DEBUG) { - cod.flags |= SP_FILE_DEBUG; + cod.flags |= SP_FLAG_DEBUG; } cod.code = sizeof(cod); cod.main = hdr->cip; diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 4f839169..5c5e004e 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -25,7 +25,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc.h 3590 2006-06-24 14:16:39Z thiadmer $ + * Version: $Id: sc.h 3636 2006-08-14 15:42:05Z thiadmer $ */ #ifndef SC_H_INCLUDED #define SC_H_INCLUDED @@ -279,11 +279,11 @@ typedef struct s_stringpair { #define opargs(n) ((n)*sizeof(cell)) /* size of typical argument */ /* Tokens recognized by lex() - * Some of these constants are assigned as well to the variable "lastst" + * Some of these constants are assigned as well to the variable "lastst" (see SC1.C) */ #define tFIRST 256 /* value of first multi-character operator */ #define tMIDDLE 280 /* value of last multi-character operator */ -#define tLAST 326 /* value of last multi-character match-able token */ +#define tLAST 329 /* value of last multi-character match-able token */ /* multi-character operators */ #define taMULT 256 /* *= */ #define taDIV 257 /* /= */ @@ -312,62 +312,66 @@ typedef struct s_stringpair { #define tDBLCOLON 280 /* :: */ /* reserved words (statements) */ #define tASSERT 281 -#define tBREAK 282 -#define tCASE 283 -#define tCHAR 284 -#define tCONST 285 -#define tCONTINUE 286 -#define tDEFAULT 287 -#define tDEFINED 288 -#define tDO 289 -#define tELSE 290 -#define tENUM 291 -#define tEXIT 292 -#define tFOR 293 -#define tFORWARD 294 -#define tGOTO 295 -#define tIF 296 -#define tNATIVE 297 -#define tNEW 298 -#define tDECL 299 -#define tOPERATOR 300 -#define tPUBLIC 301 -#define tRETURN 302 -#define tSIZEOF 303 -#define tSLEEP 304 -#define tSTATE 305 -#define tSTATIC 306 -#define tSTOCK 307 -#define tSWITCH 308 -#define tTAGOF 309 -#define tWHILE 310 +#define tBEGIN 282 +#define tBREAK 283 +#define tCASE 284 +#define tCHAR 285 +#define tCONST 286 +#define tCONTINUE 287 +#define tDEFAULT 288 +#define tDEFINED 289 +#define tDO 290 +#define tELSE 291 +#define tEND 292 +#define tENUM 293 +#define tEXIT 294 +#define tFOR 295 +#define tFORWARD 296 +#define tGOTO 297 +#define tIF 298 +#define tNATIVE 299 +#define tNEW 300 +#define tDECL 301 +#define tOPERATOR 302 +#define tPUBLIC 303 +#define tRETURN 304 +#define tSIZEOF 305 +#define tSLEEP 306 +#define tSTATE 307 +#define tSTATIC 308 +#define tSTOCK 309 +#define tSWITCH 310 +#define tTAGOF 311 +#define tTHEN 312 +#define tWHILE 313 /* compiler directives */ -#define tpASSERT 311 /* #assert */ -#define tpDEFINE 312 -#define tpELSE 313 /* #else */ -#define tpELSEIF 314 /* #elseif */ -#define tpEMIT 315 -#define tpENDIF 316 -#define tpENDINPUT 317 -#define tpENDSCRPT 318 -#define tpERROR 319 -#define tpFILE 320 -#define tpIF 321 /* #if */ -#define tINCLUDE 322 -#define tpLINE 323 -#define tpPRAGMA 324 -#define tpTRYINCLUDE 325 -#define tpUNDEF 326 +#define tpASSERT 314 /* #assert */ +#define tpDEFINE 315 +#define tpELSE 316 /* #else */ +#define tpELSEIF 317 /* #elseif */ +#define tpEMIT 318 +#define tpENDIF 319 +#define tpENDINPUT 320 +#define tpENDSCRPT 321 +#define tpERROR 322 +#define tpFILE 323 +#define tpIF 324 /* #if */ +#define tINCLUDE 325 +#define tpLINE 326 +#define tpPRAGMA 327 +#define tpTRYINCLUDE 328 +#define tpUNDEF 329 /* semicolon is a special case, because it can be optional */ -#define tTERM 327 /* semicolon or newline */ -#define tENDEXPR 328 /* forced end of expression */ +#define tTERM 330 /* semicolon or newline */ +#define tENDEXPR 331 /* forced end of expression */ /* other recognized tokens */ -#define tNUMBER 329 /* integer number */ -#define tRATIONAL 330 /* rational number */ -#define tSYMBOL 331 -#define tLABEL 332 -#define tSTRING 333 -#define tEXPR 334 /* for assigment to "lastst" only */ +#define tNUMBER 332 /* integer number */ +#define tRATIONAL 333 /* rational number */ +#define tSYMBOL 334 +#define tLABEL 335 +#define tSTRING 336 +#define tEXPR 337 /* for assigment to "lastst" only (see SC1.C) */ +#define tENDLESS 338 /* endless loop, for assigment to "lastst" only */ /* (reversed) evaluation of staging buffer */ #define sSTARTREORDER 0x01 @@ -698,15 +702,15 @@ SC_FUNC void delete_dbgstringtable(void); typedef unsigned char MEMFILE; #define tMEMFILE 1 #endif -MEMFILE *mfcreate(char *filename); +MEMFILE *mfcreate(const char *filename); void mfclose(MEMFILE *mf); int mfdump(MEMFILE *mf); -long mflength(MEMFILE *mf); +long mflength(const MEMFILE *mf); long mfseek(MEMFILE *mf,long offset,int whence); -unsigned int mfwrite(MEMFILE *mf,unsigned char *buffer,unsigned int size); +unsigned int mfwrite(MEMFILE *mf,const unsigned char *buffer,unsigned int size); unsigned int mfread(MEMFILE *mf,unsigned char *buffer,unsigned int size); char *mfgets(MEMFILE *mf,char *string,unsigned int size); -int mfputs(MEMFILE *mf,char *string); +int mfputs(MEMFILE *mf,const char *string); /* function prototypes in SCI18N.C */ #define MAXCODEPAGE 12 diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index bd4ea550..aaa97ed6 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc1.c 3591 2006-06-25 14:30:07Z thiadmer $ + * Version: $Id: sc1.c 3636 2006-08-14 15:42:05Z thiadmer $ */ #include #include @@ -109,21 +109,21 @@ static long max_stacksize(symbol *root,int *recursion); static int testsymbols(symbol *root,int level,int testlabs,int testconst); static void destructsymbols(symbol *root,int level); static constvalue *find_constval_byval(constvalue *table,cell val); +static symbol *fetchlab(char *name); static void statement(int *lastindent,int allow_decl); -static void compound(int stmt_sameline); +static void compound(int stmt_sameline,int starttok); +static int test(int label,int parens,int invert); static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr, int *tag,symbol **symptr,int chkfuncresult); static void doassert(void); static void doexit(void); -static void test(int label,int parens,int invert); -static void doif(void); -static void dowhile(void); -static void dodo(void); -static void dofor(void); +static int doif(void); +static int dowhile(void); +static int dodo(void); +static int dofor(void); static void doswitch(void); static void dogoto(void); static void dolabel(void); -static symbol *fetchlab(char *name); static void doreturn(void); static void dobreak(void); static void docont(void); @@ -134,10 +134,17 @@ static void delwhile(void); static int *readwhile(void); static void inst_datetime_defines(void); +enum { + TEST_PLAIN, /* no parentheses */ + TEST_THEN, /* '(' ')' or 'then' */ + TEST_DO, /* '(' ')' or 'do' */ + TEST_OPT, /* '(' ')' or */ +}; static int norun = 0; /* the compiler never ran */ -static int autozero = 1; /* if 1 will zero out the variable, if 0 omit the zeroing */ +static int autozero = 1; /* if 1 will zero out the variable, if 0 omit the zeroing */ static int lastst = 0; /* last executed statement type */ static int nestlevel = 0; /* number of active (open) compound statements */ +static int endlessloop= 0; /* nesting level of endless loop */ static int rettype = 0; /* the type that a "return" expression should have */ static int skipinput = 0; /* number of lines to skip from the first input file */ static int optproccall = TRUE; /* support "procedure call" */ @@ -449,9 +456,9 @@ cleanup: pc_printf("Stack/heap size: %8ld bytes; ", (long)pc_stksize*sizeof(cell)); pc_printf("estimated max. usage"); if (recursion) - pc_printf(" is unknown, due to recursion\n"); + pc_printf(": unknown, due to recursion\n"); else if ((pc_memflags & suSLEEP_INSTR)!=0) - pc_printf(" is unknown, due to the \"sleep\" instruction\n"); + pc_printf(": unknown, due to the \"sleep\" instruction\n"); else pc_printf("=%ld cells (%ld bytes)\n",stacksize,stacksize*sizeof(cell)); pc_printf("Total requirements:%8ld bytes\n", (long)hdrsize+(long)code_idx+(long)glb_declared*sizeof(cell)+(long)pc_stksize*sizeof(cell)); @@ -1415,6 +1422,9 @@ static void dumplits(void) { int j,k; + if (sc_status==statSKIP) + return; + k=0; while (k1 && dim[numdim-1]==0) { + /* also look whether, by any chance, all "counted" final dimensions are + * the same value; if so, we can store this + */ + constvalue *ld=lastdim.next; + int d,match; + for (d=0; dname,NULL,16)==d); + if (d==0) + match=ld->value; + else if (match!=ld->value) + break; + ld=ld->next; + } /* for */ + if (d==dim[numdim-2]) + dim[numdim-1]=match; + } /* if */ /* after all arrays have been initalized, we know the (major) dimensions * of the array and we can properly adjust the indirection vectors */ @@ -2446,26 +2474,28 @@ static void decl_const(int vclass) int symbolline; symbol *sym; - insert_docstring_separator(); /* see comment in newfunc() */ - tag=pc_addtag(NULL); - if (lex(&val,&str)!=tSYMBOL) /* read in (new) token */ - error(20,str); /* invalid symbol name */ - symbolline=fline; /* save line where symbol was found */ - strcpy(constname,str); /* save symbol name */ - needtoken('='); - constexpr(&val,&exprtag,NULL);/* get value */ + insert_docstring_separator(); /* see comment in newfunc() */ + do { + tag=pc_addtag(NULL); + if (lex(&val,&str)!=tSYMBOL) /* read in (new) token */ + error(20,str); /* invalid symbol name */ + symbolline=fline; /* save line where symbol was found */ + strcpy(constname,str); /* save symbol name */ + needtoken('='); + constexpr(&val,&exprtag,NULL); /* get value */ + /* add_constant() checks for duplicate definitions */ + if (!matchtag(tag,exprtag,FALSE)) { + /* temporarily reset the line number to where the symbol was defined */ + int orgfline=fline; + fline=symbolline; + error(213); /* tagname mismatch */ + fline=orgfline; + } /* if */ + sym=add_constant(constname,val,vclass,tag); + if (sym!=NULL) + sc_attachdocumentation(sym);/* attach any documenation to the constant */ + } while (matchtoken(',')); /* enddo */ /* more? */ needtoken(tTERM); - /* add_constant() checks for duplicate definitions */ - if (!matchtag(tag,exprtag,FALSE)) { - /* temporarily reset the line number to where the symbol was defined */ - int orgfline=fline; - fline=symbolline; - error(213); /* tagname mismatch */ - fline=orgfline; - } /* if */ - sym=add_constant(constname,val,vclass,tag); - if (sym!=NULL) - sc_attachdocumentation(sym);/* attach any documenation to the function */ } /* decl_enum - declare enumerated constants @@ -4597,7 +4627,7 @@ redef_enumfield: */ static void statement(int *lastindent,int allow_decl) { - int tok; + int tok,save; cell val; char *st; @@ -4650,29 +4680,26 @@ static void statement(int *lastindent,int allow_decl) } /* if */ break; case '{': - tok=fline; + case tBEGIN: + save=fline; if (!matchtoken('}')) /* {} is the empty statement */ - compound(tok==fline); + compound(save==fline,tok); /* lastst (for "last statement") does not change */ break; case ';': error(36); /* empty statement */ break; case tIF: - doif(); - lastst=tIF; + lastst=doif(); break; case tWHILE: - dowhile(); - lastst=tWHILE; + lastst=dowhile(); break; case tDO: - dodo(); - lastst=tDO; + lastst=dodo(); break; case tFOR: - dofor(); - lastst=tFOR; + lastst=dofor(); break; case tSWITCH: doswitch(); @@ -4734,23 +4761,24 @@ static void statement(int *lastindent,int allow_decl) } /* switch */ } -static void compound(int stmt_sameline) +static void compound(int stmt_sameline,int starttok) { int indent=-1; cell save_decl=declared; int count_stmt=0; int block_start=fline; /* save line where the compound block started */ + int endtok; /* if there is more text on this line, we should adjust the statement indent */ if (stmt_sameline) { int i; const unsigned char *p=lptr; /* go back to the opening brace */ - while (*p!='{') { + while (*p!=starttok) { assert(p>pline); p--; } /* while */ - assert(*p=='{'); /* it should be found */ + assert(*p==starttok); /* it should be found */ /* go forward, skipping white-space */ p++; while (*p<=' ' && *p!='\0') @@ -4764,13 +4792,14 @@ static void compound(int stmt_sameline) stmtindent++; } /* if */ + endtok=(starttok=='{') ? '}' : tEND; nestlevel+=1; /* increase compound statement level */ - while (matchtoken('}')==0){ /* repeat until compound statement is closed */ + while (matchtoken(endtok)==0){/* repeat until compound statement is closed */ if (!freading){ error(30,block_start); /* compound block not closed at end of file */ break; } else { - if (count_stmt>0 && (lastst==tRETURN || lastst==tBREAK || lastst==tCONTINUE)) + if (count_stmt>0 && (lastst==tRETURN || lastst==tBREAK || lastst==tCONTINUE || lastst==tENDLESS)) error(225); /* unreachable code */ statement(&indent,TRUE); /* do a statement */ count_stmt++; @@ -4864,11 +4893,12 @@ SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr) * * Global references: sc_intest (altered, but restored upon termination) */ -static void test(int label,int parens,int invert) +static int test(int label,int parens,int invert) { int index,tok; cell cidx; int ident,tag; + int endtok; cell constval; symbol *sym; int localstaging=FALSE; @@ -4884,8 +4914,15 @@ static void test(int label,int parens,int invert) PUSHSTK_I(sc_intest); sc_intest=TRUE; - if (parens) - needtoken('('); + endtok=0; + if (parens!=TEST_PLAIN) { + if (matchtoken('(')) + endtok=')'; + else if (parens==TEST_THEN) + endtok=tTHEN; + else if (parens==TEST_DO) + endtok=tDO; + } /* if */ do { stgget(&index,&cidx); /* mark position (of last expression) in * code generator */ @@ -4894,17 +4931,19 @@ static void test(int label,int parens,int invert) if (tok) markexpr(sEXPR,NULL,0); } while (tok); /* do */ - if (parens) - needtoken(')'); + if (endtok!=0) + needtoken(endtok); if (ident==iARRAY || ident==iREFARRAY) { char *ptr=(sym->name!=NULL) ? sym->name : "-unknown-"; error(33,ptr); /* array must be indexed */ } /* if */ if (ident==iCONSTEXPR) { /* constant expression */ + int testtype=0; sc_intest=(short)POPSTK_I();/* restore stack */ stgdel(index,cidx); if (constval) { /* code always executed */ error(206); /* redundant test: always non-zero */ + testtype=tENDLESS; } else { error(205); /* redundant code: never executed */ jumplabel(label); @@ -4913,7 +4952,7 @@ static void test(int label,int parens,int invert) stgout(0); /* write "jumplabel" code */ stgset(FALSE); /* stop staging */ } /* if */ - return; + return testtype; } /* if */ if (tag!=0 && tag!=pc_addtag("bool")) if (check_userop(lneg,tag,0,1,NULL,&tag)) @@ -4929,37 +4968,49 @@ static void test(int label,int parens,int invert) * assert() when localstaging is set to TRUE) */ stgset(FALSE); /* stop staging */ } /* if */ + return 0; } -static void doif(void) +static int doif(void) { int flab1,flab2; int ifindent; + int lastst_true; ifindent=stmtindent; /* save the indent of the "if" instruction */ flab1=getlabel(); /* get label number for false branch */ - test(flab1,TRUE,FALSE); /* get expression, branch to flab1 if false */ + test(flab1,TEST_THEN,FALSE); /* get expression, branch to flab1 if false */ statement(NULL,FALSE); /* if true, do a statement */ - if (matchtoken(tELSE)==0){ /* if...else ? */ + if (!matchtoken(tELSE)) { /* if...else ? */ setlabel(flab1); /* no, simple if..., print false label */ } else { + lastst_true=lastst; /* save last statement of the "true" branch */ /* to avoid the "dangling else" error, we want a warning if the "else" * has a lower indent than the matching "if" */ if (stmtindent0) error(217); /* loose indentation */ flab2=getlabel(); if ((lastst!=tRETURN) && (lastst!=tGOTO)) - jumplabel(flab2); + jumplabel(flab2); /* "true" branch jumps around "else" clause, unless the "true" branch statement already jumped */ setlabel(flab1); /* print false label */ statement(NULL,FALSE); /* do "else" clause */ setlabel(flab2); /* print true label */ - } /* endif */ + /* if both the "true" branch and the "false" branch ended with the same + * kind of statement, set the last statement id to that kind, rather than + * to the generic tIF; this allows for better "unreachable code" checking + */ + if (lastst==lastst_true) + return lastst; + } /* if */ + return tIF; } -static void dowhile(void) +static int dowhile(void) { int wq[wqSIZE]; /* allocate local queue */ + int save_endlessloop,retcode; + save_endlessloop=endlessloop; addwhile(wq); /* add entry to queue for "break" */ setlabel(wq[wqLOOP]); /* loop label */ /* The debugger uses the "break" opcode to be able to "break" out of @@ -4967,21 +5018,27 @@ static void dowhile(void) * tiniest loop, set it below the top of the loop */ setline(TRUE); - test(wq[wqEXIT],TRUE,FALSE); /* branch to wq[wqEXIT] if false */ + endlessloop=test(wq[wqEXIT],TEST_DO,FALSE);/* branch to wq[wqEXIT] if false */ statement(NULL,FALSE); /* if so, do a statement */ jumplabel(wq[wqLOOP]); /* and loop to "while" start */ setlabel(wq[wqEXIT]); /* exit label */ delwhile(); /* delete queue entry */ + + retcode=endlessloop ? tENDLESS : tWHILE; + endlessloop=save_endlessloop; + return retcode; } /* * Note that "continue" will in this case not jump to the top of the loop, but * to the end: just before the TRUE-or-FALSE testing code. */ -static void dodo(void) +static int dodo(void) { int wq[wqSIZE],top; + int save_endlessloop,retcode; + save_endlessloop=endlessloop; addwhile(wq); /* see "dowhile" for more info */ top=getlabel(); /* make a label first */ setlabel(top); /* loop label */ @@ -4989,26 +5046,32 @@ static void dodo(void) needtoken(tWHILE); setlabel(wq[wqLOOP]); /* "continue" always jumps to WQLOOP. */ setline(TRUE); - test(wq[wqEXIT],TRUE,FALSE); + endlessloop=test(wq[wqEXIT],TEST_OPT,FALSE); jumplabel(top); setlabel(wq[wqEXIT]); delwhile(); needtoken(tTERM); + + retcode=endlessloop ? tENDLESS : tDO; + endlessloop=save_endlessloop; + return retcode; } -static void dofor(void) +static int dofor(void) { int wq[wqSIZE],skiplab; cell save_decl; - int save_nestlevel,index; + int save_nestlevel,save_endlessloop; + int index,endtok; int *ptr; save_decl=declared; save_nestlevel=nestlevel; + save_endlessloop=endlessloop; addwhile(wq); skiplab=getlabel(); - needtoken('('); + endtok= matchtoken('(') ? ')' : tDO; if (matchtoken(';')==0) { /* new variable declarations are allowed here */ if (matchtoken(tNEW)) { @@ -5016,7 +5079,7 @@ static void dofor(void) * 'compound statement' level of it own. */ nestlevel++; - autozero=1; + autozero=1; declloc(FALSE); /* declare local variable */ } else { doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE); /* expression 1 */ @@ -5046,14 +5109,16 @@ static void dofor(void) stgmark(sSTARTREORDER); stgmark((char)(sEXPRSTART+0)); /* mark start of 2nd expression in stage */ setlabel(skiplab); /* jump to this point after 1st expression */ - if (matchtoken(';')==0) { - test(wq[wqEXIT],FALSE,FALSE); /* expression 2 (jump to wq[wqEXIT] if false) */ + if (matchtoken(';')) { + endlessloop=1; + } else { + endlessloop=test(wq[wqEXIT],TEST_PLAIN,FALSE);/* expression 2 (jump to wq[wqEXIT] if false) */ needtoken(';'); } /* if */ stgmark((char)(sEXPRSTART+1)); /* mark start of 3th expression in stage */ - if (matchtoken(')')==0) { + if (!matchtoken(endtok)) { doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE); /* expression 3 */ - needtoken(')'); + needtoken(endtok); } /* if */ stgmark(sENDREORDER); /* mark end of reversed evaluation */ stgout(index); @@ -5075,6 +5140,10 @@ static void dofor(void) delete_symbols(&loctab,nestlevel,FALSE,TRUE); nestlevel=save_nestlevel; /* reset 'compound statement' nesting level */ } /* if */ + + index=endlessloop ? tENDLESS : tFOR; + endlessloop=save_endlessloop; + return index; } /* The switch statement is incompatible with its C sibling: @@ -5092,16 +5161,17 @@ static void dofor(void) static void doswitch(void) { int lbl_table,lbl_exit,lbl_case; - int tok,swdefault,casecount; + int swdefault,casecount; + int tok,endtok; cell val; char *str; constvalue caselist = { NULL, "", 0, 0}; /* case list starts empty */ constvalue *cse,*csp; char labelname[sNAMEMAX+1]; - needtoken('('); + endtok= matchtoken('(') ? ')' : tDO; doexpr(TRUE,FALSE,FALSE,FALSE,NULL,NULL,TRUE);/* evaluate switch expression */ - needtoken(')'); + needtoken(endtok); /* generate the code for the switch statement, the label is the address * of the case table (to be generated later). */ @@ -5109,7 +5179,12 @@ static void doswitch(void) lbl_case=0; /* just to avoid a compiler warning */ ffswitch(lbl_table); - needtoken('{'); + if (matchtoken(tBEGIN)) { + endtok=tEND; + } else { + endtok='}'; + needtoken('{'); + } /* if */ lbl_exit=getlabel(); /* get label number for jumping out of switch */ swdefault=FALSE; casecount=0; @@ -5195,15 +5270,14 @@ static void doswitch(void) */ jumplabel(lbl_exit); break; - case '}': - /* nothing, but avoid dropping into "default" */ - break; default: - error(2); - indent_nowarn=TRUE; /* disable this check */ - tok='}'; /* break out of the loop after an error */ + if (tok!=endtok) { + error(2); + indent_nowarn=TRUE; /* disable this check */ + tok=endtok; /* break out of the loop after an error */ + } /* if */ } /* switch */ - } while (tok!='}'); + } while (tok!=endtok); #if !defined NDEBUG /* verify that the case table is sorted (unfortunatly, duplicates can @@ -5238,7 +5312,7 @@ static void doassert(void) if ((sc_debug & sCHKBOUNDS)!=0) { flab1=getlabel(); /* get label number for "OK" branch */ - test(flab1,FALSE,TRUE); /* get expression and branch to flab1 if true */ + test(flab1,TEST_PLAIN,TRUE);/* get expression and branch to flab1 if true */ insert_dbgline(fline); /* make sure we can find the correct line number */ ffabort(xASSERTION); setlabel(flab1); @@ -5260,6 +5334,9 @@ static void dogoto(void) cell val; symbol *sym; + /* if we were inside an endless loop, assume that we jump out of it */ + endlessloop=0; + if (lex(&val,&st)==tSYMBOL) { sym=fetchlab(st); jumplabel((int)sym->addr); @@ -5443,6 +5520,7 @@ static void dobreak(void) { int *ptr; + endlessloop=0; /* if we were inside an endless loop, we just jumped out */ ptr=readwhile(); /* readwhile() gives an error if not in loop */ needtoken(tTERM); if (ptr==NULL) @@ -5530,7 +5608,7 @@ static void dostate(void) if (matchtoken('(')) { flabel=getlabel(); /* get label number for "false" branch */ pc_docexpr=TRUE; /* attach expression as a documentation string */ - test(flabel,FALSE,FALSE); /* get expression, branch to flabel if false */ + test(flabel,TEST_PLAIN,FALSE);/* get expression, branch to flabel if false */ pc_docexpr=FALSE; needtoken(')'); } else { diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 859ec30f..4e2d6a98 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc2.c 3590 2006-06-24 14:16:39Z thiadmer $ + * Version: $Id: sc2.c 3636 2006-08-14 15:42:05Z thiadmer $ */ #include #include @@ -947,11 +947,27 @@ static int command(void) if ((ifstack[iflevel-1] & PARSEMODE)==PARSEMODE) { /* there has been a parse mode already on this level, so skip the rest */ ifstack[iflevel-1] |= (char)SKIPMODE; + /* if we were already skipping this section, allow expressions with + * undefined symbols; otherwise check the expression to catch errors + */ + if (tok==tpELSEIF) { + if (skiplevel==iflevel) + preproc_expr(&val,NULL); /* get, but ignore the expression */ + else + lptr=strchr(lptr,'\0'); + } /* if */ } else { /* previous conditions were all FALSE */ if (tok==tpELSEIF) { - /* get new expression */ - preproc_expr(&val,NULL); /* get value (or 0 on error) */ + /* if we were already skipping this section, allow expressions with + * undefined symbols; otherwise check the expression to catch errors + */ + if (skiplevel==iflevel) { + preproc_expr(&val,NULL); /* get value (or 0 on error) */ + } else { + lptr=strchr(lptr,'\0'); + val=0; + } /* if */ ifstack[iflevel-1]=(char)(val ? PARSEMODE : SKIPMODE); } else { /* a simple #else, clear skip mode */ @@ -1816,10 +1832,10 @@ char *sc_tokens[] = { "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=", "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", - "assert", "break", "case", "char", "const", "continue", "default", - "defined", "do", "else", "enum", "exit", "for", "forward", "goto", + "assert", "*begin", "break", "case", "char", "const", "continue", "default", + "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", - "sleep", "state", "static", "stock", "switch", "tagof", "while", + "sleep", "state", "static", "stock", "switch", "tagof", "*then", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", "#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma", "#tryinclude", "#undef", diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 9c5df24c..dc6785df 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc3.c 3598 2006-07-04 13:44:04Z thiadmer $ + * Version: $Id: sc3.c 3635 2006-08-13 12:19:41Z thiadmer $ */ #include #include @@ -619,9 +619,26 @@ static void plnge2(void (*oper)(void), } /* if */ } -static cell truemodulus(cell a,cell b) +static cell flooreddiv(cell a,cell b,int return_remainder) { - return (a % b + b) % b; + cell q,r; + + if (b==0) { + error(29); + return 0; + } /* if */ + /* first implement truncated division in a portable way */ + #define IABS(a) ((a)>=0 ? (a) : (-a)) + q=IABS(a)/IABS(b); + if ((cell)(a ^ b)<0) + q=-q; /* swap sign if either "a" or "b" is negative (but not both) */ + r=a-q*b; /* calculate the matching remainder */ + /* now "fiddle" with the values to get floored division */ + if (r!=0 && (cell)(r ^ b)<0) { + q--; + r+=b; + } /* if */ + return return_remainder ? r : q; } static cell calc(cell left,void (*oper)(),cell right,char *boolresult) @@ -657,9 +674,9 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult) else if (oper==os_mult) return (left * right); else if (oper==os_div) - return (left - truemodulus(left,right)) / right; + return flooreddiv(left,right,0); else if (oper==os_mod) - return truemodulus(left,right); + return flooreddiv(left,right,1); else error(29); /* invalid expression, assumed 0 (this should never occur) */ return 0; diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index 70e39dde..e271037d 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc4.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id: sc4.c 3633 2006-08-11 16:20:18Z thiadmer $ */ #include #include @@ -214,7 +214,7 @@ SC_FUNC void writetrailer(void) */ SC_FUNC void begcseg(void) { - if (curseg!=sIN_CSEG || fcurrent!=fcurseg) { + if (sc_status!=statSKIP && (curseg!=sIN_CSEG || fcurrent!=fcurseg)) { stgwrite("\n"); stgwrite("CODE "); outval(fcurrent,FALSE); @@ -232,7 +232,7 @@ SC_FUNC void begcseg(void) */ SC_FUNC void begdseg(void) { - if (curseg!=sIN_DSEG || fcurrent!=fcurseg) { + if (sc_status!=statSKIP && (curseg!=sIN_DSEG || fcurrent!=fcurseg)) { stgwrite("\n"); stgwrite("DATA "); outval(fcurrent,FALSE); @@ -245,6 +245,10 @@ SC_FUNC void begdseg(void) SC_FUNC void setline(int chkbounds) { + if (sc_asmfile) { + stgwrite("\t; line "); + outval(fline,TRUE); + } /* if */ if ((sc_debug & sSYMBOLIC)!=0 || chkbounds && (sc_debug & sCHKBOUNDS)!=0) { /* generate a "break" (start statement) opcode rather than a "line" opcode * because earlier versions of Small/Pawn have an incompatible version of the diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index 25e4baa2..1bf02541 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc5.sch 3590 2006-06-24 14:16:39Z thiadmer $ + * Version: $Id: sc5.sch 3633 2006-08-11 16:20:18Z thiadmer $ */ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]); @@ -27,13 +27,13 @@ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned ch /*-*SCPACK start of pair table, do not change or remove this line */ unsigned char errstr_table[][2] = { {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {116,105}, {100,32}, {115,32}, {101,114}, {97,108}, {101,110}, {37,115}, {133,129}, {34,139}, {141,34}, {117,110}, - {110,111}, {114,101}, {115,105}, {121,32}, {97,116}, {111,114}, {97,110}, {32,142}, {109,98}, {115,116}, {41,10}, {100,101}, {109,138}, {101,134}, {98,108}, {140,32}, - {111,108}, {114,97}, {144,130}, {118,137}, {143,99}, {102,164}, {115,121}, {166,152}, {167,160}, {117,115}, {97,32}, {115,146}, {97,158}, {149,32}, {132,161}, {105,134}, + {114,101}, {110,111}, {115,105}, {121,32}, {97,116}, {111,114}, {97,110}, {32,142}, {109,98}, {115,116}, {41,10}, {100,101}, {109,138}, {101,134}, {98,108}, {140,32}, + {111,108}, {114,97}, {145,130}, {118,137}, {143,99}, {102,164}, {115,121}, {166,152}, {167,160}, {117,115}, {97,32}, {115,146}, {97,158}, {149,32}, {132,161}, {105,134}, {103,32}, {163,175}, {103,117}, {178,156}, {136,32}, {132,179}, {131,177}, {111,102}, {116,104}, {101,120}, {105,135}, {165,159}, {101,100}, {99,104}, {118,132}, {168,151}, - {105,172}, {190,192}, {155,102}, {174,147}, {183,32}, {109,97}, {116,111}, {99,129}, {101,135}, {181,130}, {98,128}, {115,10}, {112,145}, {153,148}, {44,32}, {40,191}, - {169,130}, {151,10}, {101,10}, {207,154}, {109,208}, {116,97}, {105,99}, {194,131}, {193,128}, {34,32}, {129,32}, {132,97}, {100,105}, {146,122}, {110,32}, {137,32}, - {104,97}, {101,108}, {117,108}, {99,111}, {108,111}, {109,148}, {199,153}, {58,209}, {111,112}, {97,115}, {108,128}, {232,136}, {230,150}, {150,32}, {204,171}, {131,176}, - {212,202}, {102,105}, {119,105}, {185,238}, {109,112}, {116,136}, {165,140}, {197,147}, {102,149}, {111,32}, {131,32}, {213,176}, {110,117}, {115,117}, {118,128} + {105,172}, {190,192}, {155,102}, {174,147}, {183,32}, {109,97}, {116,111}, {99,129}, {101,135}, {112,144}, {181,130}, {98,128}, {115,10}, {153,148}, {44,32}, {40,191}, + {169,130}, {151,10}, {101,10}, {207,154}, {109,208}, {116,97}, {194,131}, {193,128}, {34,32}, {129,32}, {105,99}, {132,97}, {100,105}, {146,122}, {110,32}, {137,32}, + {104,97}, {101,108}, {117,108}, {99,111}, {108,111}, {109,148}, {199,153}, {58,209}, {111,112}, {97,115}, {108,128}, {232,136}, {230,150}, {150,32}, {201,171}, {131,176}, + {212,203}, {102,105}, {119,105}, {185,238}, {109,112}, {116,136}, {165,140}, {197,147}, {102,149}, {111,32}, {131,32}, {213,176}, {110,117}, {115,117}, {118,128} }; /*-*SCPACK end of pair table, do not change or remove this line */ @@ -134,96 +134,96 @@ static char *errmsg[] = { #else "\271pect\235\306k\212:\227\316bu\202fo\217\206\216\012", "\201l\223\252s\203g\352\315e\234\202(\255\363\201) c\355f\240\344w ea\275 \042c\351e\042\012", - "\233cl\333\237\304\252\344c\337\330\324appe\204 \372\252\343\364o\217\206\236ock\012", + "\233cl\333\237\304\252\344c\337\327\324appe\204 \372\252\343\364o\217\206\236ock\012", "\366\227 \272\242i\364le\234t\274\012", - "\273\367\242\340\376\265t\313", + "\273\367\242\340\376\265t\314", "\360a\253gn\235\306 \355\256y\012", - "\353\224\255c\226\242\312\221\327\274\012", + "\353\224\255c\226\242\313\220\326\274\012", "\360\252\354\202\363\201; \351\375m\235z\210o\012", "\266\303\335\200(nega\205ve\316z\210\371\255ou\202\304bo\217ds\232", "\266\273\255\233cl\333\214\012", - "\266out\222d\200\366\313", - "\266\273c\211l\316\242\252\261add\221s\313", - "\220 \212tr\223po\203\202(\220 pu\236\326 \366s\232", + "\266out\222d\200\366\314", + "\266\273c\211l\316\242\252\261add\220s\314", + "\221 \212tr\223po\203\202(\221 pu\236\332 \366s\232", "\266\315e\234t; \242\372s\362t\275\012", - "\042\302a\342t\331c\351\200\360\270\200l\351\202c\351\200\372s\362t\275 \315e\234t\012", + "\042\302a\342t\330c\351\200\360\270\200l\351\202c\351\200\372s\362t\275 \315e\234t\012", "m\342\205p\352\302a\342t\207\372\042s\362t\275\042\012", - "\217\327\235\277\012", + "\217\326\235\277\012", "\203i\205\211iza\237d\224\252\271ce\274\207\233cl\204\235\335\322", "\242\252lab\341\347", "\266\250 nam\200\216\012", - "\250 \211\221ad\223\327\274\347", + "\250 \211\220ad\223\326\274\347", "\360l\243u\200(n\201-\354t\232", "\303a\253gn\234\202\360\222\364\352a\253gn\234t\012", - "\042b\221ak\331\255\042\307t\203ue\331\272ou\202\304\307t\271t\012", + "\042b\220ak\330\255\042\307t\203ue\330\272ou\202\304\307t\271t\012", "\273head\357\334ff\210\207from pro\306typ\322", - "\220 \345\275\357\042#if...\042\012", + "\221 \345\275\357\042#if...\042\012", "\266\275\333ct\264\354t\012", "\266\375bscrip\202(\242\355\303\255\306\371m\226\223\375bscripts)\347", "\266\363\201\316\351\375m\235z\210o\012", "\343\364o\217\206\315e\234\202\242c\344s\235a\202\270\200\212\206\304\361\352(\231\204t\235a\202l\203\200%d\232", - "\217k\220w\336\334\221c\205v\322", - "\303\203\233x ou\202\304bo\217d\207(\330\216\232", - "\303\360\203\233x\235(\330\216\232", - "\311do\310\242\340\376\252\302a\342\202\243u\200(\311%d\232", - "\311typ\200mis\345\275 (\311%d\232", + "\217k\221w\336\334\220c\205v\322", + "\303\203\233x ou\202\304bo\217d\207(\327\216\232", + "\303\360\203\233x\235(\327\216\232", + "\312do\310\242\340\376\252\302a\342\202\243u\200(\312%d\232", + "\312typ\200mis\345\275 (\312%d\232", "e\364t\223\315e\234t\012", "\266\231r\357(po\253\236\223n\201-\365m\203\224\235\231r\203g\232", - "\271t\241 \275\333c\365\207\332l\203\322", - "\354\202\250 \340\207\220 \335\322", - "dupl\326\224\200\042c\351e\331lab\341 (\243u\200%d\232", - "\266\341lip\222s\316\303\335\200\272\242k\220wn\012", - "\266\343\230\203a\237\304cl\351\207speci\361\210\313", + "\271t\241 \275\333c\365\207\331l\203\322", + "\354\202\250 \340\207\221 \335\322", + "dupl\332\224\200\042c\351e\330lab\341 (\243u\200%d\232", + "\266\341lip\222s\316\303\335\200\272\242k\221wn\012", + "\266\343\230\203a\237\304cl\351\207speci\361\210\314", "\275\333ct\264\354\202\271ce\274\207r\226g\200f\255pack\235\231r\203g\012", - "po\222\214\337p\333me\365\207\324\314c\274\200\211l nam\235p\333me\365\313", - "\306\371m\226\223\273\265t\313", - "\217k\220w\336\303\335\200(\330\216\232", + "po\222\214\337p\333me\365\207\324\311c\274\200\211l nam\235p\333me\365\314", + "\306\371m\226\223\273\265t\314", + "\217k\221w\336\303\335\200(\327\216\232", "\303\335\310d\371\242\345\275\316\255\233\231\203a\237\303\272\306\371sm\211l\012", "\303\334\234\222\201\207d\371\242\345\275\012", "\266l\203\200\307t\203ua\214\012", "\266r\226g\322", - "\266\375bscript\316\251\200\042[ ]\331\353\224\225\207\332\305j\255\334\234\222\201\313", + "\266\375bscript\316\251\200\042[ ]\330\353\224\225\207\331\305j\255\334\234\222\201\314", "m\342\205-\334\234\222\201\337\256y\207\360f\342l\223\203i\205\211iz\274\012", - "\271ce\274\357\305ximum \374\230\264\304\334\234\222\201\313", + "\271ce\274\357\305ximum \374\230\264\304\334\234\222\201\314", "\217\345\275\235c\344s\357b\241c\200(\042}\042\232", "\231\204\202\304\273bod\223\362\270ou\202\273head\210\012", - "\256ys\316\344c\337\301\310\226\206\273\265t\207c\226\242\312pu\236\326 (\330\216\232", - "\217f\203ish\235\363\332be\370\200\343\364il\264\334\221c\205v\322", - "dupl\326\224\200\265t; sam\200\311\272p\351s\235tw\326\322", - "\273\311\367\242\340\376\252\302a\342\202\243u\200(\330\216\232", - "m\342\205p\352\042#\341se\331\334\221c\205v\310betwe\212 \042#if ... #\212\334f\042\012", - "\042#\341seif\331\334\221c\205\376f\240\344w\207\355\042#\341se\331\334\221c\205v\322", + "\256ys\316\344c\337\301\310\226\206\273\265t\207c\226\242\313pu\236\332 (\327\216\232", + "\217f\203ish\235\363\331be\370\200\343\364il\264\334\220c\205v\322", + "dupl\332\224\200\265t; sam\200\312\272p\351s\235tw\332\322", + "\273\312\367\242\340\376\252\302a\342\202\243u\200(\327\216\232", + "m\342\205p\352\042#\341se\330\334\220c\205v\310betwe\212 \042#if ... #\212\334f\042\012", + "\042#\341seif\330\334\220c\205\376f\240\344w\207\355\042#\341se\330\334\220c\205v\322", "\374\230\264\304\353\226d\207do\310\242\361\202\270\200\353\224\225\012", - "\273\221s\342\202\373\304\353\224\225\227 \360\216\012", - "c\226\242\275\226g\200\314\327\235\353\224\225\313", - "\273\311\367\201l\223\340\376\252s\203g\352\373(\311%d\232", - "\273\311\367\242\312\252\221f\210\212c\200\311\255\355\303(\311\216\232", - "\330c\226\242\312bo\270 \252\221f\210\212c\200\226\206\355\303(\330\216\232", - "\266\241\214\337\374\230\264\314ci\222\332\372#p\241g\305\012", - "\241\214\337\374\230\264\370\305\202\211\221ad\223\327\274\012", + "\273\220s\342\202\373\304\353\224\225\227 \360\216\012", + "c\226\242\275\226g\200\311\326\235\353\224\225\314", + "\273\312\367\201l\223\340\376\252s\203g\352\373(\312%d\232", + "\273\312\367\242\313\252\220f\210\212c\200\312\255\355\303(\312\216\232", + "\327c\226\242\313bo\270 \252\220f\210\212c\200\226\206\355\303(\327\216\232", + "\266\241\214\337\374\230\264\311ci\222\331\372#p\241g\305\012", + "\241\214\337\374\230\264\370\305\202\211\220ad\223\326\274\012", "\241\214\337\374\230\264\375pp\225\202wa\207\242\212\254\274\012", - "\251\210-\327\235\353\224\255\360\233cl\204\235be\370\200\251\200(\366\227\232", - "\042\335e\267\331\353\224\255\272\266\332\042\366\331\250\313", - "\273\311\360\355\303(\311\216\232", - "#\327\200p\224\365\336\324\231\204\202\362\270 \355\211p\340be\205c \275\333c\365\012", + "\251\210-\326\235\353\224\255\360\233cl\204\235be\370\200\251\200(\366\227\232", + "\042\335e\267\330\353\224\255\272\266\331\042\366\330\250\314", + "\273\312\360\355\303(\312\216\232", + "#\326\200p\224\365\336\324\231\204\202\362\270 \355\211p\340be\205c \275\333c\365\012", "\203pu\202l\203\200\306\371l\201\260(aft\264\375bs\205tu\214s\232", "\246n\325x \210r\255\372\270\200\363\201\316\255\266\273c\211l\012", "m\211\370m\235UTF-8 \212\343d\203g\316\255c\225rupt\235\361le: \213\012", - "\273\251\310bo\270 \042\221turn\331\226\206\042\221tur\336<\243ue>\042\012", - "\203\307\222\231\212\202\221tur\336typ\310(\303& n\201-\256y\232", - "\217k\220w\336\250\316\255\242\252\354\202\250 \323", + "\273\251\310bo\270 \042\220turn\330\226\206\042\220tur\336<\243ue>\042\012", + "\203\307\222\231\212\202\220tur\336typ\310(\303& n\201-\256y\232", + "\217k\221w\336\250\316\255\242\252\354\202\250 \323", "c\226\242\325k\200\252\373a\207\252\302a\342\202\243u\200f\255\355\203\233x\235\303p\333met\264\323", - "\251\210-\327\235\353\224\225\207\226\206na\205\376\366\207\367\242\340\376\315e\313", - "\252\273\255\330\367\201l\223b\341\201\260\306 \252s\203g\352au\306\345\332\323", - "\315\200\307fl\326t: \201\200\304\270\200\315\310\272\211\221ad\223a\253gn\235\306 a\220\270\264i\364le\234\325\237\323", - "\220 \315\310\204\200\327\235f\255\277\012", - "\217k\220w\336au\306\345\201\321", - "\217k\220w\336\315\200\216 f\255au\306\345\201\321", - "pu\236\326 \301\310\226\206\344c\337\301\310\367\242\340\376\315\310\323", - "\315\200\301\310\367\242\312\203i\205\211iz\235\323", - "pu\236\326 \366\207\367\242\221tur\336\256y\207\323", - "a\230i\262ou\207\354t; \373ov\210rid\200\272\221qui\221\206\323", - "\374\230\264\304\265t\207do\310\242\345\275 \327i\214\012", + "\251\210-\326\235\353\224\225\207\226\206na\205\376\366\207\367\242\340\376\315e\314", + "\252\273\255\327\367\201l\223b\341\201\260\306 \252s\203g\352au\306\345\331\323", + "\315\200\307fl\332t: \201\200\304\270\200\315\310\272\211\220ad\223a\253gn\235\306 a\221\270\264i\364le\234\325\237\323", + "\221 \315\310\204\200\326\235f\255\277\012", + "\217k\221w\336au\306\345\201\321", + "\217k\221w\336\315\200\216 f\255au\306\345\201\321", + "pu\236\332 \301\310\226\206\344c\337\301\310\367\242\340\376\315\310\323", + "\315\200\301\310\367\242\313\203i\205\211iz\235\323", + "pu\236\332 \366\207\367\242\220tur\336\256y\207\323", + "a\230i\262ou\207\354t; \373ov\210rid\200\272\220qui\220\206\323", + "\374\230\264\304\265t\207do\310\242\345\275 \326i\214\012" #endif }; @@ -248,14 +248,14 @@ static char *fatalmsg[] = { /*110*/ "assertion failed: %s\n", /*111*/ "user error: %s\n", #else - "c\226\242\221a\206from \361le\347", + "c\226\242\220a\206from \361le\347", "c\226\242writ\200\306 \361le\347", "t\254\200ov\210f\344w\347", - "\203\375ff\326i\212\202mem\225y\012", + "\203\375ff\332i\212\202mem\225y\012", "\266\351se\230l\264\203\231ruc\214\321", - "\374m\210\326 ov\210f\344w\316\271ce\274\357capacity\012", + "\374m\210\332 ov\210f\344w\316\271ce\274\357capacity\012", "\343\364il\235scrip\202\271ce\274\207\270\200\305ximum mem\225\223\335\200(%l\206bytes\232", - "\306\371m\226\223\210r\255messag\310\332\201\200l\203\322", + "\306\371m\226\223\210r\255messag\310\331\201\200l\203\322", "\343\233pag\200\305pp\357\361\352\242fo\217d\012", "\266p\224h\347", "\351s\210\237fail\274: \213\012", @@ -303,42 +303,42 @@ static char *warnmsg[] = { /*235*/ "public function lacks forward declaration (symbol \"%s\")\n", /*236*/ "unknown parameter in substitution (incorrect #define pattern)\n" #else - "\277 \272tr\244\224\235\306 %\206\275\333c\365\313", - "\221\327i\237\304\354t/\305cr\371\323", - "\374\230\264\304\265t\207do\310\242\345\275 \327i\214\012", + "\277 \272tr\244\224\235\306 %\206\275\333c\365\314", + "\220\326i\237\304\354t/\305cr\371\323", + "\374\230\264\304\265t\207do\310\242\345\275 \326i\214\012", "\250 \272nev\264\251\274\347", "\250 \272a\253gn\235\252\243u\200\270a\202\272nev\264\251\274\347", - "\221d\217d\226\202\343\233: \354\202\363\332\272z\210o\012", - "\221d\217d\226\202te\231: \354\202\363\332\272n\201-z\210o\012", - "\217k\220w\336#p\241g\305\012", - "\273\362\270 \373\221s\342\202\251\235be\370\200\327i\214\316\370c\357\221p\204s\322", - "\366\227 sho\342\206\221tur\336\252\243u\322", + "\220d\217d\226\202\343\233: \354\202\363\331\272z\210o\012", + "\220d\217d\226\202te\231: \354\202\363\331\272n\201-z\210o\012", + "\217k\221w\336#p\241g\305\012", + "\273\362\270 \373\220s\342\202\251\235be\370\200\326i\214\316\370c\357\220p\204s\322", + "\366\227 sho\342\206\220tur\336\252\243u\322", "po\253\236\200\251\200\304\250 be\370\200\203i\205\211iza\214\347", "po\253\236\223\217\203t\212\233\206a\253gn\234t\012", "po\253\236\223\217\203t\212\233\206bit\362s\200\353a\214\012", "\373mis\345\275\012", - "po\253\236\223\252\042\346\331\303\311wa\207\203t\212\233d\347", - "\363\332\340\207\220 effect\012", + "po\253\236\223\252\042\346\330\303\312wa\207\203t\212\233d\347", + "\363\331\340\207\221 effect\012", "ne\231\235\343m\234t\012", "\344os\200\203d\212\325\214\012", - "\240\206\231y\352pro\306typ\310\251\235\362\270 \350\214\337sem\326\240umn\313", - "\344c\337\330\216 s\340dow\207\252\330a\202\252\314c\274\357lev\341\012", - "\363\332\362\270 \373ov\210rid\200\324appe\204 betwe\212 p\204\212\270ese\313", + "\240\206\231y\352pro\306typ\310\251\235\362\270 \350\214\337sem\332\240umn\314", + "\344c\337\327\216 s\340dow\207\252\327a\202\252\311c\274\357lev\341\012", + "\363\331\362\270 \373ov\210rid\200\324appe\204 betwe\212 p\204\212\270ese\314", "lab\341 nam\200\216 s\340dow\207\373nam\322", - "\374\230\264\304\334git\207\271ce\274\207\241\214\337\374\230\264\314ci\222\201\012", - "\221d\217d\226\202\042\335e\267\042: \311\335\200\272\211way\2071 \323", - "\203\233\365m\203\224\200\303\335\200\372\042\335e\267\331\363\332\323", - "\217\221a\275\254\200\343\233\012", - "\252\330\272a\253gn\235\306 its\341f \323", - "m\225\200\203i\205\211l\210\207\270\355\212um \361\341d\313", + "\374\230\264\304\334git\207\271ce\274\207\241\214\337\374\230\264\311ci\222\201\012", + "\220d\217d\226\202\042\335e\267\042: \312\335\200\272\211way\2071 \323", + "\203\233\365m\203\224\200\303\335\200\372\042\335e\267\330\363\331\323", + "\217\220a\275\254\200\343\233\012", + "\252\327\272a\253gn\235\306 its\341f \323", + "m\225\200\203i\205\211l\210\207\270\355\212um \361\341d\314", "l\212g\270 \304\203i\205\211l\264\271ce\274\207\335\200\304\270\200\212um \361\341d\012", "\203\233x \373mis\345\275 \323", - "\220 i\364le\234\325\237f\255\315\200\216 \372\366\227\316\220 f\211l-back\012", - "\315\200specif\326a\237\332\370w\204\206\233cl\333\237\272ig\220\221d\012", + "\221 i\364le\234\325\237f\255\315\200\216 \372\366\227\316\221 f\211l-back\012", + "\315\200specif\332a\237\331\370w\204\206\233cl\333\237\272ig\221\220d\012", "outpu\202\361\352\272writt\212\316bu\202\362\270 \343\364ac\202\212\343d\357\334s\254\274\012", - "\315\200\330\216 s\340dow\207\252g\344b\337\301\322", - "\273\272\233pr\326\224\235\317) \213\012", - "pu\236\326 \273lack\207\370w\204\206\233cl\333\237\323", - "\217k\220w\336p\333met\264\372\375bs\205tu\237(\203c\225\221c\202#\327\200p\224\365n\232" + "\315\200\327\216 s\340dow\207\252g\344b\337\301\322", + "\273\272\233\311c\224\235\317) \213\012", + "pu\236\332 \273lack\207\370w\204\206\233cl\333\237\323", + "\217k\221w\336p\333met\264\372\375bs\205tu\237(\203c\225\220c\202#\326\200p\224\365n\232" #endif }; diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 2ea5f2d4..73845bf0 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc6.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id: sc6.c 3633 2006-08-11 16:20:18Z thiadmer $ */ #include #include @@ -670,7 +670,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) symbol *sym, **nativelist; constvalue *constptr; cell mainaddr; - char nullchar = 0; + char nullchar; /* if compression failed, restart the assembly with compaction switched off */ if (setjmp(compact_err)!=0) { @@ -785,8 +785,9 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) pc_writebin(fout,&hdr,sizeof hdr); /* dump zeros up to the rest of the header, so that we can easily "seek" */ + nullchar='\0'; for (nameofs=sizeof hdr; nameofs #include diff --git a/sourcepawn/compiler/sclist.c b/sourcepawn/compiler/sclist.c index 18c961b0..bf25550d 100644 --- a/sourcepawn/compiler/sclist.c +++ b/sourcepawn/compiler/sclist.c @@ -2,7 +2,9 @@ * * o Name list (aliases) * o Include path list - * o Macro defintions (text substitutions) + * o Macro definitions (text substitutions) + * o Documentation tags and automatic listings + * o Debug strings * * Copyright (c) ITB CompuPhase, 2001-2006 * @@ -22,7 +24,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sclist.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id: sclist.c 3633 2006-08-11 16:20:18Z thiadmer $ */ #include #include diff --git a/sourcepawn/compiler/scmemfil.c b/sourcepawn/compiler/scmemfil.c index 4924e71d..c33d2485 100644 --- a/sourcepawn/compiler/scmemfil.c +++ b/sourcepawn/compiler/scmemfil.c @@ -31,12 +31,15 @@ #include #include "memfile.h" +#if defined FORTIFY + #include +#endif typedef memfile_t MEMFILE; #define tMEMFILE 1 #include "sc.h" -MEMFILE *mfcreate(char *filename) +MEMFILE *mfcreate(const char *filename) { return memfile_creat(filename, 4096); } @@ -64,7 +67,7 @@ int mfdump(MEMFILE *mf) return okay; } -long mflength(MEMFILE *mf) +long mflength(const MEMFILE *mf) { return mf->usedoffs; } @@ -105,7 +108,7 @@ long mfseek(MEMFILE *mf,long offset,int whence) return offset; } -unsigned int mfwrite(MEMFILE *mf,unsigned char *buffer,unsigned int size) +unsigned int mfwrite(MEMFILE *mf,const unsigned char *buffer,unsigned int size) { return (memfile_write(mf, buffer, size) ? size : 0); } @@ -152,7 +155,7 @@ char *mfgets(MEMFILE *mf,char *string,unsigned int size) return string; } -int mfputs(MEMFILE *mf,char *string) +int mfputs(MEMFILE *mf,const char *string) { unsigned int written,length; diff --git a/sourcepawn/compiler/scvars.c b/sourcepawn/compiler/scvars.c index 3efef129..c1419386 100644 --- a/sourcepawn/compiler/scvars.c +++ b/sourcepawn/compiler/scvars.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: scvars.c 3577 2006-06-02 16:22:52Z thiadmer $ + * Version: $Id: scvars.c 3633 2006-08-11 16:20:18Z thiadmer $ */ #include #include /* for _MAX_PATH */ diff --git a/sourcepawn/compiler/svnrev.h b/sourcepawn/compiler/svnrev.h index b0d8a703..3843eb5b 100644 --- a/sourcepawn/compiler/svnrev.h +++ b/sourcepawn/compiler/svnrev.h @@ -1,9 +1,9 @@ #define SMC_VERSION 1 #define SMC_REVISION 0 #define SMC_BUILD 1 -#define SMC_VERSTRING "1.0.1.3599" +#define SMC_VERSTRING "1.0.1.3636" -#define SVN_REV 3599 -#define SVN_REVSTR "3599" -#define SVN_REVDATE "2006-07-05" -#define SVN_REVSTAMP 20060705L +#define SVN_REV 3636 +#define SVN_REVSTR "3636" +#define SVN_REVDATE "2006-08-14" +#define SVN_REVSTAMP 20060814L From c4d00885736174ad9467f829c656d3a70a9bdccd Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 28 Aug 2006 16:33:01 +0000 Subject: [PATCH 0038/1664] identAaAaaAtion --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4068 --- sourcepawn/compiler/sc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index aaa97ed6..96d38eee 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -5079,7 +5079,7 @@ static int dofor(void) * 'compound statement' level of it own. */ nestlevel++; - autozero=1; + autozero=1; declloc(FALSE); /* declare local variable */ } else { doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE); /* expression 1 */ From c0f7e0b57902001f8a7f8cb05b3484bf68afdf1e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 14 Sep 2006 05:34:02 +0000 Subject: [PATCH 0039/1664] initial changes - fixed a code generation bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4069 --- sourcepawn/compiler/amx.h | 1 + sourcepawn/compiler/sc.h | 2 + sourcepawn/compiler/sc3.c | 166 +++++++++++++++++++++++++++++++++----- sourcepawn/compiler/sc4.c | 20 +++++ sourcepawn/compiler/sc6.c | 1 + 5 files changed, 171 insertions(+), 19 deletions(-) diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 3c473a77..7c6b3c7e 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -619,6 +619,7 @@ typedef enum { OP_SYSREQ_D, OP_SYSREQ_ND, /* ----- */ + OP_HEAP_I, OP_NUM_OPCODES } OPCODE; diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 5c5e004e..05676716 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -602,6 +602,7 @@ SC_FUNC void defstorage(void); SC_FUNC void modstk(int delta); SC_FUNC void setstk(cell value); SC_FUNC void modheap(int delta); +SC_FUNC void modheap_i(); SC_FUNC void setheap_pri(void); SC_FUNC void setheap(cell value); SC_FUNC void cell2addr(void); @@ -610,6 +611,7 @@ SC_FUNC void addr2cell(void); SC_FUNC void char2addr(void); SC_FUNC void charalign(void); SC_FUNC void addconst(cell value); +SC_FUNC void setheap_save(cell value); /* Code generation functions for arithmetic operators. * diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index dc6785df..c09b0fa1 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -60,9 +60,104 @@ static int dbltest(void (*oper)(),value *lval1,value *lval2); static int commutative(void (*oper)()); static int constant(value *lval); +#define HEAPUSE_STATIC 0 +#define HEAPUSE_DYNAMIC 1 + +typedef struct heapuse_s { + int type; /* HEAPUSE_STATIC or HEAPUSE_DYNAMIC */ + int size; /* size of array for static (0 for dynamic) */ + struct heapuse_s *prev; /* previous array on the list */ +} heapuse_t; + +typedef struct heapuse_list_s { + struct heapuse_list_s *prev; /* last used list */ + heapuse_t *head; /* head of the current list */ +} heapuse_list_t; + static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */ static int bitwise_opercount; /* count of bitwise operators in an expression */ -static int decl_heap=0; +//static int decl_heap=0; +static heapuse_list_t *heapusage = NULL; + +/** + * Creates a new heap allocation tracker entry + */ +void pushheaplist() +{ + heapuse_list_t *newlist=(heapuse_list_t *)malloc(sizeof(heapuse_list_t)); + newlist->prev=heapusage; + newlist->head=NULL; + heapusage=newlist; +} + +/** + * Generates code to free all heap allocations on a tracker + */ +void freeheapusage(heapuse_list_t *heap) +{ + heapuse_t *cur=heap->head; + heapuse_t *tmp; + while (cur) { + if (cur->type == HEAPUSE_STATIC) { + modheap((-1)*cur->size*sizeof(cell)); + } else { + modheap_i(); + } + tmp=cur->prev; + free(cur); + cur=tmp; + } + heap->head=NULL; +} + +/** + * Pops a heap list but does not free it. + */ +heapuse_list_t *popsaveheaplist() +{ + heapuse_list_t *oldlist=heapusage; + heapusage=heapusage->prev; + return oldlist; +} + +/** + * Pops a heap list and frees it. + */ +void popheaplist() +{ + heapuse_list_t *oldlist; + assert(heapusage!=NULL); + + freeheapusage(heapusage); + assert(heapusage->head==NULL); + + oldlist=heapusage->prev; + free(heapusage); + heapusage=oldlist; +} + +/* + * Returns the size passed in + */ +int markheap(int type, int size) +{ + heapuse_t *use; + if (type==HEAPUSE_STATIC && size==0) + return 0; + use=heapusage->head; + if (use && (type==HEAPUSE_STATIC) + && (use->type == type)) + { + use->size += size; + } else { + use=(heapuse_t *)malloc(sizeof(heapuse_t)); + use->type=type; + use->size=size; + use->prev=heapusage->head; + heapusage->head=use; + } + return size; +} /* Function addresses of binary operators for signed operations */ static void (*op1[17])(void) = { @@ -684,15 +779,13 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult) SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult) { - int locheap=decl_heap; value lval={0}; + pushheaplist(); if (hier14(&lval)) rvalue(&lval); /* scrap any arrays left on the heap */ - assert(decl_heap>=locheap); - modheap((locheap-decl_heap)*sizeof(cell)); /* remove heap space, so negative delta */ - decl_heap=locheap; + popheaplist(); if (lval.ident==iCONSTEXPR && val!=NULL) /* constant expression */ *val=lval.constval; @@ -1047,6 +1140,34 @@ static int hier14(value *lval1) return FALSE; /* expression result is never an lvalue */ } +/** + * Sums up array usage in the current heap tracer and convert it into a dynamic array. + * This is used for the ternary operator, which needs to convert its array usage into + * something dynamically managed. + * !Note: + * This might break if expressions can ever return dynamic arrays. + * Thus, we assert() if something is non-static here. + * Right now, this poses no problem because this type of expression is impossible: + * (a() ? return_array() : return_array()) ? return_array() : return_array() + */ + +void dynarray_from_heaplist(heapuse_list_t *heap) +{ + heapuse_t *use=heap->head; + heapuse_t *tmp; + long total=0; + while (use) { + assert(use->type==HEAPUSE_STATIC); + total+=use->size; + tmp=use->prev; + free(use); + use=tmp; + } + free(heap); + if (total) + setheap_save(total); +} + static int hier13(value *lval) { int lvalue=plnge1(hier12,lval); @@ -1055,7 +1176,9 @@ static int hier13(value *lval) int flab2=getlabel(); value lval2={0}; int array1,array2; - + heapuse_list_t *heap; + + pushheaplist(); if (lvalue) { rvalue(lval); } else if (lval->ident==iCONSTEXPR) { @@ -1072,6 +1195,9 @@ static int hier13(value *lval) sc_allowtags=(short)POPSTK_I(); /* restore */ jumplabel(flab2); setlabel(flab1); + heap=popsaveheaplist(); + dynarray_from_heaplist(heap); + pushheaplist(); needtoken(':'); if (hier13(&lval2)) rvalue(&lval2); @@ -1090,6 +1216,11 @@ static int hier13(value *lval) if (!matchtag(lval->tag,lval2.tag,FALSE)) error(213); /* tagname mismatch ('true' and 'false' expressions) */ setlabel(flab2); + heap=popsaveheaplist(); + dynarray_from_heaplist(heap); + if (array1 && array2) { + markheap(HEAPUSE_DYNAMIC, 0); + } if (lval->ident==iARRAY) lval->ident=iREFARRAY; /* iARRAY becomes iREFARRAY */ else if (lval->ident!=iREFARRAY) @@ -1871,6 +2002,7 @@ static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int */ assert(array_sz>=size); modheap((int)array_sz*sizeof(cell)); + markheap(HEAPUSE_STATIC, array_sz); /* ??? should perhaps fill with zeros first */ memcopy(size*sizeof(cell)); moveto1(); @@ -1914,7 +2046,6 @@ static void callfunction(symbol *sym,value *lval_result,int matchparanthesis) { static long nest_stkusage=0L; static int nesting=0; - int locheap; int close,lvalue; int argpos; /* index in the output stream (argpos==nargs if positional parameters) */ int argidx=0; /* index in "arginfo" list */ @@ -1946,12 +2077,12 @@ static int nesting=0; assert(retsize>0); modheap(retsize*sizeof(cell));/* address is in ALT */ pushreg(sALT); /* pass ALT as the last (hidden) parameter */ - decl_heap+=retsize; + markheap(HEAPUSE_STATIC, retsize); /* also mark the ident of the result as "array" */ lval_result->ident=iREFARRAY; lval_result->sym=symret; } /* if */ - locheap=decl_heap; + pushheaplist(); nesting++; assert(nest_stkusage>=0); @@ -2054,14 +2185,14 @@ static int nesting=0; } else { rvalue(&lval); /* get value in PRI */ setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc++; + heapalloc+=markheap(HEAPUSE_STATIC, 1); nest_stkusage++; } /* if */ } else if (lvalue) { address(lval.sym,sPRI); } else { setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc++; + heapalloc+=markheap(HEAPUSE_STATIC, 1); nest_stkusage++; } /* if */ } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION @@ -2073,7 +2204,7 @@ static int nesting=0; /* allocate a cell on the heap and store the * value (already in PRI) there */ setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc++; + heapalloc+=markheap(HEAPUSE_STATIC, 1); nest_stkusage++; } /* if */ /* ??? handle const array passed by reference */ @@ -2111,7 +2242,7 @@ static int nesting=0; address(lval.sym,sPRI); } else { setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc++; + heapalloc+=markheap(HEAPUSE_STATIC, 1); nest_stkusage++; } /* if */ } /* if */ @@ -2258,7 +2389,7 @@ static int nesting=0; } else if (arg[argidx].ident==iREFERENCE) { setheap(arg[argidx].defvalue.val); /* address of the value on the heap in PRI */ - heapalloc++; + heapalloc+=markheap(HEAPUSE_STATIC, 1); nest_stkusage++; } else { int dummytag=arg[argidx].tags[0]; @@ -2329,7 +2460,6 @@ static int nesting=0; markusage(sym,uREAD); /* do not mark as "used" when this call itself is skipped */ if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL) sym->x.lib->value += 1; /* increment "usage count" of the library */ - modheap(-heapalloc*sizeof(cell)); if (symret!=NULL) popreg(sPRI); /* pop hidden parameter as function result */ sideeffect=TRUE; /* assume functions carry out a side-effect */ @@ -2339,7 +2469,7 @@ static int nesting=0; /* maintain max. amount of memory used */ { long totalsize; - totalsize=declared+decl_heap+1; /* local variables & return value size, + totalsize=declared+heapalloc+1; /* local variables & return value size, * +1 for PROC opcode */ if (lval_result->ident==iREFARRAY) totalsize++; /* add hidden parameter (on the stack) */ @@ -2361,9 +2491,7 @@ static int nesting=0; * this function has as a result (in other words, scrap all arrays on the * heap that caused by expressions in the function arguments) */ - assert(decl_heap>=locheap); - modheap((locheap-decl_heap)*sizeof(cell)); /* remove heap space, so negative delta */ - decl_heap=locheap; + popheaplist(); nesting--; } diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index e271037d..d0d11830 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -844,6 +844,26 @@ SC_FUNC void modheap(int delta) } /* if */ } +SC_FUNC void modheap_i() +{ + stgwrite("\theap.i\n"); + code_idx+=opcodes(1); +} + +SC_FUNC void setheap_save(cell value) +{ + pushreg(sPRI); + pushreg(sALT); + stgwrite("\tconst.pri "); + outval(value, TRUE); + code_idx+=opcodes(1)+opargs(1); + stgwrite("\theap "); + outval(sizeof(cell), TRUE); + stgwrite("\tstor.pri\n"); + popreg(sALT); + popreg(sPRI); +} + SC_FUNC void setheap_pri(void) { stgwrite("\theap "); /* ALT = HEA++ */ diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 73845bf0..c8ad1082 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -493,6 +493,7 @@ static OPCODEC opcodelist[] = { { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, { 45, "heap", sIN_CSEG, parm1 }, + {160, "heap.i", sIN_CSEG, parm0 }, { 27, "idxaddr", sIN_CSEG, parm0 }, { 28, "idxaddr.b", sIN_CSEG, parm1 }, {109, "inc", sIN_CSEG, parm1 }, From f53fe346ae71bcd1e201c46a91cd31efda37c632 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 14 Sep 2006 07:02:02 +0000 Subject: [PATCH 0040/1664] changed this a bit to be nicer --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4070 --- sourcepawn/compiler/sc3.c | 8 ++++---- sourcepawn/compiler/sc4.c | 19 +++++++++---------- sourcepawn/compiler/sc6.c | 4 +++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index c09b0fa1..8c306b34 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1165,7 +1165,7 @@ void dynarray_from_heaplist(heapuse_list_t *heap) } free(heap); if (total) - setheap_save(total); + setheap_save(-total*sizeof(cell)); } static int hier13(value *lval) @@ -1193,11 +1193,11 @@ static int hier13(value *lval) if (lval->ident==iCONSTEXPR) /* load constant here */ ldconst(lval->constval,sPRI); sc_allowtags=(short)POPSTK_I(); /* restore */ - jumplabel(flab2); - setlabel(flab1); heap=popsaveheaplist(); dynarray_from_heaplist(heap); pushheaplist(); + jumplabel(flab2); + setlabel(flab1); needtoken(':'); if (hier13(&lval2)) rvalue(&lval2); @@ -1215,9 +1215,9 @@ static int hier13(value *lval) /* ??? if both are arrays, should check dimensions */ if (!matchtag(lval->tag,lval2.tag,FALSE)) error(213); /* tagname mismatch ('true' and 'false' expressions) */ - setlabel(flab2); heap=popsaveheaplist(); dynarray_from_heaplist(heap); + setlabel(flab2); if (array1 && array2) { markheap(HEAPUSE_DYNAMIC, 0); } diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index d0d11830..f4d969af 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -846,22 +846,21 @@ SC_FUNC void modheap(int delta) SC_FUNC void modheap_i() { - stgwrite("\theap.i\n"); - code_idx+=opcodes(1); + pushreg(sPRI); + pushreg(sALT); + stgwrite("\tpop.h.pri\n"); + stgwrite("\theap.pri\n"); + code_idx+=opcodes(2); + popreg(sALT); + popreg(sPRI); } SC_FUNC void setheap_save(cell value) { - pushreg(sPRI); - pushreg(sALT); - stgwrite("\tconst.pri "); + assert(value); + stgwrite("\tpush.h.c "); outval(value, TRUE); code_idx+=opcodes(1)+opargs(1); - stgwrite("\theap "); - outval(sizeof(cell), TRUE); - stgwrite("\tstor.pri\n"); - popreg(sALT); - popreg(sPRI); } SC_FUNC void setheap_pri(void) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index c8ad1082..7539a09b 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -493,7 +493,7 @@ static OPCODEC opcodelist[] = { { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, { 45, "heap", sIN_CSEG, parm1 }, - {160, "heap.i", sIN_CSEG, parm0 }, + {160, "heap.pri", sIN_CSEG, parm0 }, { 27, "idxaddr", sIN_CSEG, parm0 }, { 28, "idxaddr.b", sIN_CSEG, parm1 }, {109, "inc", sIN_CSEG, parm1 }, @@ -544,12 +544,14 @@ static OPCODEC opcodelist[] = { { 84, "not", sIN_CSEG, parm0 }, { 82, "or", sIN_CSEG, parm0 }, { 43, "pop.alt", sIN_CSEG, parm0 }, + {162, "pop.h.pri", sIN_CSEG, parm0 }, { 42, "pop.pri", sIN_CSEG, parm0 }, { 46, "proc", sIN_CSEG, parm0 }, { 40, "push", sIN_CSEG, parm1 }, {133, "push.adr", sIN_CSEG, parm1 }, /* version 4 */ { 37, "push.alt", sIN_CSEG, parm0 }, { 39, "push.c", sIN_CSEG, parm1 }, + {161, "push.h.c", sIN_CSEG, parm1 }, { 36, "push.pri", sIN_CSEG, parm0 }, { 38, "push.r", sIN_CSEG, parm1 }, /* obsolete (never generated) */ { 41, "push.s", sIN_CSEG, parm1 }, From 103f958bae5a40a4fc37b93f000a9b336b17f2d0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 14 Sep 2006 17:08:33 +0000 Subject: [PATCH 0041/1664] fixed whitespace --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4071 --- sourcepawn/compiler/sc3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 8c306b34..a8124de6 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1218,9 +1218,9 @@ static int hier13(value *lval) heap=popsaveheaplist(); dynarray_from_heaplist(heap); setlabel(flab2); - if (array1 && array2) { + if (array1 && array2) { markheap(HEAPUSE_DYNAMIC, 0); - } + } if (lval->ident==iARRAY) lval->ident=iREFARRAY; /* iARRAY becomes iREFARRAY */ else if (lval->ident!=iREFARRAY) @@ -2002,7 +2002,7 @@ static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int */ assert(array_sz>=size); modheap((int)array_sz*sizeof(cell)); - markheap(HEAPUSE_STATIC, array_sz); + markheap(HEAPUSE_STATIC, array_sz); /* ??? should perhaps fill with zeros first */ memcopy(size*sizeof(cell)); moveto1(); From 70a960dd843fda89032dc6b3f6102db24d9e93e9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 19 Sep 2006 22:26:13 +0000 Subject: [PATCH 0042/1664] initial import of magical new API... FINALLY! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4072 --- sourcepawn/include/sp_vm_api.h | 133 ++++ sourcepawn/include/sp_vm_context.h | 309 +++++++++ sourcepawn/include/sp_vm_types.h | 46 +- sourcepawn/vm/msvc8/vm.vcproj | 38 +- sourcepawn/vm/sp_vm.c | 648 ------------------ sourcepawn/vm/sp_vm.h | 322 --------- sourcepawn/vm/sp_vm_basecontext.cpp | 611 +++++++++++++++++ sourcepawn/vm/sp_vm_basecontext.h | 53 ++ sourcepawn/vm/sp_vm_debug.c | 94 --- sourcepawn/vm/sp_vm_debug.h | 52 -- .../vm/{sp_reader.c => sp_vm_engine.cpp} | 67 +- sourcepawn/vm/sp_vm_engine.h | 73 ++ 12 files changed, 1289 insertions(+), 1157 deletions(-) create mode 100644 sourcepawn/include/sp_vm_api.h create mode 100644 sourcepawn/include/sp_vm_context.h delete mode 100644 sourcepawn/vm/sp_vm.c delete mode 100644 sourcepawn/vm/sp_vm.h create mode 100644 sourcepawn/vm/sp_vm_basecontext.cpp create mode 100644 sourcepawn/vm/sp_vm_basecontext.h delete mode 100644 sourcepawn/vm/sp_vm_debug.c delete mode 100644 sourcepawn/vm/sp_vm_debug.h rename sourcepawn/vm/{sp_reader.c => sp_vm_engine.cpp} (74%) create mode 100644 sourcepawn/vm/sp_vm_engine.h diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h new file mode 100644 index 00000000..c469093a --- /dev/null +++ b/sourcepawn/include/sp_vm_api.h @@ -0,0 +1,133 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_ +#define _INCLUDE_SOURCEPAWN_VM_API_H_ + +#include +#include "sp_vm_types.h" +#include "sp_vm_context.h" + +namespace SourcePawn +{ + class IPluginContext; + + /** + * Contains helper functions used by VMs and the host app + */ + class ISourcePawnEngine + { + public: + /** + * Loads a named file from a file pointer. + * Using this means base memory will be allocated by the VM. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ + virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; + + /** + * Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ + virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; + + /** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ + virtual int FreeFromMemory(sp_plugin_t *plugin) =0; + + /** + * Creates a new IContext from a context handle. + * + * @param ctx Context to use as a basis for the IPluginContext. + * @return New IPluginContext handle. + */ + virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0; + + /** + * Frees a context. + * + * @param ctx Context pointer to free. + */ + virtual void FreeBaseContext(IPluginContext *ctx) =0; + + /** + * Allocates memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *BaseAlloc(size_t size) =0; + + /** + * Frees memory allocated with BaseAlloc. + * + * @param mem Memory address to free. + */ + virtual void BaseFree(void *memory) =0; + }; + + class ICompilation; + + class IVirtualMachine + { + public: + /** + * Returns the string name of a VM implementation. + */ + virtual const char *GetVMName() =0; + + /** + * Begins a new compilation + * + * @param plugin Pointer to a plugin structure. + * @return New compilation pointer. + */ + virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; + + /** + * Sets a compilation option. + * + * @param co Pointer to a compilation. + * @param key Option key name. + * @param val Option value string. + * @return True if option could be set, false otherwise. + */ + virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; + + /** + * Finalizes a compilation into a new IContext. + * Note: This will free the ICompilation pointer. + * + * @param co Compilation pointer. + * @return New plugin context. + */ + virtual IPluginContext *CompileToContext(ICompilation *co) =0; + + /** + * Frees any internal variable usage on a context. + * + * @param ctx Context structure pointer. + */ + virtual void FreeContextVars(sp_context_t *ctx) =0; + + /** + * Calls the "execute" function on a context. + * + * @param ctx Executes a function in a context. + * @param code_idx Index into the code section. + * @param result Pointer to store result in. + * @return Error code (if any). + */ + virtual int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) =0; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_API_H_ diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h new file mode 100644 index 00000000..e10dfca8 --- /dev/null +++ b/sourcepawn/include/sp_vm_context.h @@ -0,0 +1,309 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ +#define _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ + +#include "sp_vm_types.h" + +/***************** + ** Note that all functions return a non-zero error code on failure + * unless otherwise noted. + * All input pointers must be valid unless otherwise noted as optional. + * All output pointers on failure are undefined. + * All local address are guaranteed to be positive. However, they are stored + * as signed integers, because they must logically fit inside a cell. + */ + +namespace SourcePawn +{ + class IVirtualMachine; + + class IPluginDebugInfo + { + public: + /** + * Given a code pointer, finds the file it is associated with. + * + * @param addr Code address offset. + * @param filename Pointer to store filename pointer in. + */ + virtual int LookupFile(ucell_t addr, const char **filename) =0; + + /** + * Given a code pointer, finds the function it is associated with. + * + * @param addr Code address offset. + * @param name Pointer to store function name pointer in. + */ + virtual int LookupFunction(ucell_t addr, const char **name) =0; + + /** + * Given a code pointer, finds the line it is associated with. + * + * @param addr Code address offset. + * @param line Pointer to store line number in. + */ + virtual int LookupLine(ucell_t addr, uint32_t *line) =0; + }; + + class IPluginContext + { + public: + virtual ~IPluginContext() { }; + public: + /** + * Returns the parent IVirtualMachine. + * + * @return Parent virtual machine pointer. + */ + virtual IVirtualMachine *GetVirtualMachine() =0; + + /** + * Returns the child sp_context_t structure. + * + * @return Child sp_context_t structure. + */ + virtual sp_context_t *GetContext() =0; + + /** + * Returns true if the plugin is in debug mode. + * + * @return True if in debug mode, false otherwise. + */ + virtual bool IsDebugging() =0; + + /** + * Installs a debug break and returns the old one, if any. + * This will fail if the plugin is not debugging. + * + * @param newpfn New function pointer. + * @param oldpfn Pointer to retrieve old function pointer. + */ + virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; + + /** + * Returns debug info. + * + * @return IPluginDebugInfo, or NULL if no debug info found. + */ + virtual IPluginDebugInfo *GetDebugInfo() =0; + + /** + * Allocs memory on the secondary stack of a plugin. + * Note that although called a heap, it is in fact a stack. + * + * @param cells Number of cells to allocate. + * @param local_adddr Will be filled with data offset to heap. + * @param phys_addr Physical address to heap memory. + */ + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * Pops a heap address off the heap stack. Use this to free memory allocated with + * SP_HeapAlloc(). + * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations + * with this native should be performed in precisely the REVERSE order. + * + * @param local_addr Local address to free. + */ + virtual int HeapPop(cell_t local_addr) =0; + + /** + * Releases a heap address using a different method than SP_HeapPop(). + * This allows you to release in any order. However, if you allocate N + * objects, release only some of them, then begin allocating again, + * you cannot go back and starting freeing the originals. + * In other words, for each chain of allocations, if you start deallocating, + * then allocating more in a chain, you must only deallocate from the current + * allocation chain. This is basically HeapPop() except on a larger scale. + * + * @param local_addr Local address to free. + */ + virtual int HeapRelease(cell_t local_addr) =0; + + /** + * Finds a native by name. + * + * @param name Name of native. + * @param index Optionally filled with native index number. + */ + virtual int FindNativeByName(const char *name, uint32_t *index) =0; + + /** + * Gets native info by index. + * + * @param index Index number of native. + * @param native Optionally filled with pointer to native structure. + */ + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; + + /** + * Gets the number of natives. + * + * @return Filled with the number of natives. + */ + virtual uint32_t GetNativesNum() =0; + + /** + * Finds a public function by name. + * + * @param name Name of public + * @param index Optionally filled with public index number. + */ + virtual int FindPublicByName(const char *name, uint32_t *index) =0; + + /** + * Gets public function info by index. + * + * @param index Public function index number. + * @param pblic Optionally filled with pointer to public structure. + */ + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; + + /** + * Gets the number of public functions. + * + * @return Filled with the number of public functions. + */ + virtual uint32_t GetPublicsNum() =0; + + /** + * Gets public variable info by index. + * @param index Public variable index number. + * @param pubvar Optionally filled with pointer to pubvar structure. + */ + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; + + /** + * Finds a public variable by name. + * + * @param name Name of pubvar + * @param index Optionally filled with pubvar index number. + * @param local_addr Optionally filled with local address offset. + * @param phys_addr Optionally filled with relocated physical address. + */ + virtual int FindPubvarByName(const char *name, uint32_t *index) =0; + + /** + * Gets the addresses of a public variable. + * + * @param index Index of public variable. + * @param local_addr Address to store local address in. + * @param phys_addr Address to store physically relocated in. + */ + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * Returns the number of public variables. + * + * @return Number of public variables. + */ + virtual uint32_t GetPubVarsNum() =0; + + /** + * Round-about method of converting a plugin reference to a physical address + * + * @param local_addr Local address in plugin. + * @param phys_addr Optionally filled with relocated physical address. + */ + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; + + /** + * Converts a local address to a physical string. + * Note that SourcePawn does not support packed strings, as such this function is + * 'cell to char' only. + * + * @param local_addr Local address in plugin. + * @param buffer Destination output buffer. + * @param maxlength Maximum length of output buffer, including null terminator. + * @param chars Optionally filled with the number of characters written. + */ + virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) =0; + + /** + * Converts a physical string to a local address. + * Note that SourcePawn does not support packed strings. + * + * @param local_addr Local address in plugin. + * @param chars Number of chars to write, including NULL terminator. + * @param source Source string to copy. + */ + virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + + /** + * Pushes a cell onto the stack. Increases the parameter count by one. + * + * @param value Cell value. + */ + virtual int PushCell(cell_t value) =0; + + /** + * Pushes an array of cells onto the stack. Increases the parameter count by one. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; + + /** + * Pushes a string onto the stack (by reference) and increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ + virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; + + /** + * Individually pushes each cell of an array of cells onto the stack. Increases the + * parameter count by the number of cells pushed. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * + * @param array Array of cells to read from. + * @param numcells Number of cells to read. + */ + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; + + /** + * Binds a list of native names and their function pointers to a context. + * If num is 0, the list is read until an entry with a NULL name is reached. + * All natives are assigned a status of SP_NATIVE_OKAY by default. + * If overwrite is non-zero, already registered natives will be overwritten. + * + * @param natives Array of natives. + * @param num Number of natives in array. + */ + virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; + + /** + * Binds a single native. Overwrites any existing bind. + * If the context does not contain the native that will be binded the function will return + * with a SP_ERR_NOT_FOUND error. + * + * @param native Pointer to native. + * @param status Status value to set (should be SP_NATIVE_OKAY). + */ + virtual int BindNative(sp_nativeinfo_t *native, uint32_t status) =0; + + /** + * Binds a single native to any non-registered or pending native. + * Status is automatically set to pending. + * + * @param native Native to bind. + */ + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; + + /** + * Executes a public function. + */ + virtual int Execute(uint32_t public_func, cell_t *result) =0; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index f3f9c618..bb133369 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -19,6 +19,7 @@ typedef int32_t cell_t; #define SP_ERR_INDEX 7 /* Invalid index parameter */ #define SP_ERR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ #define SP_ERR_STACKERR 9 /* Stack/Heap collision */ +#define SP_ERR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ /********************************************** *** The following structures are reference structures. @@ -125,6 +126,15 @@ typedef struct sp_native_s uint32_t status; /* status flags */ } sp_native_t; +/** + * Used for setting natives from modules/host apps. + */ +typedef struct sp_nativeinfo_s +{ + const char *name; + SPVM_NATIVE_FUNC func; +} sp_nativeinfo_t; + /** * Debug file table */ @@ -159,49 +169,39 @@ typedef struct sp_debug_symbol_s sp_fdbg_symbol_t *sym; /* pointer to original symbol */ } sp_debug_symbol_t; -/** - * Executes a Context. - * @sp_context_s - Execution Context - * @uint32_t - Offset from code pointer - * @res - return value of function - * @return - error code (0=none) - */ -typedef int (*SPVM_EXEC)(struct sp_context_s *, - uint32_t, - cell_t *res); - /** * Breaks into a debugger */ typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *); -#define SP_CONTEXT_DEBUG (1<<0) /* in debug mode */ -#define SP_CONTEXT_INHERIT_MEMORY (1<<1) /* inherits memory pointers */ -#define SP_CONTEXT_INHERIT_CODE (1<<2) /* inherits code pointers */ +#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ /** * This is the heart of the VM. It contains all of the runtime * information about a plugin context. - * It is split into three sections. + * Note that user[0..3] can be used for any user based pointers. + * vm[0..3] should not be touched, as it is reserved for the VM. */ typedef struct sp_context_s { /* general/parent information */ void *base; /* base of generated code and memory */ sp_plugin_t *plugin; /* pointer back to parent information */ - struct sp_context_s *parent; /* pointer to parent context */ - uint32_t flags; /* context flags */ + void *context; /* pointer to IPluginContext */ + void *vmbase; /* pointer to IVirtualMachine */ + void *user[4]; /* user specific pointers */ + void *vm[4]; /* VM specific pointers */ + uint32_t flags; /* compilation flags */ SPVM_DEBUGBREAK dbreak; /* debug break function */ - void *user; /* user specific pointer */ - /* execution specific data */ - SPVM_EXEC exec; /* execution base */ - cell_t pri; /* PRI register */ - cell_t alt; /* ALT register */ + /* context runtime information */ + ucell_t memory; /* total memory size; */ uint8_t *data; /* data chunk */ cell_t heapbase; /* heap base */ + /* execution specific data */ + cell_t pri; /* PRI register */ + cell_t alt; /* ALT register */ cell_t hp; /* heap pointer */ cell_t sp; /* stack pointer */ - ucell_t memory; /* total memory size; */ int32_t err; /* error code */ uint32_t pushcount; /* push count */ /* context rebased database */ diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 2516a305..9fd1a5ce 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -176,7 +176,11 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -186,19 +190,11 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - - - @@ -308,6 +304,26 @@ + + + + + + + + + + diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c deleted file mode 100644 index 303b92c3..00000000 --- a/sourcepawn/vm/sp_vm.c +++ /dev/null @@ -1,648 +0,0 @@ -#include -#include -#include -#include -#include "sp_vm.h" - -#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) -#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) - -/*int main() -{ - /** temporary testing area */ - /*sp_context_t ctx; - cell_t l, *p; - cell_t arr1[] = {1,3,3,7}; - cell_t arr2[] = {123,1234,12345,123456}; - const char *str = "hat hat"; - char buf[20]; - - ctx.data = (uint8_t *)malloc(50000); - ctx.memory = 50000; - ctx.heapbase = 200; - ctx.hp = ctx.heapbase; - ctx.sp = 45000; - - assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); - assert(SP_HeapPop(&ctx, l) == SP_ERR_NONE); - assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); - assert(SP_HeapRelease(&ctx, 4) == SP_ERR_INVALID_ADDRESS); - assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE); - assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); - assert(SP_PushCell(&ctx, 1337) == SP_ERR_NONE); - assert(SP_PushCellArray(&ctx, &l, &p, arr1, 4) == SP_ERR_NONE); - assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); - assert(SP_PushCellsFromArray(&ctx, arr2, 4) == SP_ERR_NONE); - assert(SP_PushString(&ctx, &l, &p, str) == SP_ERR_NONE); - assert(SP_LocalToString(&ctx, l, NULL, buf, 20) == SP_ERR_NONE); - assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE); - - return 0; -}*/ - -int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr) -{ - cell_t *addr; - ucell_t realmem; - -#if 0 - if (cells > CELLBOUNDMAX) - { - return SP_ERR_PARAM; - } -#else - assert(cells < CELLBOUNDMAX); -#endif - - realmem = cells * sizeof(cell_t); - - /** - * Check if the space between the heap and stack is sufficient. - */ - if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) - { - return SP_ERR_HEAPLOW; - } - - addr = (cell_t *)(ctx->data + ctx->hp); - /* store size of allocation in cells */ - *addr = (cell_t)cells; - addr++; - ctx->hp += sizeof(cell_t); - - *local_addr = ctx->hp; - - if (phys_addr) - { - *phys_addr = addr; - } - - ctx->hp += realmem; - - return SP_ERR_NONE; -} - -int SP_HeapPop(sp_context_t *ctx, cell_t local_addr) -{ - cell_t cellcount; - cell_t *addr; - - /* check the bounds of this address */ - local_addr -= sizeof(cell_t); - if (local_addr < ctx->heapbase || local_addr >= ctx->sp) - { - return SP_ERR_INVALID_ADDRESS; - } - - addr = (cell_t *)(ctx->data + local_addr); - cellcount = (*addr) * sizeof(cell_t); - /* check if this memory count looks valid */ - if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) - { - return SP_ERR_INVALID_ADDRESS; - } - - ctx->hp = local_addr; - - return SP_ERR_NONE; -} - -int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr) -{ - if (local_addr < ctx->heapbase) - { - return SP_ERR_INVALID_ADDRESS; - } - - ctx->hp = local_addr - sizeof(cell_t); - - return SP_ERR_NONE; -} - -int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.natives_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->natives[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERR_NOT_FOUND; -} - -int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native) -{ - if (index >= ctx->plugin->info.natives_num) - { - return SP_ERR_INDEX; - } - - if (native) - { - *native = &(ctx->natives[index]); - } - - return SP_ERR_NONE; -} - -int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num) -{ - *num = ctx->plugin->info.natives_num; - - return SP_ERR_NONE; -} - -int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.publics_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->publics[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERR_NOT_FOUND; -} - -int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic) -{ - if (index >= ctx->plugin->info.publics_num) - { - return SP_ERR_INDEX; - } - - if (pblic) - { - *pblic = &(ctx->publics[index]); - } - - return SP_ERR_NONE; -} - -int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num) -{ - *num = ctx->plugin->info.publics_num; - - return SP_ERR_NONE; -} - -int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERR_INDEX; - } - - if (pubvar) - { - *pubvar = &(ctx->pubvars[index]); - } - - return SP_ERR_NONE; -} - -int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.pubvars_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->pubvars[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERR_NOT_FOUND; -} - -int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERR_INDEX; - } - - *local_addr = ctx->plugin->info.pubvars[index].address; - *phys_addr = ctx->pubvars[index].offs; - - return SP_ERR_NONE; -} - -int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num) -{ - *num = ctx->plugin->info.pubvars_num; - - return SP_ERR_NONE; -} - -int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite) -{ - uint32_t i, j, max; - - max = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) - { - continue; - } - - for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) - { - ctx->natives[i].pfn = natives[j].func; - ctx->natives[i].status = SP_NATIVE_OKAY; - } - } - } - - return SP_ERR_NONE; -} - -int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status) -{ - uint32_t index; - int err; - - if ((err = SP_FindNativeByName(ctx, native->name, &index)) != SP_ERR_NONE) - { - return err; - } - - ctx->natives[index].pfn = native->func; - ctx->natives[index].status = status; - - return SP_ERR_NONE; -} - -int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native) -{ - uint32_t nativesnum, i; - - nativesnum = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status != SP_NATIVE_OKAY) - { - ctx->natives[i].pfn = native; - ctx->natives[i].status = SP_NATIVE_PENDING; - } - } - - return SP_ERR_NONE; -} - -int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) - { - return SP_ERR_INVALID_ADDRESS; - } - - if (phys_addr) - { - *phys_addr = (cell_t *)(ctx->data + local_addr); - } - - return SP_ERR_NONE; -} - -int SP_PushCell(sp_context_t *ctx, cell_t value) -{ - if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) - { - return SP_ERR_STACKERR; - } - - ctx->sp -= sizeof(cell_t); - *(cell_t *)(ctx->data + ctx->sp) = value; - ctx->pushcount++; - - return SP_ERR_NONE; -} - -int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells) -{ - unsigned int i; - int err; - - for (i=0; isp += (cell_t)(i * sizeof(cell_t)); - ctx->pushcount -= i; - return err; - } - } - - return SP_ERR_NONE; -} - -int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) -{ - cell_t *ph_addr; - int err; - - if ((err = SP_HeapAlloc(ctx, numcells, local_addr, &ph_addr)) != SP_ERR_NONE) - { - return err; - } - - memcpy(ph_addr, array, numcells * sizeof(cell_t)); - - if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE) - { - SP_HeapRelease(ctx, *local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERR_NONE; -} - -int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buffer, size_t maxlength) -{ - int len = 0; - cell_t *src; - - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) - { - return SP_ERR_INVALID_ADDRESS; - } - - src = (cell_t *)(ctx->data + local_addr); - while ((*src != '\0') && ((size_t)len < maxlength)) - { - buffer[len++] = (char)*src++; - } - - if ((size_t)len >= maxlength) - { - len = maxlength - 1; - } - if (len >= 0) - { - buffer[len] = '\0'; - } - - if (chars) - { - *chars = len; - } - - return SP_ERR_NONE; -} - -int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, const char *string) -{ - cell_t *ph_addr; - int err; - unsigned int i, numcells = strlen(string); - - if ((err = SP_HeapAlloc(ctx, numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE) - { - return err; - } - - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) - { - return SP_ERR_INVALID_ADDRESS; - } - - len = strlen(source); - dest = (cell_t *)(ctx->data + local_addr); - - if ((size_t)len >= chars) - { - len = chars - 1; - } - - for (i=0; ibase = plugin->base; - context->plugin = plugin; - context->flags = plugin->flags; - - context->data = (uint8_t *)malloc(plugin->memory); - memcpy(context->data, plugin->data, plugin->data_size); - context->memory = plugin->memory; - context->heapbase = (cell_t)(plugin->data_size); - - strbase = plugin->info.stringbase; - - if (max = plugin->info.publics_num) - { - context->publics = (sp_public_t *)malloc(sizeof(sp_public_t) * max); - for (iter=0; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; - context->publics[iter].offs = plugin->info.publics[iter].address; - } - } - - if (max = plugin->info.pubvars_num) - { - dat = plugin->data; - context->pubvars = (sp_pubvar_t *)malloc(sizeof(sp_pubvar_t) * max); - for (iter=0; iterpubvars[iter].name = strbase + plugin->info.pubvars[iter].name; - context->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); - } - } - - if (max = plugin->info.natives_num) - { - context->natives = (sp_native_t *)malloc(sizeof(sp_native_t) * max); - for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; - context->natives[iter].pfn = SP_NoExecNative; - context->natives[iter].status = SP_NATIVE_NONE; - } - } - - strbase = plugin->debug.stringbase; - - if (plugin->flags & SP_FLAG_DEBUG) - { - max = plugin->debug.files_num; - context->files = (sp_debug_file_t *)malloc(sizeof(sp_debug_file_t) * max); - for (iter=0; iterfiles[iter].addr = plugin->debug.files[iter].addr; - context->files[iter].name = strbase + plugin->debug.files[iter].name; - } - - max = plugin->debug.lines_num; - context->lines = (sp_debug_line_t *)malloc(sizeof(sp_debug_line_t) * max); - for (iter=0; iterlines[iter].addr = plugin->debug.lines[iter].addr; - context->lines[iter].line = plugin->debug.lines[iter].line; - } - - cursor = (uint8_t *)(plugin->debug.symbols); - max = plugin->debug.syms_num; - context->symbols = (sp_debug_symbol_t *)malloc(sizeof(sp_debug_symbol_t) * max); - for (iter=0; itersymbols[iter].codestart = sym->codestart; - context->symbols[iter].codeend = sym->codeend; - context->symbols[iter].name = strbase + sym->name; - context->symbols[iter].sym = sym; - - if (sym->dimcount > 0) - { - cursor += sizeof(sp_fdbg_symbol_t); - arr = (sp_fdbg_arraydim_t *)cursor; - context->symbols[iter].dims = arr; - cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; - continue; - } - - context->symbols[iter].dims = NULL; - cursor += sizeof(sp_fdbg_symbol_t); - } - } - - *ctx = context; - return SP_ERR_NONE; -} - -int SP_FreeBaseContext(sp_context_t *ctx) -{ - if (ctx->flags & SP_FLAG_DEBUG) - { - free(ctx->symbols); - free(ctx->lines); - free(ctx->files); - } - if (ctx->plugin->info.natives) - { - free(ctx->natives); - } - if (ctx->plugin->info.pubvars_num) - { - free(ctx->pubvars); - } - if (ctx->plugin->info.publics_num) - { - free(ctx->publics); - } - free(ctx->data); - free(ctx); - - return SP_ERR_NONE; -} - -cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params) -{ - ctx->err = SP_ERR_NATIVE_PENDING; - - return 0; -} \ No newline at end of file diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h deleted file mode 100644 index 8ed41cb2..00000000 --- a/sourcepawn/vm/sp_vm.h +++ /dev/null @@ -1,322 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_H_ -#define _INCLUDE_SOURCEPAWN_VM_H_ - -#include -#include "sp_vm_types.h" - -/***************** - ** Note that all functions return a non-zero error code on failure - * unless otherwise noted. - * All input pointers must be valid unless otherwise noted as optional. - * All output pointers on failure are undefined. - * All local address are guaranteed to be positive. However, they are stored - * as signed integers, because they must logically fit inside a cell. - */ - -typedef struct sp_nativeinfo_s -{ - const char *name; - SPVM_NATIVE_FUNC func; -} sp_nativeinfo_t; - -/** - * Loads a named file from a file pointer. - * Using this means base memory will be allocated by the VM. - * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. - */ -sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err); - -/** - * Loads a file from a base memory address. - * - * @param base Base address of the plugin's memory region. - * @param plugin If NULL, a new plugin pointer is returned. - * Otherwise, the passed pointer is used. - * @param err Optional error code pointer. - * @return The resulting plugin pointer. - */ -sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); - -/** - * Frees all of the memory associated with a plugin file. - * If allocated using SP_LoadFromMemory, the base and plugin pointer - * itself are not freed (so this may end up doing nothing). - */ -int SP_FreeFromMemory(sp_plugin_t *plugin); - -/** - * Allocs memory on the secondary stack of a plugin. - * Note that although called a heap, it is in fact a stack. - * - * @param ctx Context pointer. - * @param cells Number of cells to allocate. - * @param local_adddr Will be filled with data offset to heap. - * @param phys_addr Physical address to heap memory. - */ -int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr); - -/** - * Pops a heap address off the heap stack. Use this to free memory allocated with - * SP_HeapAlloc(). - * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations - * with this native should be performed in precisely the REVERSE order. - */ -int SP_HeapPop(sp_context_t *ctx, cell_t local_addr); - -/** - * Releases a heap address using a different method than SP_HeapPop(). - * This allows you to release in any order. However, if you allocate N - * objects, release only some of them, then begin allocating again, - * you cannot go back and starting freeing the originals. - * In other words, for each chain of allocations, if you start deallocating, - * then allocating more in a chain, you must only deallocate from the current - * allocation chain. This is basically SP_HeapPop() except on a larger scale. - */ -int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr); - -/** - * Finds a native by name. - * - * @param ctx Context pointer. - * @param name Name of native. - * @param index Optionally filled with native index number. - */ -int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index); - -/** - * Gets native info by index. - * - * @param ctx Context pointer. - * @param index Index number of native. - * @param native Optionally filled with pointer to native structure. - */ -int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native); - -/** - * Gets the number of natives. - * - * @param ctx Context pointer. - * @param num Filled with the number of natives. - */ -int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num); - -/** - * Finds a public function by name. - * - * @param ctx Context pointer. - * @param name Name of public - * @param index Optionally filled with public index number. - */ -int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index); - - -/** - * Gets public function info by index. - * - * @param ctx Context pointer. - * @param index Public function index number. - * @param pblic Optionally filled with pointer to public structure. - */ -int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic); - -/** - * Gets the number of public functions. - * - * @param ctx Context pointer. - * @param num Filled with the number of public functions. - */ -int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num); - -/** - * Gets public variable info by index. - * @param ctx Context pointer. - * @param index Public variable index number. - * @param pubvar Optionally filled with pointer to pubvar structure. - */ -int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar); - -/** - * Finds a public variable by name. - * - * @param ctx Context pointer. - * @param name Name of pubvar - * @param index Optionally filled with pubvar index number. - * @param local_addr Optionally filled with local address offset. - * @param phys_addr Optionally filled with relocated physical address. - */ -int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index); - -//:TODO: fill in the info of this function, hi -int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr); - -/** -* Gets the number of public variables. -* -* @param ctx Context pointer. -* @param num Filled with the number of public variables. -*/ -int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num); - -/** - * Round-about method of converting a plugin reference to a physical address - * - * @param ctx Context pointer. - * @param local_addr Local address in plugin. - * @param phys_addr Optionally filled with relocated physical address. - */ -int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr); - -/** - * Converts a local address to a physical string. - * Note that SourcePawn does not support packed strings, as such this function is - * 'cell to char' only. - * - * @param ctx Context pointer. - * @param local_addr Local address in plugin. - * @param chars Optionally filled with the number of characters written. - * @param buffer Destination output buffer. - * @param maxlength Maximum length of output buffer, including null terminator. - */ -int SP_LocalToString(sp_context_t *ctx, - cell_t local_addr, - int *chars, - char *buffer, - size_t maxlength); - -/** - * Converts a physical string to a local address. - * Note that SourcePawn does not support packed strings. - * @param ctx Context pointer - * @param local_addr Local address in plugin. - * @param chars Number of chars to write, including NULL terminator. - * @param source Source string to copy. - */ -int SP_StringToLocal(sp_context_t *ctx, - cell_t local_addr, - size_t chars, - const char *source); - -/** - * Pushes a cell onto the stack. Increases the parameter count by one. - * - * @param ctx Context pointer. - * @param value Cell value. - */ -int SP_PushCell(sp_context_t *ctx, cell_t value); - -/** - * Pushes an array of cells onto the stack. Increases the parameter count by one. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * Note that this does not release the heap, so you should release it after - * calling SP_Execute(). - * - * @param ctx Context pointer. - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. - */ -int SP_PushCellArray(sp_context_t *ctx, - cell_t *local_addr, - cell_t **phys_addr, - cell_t array[], - unsigned int numcells); - -/** - * Pushes a string onto the stack (by reference) and increases the parameter count by one. - * Note that this does not release the heap, so you should release it after - * calling SP_Execute(). - * - * @param ctx Context pointer. - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. - */ -int SP_PushString(sp_context_t *ctx, - cell_t *local_addr, - cell_t **phys_addr, - const char *string); - -/** - * Individually pushes each cell of an array of cells onto the stack. Increases the - * parameter count by the number of cells pushed. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * - * @param ctx Context pointer. - * @param array Array of cells to read from. - * @param numcells Number of cells to read. - */ -int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells); - -/** - * Binds a list of native names and their function pointers to a context. - * If num is 0, the list is read until an entry with a NULL name is reached. - * All natives are assigned a status of SP_NATIVE_OKAY by default. - * If overwrite is non-zero, already registered natives will be overwritten. - * - * @param ctx Context pointer. - * @param natives Array of natives. - * @param num Number of natives in array. - */ -int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite); - -/** - * Binds a single native. Overwrites any existing bind. - * If the context does not contain the native that will be binded the function will return - * with a SP_ERR_NOT_FOUND error. - * - * @param ctx Context pointer. - * @param native Pointer to native. - * @param status Status value to set (should be SP_NATIVE_OKAY). - */ -int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status); - -/** - * Binds a single native to any non-registered or pending native. - * Status is automatically set to pending. - * - * @param ctx Context pointer. - */ -int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native); - -/** - * Executes a public function in a context. - * The parameter count is set to zero during execution. - * All context-specific variables that are modified are saved before execution, - * thus allowing nested calls to SP_Execute(). - * - * @param ctx Context pointer. - * @param idx Public function index number. - * @param result Optional pointer to store return value. - */ -int SP_Execute(sp_context_t *ctx, uint32_t idx, cell_t *result); - -/** - * Creates a base context. The context is not bound to any JIT, and thus - * inherits the parent code pointer of the file structure. It does, - * however, have relocated info+debug tables (even though the code address - * do not need to be relocated). - * It is guaranteed to have a newly allocated and copied memory layout - * of the data, heap and stack, and thus relevant address in the info/debug - * tables must be relocated. - * - * @param plugin Plugin file structure to build a context form. - * @param ctx Pointer to store newly created context pointer. - */ -int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx); - -/** - * Frees a base context. - * - * @param ctx Context pointer. - */ -int SP_FreeBaseContext(sp_context_t *ctx); - -//:TODO: fill in this -cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params); - -#endif //_INCLUDE_SOURCEPAWN_VM_H_ diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp new file mode 100644 index 00000000..bc38cc82 --- /dev/null +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -0,0 +1,611 @@ +#include +#include +#include +#include "sp_vm_api.h" +#include "sp_vm_basecontext.h" + +using namespace SourcePawn; + +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) + +BaseContext::BaseContext(sp_context_t *_ctx) +{ + ctx = _ctx; +} + +IVirtualMachine *BaseContext::GetVirtualMachine() +{ + return (IVirtualMachine *)ctx->vmbase; +} + +sp_context_t *BaseContext::GetContext() +{ + return ctx; +} + +bool BaseContext::IsDebugging() +{ + return (ctx->flags & SPFLAG_PLUGIN_DEBUG); +} + +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) +{ + if (!IsDebugging()) + { + return SP_ERR_NOTDEBUGGING; + } + + *oldpfn = ctx->dbreak; + ctx->dbreak = newpfn; + + return SP_ERR_NONE; +} + +IPluginDebugInfo *BaseContext::GetDebugInfo() +{ + return this; +} + +int BaseContext::Execute(uint32_t public_func, cell_t *result) +{ + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; + + int err; + sp_public_t *pubfunc; + if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERR_NONE) + { + return err; + } + + return vm->ContextExecute(ctx, pubfunc->offs, result); +} + +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) +{ + cell_t *addr; + ucell_t realmem; + +#if 0 + if (cells > CELLBOUNDMAX) + { + return SP_ERR_PARAM; + } +#else + assert(cells < CELLBOUNDMAX); +#endif + + realmem = cells * sizeof(cell_t); + + /** + * Check if the space between the heap and stack is sufficient. + */ + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) + { + return SP_ERR_HEAPLOW; + } + + addr = (cell_t *)(ctx->data + ctx->hp); + /* store size of allocation in cells */ + *addr = (cell_t)cells; + addr++; + ctx->hp += sizeof(cell_t); + + *local_addr = ctx->hp; + + if (phys_addr) + { + *phys_addr = addr; + } + + ctx->hp += realmem; + + return SP_ERR_NONE; +} + +int BaseContext::HeapPop(cell_t local_addr) +{ + cell_t cellcount; + cell_t *addr; + + /* check the bounds of this address */ + local_addr -= sizeof(cell_t); + if (local_addr < ctx->heapbase || local_addr >= ctx->sp) + { + return SP_ERR_INVALID_ADDRESS; + } + + addr = (cell_t *)(ctx->data + local_addr); + cellcount = (*addr) * sizeof(cell_t); + /* check if this memory count looks valid */ + if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) + { + return SP_ERR_INVALID_ADDRESS; + } + + ctx->hp = local_addr; + + return SP_ERR_NONE; +} + + +int BaseContext::HeapRelease(cell_t local_addr) +{ + if (local_addr < ctx->heapbase) + { + return SP_ERR_INVALID_ADDRESS; + } + + ctx->hp = local_addr - sizeof(cell_t); + + return SP_ERR_NONE; +} + +int BaseContext::FindNativeByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.natives_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->natives[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) +{ + if (index >= ctx->plugin->info.natives_num) + { + return SP_ERR_INDEX; + } + + if (native) + { + *native = &(ctx->natives[index]); + } + + return SP_ERR_NONE; +} + + +uint32_t BaseContext::GetNativesNum() +{ + return ctx->plugin->info.natives_num; +} + +int BaseContext::FindPublicByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.publics_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->publics[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) +{ + if (index >= ctx->plugin->info.publics_num) + { + return SP_ERR_INDEX; + } + + if (pblic) + { + *pblic = &(ctx->publics[index]); + } + + return SP_ERR_NONE; +} + +uint32_t BaseContext::GetPublicsNum() +{ + return ctx->plugin->info.publics_num; +} + +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERR_INDEX; + } + + if (pubvar) + { + *pubvar = &(ctx->pubvars[index]); + } + + return SP_ERR_NONE; +} + +int BaseContext::FindPubvarByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.pubvars_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->pubvars[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERR_NOT_FOUND; +} + +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERR_INDEX; + } + + *local_addr = ctx->plugin->info.pubvars[index].address; + *phys_addr = ctx->pubvars[index].offs; + + return SP_ERR_NONE; +} + +uint32_t BaseContext::GetPubVarsNum() +{ + return ctx->plugin->info.pubvars_num; +} + +int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) +{ + uint32_t i, j, max; + + max = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) + { + continue; + } + + for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) + { + ctx->natives[i].pfn = natives[j].func; + ctx->natives[i].status = SP_NATIVE_OKAY; + } + } + } + + return SP_ERR_NONE; +} + + + +int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) +{ + uint32_t index; + int err; + + if ((err = FindNativeByName(native->name, &index)) != SP_ERR_NONE) + { + return err; + } + + ctx->natives[index].pfn = native->func; + ctx->natives[index].status = status; + + return SP_ERR_NONE; +} + +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) +{ + uint32_t nativesnum, i; + + nativesnum = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status != SP_NATIVE_OKAY) + { + ctx->natives[i].pfn = native; + ctx->natives[i].status = SP_NATIVE_PENDING; + } + } + + return SP_ERR_NONE; +} + +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) +{ + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { + return SP_ERR_INVALID_ADDRESS; + } + + if (phys_addr) + { + *phys_addr = (cell_t *)(ctx->data + local_addr); + } + + return SP_ERR_NONE; +} + +int BaseContext::PushCell(cell_t value) +{ + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) + { + return SP_ERR_STACKERR; + } + + ctx->sp -= sizeof(cell_t); + *(cell_t *)(ctx->data + ctx->sp) = value; + ctx->pushcount++; + + return SP_ERR_NONE; +} + +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) +{ + unsigned int i; + int err; + + for (i=0; isp += (cell_t)(i * sizeof(cell_t)); + ctx->pushcount -= i; + return err; + } + } + + return SP_ERR_NONE; +} + +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) +{ + cell_t *ph_addr; + int err; + + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERR_NONE) + { + return err; + } + + memcpy(ph_addr, array, numcells * sizeof(cell_t)); + + if ((err = PushCell(*local_addr)) != SP_ERR_NONE) + { + HeapRelease(*local_addr); + return err; + } + + if (phys_addr) + { + *phys_addr = ph_addr; + } + + return SP_ERR_NONE; +} + +int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) +{ + int len = 0; + cell_t *src; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { + return SP_ERR_INVALID_ADDRESS; + } + + src = (cell_t *)(ctx->data + local_addr); + while ((*src != '\0') && ((size_t)len < maxlength)) + { + buffer[len++] = (char)*src++; + } + + if ((size_t)len >= maxlength) + { + len = maxlength - 1; + } + if (len >= 0) + { + buffer[len] = '\0'; + } + + if (chars) + { + *chars = len; + } + + return SP_ERR_NONE; +} + +int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) +{ + cell_t *ph_addr; + int err; + unsigned int i, numcells = strlen(string); + + if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE) + { + return err; + } + + for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + { + return SP_ERR_INVALID_ADDRESS; + } + + len = strlen(source); + dest = (cell_t *)(ctx->data + local_addr); + + if ((size_t)len >= chars) + { + len = chars - 1; + } + + for (i=0; i>1) + +int BaseContext::LookupFile(ucell_t addr, const char **filename) +{ + int high, low, mid; + + high = ctx->plugin->debug.files_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->files[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERR_NOT_FOUND; + } + + *filename = ctx->files[low].name; + + return SP_ERR_NONE; +} + +int BaseContext::LookupFunction(ucell_t addr, const char **name) +{ + uint32_t iter, max = ctx->plugin->debug.syms_num; + + for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) + && (ctx->symbols[iter].codestart <= addr) + && (ctx->symbols[iter].codeend > addr)) + { + break; + } + } + + if (iter >= max) + { + return SP_ERR_NOT_FOUND; + } + + *name = ctx->symbols[iter].name; + + return SP_ERR_NONE; +} + +int BaseContext::LookupLine(ucell_t addr, uint32_t *line) +{ + int high, low, mid; + + high = ctx->plugin->debug.lines_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->lines[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERR_NOT_FOUND; + } + + *line = ctx->lines[low].line; + + return SP_ERR_NONE; +} diff --git a/sourcepawn/vm/sp_vm_basecontext.h b/sourcepawn/vm/sp_vm_basecontext.h new file mode 100644 index 00000000..e49972e4 --- /dev/null +++ b/sourcepawn/vm/sp_vm_basecontext.h @@ -0,0 +1,53 @@ +#ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ +#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ + +#include "sp_vm_context.h" + +namespace SourcePawn +{ + class BaseContext : + public IPluginContext, + public IPluginDebugInfo + { + public: + BaseContext(sp_context_t *ctx); + public: //IPluginContext + IVirtualMachine *GetVirtualMachine(); + sp_context_t *GetContext(); + bool IsDebugging(); + int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn); + IPluginDebugInfo *GetDebugInfo(); + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); + virtual int HeapPop(cell_t local_addr); + virtual int HeapRelease(cell_t local_addr); + virtual int FindNativeByName(const char *name, uint32_t *index); + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native); + virtual uint32_t GetNativesNum(); + virtual int FindPublicByName(const char *name, uint32_t *index); + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); + virtual uint32_t GetPublicsNum(); + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); + virtual int FindPubvarByName(const char *name, uint32_t *index); + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); + virtual uint32_t GetPubVarsNum(); + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); + virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars); + virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); + virtual int PushCell(cell_t value); + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); + virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); + virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); + virtual int BindNative(sp_nativeinfo_t *native, uint32_t status); + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); + virtual int Execute(uint32_t public_func, cell_t *result); + public: //IPluginDebugInfo + virtual int LookupFile(ucell_t addr, const char **filename); + virtual int LookupFunction(ucell_t addr, const char **name); + virtual int LookupLine(ucell_t addr, uint32_t *line); + private: + sp_context_t *ctx; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_ diff --git a/sourcepawn/vm/sp_vm_debug.c b/sourcepawn/vm/sp_vm_debug.c deleted file mode 100644 index 862af16d..00000000 --- a/sourcepawn/vm/sp_vm_debug.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "sp_vm.h" -#include "sp_vm_debug.h" - -#define USHR(x) ((unsigned int)(x)>>1) - -int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename) -{ - int high, low, mid; - - high = ctx->plugin->debug.files_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->files[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERR_NOT_FOUND; - } - - *filename = ctx->files[low].name; - - return SP_ERR_NONE; -} - -int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name) -{ - uint32_t iter, max = ctx->plugin->debug.syms_num; - - for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) - && (ctx->symbols[iter].codestart <= addr) - && (ctx->symbols[iter].codeend > addr)) - { - break; - } - } - - if (iter >= max) - { - return SP_ERR_NOT_FOUND; - } - - *name = ctx->symbols[iter].name; - - return SP_ERR_NONE; -} - -int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line) -{ - int high, low, mid; - - high = ctx->plugin->debug.lines_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->lines[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERR_NOT_FOUND; - } - - *line = ctx->lines[low].line; - - return SP_ERR_NONE; -} - -int SP_DbgInstallBreak(sp_context_t *ctx, SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) -{ - if (ctx->dbreak) - *oldpfn = ctx->dbreak; - - ctx->dbreak = newpfn; - - return SP_ERR_NONE; -} diff --git a/sourcepawn/vm/sp_vm_debug.h b/sourcepawn/vm/sp_vm_debug.h deleted file mode 100644 index 901f955c..00000000 --- a/sourcepawn/vm/sp_vm_debug.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_DEBUG_H -#define _INCLUDE_SOURCEPAWN_VM_DEBUG_H - -/***************** - ** Note that all functions return a non-zero error code on failure - * unless otherwise noted. - * All input pointers must be valid unless otherwise noted as optional. - * All output pointers on failure are undefined. - * All local address are guaranteed to be positive. However, they are stored - * as signed integers, because they must logically fit inside a cell. - */ - -/** - * Given a code pointer, finds the file it is associated with. - * - * @param ctx Context pointer. - * @param addr Code address offset. - * @param filename Pointer to store filename pointer in. - */ -int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename); - -/** - * Given a code pointer, finds the function it is associated with. - * - * @param ctx Context pointer. - * @param addr Code address offset. - * @param name Pointer to store function name pointer in. - */ -int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name); - -/** - * Given a code pointer, finds the line it is associated with. - * - * @param ctx Context pointer. - * @param addr Code address offset. - * @param line Pointer to store line number in. - */ -int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line); - -/** - * Installs a debug break and returns the old one, if any. - * - * @param ctx Context pointer. - * @param newpfn New function pointer. - * @param oldpfn Pointer to retrieve old function pointer. - */ -int SP_DbgInstallBreak(sp_context_t *ctx, - SPVM_DEBUGBREAK newpfn, - SPVM_DEBUGBREAK *oldpfn); - - -#endif //_INCLUDE_SOURCEPAWN_VM_DEBUG_H diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_vm_engine.cpp similarity index 74% rename from sourcepawn/vm/sp_reader.c rename to sourcepawn/vm/sp_vm_engine.cpp index 7f6b17c6..5bae6220 100644 --- a/sourcepawn/vm/sp_reader.c +++ b/sourcepawn/vm/sp_vm_engine.cpp @@ -1,7 +1,37 @@ #include #include -#include "sp_vm.h" +#include "sp_file_headers.h" +#include "sp_vm_types.h" +#include "sp_vm_engine.h" #include "zlib/zlib.h" +#include "sp_vm_basecontext.h" + +using namespace SourcePawn; + +void *SourcePawnEngine::BaseAlloc(size_t size) +{ + return malloc(size); +} + +void SourcePawnEngine::BaseFree(void *memory) +{ + free(memory); +} + +IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx) +{ + return new BaseContext(ctx); +} + +void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx) +{ + sp_context_t *_ctx = ctx->GetContext(); + IVirtualMachine *vm = ctx->GetVirtualMachine(); + + vm->FreeContextVars(_ctx); + + delete ctx; +} sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err) { @@ -15,7 +45,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, while (sectnum < hdr->sections) { - nameptr = base + hdr->stringtab + secptr->nameoffs; + nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs); if (!(plugin->pcode) && !strcmp(nameptr, ".code")) { @@ -48,7 +78,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, } else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) { - plugin->info.stringbase = base + secptr->dataoffs; + plugin->info.stringbase = (const char *)(base + secptr->dataoffs); } else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files")) { @@ -71,7 +101,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, } else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) { - plugin->debug.stringbase = base + secptr->dataoffs; + plugin->debug.stringbase = (const char *)(base + secptr->dataoffs); } secptr++; @@ -104,7 +134,7 @@ return_error: return NULL; } -sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err) +sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) { sp_file_hdr_t hdr; sp_plugin_t *plugin; @@ -184,6 +214,8 @@ sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err) return NULL; } + plugin->allocflags = 0; + return plugin; return_error: @@ -194,7 +226,7 @@ return_error: return NULL; } -sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) +sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) { sp_file_hdr_t hdr; uint8_t noptr = 0; @@ -207,7 +239,7 @@ sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) noptr = 1; } - if (!_ReadPlugin(&hdr, base, plugin, err)) + if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err)) { if (noptr) { @@ -216,5 +248,26 @@ sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) return NULL; } + if (!noptr) + { + plugin->allocflags |= SP_FA_SELF_EXTERNAL; + } + plugin->allocflags |= SP_FA_BASE_EXTERNAL; + return plugin; } + +int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) +{ + if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL)) + { + free(plugin->base); + plugin->base = NULL; + } + if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL)) + { + free(plugin); + } + + return SP_ERR_NONE; +} diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h new file mode 100644 index 00000000..13b18557 --- /dev/null +++ b/sourcepawn/vm/sp_vm_engine.h @@ -0,0 +1,73 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ +#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ + +#include "sp_vm_api.h" + +namespace SourcePawn +{ + class SourcePawnEngine : public ISourcePawnEngine + { + public: + /** + * Loads a named file from a file pointer. + * Using this means base memory will be allocated by the VM. + * Note: The file handle position may be undefined on entry, and is + * always undefined on conclusion. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ + sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); + + /** + * Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ + sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); + + /** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ + int FreeFromMemory(sp_plugin_t *plugin); + + /** + * Creates a new IContext from a context handle. + * + * @param ctx Context to use as a basis for the IPluginContext. + * @return New IPluginContext handle. + */ + IPluginContext *CreateBaseContext(sp_context_t *ctx); + + /** + * Frees a context. + * + * @param ctx Context pointer to free. + */ + void FreeBaseContext(IPluginContext *ctx); + + /** + * Allocates memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + void *BaseAlloc(size_t size); + + /** + * Frees memory allocated with BaseAlloc. + * + * @param mem Memory address to free. + */ + void BaseFree(void *memory); + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ From 302636d5e0eb75888c50a81edc9293c60c4719a3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 00:41:24 +0000 Subject: [PATCH 0043/1664] test dummy import of JIT structure --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4073 --- sourcepawn/vm/jit/jit_helpers.cpp | 100 +++ sourcepawn/vm/jit/jit_helpers.h | 49 ++ sourcepawn/vm/jit/x86/dll_exports.cpp | 1 + sourcepawn/vm/jit/x86/dll_exports.h | 8 + sourcepawn/vm/jit/x86/jit_x86.cpp | 40 ++ sourcepawn/vm/jit/x86/jit_x86.h | 31 + sourcepawn/vm/jit/x86/msvc8/jit-x86.sln | 20 + sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 254 +++++++ sourcepawn/vm/jit/x86/x86_macros.h | 770 +++++++++++++++++++++ sourcepawn/vm/msvc8/vm.vcproj | 4 + 10 files changed, 1277 insertions(+) create mode 100644 sourcepawn/vm/jit/jit_helpers.cpp create mode 100644 sourcepawn/vm/jit/jit_helpers.h create mode 100644 sourcepawn/vm/jit/x86/dll_exports.cpp create mode 100644 sourcepawn/vm/jit/x86/dll_exports.h create mode 100644 sourcepawn/vm/jit/x86/jit_x86.cpp create mode 100644 sourcepawn/vm/jit/x86/jit_x86.h create mode 100644 sourcepawn/vm/jit/x86/msvc8/jit-x86.sln create mode 100644 sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj create mode 100644 sourcepawn/vm/jit/x86/x86_macros.h diff --git a/sourcepawn/vm/jit/jit_helpers.cpp b/sourcepawn/vm/jit/jit_helpers.cpp new file mode 100644 index 00000000..04f5d7c6 --- /dev/null +++ b/sourcepawn/vm/jit/jit_helpers.cpp @@ -0,0 +1,100 @@ +#include +#include +#include "jit_helpers.h" + +cell_t jit_read_cell(jitinfo_t *jit) +{ + cell_t val = *(jit->inptr); + jit->inptr++; + return val; +} + +cell_t jit_read_cell_null(jitinfo_t *jit) +{ + return 0; +} + +cell_t *jit_read_cellptr(jitinfo_t *jit) +{ + cell_t *val = *(cell_t **)(jit->inptr); + jit->inptr++; + return val; +} + +cell_t *jit_read_cellptr_null(jitinfo_t *jit) +{ + return NULL; +} + +void jit_write_ubyte(jitinfo_t *jit, jit_uint8_t c) +{ + *(jit->outptr++) = c; +} + +void jit_write_ubyte_null(jitinfo_t *jit, jit_uint8_t c) +{ + jit->outptr++; +} + +void jit_write_byte(jitinfo_t *jit, jit_int8_t c) +{ + *(jit->outptr++) = c; +} + +void jit_write_byte_null(jitinfo_t *jit, jit_int8_t c) +{ + jit->outptr++; +} + +void jit_write_int32(jitinfo_t *jit, jit_int32_t c) +{ + jit_int32_t *ptr = (jit_int32_t *)jit->outptr; + *ptr = c; + jit->outptr += sizeof(jit_int32_t); +} + +void jit_write_int32_null(jitinfo_t *jit, jit_int32_t c) +{ + jit->outptr += sizeof(jit_int32_t); +} + +void jit_write_int64(jitinfo_t *jit, jit_int64_t c) +{ + jit_int64_t *ptr = (jit_int64_t *)jit->outptr; + *ptr = c; + jit->outptr += sizeof(jit_int64_t); +} + +void jit_write_int64_null(jitinfo_t *jit, jit_int64_t c) +{ + jit->outptr += sizeof(jit_int64_t); +} + +jitoffs_t jit_curpos(jitinfo_t *jit) +{ + return (jit->outptr - jit->outbase); +} + +jitwritefuncs_t g_write_funcs = +{ + jit_read_cell, + jit_read_cellptr, + jit_write_ubyte, + jit_write_byte, + jit_write_int32, + jit_write_int64, + jit_curpos +}; + +jitwritefuncs_t g_write_null_funcs = +{ + jit_read_cell_null, + jit_read_cellptr_null, + jit_write_ubyte_null, + jit_write_byte_null, + jit_write_int32_null, + jit_write_int64_null, + jit_curpos +}; + + diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h new file mode 100644 index 00000000..60ae30bd --- /dev/null +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -0,0 +1,49 @@ +#ifndef _INCLUDE_AMX_JIT_H +#define _INCLUDE_AMX_JIT_H + +#include + +#if defined HAVE_STDINT_H && !defined WIN32 +#include +typedef int8_t jit_int8_t; +typedef uint8_t jit_uint8_t; +typedef int32_t jit_int32_t; +typedef uint32_t jit_uint32_t; +typedef int64_t jit_int64_t; +typedef uint64_t jit_uint64_t; +#elif defined WIN32 +typedef __int8 jit_int8_t; +typedef unsigned __int8 jit_uint8_t; +typedef __int32 jit_int32_t; +typedef unsigned __int32 jit_uint32_t; +typedef __int64 jit_int64_t; +typedef unsigned __int64 jit_uint64_t; +#endif + +typedef char * jitcode_t; +typedef unsigned int jitoffs_t; + +//functions for writing to a JIT +typedef struct tagJITWRITEFUNCS +{ + //Reading from the input stream + cell_t (*read_cell)(struct tagJITINFO *); + cell_t *(*read_cellptr)(struct tagJITINFO *); + //Writing to the output stream + void (*write_ubyte)(struct tagJITINFO *, jit_uint8_t); + void (*write_byte)(struct tagJITINFO *, jit_int8_t); + void (*write_int32)(struct tagJITINFO *, jit_int32_t); + void (*write_int64)(struct tagJITINFO *, jit_int64_t); + //helpers + jitoffs_t (*jit_curpos)(struct tagJITINFO *); +} jitwritefuncs_t; + +typedef struct tagJITINFO +{ + jitwritefuncs_t wrfuncs; + cell_t *inptr; /* input pointer */ + jitcode_t outbase; /* output pointer */ + jitcode_t outptr; /* output base */ +} jitinfo_t; + +#endif //_INCLUDE_AMX_JIT_H diff --git a/sourcepawn/vm/jit/x86/dll_exports.cpp b/sourcepawn/vm/jit/x86/dll_exports.cpp new file mode 100644 index 00000000..e1723f9e --- /dev/null +++ b/sourcepawn/vm/jit/x86/dll_exports.cpp @@ -0,0 +1 @@ +#include diff --git a/sourcepawn/vm/jit/x86/dll_exports.h b/sourcepawn/vm/jit/x86/dll_exports.h new file mode 100644 index 00000000..568ecd92 --- /dev/null +++ b/sourcepawn/vm/jit/x86/dll_exports.h @@ -0,0 +1,8 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ +#define _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ + +#include + + + +#endif //_INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp new file mode 100644 index 00000000..e185a95b --- /dev/null +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -0,0 +1,40 @@ +#include +#include +#include "jit_x86.h" + +const char *JITX86::GetVMName() +{ + return "JIT (x86)"; +} + +ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) +{ + CompData *data = new CompData; + + data->plugin = plugin; + + return data; +} + +void JITX86::AbortCompilation(ICompilation *co) +{ + delete (CompData *)co; +} + +bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char *val) +{ + CompData *data = (CompData *)co; + + if (strcmp(key, "debug") == 0) + { + data->debug = (atoi(val) == 1); + if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG)) + { + data->debug = false; + return false; + } + return true; + } + + return false; +} diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h new file mode 100644 index 00000000..39724dde --- /dev/null +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -0,0 +1,31 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_H_ +#define _INCLUDE_SOURCEPAWN_JIT_X86_H_ + +#include + +using namespace SourcePawn; + +class CompData : public ICompilation +{ +public: + CompData() : plugin(NULL), debug(false) + { + }; +public: + sp_plugin_t *plugin; + bool debug; +}; + +class JITX86 : public IVirtualMachine +{ +public: + const char *GetVMName() =0; + ICompilation *StartCompilation(sp_plugin_t *plugin); + bool SetCompilationOption(ICompilation *co, const char *key, const char *val) ; + IPluginContext *CompileToContext(ICompilation *co); + void AbortCompilation(ICompilation *co); + void FreeContextVars(sp_context_t *ctx); + int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); +}; + +#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln b/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln new file mode 100644 index 00000000..149b2fc1 --- /dev/null +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jit-x86", "jit-x86.vcproj", "{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.Build.0 = Debug|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.ActiveCfg = Release|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj new file mode 100644 index 00000000..4b97f131 --- /dev/null +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h new file mode 100644 index 00000000..703e4c3a --- /dev/null +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -0,0 +1,770 @@ +#ifndef _INCLUDE_JIT_X86_MACROS_H +#define _INCLUDE_JIT_X86_MACROS_H + +//MOD R/M +#define MOD_MEM_REG 0 +#define MOD_DISP8 1 +#define MOD_DISP32 2 +#define MOD_REG 3 + +//SIB +#define NOSCALE 0 +#define SCALE2 1 +#define SCALE4 2 +#define SCALE8 3 + +//Register codes +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_SIB 4 +#define REG_NOIDX 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 + +//condition codes (for example, Jcc opcodes) +#define CC_B 0x2 +#define CC_NAE CC_B +#define CC_NB 0x3 +#define CC_AE CC_NB +#define CC_E 0x4 +#define CC_Z CC_E +#define CC_NE 0x5 +#define CC_NZ CC_NE +#define CC_NA 0x6 +#define CC_BE CC_NA +#define CC_A 0x7 +#define CC_NBE CC_A +#define CC_L 0xC +#define CC_NGE CC_L +#define CC_NL 0xD +#define CC_GE CC_NL +#define CC_NG 0xE +#define CC_LE CC_NG +#define CC_G 0xF +#define CC_NLE CC_G + +//Opcodes with encoding information +#define IA32_XOR_RM_REG 0x31 // encoding is /r +#define IA32_XOR_EAX_IMM32 0x35 // encoding is /r +#define IA32_XOR_RM_IMM32 0x81 // encoding is /6 +#define IA32_XOR_RM_IMM8 0x83 // encoding is /6 +#define IA32_ADD_RM_REG 0x01 // encoding is /r +#define IA32_ADD_RM_IMM32 0x81 // encoding is /0 +#define IA32_ADD_RM_IMM8 0x83 // encoding is /0 +#define IA32_ADD_EAX_IMM32 0x05 // no extra encoding +#define IA32_SUB_RM_REG 0x29 // encoding is /r +#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 +#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 +#define IA32_JMP_IMM32 0xE9 // encoding is imm32 +#define IA32_CALL_IMM32 0xE8 // relative call, +#define IA32_MOV_REG_IMM 0xB8 // encoding is +r +#define IA32_MOV_RM_REG 0x89 // encoding is /r +#define IA32_MOV_REG_MEM 0x8B // encoding is /r +#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 +#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 +#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 +#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding +#define IA32_TEST_RM_REG 0x85 // encoding is /r +#define IA32_JCC_IMM 0x70 // encoding is +cc +#define IA32_JCC_IMM32_1 0x0F // opcode part 1 +#define IA32_JCC_IMM32_2 0x80 // encoding is +cc +#define IA32_RET 0xC3 // no extra encoding +#define IA32_NEG_RM 0xF7 // encoding is /3 +#define IA32_INC_REG 0x40 // encoding is +r +#define IA32_INC_RM 0xFF // encoding is /0 +#define IA32_DEC_REG 0x48 // encoding is +r +#define IA32_DEC_RM 0xFF // encoding is /1 +#define IA32_OR_RM_REG 0x09 // encoding is /r +#define IA32_AND_RM_REG 0x21 // encoding is /r +#define IA32_NOT_RM 0xF7 // encoding is /2 +#define IA32_DIV_RM 0xF7 // encoding is /6 +#define IA32_MUL_RM 0xF7 // encoding is /4 +#define IA32_IMUL_RM 0xF7 // encoding is /5 +#define IA32_IDIV_RM 0xF7 // encoding is /7 +#define IA32_IMUL_REG_IMM32 0x69 // encoding is /r +#define IA32_IMUL_REG_IMM8 0x6B // encoding is /r +#define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 +#define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 +#define IA32_SAR_RM_CL 0xD3 // encoding is /7 +#define IA32_SHR_RM_CL 0xD3 // encoding is /5 +#define IA32_SHL_RM_CL 0xD3 // encoding is /4 +#define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 +#define IA32_CMP_RM_REG 0x39 // encoding is /r +#define IA32_SETCC_RM8_1 0x0F // opcode part 1 +#define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits) +#define IA32_XCHG_EAX_REG 0x90 // encoding is +r +#define IA32_XCHG_RM_REG 0x87 // encoding is /r +#define IA32_LEA_REG_MEM 0x8D // encoding is /r +#define IA32_POP_REG 0x58 // encoding is +r +#define IA32_PUSH_REG 0x50 // encoding is +r +#define IA32_REP 0xF3 // no extra encoding +#define IA32_MOVSD 0xA5 // no extra encoding +#define IA32_MOVSB 0xA4 // no extra encoding +#define IA32_STOSD 0xAB // no extra encoding +#define IA32_CLD 0xFC // no extra encoding + +inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) +{ + jit_uint8_t modrm = (mode << 6); + + modrm |= (reg << 3); + modrm |= (rm); + + return modrm; +} + +//mode is the scaling method - NOSCALE ... SCALE8 +//index is the register that is scaled +//base is the base register +inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t base) +{ + jit_uint8_t sib = (mode << 6); + + sib |= (index << 3); + sib |= (base); + + return sib; +} + +/*********************** + * INCREMENT/DECREMENT * + ***********************/ + +inline void IA32_Inc_Rm_Disp32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, reg)); + jit->wrfuncs.write_int32(jit, disp); +} + +inline void IA32_Inc_Rm_Disp8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, reg)); + jit->wrfuncs.write_byte(jit, disp); +} + +inline void IA32_Inc_Rm_Disp_Reg(jitinfo_t *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) +{ + jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, reg, base)); +} + +inline void IA32_Inc_Reg(jitinfo_t *jit, jit_uint8_t reg) +{ + jit->wrfuncs.write_ubyte(jit, IA32_INC_REG+reg); +} + +inline void IA32_Dec_Rm_Disp32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 1, reg)); + jit->wrfuncs.write_int32(jit, disp); +} + +inline void IA32_Dec_Rm_Disp8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 1, reg)); + jit->wrfuncs.write_byte(jit, disp); +} + +inline void IA32_Dec_Rm_Disp_Reg(jitinfo_t *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) +{ + jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, reg, base)); +} + +inline void IA32_Dec_Reg(jitinfo_t *jit, jit_uint8_t reg) +{ + jit->wrfuncs.write_ubyte(jit, IA32_DEC_REG+reg); +} + +/**************** + * BINARY LOGIC * + ****************/ + +inline void IA32_Xor_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(dest_mode, src, dest)); +} + +inline void IA32_Xor_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XOR_EAX_IMM32); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_Xor_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_Xor_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->wrfuncs.write_byte(jit, value); +} + +inline void IA32_Neg_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_NEG_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 3, reg)); +} + +inline void IA32_Or_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_OR_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_And_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_AND_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_Not_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_NOT_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 2, reg)); +} + +inline void IA32_Shr_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SHR_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, dest)); + jit->wrfuncs.write_ubyte(jit, value); +} + +inline void IA32_Shl_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SHL_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, dest)); + jit->wrfuncs.write_ubyte(jit, value); +} + +inline void IA32_Sar_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SAR_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, dest)); + jit->wrfuncs.write_ubyte(jit, value); +} + +inline void IA32_Sar_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SAR_RM_CL); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, reg)); +} + +inline void IA32_Shr_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SHR_RM_CL); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); +} + +inline void IA32_Shl_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SHL_RM_CL); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, reg)); +} + +inline void IA32_Xchg_Eax_Reg(jitinfo_t *jit, jit_uint8_t reg) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XCHG_EAX_REG+reg); +} + +inline void IA32_Xchg_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_XCHG_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +/********************** + * ARITHMETIC (BASIC) * + **********************/ + +inline void IA32_Add_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_Add_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->wrfuncs.write_byte(jit, value); +} + +inline void IA32_Add_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_Add_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_EAX_IMM32); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_Sub_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_Sub_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Sub_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->wrfuncs.write_int32(jit, val); +} + +inline void IA32_Div_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_DIV_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); +} + +inline void IA32_IDiv_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_IDIV_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, reg)); +} + +inline void IA32_Mul_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MUL_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, reg)); +} + +inline void IA32_IMul_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_IMUL_RM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); +} + +inline void IA32_IMul_Reg_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_IMUL_REG_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->wrfuncs.write_byte(jit, value); +} + +inline void IA32_IMul_Reg_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_IMUL_REG_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_Add_Rm_Reg_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); + jit->wrfuncs.write_byte(jit, disp); +} + +inline void IA32_Add_Rm_Imm8_Disp8(jitinfo_t *jit, + jit_uint8_t dest, + jit_int8_t val, + jit_int8_t disp8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->wrfuncs.write_byte(jit, disp8); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Add_Rm_Imm32_Disp8(jitinfo_t *jit, + jit_uint8_t dest, + jit_int32_t val, + jit_int8_t disp8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->wrfuncs.write_byte(jit, disp8); + jit->wrfuncs.write_int32(jit, val); +} + +inline void IA32_Add_Rm_Imm8_Disp32(jitinfo_t *jit, + jit_uint8_t dest, + jit_int8_t val, + jit_int32_t disp32) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); + jit->wrfuncs.write_int32(jit, disp32); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Add_Rm_Imm8_Disp_Reg(jitinfo_t *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_int8_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Sub_Rm_Imm8_Disp8(jitinfo_t *jit, + jit_uint8_t dest, + jit_int8_t val, + jit_int8_t disp8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 5, dest)); + jit->wrfuncs.write_byte(jit, disp8); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Sub_Rm_Imm8_Disp32(jitinfo_t *jit, + jit_uint8_t dest, + jit_int8_t val, + jit_int32_t disp32) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 5, dest)); + jit->wrfuncs.write_int32(jit, disp32); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Sub_Rm_Imm8_Disp_Reg(jitinfo_t *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_int8_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->wrfuncs.write_byte(jit, val); +} + +/** +* Memory Instructions +*/ + +inline void IA32_Lea_Reg_DispRegMult(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) +{ + jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, src_index, src_base)); +} + +inline void IA32_Lea_Reg_DispRegMultImm8(jitinfo_t *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t scale, + jit_int8_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, src_index, src_base)); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Lea_DispRegImm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); + jit->wrfuncs.write_byte(jit, val); +} + +inline void IA32_Lea_DispRegImm32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); + jit->wrfuncs.write_int32(jit, val); +} + +/** +* Stack Instructions +*/ + +inline void IA32_Pop_Reg(jitinfo_t *jit, jit_uint8_t reg) +{ + jit->wrfuncs.write_ubyte(jit, IA32_POP_REG+reg); +} + +inline void IA32_Push_Reg(jitinfo_t *jit, jit_uint8_t reg) +{ + jit->wrfuncs.write_ubyte(jit, IA32_PUSH_REG+reg); +} + +/** + * Moving from REGISTER/MEMORY to REGISTER + */ + +inline void IA32_Mov_Reg_Rm(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, dest, src)); +} + +inline void IA32_Mov_Reg_Rm_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, src)); + jit->wrfuncs.write_byte(jit, disp); +} + +inline void IA32_Mov_Reg_Rm_Disp32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, src)); + jit->wrfuncs.write_int32(jit, disp); +} + +inline void IA32_Mov_Reg_Rm_Disp_Reg(jitinfo_t *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t src_scale) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(src_scale, src_index, src_base)); +} + +/** + * Moving from REGISTER to REGISTER/MEMORY + */ + +inline void IA32_Mov_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_Mov_Rm_Reg_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); + jit->wrfuncs.write_byte(jit, disp); +} + +inline void IA32_Mov_Rm_Reg_Disp32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, src, dest)); + jit->wrfuncs.write_int32(jit, disp); +} + +inline void IA32_Mov_Rm_Reg_Disp_Reg(jitinfo_t *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_uint8_t src) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); +} + +/** + * Moving from IMMEDIATE to REGISTER + */ + +inline void IA32_Mov_Reg_Imm32(jitinfo_t *jit, jit_uint8_t dest, jit_int32_t num) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_IMM+dest); + jit->wrfuncs.write_int32(jit, num); +} + +inline void IA32_Mov_Rm_Imm32_Disp8(jitinfo_t *jit, + jit_uint8_t dest, + jit_int32_t val, + jit_int8_t disp8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->wrfuncs.write_byte(jit, disp8); + jit->wrfuncs.write_int32(jit, val); +} + +inline void IA32_Mov_Rm_Imm32_Disp32(jitinfo_t *jit, + jit_uint8_t dest, + jit_int32_t val, + jit_int32_t disp32) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); + jit->wrfuncs.write_int32(jit, disp32); + jit->wrfuncs.write_int32(jit, val); +} + +inline void IA32_Mov_Rm_Imm32_Disp_Reg(jitinfo_t *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_int32_t val) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->wrfuncs.write_int32(jit, val); +} + +/** + * Branching/Jumping + */ + +inline jitoffs_t IA32_Jump_Cond_Imm8(jitinfo_t *jit, jit_uint8_t cond, jit_int8_t disp) +{ + jitoffs_t ptr; + jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM+cond); + ptr = (jit->outptr-jit->outbase); + jit->wrfuncs.write_byte(jit, disp); + return ptr; +} + +inline jitoffs_t IA32_Jump_Imm32(jitinfo_t *jit, jit_int32_t disp) +{ + jitoffs_t ptr; + jit->wrfuncs.write_ubyte(jit, IA32_JMP_IMM32); + ptr = (jit->outptr-jit->outbase); + jit->wrfuncs.write_int32(jit, disp); + return ptr; +} + +inline jitoffs_t IA32_Jump_Cond_Imm32(jitinfo_t *jit, jit_uint8_t cond, jit_int32_t disp) +{ + jitoffs_t ptr; + jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM32_1); + jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM32_2+cond); + ptr = (jit->outptr-jit->outbase); + jit->wrfuncs.write_int32(jit, disp); + return ptr; +} + +inline jitoffs_t IA32_Call_Imm32(jitinfo_t *jit, jit_int32_t disp) +{ + jitoffs_t ptr; + jit->wrfuncs.write_ubyte(jit, IA32_CALL_IMM32); + ptr = (jit->outptr-jit->outbase); + jit->wrfuncs.write_int32(jit, disp); + return ptr; +} + +inline void IA32_Write_Jump8(jitinfo_t *jit, jitoffs_t jmp, jitoffs_t target) +{ + //save old ptr + jitcode_t oldptr = jit->outptr; + //get relative difference + jit_int8_t diff = (target - (jmp + 1)); + //overwrite old value + jit->outptr = jit->outbase + jmp; + jit->wrfuncs.write_byte(jit, diff); + //restore old ptr + jit->outptr = oldptr; +} + +inline void IA32_Send_Jump8_Here(jitinfo_t *jit, jitoffs_t jmp) +{ + jitoffs_t curptr = jit->wrfuncs.jit_curpos(jit); + IA32_Write_Jump8(jit, jmp, curptr); +} + +inline void IA32_Return(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_RET); +} + +inline void IA32_Test_Rm_Reg(jitinfo_t *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_TEST_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, reg2, reg1)); +} + +inline void IA32_Cmp_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_REG); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); +} + +inline void IA32_Cmp_Rm_Imm8(jitinfo_t *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, rm)); + jit->wrfuncs.write_byte(jit, imm8); +} + +inline void IA32_Cmp_Rm_Imm32(jitinfo_t *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM32); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, rm)); + jit->wrfuncs.write_int32(jit, imm32); +} + +inline void IA32_Cmp_Rm_Disp8_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM8); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 7, reg)); + jit->wrfuncs.write_byte(jit, disp); + jit->wrfuncs.write_byte(jit, imm8); +} + +inline void IA32_Cmp_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CMP_EAX_IMM32); + jit->wrfuncs.write_int32(jit, value); +} + +inline void IA32_SetCC_Rm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t cond) +{ + jit->wrfuncs.write_ubyte(jit, IA32_SETCC_RM8_1); + jit->wrfuncs.write_ubyte(jit, IA32_SETCC_RM8_2+cond); + jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_REG, 0, reg)); +} + +inline void IA32_Rep(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_REP); +} + +inline void IA32_Movsd(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOVSD); +} + +inline void IA32_Movsb(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_MOVSB); +} + +inline void IA32_Stosd(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_STOSD); +} + +inline void IA32_Cld(jitinfo_t *jit) +{ + jit->wrfuncs.write_ubyte(jit, IA32_CLD); +} + +#endif //_INCLUDE_JIT_X86_MACROS_H diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 9fd1a5ce..4e53d0b5 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -189,6 +189,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + From 45aa73592874987046da4f3cd98b18b628a23fe6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 01:59:56 +0000 Subject: [PATCH 0044/1664] initial recleaning of this mess, preparing for merge of JIT proper --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4074 --- sourcepawn/include/sp_vm_api.h | 16 +- sourcepawn/include/sp_vm_base.h | 14 + sourcepawn/include/sp_vm_types.h | 1 + sourcepawn/vm/jit/jit_helpers.cpp | 100 ---- sourcepawn/vm/jit/jit_helpers.h | 68 ++- sourcepawn/vm/jit/x86/jit_x86.cpp | 249 +++++++++ sourcepawn/vm/jit/x86/jit_x86.h | 178 ++++++- sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 4 - sourcepawn/vm/jit/x86/x86_macros.h | 586 +++++++++++---------- 9 files changed, 795 insertions(+), 421 deletions(-) create mode 100644 sourcepawn/include/sp_vm_base.h delete mode 100644 sourcepawn/vm/jit/jit_helpers.cpp diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index c469093a..8c6e7589 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -74,7 +74,11 @@ namespace SourcePawn virtual void BaseFree(void *memory) =0; }; - class ICompilation; + class ICompilation + { + public: + virtual ~ICompilation() { }; + }; class IVirtualMachine { @@ -107,9 +111,17 @@ namespace SourcePawn * Note: This will free the ICompilation pointer. * * @param co Compilation pointer. + * @param err Filled with error code on exit. * @return New plugin context. */ - virtual IPluginContext *CompileToContext(ICompilation *co) =0; + virtual IPluginContext *CompileToContext(ICompilation *co, int *err) =0; + + /** + * Aborts a compilation and frees the ICompilation pointer. + * + * @param co Compilation pointer. + */ + virtual void AbortCompilation(ICompilation *co) =0; /** * Frees any internal variable usage on a context. diff --git a/sourcepawn/include/sp_vm_base.h b/sourcepawn/include/sp_vm_base.h new file mode 100644 index 00000000..63dc63b9 --- /dev/null +++ b/sourcepawn/include/sp_vm_base.h @@ -0,0 +1,14 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_ +#define _INCLUDE_SOURCEPAWN_VM_BASE_H_ + +#include + +#if defined WIN32 +#define EXPORT_LINK extern "C" __declspec(dllexport) +#else if defined __GNUC__ +#define EXPORT_LINK extern "C" __attribute__((visibility("default"))) +#endif + +typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); + +#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index bb133369..8de64699 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -20,6 +20,7 @@ typedef int32_t cell_t; #define SP_ERR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ #define SP_ERR_STACKERR 9 /* Stack/Heap collision */ #define SP_ERR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ +#define SP_ERR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ /********************************************** *** The following structures are reference structures. diff --git a/sourcepawn/vm/jit/jit_helpers.cpp b/sourcepawn/vm/jit/jit_helpers.cpp deleted file mode 100644 index 04f5d7c6..00000000 --- a/sourcepawn/vm/jit/jit_helpers.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include "jit_helpers.h" - -cell_t jit_read_cell(jitinfo_t *jit) -{ - cell_t val = *(jit->inptr); - jit->inptr++; - return val; -} - -cell_t jit_read_cell_null(jitinfo_t *jit) -{ - return 0; -} - -cell_t *jit_read_cellptr(jitinfo_t *jit) -{ - cell_t *val = *(cell_t **)(jit->inptr); - jit->inptr++; - return val; -} - -cell_t *jit_read_cellptr_null(jitinfo_t *jit) -{ - return NULL; -} - -void jit_write_ubyte(jitinfo_t *jit, jit_uint8_t c) -{ - *(jit->outptr++) = c; -} - -void jit_write_ubyte_null(jitinfo_t *jit, jit_uint8_t c) -{ - jit->outptr++; -} - -void jit_write_byte(jitinfo_t *jit, jit_int8_t c) -{ - *(jit->outptr++) = c; -} - -void jit_write_byte_null(jitinfo_t *jit, jit_int8_t c) -{ - jit->outptr++; -} - -void jit_write_int32(jitinfo_t *jit, jit_int32_t c) -{ - jit_int32_t *ptr = (jit_int32_t *)jit->outptr; - *ptr = c; - jit->outptr += sizeof(jit_int32_t); -} - -void jit_write_int32_null(jitinfo_t *jit, jit_int32_t c) -{ - jit->outptr += sizeof(jit_int32_t); -} - -void jit_write_int64(jitinfo_t *jit, jit_int64_t c) -{ - jit_int64_t *ptr = (jit_int64_t *)jit->outptr; - *ptr = c; - jit->outptr += sizeof(jit_int64_t); -} - -void jit_write_int64_null(jitinfo_t *jit, jit_int64_t c) -{ - jit->outptr += sizeof(jit_int64_t); -} - -jitoffs_t jit_curpos(jitinfo_t *jit) -{ - return (jit->outptr - jit->outbase); -} - -jitwritefuncs_t g_write_funcs = -{ - jit_read_cell, - jit_read_cellptr, - jit_write_ubyte, - jit_write_byte, - jit_write_int32, - jit_write_int64, - jit_curpos -}; - -jitwritefuncs_t g_write_null_funcs = -{ - jit_read_cell_null, - jit_read_cellptr_null, - jit_write_ubyte_null, - jit_write_byte_null, - jit_write_int32_null, - jit_write_int64_null, - jit_curpos -}; - - diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index 60ae30bd..0b8fcda6 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -1,5 +1,5 @@ -#ifndef _INCLUDE_AMX_JIT_H -#define _INCLUDE_AMX_JIT_H +#ifndef _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ +#define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ #include @@ -23,27 +23,53 @@ typedef unsigned __int64 jit_uint64_t; typedef char * jitcode_t; typedef unsigned int jitoffs_t; -//functions for writing to a JIT -typedef struct tagJITWRITEFUNCS +class JitWriter { - //Reading from the input stream - cell_t (*read_cell)(struct tagJITINFO *); - cell_t *(*read_cellptr)(struct tagJITINFO *); - //Writing to the output stream - void (*write_ubyte)(struct tagJITINFO *, jit_uint8_t); - void (*write_byte)(struct tagJITINFO *, jit_int8_t); - void (*write_int32)(struct tagJITINFO *, jit_int32_t); - void (*write_int64)(struct tagJITINFO *, jit_int64_t); - //helpers - jitoffs_t (*jit_curpos)(struct tagJITINFO *); -} jitwritefuncs_t; - -typedef struct tagJITINFO -{ - jitwritefuncs_t wrfuncs; +public: + inline cell_t read_cell() + { + cell_t val = *(inptr); + inptr++; + return val; + } + inline cell_t read_cellptr() + { + cell_t *val = *(cell_t **)(inptr); + inptr++; + return val; + } + inline void write_ubyte(jit_uint8_t c) + { + if (outptr) + { + *outptr = c; + } + outptr++; + } + inline void write_byte(jit_int8_t c) + { + if (outptr) + { + *outptr = c; + } + outptr++; + } + inline void write_int32(jit_int32_t c) + { + if (outptr) + { + *(jit_int32_t *)ptr = c; + } + outptr += sizeof(jit_int32_t); + } + inline jitoffs_t jit_curpos() + { + return (outptr - outbase); + } +public: cell_t *inptr; /* input pointer */ jitcode_t outbase; /* output pointer */ jitcode_t outptr; /* output base */ -} jitinfo_t; +}; -#endif //_INCLUDE_AMX_JIT_H +#endif //_INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e185a95b..18870336 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -2,6 +2,255 @@ #include #include "jit_x86.h" +int OpAdvTable[OP_NUM_OPCODES]; + +JITX86::JITX86() +{ + memset(OpAdvTable, -1, sizeof(OpAdvTable)); + + /* instructions with 5 parameters */ + OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5; + + /* instructions with 4 parameters */ + OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4; + + /* instructions with 3 parameters */ + OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3; + + /* instructions with 2 parameters */ + OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2; + OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2; + OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; + OpAdvTable[OP_CONST] = sizeof(cell_t)*2; + OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; + + /* instructions with 1 parameter */ + OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); + OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t); + OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_LREF_PRI] = sizeof(cell_t); + OpAdvTable[OP_LREF_ALT] = sizeof(cell_t); + OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_LODB_I] = sizeof(cell_t); + OpAdvTable[OP_CONST_PRI] = sizeof(cell_t); + OpAdvTable[OP_CONST_ALT] = sizeof(cell_t); + OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t); + OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t); + OpAdvTable[OP_STOR_PRI] = sizeof(cell_t); + OpAdvTable[OP_STOR_ALT] = sizeof(cell_t); + OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_SREF_PRI] = sizeof(cell_t); + OpAdvTable[OP_SREF_ALT] = sizeof(cell_t); + OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_STRB_I] = sizeof(cell_t); + OpAdvTable[OP_LIDX_B] = sizeof(cell_t); + OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t); + OpAdvTable[OP_ALIGN_PRI] = sizeof(cell_t); + OpAdvTable[OP_ALIGN_ALT] = sizeof(cell_t); + OpAdvTable[OP_LCTRL] = sizeof(cell_t); + OpAdvTable[OP_SCTRL] = sizeof(cell_t); + OpAdvTable[OP_PUSH_R] = sizeof(cell_t); + OpAdvTable[OP_PUSH_C] = sizeof(cell_t); + OpAdvTable[OP_PUSH] = sizeof(cell_t); + OpAdvTable[OP_PUSH_S] = sizeof(cell_t); + OpAdvTable[OP_STACK] = sizeof(cell_t); + OpAdvTable[OP_HEAP] = sizeof(cell_t); + OpAdvTable[OP_JREL] = sizeof(cell_t); + OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_ADD_C] = sizeof(cell_t); + OpAdvTable[OP_SMUL_C] = sizeof(cell_t); + OpAdvTable[OP_ZERO] = sizeof(cell_t); + OpAdvTable[OP_ZERO_S] = sizeof(cell_t); + OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_INC] = sizeof(cell_t); + OpAdvTable[OP_INC_S] = sizeof(cell_t); + OpAdvTable[OP_DEC] = sizeof(cell_t); + OpAdvTable[OP_DEC_S] = sizeof(cell_t); + OpAdvTable[OP_MOVS] = sizeof(cell_t); + OpAdvTable[OP_CMPS] = sizeof(cell_t); + OpAdvTable[OP_FILL] = sizeof(cell_t); + OpAdvTable[OP_HALT] = sizeof(cell_t); + OpAdvTable[OP_BOUNDS] = sizeof(cell_t); + OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); + + /* instructions with 0 parameters */ + OpAdvTable[OP_LOAD_I] = 0; + OpAdvTable[OP_STOR_I] = 0; + OpAdvTable[OP_LIDX] = 0; + OpAdvTable[OP_IDXADDR] = 0; + OpAdvTable[OP_MOVE_PRI] = 0; + OpAdvTable[OP_MOVE_ALT] = 0; + OpAdvTable[OP_XCHG] = 0; + OpAdvTable[OP_PUSH_PRI] = 0; + OpAdvTable[OP_PUSH_ALT] = 0; + OpAdvTable[OP_POP_PRI] = 0; + OpAdvTable[OP_POP_ALT] = 0; + OpAdvTable[OP_PROC] = 0; + OpAdvTable[OP_RET] = 0; + OpAdvTable[OP_RETN] = 0; + OpAdvTable[OP_CALL_PRI] = 0; + OpAdvTable[OP_SHL] = 0; + OpAdvTable[OP_SHR] = 0; + OpAdvTable[OP_SSHR] = 0; + OpAdvTable[OP_SMUL] = 0; + OpAdvTable[OP_SDIV] = 0; + OpAdvTable[OP_SDIV_ALT] = 0; + OpAdvTable[OP_UMUL] = 0; + OpAdvTable[OP_UDIV] = 0; + OpAdvTable[OP_UDIV_ALT] = 0; + OpAdvTable[OP_ADD] = 0; + OpAdvTable[OP_SUB] = 0; + OpAdvTable[OP_SUB_ALT] = 0; + OpAdvTable[OP_AND] = 0; + OpAdvTable[OP_OR] = 0; + OpAdvTable[OP_XOR] = 0; + OpAdvTable[OP_NOT] = 0; + OpAdvTable[OP_NEG] = 0; + OpAdvTable[OP_INVERT] = 0; + OpAdvTable[OP_ZERO_PRI] = 0; + OpAdvTable[OP_ZERO_ALT] = 0; + OpAdvTable[OP_SIGN_PRI] = 0; + OpAdvTable[OP_SIGN_ALT] = 0; + OpAdvTable[OP_EQ] = 0; + OpAdvTable[OP_NEQ] = 0; + OpAdvTable[OP_LESS] = 0; + OpAdvTable[OP_LEQ] = 0; + OpAdvTable[OP_GRTR] = 0; + OpAdvTable[OP_GEQ] = 0; + OpAdvTable[OP_SLESS] = 0; + OpAdvTable[OP_SLEQ] = 0; + OpAdvTable[OP_SGRTR] = 0; + OpAdvTable[OP_SGEQ] = 0; + OpAdvTable[OP_INC_PRI] = 0; + OpAdvTable[OP_INC_ALT] = 0; + OpAdvTable[OP_INC_I] = 0; + OpAdvTable[OP_DEC_PRI] = 0; + OpAdvTable[OP_DEC_ALT] = 0; + OpAdvTable[OP_DEC_I] = 0; + OpAdvTable[OP_JUMP_PRI] = 0; + OpAdvTable[OP_SWAP_PRI] = 0; + OpAdvTable[OP_SWAP_ALT] = 0; + OpAdvTable[OP_NOP] = 0; + OpAdvTable[OP_BREAK] = 0; + + /* opcodes that need relocation */ + OpAdvTable[OP_CALL] = -2; + OpAdvTable[OP_JUMP] = -2; + OpAdvTable[OP_JZER] = -2; + OpAdvTable[OP_JNZ] = -2; + OpAdvTable[OP_JEQ] = -2; + OpAdvTable[OP_JNEQ] = -2; + OpAdvTable[OP_JLESS] = -2; + OpAdvTable[OP_JLEQ] = -2; + OpAdvTable[OP_JGRTR] = -2; + OpAdvTable[OP_JGEQ] = -2; + OpAdvTable[OP_JSLESS] = -2; + OpAdvTable[OP_JSLEQ] = -2; + OpAdvTable[OP_JSGRTR] = -2; + OpAdvTable[OP_JSGEQ] = -2; + OpAdvTable[OP_SWITCH] = -2; + + /* opcodes that are totally invalid */ + OpAdvTable[OP_FILE] = -3; + OpAdvTable[OP_SYMBOL] = -3; + OpAdvTable[OP_LINE] = -3; + OpAdvTable[OP_SRANGE] = -3; + OpAdvTable[OP_SYMTAG] = -3; + OpAdvTable[OP_SYSREQ_D] = -3; + OpAdvTable[OP_SYSREQ_ND] = -3; +} + +IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) +{ + CompData *data = (CompData *)co; + sp_plugin_t *plugin = data->plugin; + + /* The first phase is to browse */ + uint8_t *code = plugin->pcode; + uint8_t *cip; + uint8_t *end_cip = plugin->pcode + plugin->pcode_size; + OPCODE op; + int op_c; + uint32_t reloc_count = 0; + + /* FIRST PASS (light load) - Get initial opcode information */ + for (cip = code; cip < end_cip;) + { + op = (OPCODE)*(ucell_t *)cip; + if ((unsigned)op >= OP_NUM_OPCODES) + { + AbortCompilation(co); + *err = SP_ERR_INVALID_INSTRUCTION; + return NULL; + } + cip += sizeof(cell_t); + op_c = OpAdvTable[op]; + if (op_c >= 0) + { + cip += op_c; + } else if (op_c == -3) { + AbortCompilation(co); + *err = SP_ERR_INVALID_INSTRUCTION; + return NULL; + } else if (op_c == -2) { + reloc_count++; + cip += sizeof(cell_t); + } else if (op_c == -1) { + switch (op) + { + case OP_SYSREQ_C: + case OP_SYSREQ_PRI: + case OP_SYSREQ_N: + { + if (!data->always_inline) + { + reloc_count++; + } + break; + } + case OP_CASETBL: + { + ucell_t num = *(ucell_t *)cip; + cip += sizeof(cell_t); + reloc_count += (num + 1); + cip += ((2*num) + 1) * sizeof(cell_t); + break; + } + default: + { + AbortCompilation(co); + *err = SP_ERR_INVALID_INSTRUCTION; + return NULL; + } + } + } + } + + *err = SP_ERR_NONE; + + return NULL; +} + const char *JITX86::GetVMName() { return "JIT (x86)"; diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 39724dde..acc1764a 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -8,24 +8,198 @@ using namespace SourcePawn; class CompData : public ICompilation { public: - CompData() : plugin(NULL), debug(false) + CompData() : plugin(NULL), debug(false), always_inline(true) { }; public: sp_plugin_t *plugin; + bool always_inline; bool debug; }; class JITX86 : public IVirtualMachine { +public: + JITX86(); public: const char *GetVMName() =0; ICompilation *StartCompilation(sp_plugin_t *plugin); bool SetCompilationOption(ICompilation *co, const char *key, const char *val) ; - IPluginContext *CompileToContext(ICompilation *co); + IPluginContext *CompileToContext(ICompilation *co, int *err); void AbortCompilation(ICompilation *co); void FreeContextVars(sp_context_t *ctx); int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; +typedef enum +{ + OP_NONE, /* invalid opcode */ + OP_LOAD_PRI, //DONE + OP_LOAD_ALT, //DONE + OP_LOAD_S_PRI, //DONE + OP_LOAD_S_ALT, //DONE + OP_LREF_PRI, //DONE + OP_LREF_ALT, //DONE + OP_LREF_S_PRI, //DONE + OP_LREF_S_ALT, //DONE + OP_LOAD_I, //DONE + OP_LODB_I, + OP_CONST_PRI, //DONE + OP_CONST_ALT, //DONE + OP_ADDR_PRI, //DONE + OP_ADDR_ALT, //DONE + OP_STOR_PRI, //DONE + OP_STOR_ALT, //DONE + OP_STOR_S_PRI, //DONE + OP_STOR_S_ALT, //DONE + OP_SREF_PRI, //DONE + OP_SREF_ALT, //DONE + OP_SREF_S_PRI, //DONE + OP_SREF_S_ALT, //DONE + OP_STOR_I, //DONE + OP_STRB_I, + OP_LIDX, //DONE + OP_LIDX_B, + OP_IDXADDR, //DONE + OP_IDXADDR_B, + OP_ALIGN_PRI, //DONE + OP_ALIGN_ALT, //DONE + OP_LCTRL, + OP_SCTRL, + OP_MOVE_PRI, //DONE + OP_MOVE_ALT, //DONE + OP_XCHG, //DONE + OP_PUSH_PRI, //DONE + OP_PUSH_ALT, //DONE + OP_PUSH_R, //DONE + OP_PUSH_C, //DONE + OP_PUSH, //DONE + OP_PUSH_S, //DONE + OP_POP_PRI, //DONE + OP_POP_ALT, //DONE + OP_STACK, //DONE + OP_HEAP, //DONE + OP_PROC, //DONE + OP_RET, + OP_RETN, //DONE + OP_CALL, + OP_CALL_PRI, + OP_JUMP, //DONE + OP_JREL, //DONE + OP_JZER, //DONE + OP_JNZ, //DONE + OP_JEQ, //DONE + OP_JNEQ, //DONE + OP_JLESS, //DONE + OP_JLEQ, //DONE + OP_JGRTR, //DONE + OP_JGEQ, //DONE + OP_JSLESS, //DONE + OP_JSLEQ, //DONE + OP_JSGRTR, //DONE + OP_JSGEQ, //DONE + OP_SHL, //DONE + OP_SHR, //DONE + OP_SSHR, //DONE + OP_SHL_C_PRI, //DONE + OP_SHL_C_ALT, //DONE + OP_SHR_C_PRI, //DONE + OP_SHR_C_ALT, //DONE + OP_SMUL, //DONE + OP_SDIV, //DONE + OP_SDIV_ALT, //DONE + OP_UMUL, //DONE + OP_UDIV, //DONE + OP_UDIV_ALT, //DONE + OP_ADD, //DONE + OP_SUB, //DONE + OP_SUB_ALT, //DONE + OP_AND, //DONE + OP_OR, //DONE + OP_XOR, //DONE + OP_NOT, //DONE + OP_NEG, //DONE + OP_INVERT, //DONE + OP_ADD_C, //DONE + OP_SMUL_C, //DONE + OP_ZERO_PRI, //DONE + OP_ZERO_ALT, //DONE + OP_ZERO, //DONE + OP_ZERO_S, //DONE + OP_SIGN_PRI, //DONE + OP_SIGN_ALT, //DONE + OP_EQ, //DONE + OP_NEQ, //DONE + OP_LESS, //DONE + OP_LEQ, //DONE + OP_GRTR, //DONE + OP_GEQ, //DONE + OP_SLESS, //DONE + OP_SLEQ, //DONE + OP_SGRTR, //DONE + OP_SGEQ, //DONE + OP_EQ_C_PRI, //DONE + OP_EQ_C_ALT, //DONE + OP_INC_PRI, //DONE + OP_INC_ALT, //DONE + OP_INC, //DONE + OP_INC_S, //DONE + OP_INC_I, //DONE + OP_DEC_PRI, //DONE + OP_DEC_ALT, //DONE + OP_DEC, //DONE + OP_DEC_S, //DONE + OP_DEC_I, //DONE + OP_MOVS, //DONE + OP_CMPS, //DONE + OP_FILL, //DONE + OP_HALT, //DONE + OP_BOUNDS, + OP_SYSREQ_PRI, + OP_SYSREQ_C, + OP_FILE, + OP_LINE, + OP_SYMBOL, + OP_SRANGE, + OP_JUMP_PRI, + OP_SWITCH, + OP_CASETBL, //DONE + OP_SWAP_PRI, //DONE + OP_SWAP_ALT, //DONE + OP_PUSH_ADR, //DONE + OP_NOP, //DONE + OP_SYSREQ_N, + OP_SYMTAG, + OP_BREAK, + OP_PUSH2_C, //DONE + OP_PUSH2, //DONE + OP_PUSH2_S, //DONE + OP_PUSH2_ADR, //DONE + OP_PUSH3_C, //DONE + OP_PUSH3, //DONE + OP_PUSH3_S, //DONE + OP_PUSH3_ADR, //DONE + OP_PUSH4_C, //DONE + OP_PUSH4, //DONE + OP_PUSH4_S, //DONE + OP_PUSH4_ADR, //DONE + OP_PUSH5_C, //DONE + OP_PUSH5, //DONE + OP_PUSH5_S, //DONE + OP_PUSH5_ADR, //DONE + OP_LOAD_BOTH, + OP_LOAD_S_BOTH, + OP_CONST, + OP_CONST_S, + /* ----- */ + OP_SYSREQ_D, + OP_SYSREQ_ND, + /* ----- */ + OP_HEAP_PRI, + OP_PUSH_HEAP_C, + OP_POP_HEAP_PRI, + /* ----- */ + OP_NUM_OPCODES +} OPCODE; + #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj index 4b97f131..037ef66b 100644 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj @@ -187,10 +187,6 @@ /> - - diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 703e4c3a..ec373613 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -1,6 +1,8 @@ #ifndef _INCLUDE_JIT_X86_MACROS_H #define _INCLUDE_JIT_X86_MACROS_H +#include "..\jit_helpers.h" + //MOD R/M #define MOD_MEM_REG 0 #define MOD_DISP8 1 @@ -134,544 +136,544 @@ inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t bas * INCREMENT/DECREMENT * ***********************/ -inline void IA32_Inc_Rm_Disp32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t disp) +inline void IA32_Inc_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, reg)); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_INC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, reg)); + jit->write_int32(jit, disp); } -inline void IA32_Inc_Rm_Disp8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp) +inline void IA32_Inc_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, reg)); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_INC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, reg)); + jit->write_byte(jit, disp); } -inline void IA32_Inc_Rm_Disp_Reg(jitinfo_t *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) +inline void IA32_Inc_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) { - jit->wrfuncs.write_ubyte(jit, IA32_INC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, reg, base)); + jit->write_ubyte(jit, IA32_INC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(scale, reg, base)); } -inline void IA32_Inc_Reg(jitinfo_t *jit, jit_uint8_t reg) +inline void IA32_Inc_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->wrfuncs.write_ubyte(jit, IA32_INC_REG+reg); + jit->write_ubyte(jit, IA32_INC_REG+reg); } -inline void IA32_Dec_Rm_Disp32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t disp) +inline void IA32_Dec_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 1, reg)); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_DEC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 1, reg)); + jit->write_int32(jit, disp); } -inline void IA32_Dec_Rm_Disp8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp) +inline void IA32_Dec_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 1, reg)); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_DEC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 1, reg)); + jit->write_byte(jit, disp); } -inline void IA32_Dec_Rm_Disp_Reg(jitinfo_t *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) +inline void IA32_Dec_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) { - jit->wrfuncs.write_ubyte(jit, IA32_DEC_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, reg, base)); + jit->write_ubyte(jit, IA32_DEC_RM); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(scale, reg, base)); } -inline void IA32_Dec_Reg(jitinfo_t *jit, jit_uint8_t reg) +inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->wrfuncs.write_ubyte(jit, IA32_DEC_REG+reg); + jit->write_ubyte(jit, IA32_DEC_REG+reg); } /**************** * BINARY LOGIC * ****************/ -inline void IA32_Xor_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) +inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) { - jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(dest_mode, src, dest)); + jit->write_ubyte(jit, IA32_XOR_RM_REG); + jit->write_ubyte(jit, ia32_modrm(dest_mode, src, dest)); } -inline void IA32_Xor_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_XOR_EAX_IMM32); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_XOR_EAX_IMM32); + jit->write_int32(jit, value); } -inline void IA32_Xor_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) +inline void IA32_Xor_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_XOR_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->write_int32(jit, value); } -inline void IA32_Xor_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) +inline void IA32_Xor_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_XOR_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); - jit->wrfuncs.write_byte(jit, value); + jit->write_ubyte(jit, IA32_XOR_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->write_byte(jit, value); } -inline void IA32_Neg_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_NEG_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 3, reg)); + jit->write_ubyte(jit, IA32_NEG_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 3, reg)); } -inline void IA32_Or_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Or_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_OR_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_OR_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_And_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_And_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_AND_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_AND_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_Not_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_NOT_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 2, reg)); + jit->write_ubyte(jit, IA32_NOT_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 2, reg)); } -inline void IA32_Shr_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SHR_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, dest)); - jit->wrfuncs.write_ubyte(jit, value); + jit->write_ubyte(jit, IA32_SHR_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 5, dest)); + jit->write_ubyte(jit, value); } -inline void IA32_Shl_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SHL_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, dest)); - jit->wrfuncs.write_ubyte(jit, value); + jit->write_ubyte(jit, IA32_SHL_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 4, dest)); + jit->write_ubyte(jit, value); } -inline void IA32_Sar_Rm_Imm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) +inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SAR_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, dest)); - jit->wrfuncs.write_ubyte(jit, value); + jit->write_ubyte(jit, IA32_SAR_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 7, dest)); + jit->write_ubyte(jit, value); } -inline void IA32_Sar_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Sar_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SAR_RM_CL); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, reg)); + jit->write_ubyte(jit, IA32_SAR_RM_CL); + jit->write_ubyte(jit, ia32_modrm(mode, 7, reg)); } -inline void IA32_Shr_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Shr_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SHR_RM_CL); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_ubyte(jit, IA32_SHR_RM_CL); + jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); } -inline void IA32_Shl_Rm_CL(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Shl_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SHL_RM_CL); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, reg)); + jit->write_ubyte(jit, IA32_SHL_RM_CL); + jit->write_ubyte(jit, ia32_modrm(mode, 4, reg)); } -inline void IA32_Xchg_Eax_Reg(jitinfo_t *jit, jit_uint8_t reg) +inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->wrfuncs.write_ubyte(jit, IA32_XCHG_EAX_REG+reg); + jit->write_ubyte(jit, IA32_XCHG_EAX_REG+reg); } -inline void IA32_Xchg_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Xchg_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_XCHG_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_XCHG_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } /********************** * ARITHMETIC (BASIC) * **********************/ -inline void IA32_Add_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_ADD_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_Add_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) +inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->wrfuncs.write_byte(jit, value); + jit->write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->write_byte(jit, value); } -inline void IA32_Add_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) +inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_ADD_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->write_int32(jit, value); } -inline void IA32_Add_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +inline void IA32_Add_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_EAX_IMM32); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_ADD_EAX_IMM32); + jit->write_int32(jit, value); } -inline void IA32_Sub_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_SUB_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_Sub_Rm_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) +inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_byte(jit, val); } -inline void IA32_Sub_Rm_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) +inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_SUB_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_int32(jit, val); } -inline void IA32_Div_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_DIV_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->write_ubyte(jit, IA32_DIV_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); } -inline void IA32_IDiv_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_IDiv_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_IDIV_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, reg)); + jit->write_ubyte(jit, IA32_IDIV_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 7, reg)); } -inline void IA32_Mul_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Mul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_MUL_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 4, reg)); + jit->write_ubyte(jit, IA32_MUL_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 4, reg)); } -inline void IA32_IMul_Rm(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_IMul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_IMUL_RM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_ubyte(jit, IA32_IMUL_RM); + jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); } -inline void IA32_IMul_Reg_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) +inline void IA32_IMul_Reg_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_IMUL_REG_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->wrfuncs.write_byte(jit, value); + jit->write_ubyte(jit, IA32_IMUL_REG_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->write_byte(jit, value); } -inline void IA32_IMul_Reg_Imm32(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) +inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_IMUL_REG_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_IMUL_REG_IMM32); + jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); + jit->write_int32(jit, value); } -inline void IA32_Add_Rm_Reg_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_ADD_RM_REG); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(jit, disp); } -inline void IA32_Add_Rm_Imm8_Disp8(jitinfo_t *jit, +inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, jit_int8_t disp8) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->wrfuncs.write_byte(jit, disp8); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(jit, disp8); + jit->write_byte(jit, val); } -inline void IA32_Add_Rm_Imm32_Disp8(jitinfo_t *jit, +inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_int8_t disp8) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->wrfuncs.write_byte(jit, disp8); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_ADD_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(jit, disp8); + jit->write_int32(jit, val); } -inline void IA32_Add_Rm_Imm8_Disp32(jitinfo_t *jit, +inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, jit_int32_t disp32) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); - jit->wrfuncs.write_int32(jit, disp32); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(jit, disp32); + jit->write_byte(jit, val); } -inline void IA32_Add_Rm_Imm8_Disp_Reg(jitinfo_t *jit, +inline void IA32_Add_Rm_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int8_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_ADD_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(jit, val); } -inline void IA32_Sub_Rm_Imm8_Disp8(jitinfo_t *jit, +inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, jit_int8_t disp8) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 5, dest)); - jit->wrfuncs.write_byte(jit, disp8); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 5, dest)); + jit->write_byte(jit, disp8); + jit->write_byte(jit, val); } -inline void IA32_Sub_Rm_Imm8_Disp32(jitinfo_t *jit, +inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, jit_int32_t disp32) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 5, dest)); - jit->wrfuncs.write_int32(jit, disp32); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 5, dest)); + jit->write_int32(jit, disp32); + jit->write_byte(jit, val); } -inline void IA32_Sub_Rm_Imm8_Disp_Reg(jitinfo_t *jit, +inline void IA32_Sub_Rm_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int8_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_SUB_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(jit, val); } /** * Memory Instructions */ -inline void IA32_Lea_Reg_DispRegMult(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) +inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) { - jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, src_index, src_base)); + jit->write_ubyte(jit, IA32_LEA_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(scale, src_index, src_base)); } -inline void IA32_Lea_Reg_DispRegMultImm8(jitinfo_t *jit, +inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale, jit_int8_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(scale, src_index, src_base)); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_LEA_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(scale, src_index, src_base)); + jit->write_byte(jit, val); } -inline void IA32_Lea_DispRegImm8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) +inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); - jit->wrfuncs.write_byte(jit, val); + jit->write_ubyte(jit, IA32_LEA_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); + jit->write_byte(jit, val); } -inline void IA32_Lea_DispRegImm32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) +inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_LEA_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_LEA_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); + jit->write_int32(jit, val); } /** * Stack Instructions */ -inline void IA32_Pop_Reg(jitinfo_t *jit, jit_uint8_t reg) +inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->wrfuncs.write_ubyte(jit, IA32_POP_REG+reg); + jit->write_ubyte(jit, IA32_POP_REG+reg); } -inline void IA32_Push_Reg(jitinfo_t *jit, jit_uint8_t reg) +inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->wrfuncs.write_ubyte(jit, IA32_PUSH_REG+reg); + jit->write_ubyte(jit, IA32_PUSH_REG+reg); } /** * Moving from REGISTER/MEMORY to REGISTER */ -inline void IA32_Mov_Reg_Rm(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, dest, src)); + jit->write_ubyte(jit, IA32_MOV_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(mode, dest, src)); } -inline void IA32_Mov_Reg_Rm_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, src)); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_MOV_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(jit, disp); } -inline void IA32_Mov_Reg_Rm_Disp32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, src)); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_MOV_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, src)); + jit->write_int32(jit, disp); } -inline void IA32_Mov_Reg_Rm_Disp_Reg(jitinfo_t *jit, +inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t src_scale) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_MEM); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(src_scale, src_index, src_base)); + jit->write_ubyte(jit, IA32_MOV_REG_MEM); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(src_scale, src_index, src_base)); } /** * Moving from REGISTER to REGISTER/MEMORY */ -inline void IA32_Mov_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_MOV_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_Mov_Rm_Reg_Disp8(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_MOV_RM_REG); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(jit, disp); } -inline void IA32_Mov_Rm_Reg_Disp32(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, src, dest)); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_MOV_RM_REG); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, src, dest)); + jit->write_int32(jit, disp); } -inline void IA32_Mov_Rm_Reg_Disp_Reg(jitinfo_t *jit, +inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_uint8_t src) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, src, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_ubyte(jit, IA32_MOV_RM_REG); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); } /** * Moving from IMMEDIATE to REGISTER */ -inline void IA32_Mov_Reg_Imm32(jitinfo_t *jit, jit_uint8_t dest, jit_int32_t num) +inline void IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_REG_IMM+dest); - jit->wrfuncs.write_int32(jit, num); + jit->write_ubyte(jit, IA32_MOV_REG_IMM+dest); + jit->write_int32(jit, num); } -inline void IA32_Mov_Rm_Imm32_Disp8(jitinfo_t *jit, +inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_int8_t disp8) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->wrfuncs.write_byte(jit, disp8); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(jit, disp8); + jit->write_int32(jit, val); } -inline void IA32_Mov_Rm_Imm32_Disp32(jitinfo_t *jit, +inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_int32_t disp32) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); - jit->wrfuncs.write_int32(jit, disp32); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(jit, disp32); + jit->write_int32(jit, val); } -inline void IA32_Mov_Rm_Imm32_Disp_Reg(jitinfo_t *jit, +inline void IA32_Mov_Rm_Imm32_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int32_t val) { - jit->wrfuncs.write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->wrfuncs.write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->wrfuncs.write_int32(jit, val); + jit->write_ubyte(jit, IA32_MOV_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_int32(jit, val); } /** * Branching/Jumping */ -inline jitoffs_t IA32_Jump_Cond_Imm8(jitinfo_t *jit, jit_uint8_t cond, jit_int8_t disp) +inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_t disp) { jitoffs_t ptr; - jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM+cond); - ptr = (jit->outptr-jit->outbase); - jit->wrfuncs.write_byte(jit, disp); + jit->write_ubyte(jit, IA32_JCC_IMM+cond); + ptr = jit->jit_curpos(); + jit->write_byte(jit, disp); return ptr; } -inline jitoffs_t IA32_Jump_Imm32(jitinfo_t *jit, jit_int32_t disp) +inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; - jit->wrfuncs.write_ubyte(jit, IA32_JMP_IMM32); - ptr = (jit->outptr-jit->outbase); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_JMP_IMM32); + ptr = jit->jit_curpos(); + jit->write_int32(jit, disp); return ptr; } -inline jitoffs_t IA32_Jump_Cond_Imm32(jitinfo_t *jit, jit_uint8_t cond, jit_int32_t disp) +inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp) { jitoffs_t ptr; - jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM32_1); - jit->wrfuncs.write_ubyte(jit, IA32_JCC_IMM32_2+cond); - ptr = (jit->outptr-jit->outbase); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_JCC_IMM32_1); + jit->write_ubyte(jit, IA32_JCC_IMM32_2+cond); + ptr = jit->jit_curpos(); + jit->write_int32(jit, disp); return ptr; } -inline jitoffs_t IA32_Call_Imm32(jitinfo_t *jit, jit_int32_t disp) +inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; - jit->wrfuncs.write_ubyte(jit, IA32_CALL_IMM32); - ptr = (jit->outptr-jit->outbase); - jit->wrfuncs.write_int32(jit, disp); + jit->write_ubyte(jit, IA32_CALL_IMM32); + ptr = jit->jit_curpos(); + jit->write_int32(jit, disp); return ptr; } -inline void IA32_Write_Jump8(jitinfo_t *jit, jitoffs_t jmp, jitoffs_t target) +inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) { //save old ptr jitcode_t oldptr = jit->outptr; @@ -679,92 +681,92 @@ inline void IA32_Write_Jump8(jitinfo_t *jit, jitoffs_t jmp, jitoffs_t target) jit_int8_t diff = (target - (jmp + 1)); //overwrite old value jit->outptr = jit->outbase + jmp; - jit->wrfuncs.write_byte(jit, diff); + jit->write_byte(jit, diff); //restore old ptr jit->outptr = oldptr; } -inline void IA32_Send_Jump8_Here(jitinfo_t *jit, jitoffs_t jmp) +inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->wrfuncs.jit_curpos(jit); + jitoffs_t curptr = jit->jit_curpos(jit); IA32_Write_Jump8(jit, jmp, curptr); } -inline void IA32_Return(jitinfo_t *jit) +inline void IA32_Return(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_RET); + jit->write_ubyte(jit, IA32_RET); } -inline void IA32_Test_Rm_Reg(jitinfo_t *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode) +inline void IA32_Test_Rm_Reg(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_TEST_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, reg2, reg1)); + jit->write_ubyte(jit, IA32_TEST_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, reg2, reg1)); } -inline void IA32_Cmp_Rm_Reg(jitinfo_t *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_REG); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(jit, IA32_CMP_RM_REG); + jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); } -inline void IA32_Cmp_Rm_Imm8(jitinfo_t *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) +inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) { - jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, rm)); - jit->wrfuncs.write_byte(jit, imm8); + jit->write_ubyte(jit, IA32_CMP_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(mode, 7, rm)); + jit->write_byte(jit, imm8); } -inline void IA32_Cmp_Rm_Imm32(jitinfo_t *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32) +inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32) { - jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM32); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(mode, 7, rm)); - jit->wrfuncs.write_int32(jit, imm32); + jit->write_ubyte(jit, IA32_CMP_RM_IMM32); + jit->write_ubyte(jit, ia32_modrm(mode, 7, rm)); + jit->write_int32(jit, imm32); } -inline void IA32_Cmp_Rm_Disp8_Imm8(jitinfo_t *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) +inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) { - jit->wrfuncs.write_ubyte(jit, IA32_CMP_RM_IMM8); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_DISP8, 7, reg)); - jit->wrfuncs.write_byte(jit, disp); - jit->wrfuncs.write_byte(jit, imm8); + jit->write_ubyte(jit, IA32_CMP_RM_IMM8); + jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 7, reg)); + jit->write_byte(jit, disp); + jit->write_byte(jit, imm8); } -inline void IA32_Cmp_Eax_Imm32(jitinfo_t *jit, jit_int32_t value) +inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->wrfuncs.write_ubyte(jit, IA32_CMP_EAX_IMM32); - jit->wrfuncs.write_int32(jit, value); + jit->write_ubyte(jit, IA32_CMP_EAX_IMM32); + jit->write_int32(jit, value); } -inline void IA32_SetCC_Rm8(jitinfo_t *jit, jit_uint8_t reg, jit_uint8_t cond) +inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond) { - jit->wrfuncs.write_ubyte(jit, IA32_SETCC_RM8_1); - jit->wrfuncs.write_ubyte(jit, IA32_SETCC_RM8_2+cond); - jit->wrfuncs.write_ubyte(jit, ia32_modrm(MOD_REG, 0, reg)); + jit->write_ubyte(jit, IA32_SETCC_RM8_1); + jit->write_ubyte(jit, IA32_SETCC_RM8_2+cond); + jit->write_ubyte(jit, ia32_modrm(MOD_REG, 0, reg)); } -inline void IA32_Rep(jitinfo_t *jit) +inline void IA32_Rep(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_REP); + jit->write_ubyte(jit, IA32_REP); } -inline void IA32_Movsd(jitinfo_t *jit) +inline void IA32_Movsd(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_MOVSD); + jit->write_ubyte(jit, IA32_MOVSD); } -inline void IA32_Movsb(jitinfo_t *jit) +inline void IA32_Movsb(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_MOVSB); + jit->write_ubyte(jit, IA32_MOVSB); } -inline void IA32_Stosd(jitinfo_t *jit) +inline void IA32_Stosd(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_STOSD); + jit->write_ubyte(jit, IA32_STOSD); } -inline void IA32_Cld(jitinfo_t *jit) +inline void IA32_Cld(JitWriter *jit) { - jit->wrfuncs.write_ubyte(jit, IA32_CLD); + jit->write_ubyte(jit, IA32_CLD); } #endif //_INCLUDE_JIT_X86_MACROS_H From f7df595ca51498bec8e3c315d5dc505a4bdc2cc8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 02:56:20 +0000 Subject: [PATCH 0045/1664] note! we're still not at the point of a build committed here to fill in more structural integrity --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4075 --- sourcepawn/vm/jit/jit_helpers.h | 4 +- sourcepawn/vm/jit/x86/jit_x86.cpp | 400 +++++++++++--------- sourcepawn/vm/jit/x86/jit_x86.h | 182 +-------- sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 12 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 267 +++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 184 +++++++++ sourcepawn/vm/jit/x86/x86_macros.h | 414 ++++++++++----------- 7 files changed, 914 insertions(+), 549 deletions(-) create mode 100644 sourcepawn/vm/jit/x86/opcode_helpers.cpp create mode 100644 sourcepawn/vm/jit/x86/opcode_helpers.h diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index 0b8fcda6..bbfda1ec 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -32,7 +32,7 @@ public: inptr++; return val; } - inline cell_t read_cellptr() + inline cell_t *read_cellptr() { cell_t *val = *(cell_t **)(inptr); inptr++; @@ -58,7 +58,7 @@ public: { if (outptr) { - *(jit_int32_t *)ptr = c; + *(jit_int32_t *)outptr = c; } outptr += sizeof(jit_int32_t); } diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 18870336..0e6bb669 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1,183 +1,129 @@ #include #include #include "jit_x86.h" +#include "..\jit_helpers.h" +#include "opcode_helpers.h" +#include "x86_macros.h" -int OpAdvTable[OP_NUM_OPCODES]; - -JITX86::JITX86() +inline void WriteOp_Move_Pri(JitWriter *jit) { - memset(OpAdvTable, -1, sizeof(OpAdvTable)); + //mov eax, edx + IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} - /* instructions with 5 parameters */ - OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5; +inline void WriteOp_Move_Alt(JitWriter *jit) +{ + //mov edx, eax + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); +} - /* instructions with 4 parameters */ - OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4; +inline void WriteOp_Xchg(JitWriter *jit) +{ + /* :TODO: change this? */ + //xchg eax, edx + IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT); +} - /* instructions with 3 parameters */ - OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3; +inline void WriteOp_Push(JitWriter *jit) +{ + //push stack, DAT offset based + //sub ebp, 4 + //mov ecx, [edi+] + //mov [ebp], ecx + cell_t val = jit->read_cell(); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + //optimize encoding a bit... + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); +} - /* instructions with 2 parameters */ - OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2; - OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2; - OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; - OpAdvTable[OP_CONST] = sizeof(cell_t)*2; - OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; +inline void WriteOp_Push_S(JitWriter *jit) +{ + //push stack, FRM offset based + //sub ebp, 4 + //mov ecx, [ebx+] + //mov [ebp], ecx + cell_t val = jit->read_cell(); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + //optimize encoding a bit... + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); +} - /* instructions with 1 parameter */ - OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); - OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t); - OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_LREF_PRI] = sizeof(cell_t); - OpAdvTable[OP_LREF_ALT] = sizeof(cell_t); - OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_LODB_I] = sizeof(cell_t); - OpAdvTable[OP_CONST_PRI] = sizeof(cell_t); - OpAdvTable[OP_CONST_ALT] = sizeof(cell_t); - OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t); - OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t); - OpAdvTable[OP_STOR_PRI] = sizeof(cell_t); - OpAdvTable[OP_STOR_ALT] = sizeof(cell_t); - OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_SREF_PRI] = sizeof(cell_t); - OpAdvTable[OP_SREF_ALT] = sizeof(cell_t); - OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_STRB_I] = sizeof(cell_t); - OpAdvTable[OP_LIDX_B] = sizeof(cell_t); - OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t); - OpAdvTable[OP_ALIGN_PRI] = sizeof(cell_t); - OpAdvTable[OP_ALIGN_ALT] = sizeof(cell_t); - OpAdvTable[OP_LCTRL] = sizeof(cell_t); - OpAdvTable[OP_SCTRL] = sizeof(cell_t); - OpAdvTable[OP_PUSH_R] = sizeof(cell_t); - OpAdvTable[OP_PUSH_C] = sizeof(cell_t); - OpAdvTable[OP_PUSH] = sizeof(cell_t); - OpAdvTable[OP_PUSH_S] = sizeof(cell_t); - OpAdvTable[OP_STACK] = sizeof(cell_t); - OpAdvTable[OP_HEAP] = sizeof(cell_t); - OpAdvTable[OP_JREL] = sizeof(cell_t); - OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_ADD_C] = sizeof(cell_t); - OpAdvTable[OP_SMUL_C] = sizeof(cell_t); - OpAdvTable[OP_ZERO] = sizeof(cell_t); - OpAdvTable[OP_ZERO_S] = sizeof(cell_t); - OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_INC] = sizeof(cell_t); - OpAdvTable[OP_INC_S] = sizeof(cell_t); - OpAdvTable[OP_DEC] = sizeof(cell_t); - OpAdvTable[OP_DEC_S] = sizeof(cell_t); - OpAdvTable[OP_MOVS] = sizeof(cell_t); - OpAdvTable[OP_CMPS] = sizeof(cell_t); - OpAdvTable[OP_FILL] = sizeof(cell_t); - OpAdvTable[OP_HALT] = sizeof(cell_t); - OpAdvTable[OP_BOUNDS] = sizeof(cell_t); - OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); +inline void WriteOp_Push4_C(JitWriter *jit) +{ + Macro_PushN_C(jit, 4); +} - /* instructions with 0 parameters */ - OpAdvTable[OP_LOAD_I] = 0; - OpAdvTable[OP_STOR_I] = 0; - OpAdvTable[OP_LIDX] = 0; - OpAdvTable[OP_IDXADDR] = 0; - OpAdvTable[OP_MOVE_PRI] = 0; - OpAdvTable[OP_MOVE_ALT] = 0; - OpAdvTable[OP_XCHG] = 0; - OpAdvTable[OP_PUSH_PRI] = 0; - OpAdvTable[OP_PUSH_ALT] = 0; - OpAdvTable[OP_POP_PRI] = 0; - OpAdvTable[OP_POP_ALT] = 0; - OpAdvTable[OP_PROC] = 0; - OpAdvTable[OP_RET] = 0; - OpAdvTable[OP_RETN] = 0; - OpAdvTable[OP_CALL_PRI] = 0; - OpAdvTable[OP_SHL] = 0; - OpAdvTable[OP_SHR] = 0; - OpAdvTable[OP_SSHR] = 0; - OpAdvTable[OP_SMUL] = 0; - OpAdvTable[OP_SDIV] = 0; - OpAdvTable[OP_SDIV_ALT] = 0; - OpAdvTable[OP_UMUL] = 0; - OpAdvTable[OP_UDIV] = 0; - OpAdvTable[OP_UDIV_ALT] = 0; - OpAdvTable[OP_ADD] = 0; - OpAdvTable[OP_SUB] = 0; - OpAdvTable[OP_SUB_ALT] = 0; - OpAdvTable[OP_AND] = 0; - OpAdvTable[OP_OR] = 0; - OpAdvTable[OP_XOR] = 0; - OpAdvTable[OP_NOT] = 0; - OpAdvTable[OP_NEG] = 0; - OpAdvTable[OP_INVERT] = 0; - OpAdvTable[OP_ZERO_PRI] = 0; - OpAdvTable[OP_ZERO_ALT] = 0; - OpAdvTable[OP_SIGN_PRI] = 0; - OpAdvTable[OP_SIGN_ALT] = 0; - OpAdvTable[OP_EQ] = 0; - OpAdvTable[OP_NEQ] = 0; - OpAdvTable[OP_LESS] = 0; - OpAdvTable[OP_LEQ] = 0; - OpAdvTable[OP_GRTR] = 0; - OpAdvTable[OP_GEQ] = 0; - OpAdvTable[OP_SLESS] = 0; - OpAdvTable[OP_SLEQ] = 0; - OpAdvTable[OP_SGRTR] = 0; - OpAdvTable[OP_SGEQ] = 0; - OpAdvTable[OP_INC_PRI] = 0; - OpAdvTable[OP_INC_ALT] = 0; - OpAdvTable[OP_INC_I] = 0; - OpAdvTable[OP_DEC_PRI] = 0; - OpAdvTable[OP_DEC_ALT] = 0; - OpAdvTable[OP_DEC_I] = 0; - OpAdvTable[OP_JUMP_PRI] = 0; - OpAdvTable[OP_SWAP_PRI] = 0; - OpAdvTable[OP_SWAP_ALT] = 0; - OpAdvTable[OP_NOP] = 0; - OpAdvTable[OP_BREAK] = 0; +inline void WriteOp_Push5_C(JitWriter *jit) +{ + Macro_PushN_C(jit, 5); +} - /* opcodes that need relocation */ - OpAdvTable[OP_CALL] = -2; - OpAdvTable[OP_JUMP] = -2; - OpAdvTable[OP_JZER] = -2; - OpAdvTable[OP_JNZ] = -2; - OpAdvTable[OP_JEQ] = -2; - OpAdvTable[OP_JNEQ] = -2; - OpAdvTable[OP_JLESS] = -2; - OpAdvTable[OP_JLEQ] = -2; - OpAdvTable[OP_JGRTR] = -2; - OpAdvTable[OP_JGEQ] = -2; - OpAdvTable[OP_JSLESS] = -2; - OpAdvTable[OP_JSLEQ] = -2; - OpAdvTable[OP_JSGRTR] = -2; - OpAdvTable[OP_JSGEQ] = -2; - OpAdvTable[OP_SWITCH] = -2; +inline void WriteOp_Push2_Adr(JitWriter *jit) +{ + Macro_PushN_Addr(jit, 2); +} - /* opcodes that are totally invalid */ - OpAdvTable[OP_FILE] = -3; - OpAdvTable[OP_SYMBOL] = -3; - OpAdvTable[OP_LINE] = -3; - OpAdvTable[OP_SRANGE] = -3; - OpAdvTable[OP_SYMTAG] = -3; - OpAdvTable[OP_SYSREQ_D] = -3; - OpAdvTable[OP_SYSREQ_ND] = -3; +inline void WriteOp_Push3_Adr(JitWriter *jit) +{ + Macro_PushN_Addr(jit, 3); +} + +inline void WriteOp_Push4_Adr(JitWriter *jit) +{ + Macro_PushN_Addr(jit, 4); +} + +inline void WriteOp_Push5_Adr(JitWriter *jit) +{ + Macro_PushN_Addr(jit, 5); +} + +inline void WriteOp_Push2_S(JitWriter *jit) +{ + Macro_PushN_S(jit, 2); +} + +inline void WriteOp_Push3_S(JitWriter *jit) +{ + Macro_PushN_S(jit, 3); +} + +inline void WriteOp_Push4_S(JitWriter *jit) +{ + Macro_PushN_S(jit, 4); +} + +inline void WriteOp_Push5_S(JitWriter *jit) +{ + Macro_PushN_S(jit, 5); +} + +inline void WriteOp_Push5(JitWriter *jit) +{ + Macro_PushN(jit, 5); +} + +inline void WriteOp_Push4(JitWriter *jit) +{ + Macro_PushN(jit, 4); +} + +inline void WriteOp_Push3(JitWriter *jit) +{ + Macro_PushN(jit, 3); +} + +inline void WriteOp_Push2(JitWriter *jit) +{ + Macro_PushN(jit, 2); } IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) @@ -246,6 +192,126 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) } } + JitWriter writer; + + writer.inptr = (cell_t *)code; + writer.outptr = NULL; + writer.outbase = NULL; + +//redo_pass: + /* SECOND PASS (medium load): writer.outbase is NULL, getting size only + * THIRD PASS (heavy load!!): writer.outbase is valid and output is written + */ + cell_t *endptr = (cell_t *)(end_cip); + JitWriter *jit = &writer; + for (; writer.inptr <= endptr;) + { + op = (OPCODE)writer.read_cell(); + switch (op) + { + case OP_MOVE_PRI: + { + WriteOp_Move_Pri(jit); + break; + } + case OP_MOVE_ALT: + { + WriteOp_Move_Alt(jit); + break; + } + case OP_XCHG: + { + WriteOp_Xchg(jit); + break; + } + case OP_PUSH: + { + WriteOp_Push(jit); + break; + } + case OP_PUSH_S: + { + WriteOp_Push_S(jit); + break; + } + case OP_PUSH4_C: + { + WriteOp_Push4_C(jit); + break; + } + case OP_PUSH5_C: + { + WriteOp_Push5_C(jit); + break; + } + case OP_PUSH2_ADR: + { + WriteOp_Push2_Adr(jit); + break; + } + case OP_PUSH3_ADR: + { + WriteOp_Push3_Adr(jit); + break; + } + case OP_PUSH4_ADR: + { + WriteOp_Push4_Adr(jit); + break; + } + case OP_PUSH5_ADR: + { + WriteOp_Push5_Adr(jit); + break; + } + case OP_PUSH2_S: + { + WriteOp_Push2_S(jit); + break; + } + case OP_PUSH3_S: + { + WriteOp_Push3_S(jit); + break; + } + case OP_PUSH4_S: + { + WriteOp_Push4_S(jit); + break; + } + case OP_PUSH5_S: + { + WriteOp_Push5_S(jit); + break; + } + case OP_PUSH5: + { + WriteOp_Push5(jit); + break; + } + case OP_PUSH4: + { + WriteOp_Push4(jit); + break; + } + case OP_PUSH3: + { + WriteOp_Push3(jit); + break; + } + case OP_PUSH2: + { + WriteOp_Push2(jit); + break; + } + default: + { + /* :TODO: error! */ + break; + } + } + } + *err = SP_ERR_NONE; return NULL; diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index acc1764a..b78ca8a2 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -1,6 +1,7 @@ #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_H_ +#include #include using namespace SourcePawn; @@ -31,175 +32,16 @@ public: int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; -typedef enum -{ - OP_NONE, /* invalid opcode */ - OP_LOAD_PRI, //DONE - OP_LOAD_ALT, //DONE - OP_LOAD_S_PRI, //DONE - OP_LOAD_S_ALT, //DONE - OP_LREF_PRI, //DONE - OP_LREF_ALT, //DONE - OP_LREF_S_PRI, //DONE - OP_LREF_S_ALT, //DONE - OP_LOAD_I, //DONE - OP_LODB_I, - OP_CONST_PRI, //DONE - OP_CONST_ALT, //DONE - OP_ADDR_PRI, //DONE - OP_ADDR_ALT, //DONE - OP_STOR_PRI, //DONE - OP_STOR_ALT, //DONE - OP_STOR_S_PRI, //DONE - OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //DONE - OP_SREF_ALT, //DONE - OP_SREF_S_PRI, //DONE - OP_SREF_S_ALT, //DONE - OP_STOR_I, //DONE - OP_STRB_I, - OP_LIDX, //DONE - OP_LIDX_B, - OP_IDXADDR, //DONE - OP_IDXADDR_B, - OP_ALIGN_PRI, //DONE - OP_ALIGN_ALT, //DONE - OP_LCTRL, - OP_SCTRL, - OP_MOVE_PRI, //DONE - OP_MOVE_ALT, //DONE - OP_XCHG, //DONE - OP_PUSH_PRI, //DONE - OP_PUSH_ALT, //DONE - OP_PUSH_R, //DONE - OP_PUSH_C, //DONE - OP_PUSH, //DONE - OP_PUSH_S, //DONE - OP_POP_PRI, //DONE - OP_POP_ALT, //DONE - OP_STACK, //DONE - OP_HEAP, //DONE - OP_PROC, //DONE - OP_RET, - OP_RETN, //DONE - OP_CALL, - OP_CALL_PRI, - OP_JUMP, //DONE - OP_JREL, //DONE - OP_JZER, //DONE - OP_JNZ, //DONE - OP_JEQ, //DONE - OP_JNEQ, //DONE - OP_JLESS, //DONE - OP_JLEQ, //DONE - OP_JGRTR, //DONE - OP_JGEQ, //DONE - OP_JSLESS, //DONE - OP_JSLEQ, //DONE - OP_JSGRTR, //DONE - OP_JSGEQ, //DONE - OP_SHL, //DONE - OP_SHR, //DONE - OP_SSHR, //DONE - OP_SHL_C_PRI, //DONE - OP_SHL_C_ALT, //DONE - OP_SHR_C_PRI, //DONE - OP_SHR_C_ALT, //DONE - OP_SMUL, //DONE - OP_SDIV, //DONE - OP_SDIV_ALT, //DONE - OP_UMUL, //DONE - OP_UDIV, //DONE - OP_UDIV_ALT, //DONE - OP_ADD, //DONE - OP_SUB, //DONE - OP_SUB_ALT, //DONE - OP_AND, //DONE - OP_OR, //DONE - OP_XOR, //DONE - OP_NOT, //DONE - OP_NEG, //DONE - OP_INVERT, //DONE - OP_ADD_C, //DONE - OP_SMUL_C, //DONE - OP_ZERO_PRI, //DONE - OP_ZERO_ALT, //DONE - OP_ZERO, //DONE - OP_ZERO_S, //DONE - OP_SIGN_PRI, //DONE - OP_SIGN_ALT, //DONE - OP_EQ, //DONE - OP_NEQ, //DONE - OP_LESS, //DONE - OP_LEQ, //DONE - OP_GRTR, //DONE - OP_GEQ, //DONE - OP_SLESS, //DONE - OP_SLEQ, //DONE - OP_SGRTR, //DONE - OP_SGEQ, //DONE - OP_EQ_C_PRI, //DONE - OP_EQ_C_ALT, //DONE - OP_INC_PRI, //DONE - OP_INC_ALT, //DONE - OP_INC, //DONE - OP_INC_S, //DONE - OP_INC_I, //DONE - OP_DEC_PRI, //DONE - OP_DEC_ALT, //DONE - OP_DEC, //DONE - OP_DEC_S, //DONE - OP_DEC_I, //DONE - OP_MOVS, //DONE - OP_CMPS, //DONE - OP_FILL, //DONE - OP_HALT, //DONE - OP_BOUNDS, - OP_SYSREQ_PRI, - OP_SYSREQ_C, - OP_FILE, - OP_LINE, - OP_SYMBOL, - OP_SRANGE, - OP_JUMP_PRI, - OP_SWITCH, - OP_CASETBL, //DONE - OP_SWAP_PRI, //DONE - OP_SWAP_ALT, //DONE - OP_PUSH_ADR, //DONE - OP_NOP, //DONE - OP_SYSREQ_N, - OP_SYMTAG, - OP_BREAK, - OP_PUSH2_C, //DONE - OP_PUSH2, //DONE - OP_PUSH2_S, //DONE - OP_PUSH2_ADR, //DONE - OP_PUSH3_C, //DONE - OP_PUSH3, //DONE - OP_PUSH3_S, //DONE - OP_PUSH3_ADR, //DONE - OP_PUSH4_C, //DONE - OP_PUSH4, //DONE - OP_PUSH4_S, //DONE - OP_PUSH4_ADR, //DONE - OP_PUSH5_C, //DONE - OP_PUSH5, //DONE - OP_PUSH5_S, //DONE - OP_PUSH5_ADR, //DONE - OP_LOAD_BOTH, - OP_LOAD_S_BOTH, - OP_CONST, - OP_CONST_S, - /* ----- */ - OP_SYSREQ_D, - OP_SYSREQ_ND, - /* ----- */ - OP_HEAP_PRI, - OP_PUSH_HEAP_C, - OP_POP_HEAP_PRI, - /* ----- */ - OP_NUM_OPCODES -} OPCODE; +#define AMX_REG_PRI REG_EAX +#define AMX_REG_ALT REG_EDX +#define AMX_REG_STK REG_EBP +#define AMX_REG_DAT REG_EDI +#define AMX_REG_TMP REG_ECX +#define AMX_REG_INFO REG_ESI +#define AMX_REG_FRM REG_EBX + +#define AMX_INFO_FRM AMX_REG_INFO +#define AMX_INFO_HEAP 4 +#define AMX_INFO_RETVAL 12 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj index 037ef66b..f5607836 100644 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj @@ -191,6 +191,10 @@ RelativePath="..\jit_x86.cpp" > + + + + diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp new file mode 100644 index 00000000..879abbf1 --- /dev/null +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -0,0 +1,267 @@ +#include +#include +#include "jit_x86.h" +#include "opcode_helpers.h" +#include "x86_macros.h" + +int OpAdvTable[OP_NUM_OPCODES]; + +void Macro_PushN_Addr(JitWriter *jit, int i) +{ + //push eax + //mov eax, frm + //loop i times: + // lea ecx, [eax+] + // mov [ebp-4*i], ecx + //sub ebp, 4*N + //pop eax + + cell_t val; + int n = 1; + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_INFO_FRM, MOD_MEM_REG); + do + { + val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val); + else + IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); + } while (n++ < i); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + +void Macro_PushN_S(JitWriter *jit, int i) +{ + //loop i times: + // mov ecx, [ebx+] + // mov [ebp-4*i], ecx + //sub ebp, 4*N + + cell_t val; + int n = 1; + do + { + val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); + } while (n++ < i); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); +} + +void Macro_PushN_C(JitWriter *jit, int i) +{ + //loop i times: + // mov [ebp-4*i], + //sub ebp, 4*N + + int n = 1; + do + { + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n); + } while (n++ < i); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); +} + +void Macro_PushN(JitWriter *jit, int i) +{ + //loop i times: + // mov ecx, [edi+] + // mov [ebp-4*i], ecx + //sub ebp, 4*N + + cell_t val; + int n = 1; + do + { + val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); + } while (n++ < i); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); +} + +JITX86::JITX86() +{ + memset(OpAdvTable, -1, sizeof(OpAdvTable)); + + /* instructions with 5 parameters */ + OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5; + OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5; + + /* instructions with 4 parameters */ + OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4; + OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4; + + /* instructions with 3 parameters */ + OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3; + OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3; + + /* instructions with 2 parameters */ + OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2; + OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2; + OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2; + OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; + OpAdvTable[OP_CONST] = sizeof(cell_t)*2; + OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; + + /* instructions with 1 parameter */ + OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); + OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t); + OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_LREF_PRI] = sizeof(cell_t); + OpAdvTable[OP_LREF_ALT] = sizeof(cell_t); + OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_LODB_I] = sizeof(cell_t); + OpAdvTable[OP_CONST_PRI] = sizeof(cell_t); + OpAdvTable[OP_CONST_ALT] = sizeof(cell_t); + OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t); + OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t); + OpAdvTable[OP_STOR_PRI] = sizeof(cell_t); + OpAdvTable[OP_STOR_ALT] = sizeof(cell_t); + OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_SREF_PRI] = sizeof(cell_t); + OpAdvTable[OP_SREF_ALT] = sizeof(cell_t); + OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t); + OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t); + OpAdvTable[OP_STRB_I] = sizeof(cell_t); + OpAdvTable[OP_LIDX_B] = sizeof(cell_t); + OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t); + OpAdvTable[OP_ALIGN_PRI] = sizeof(cell_t); + OpAdvTable[OP_ALIGN_ALT] = sizeof(cell_t); + OpAdvTable[OP_LCTRL] = sizeof(cell_t); + OpAdvTable[OP_SCTRL] = sizeof(cell_t); + OpAdvTable[OP_PUSH_C] = sizeof(cell_t); + OpAdvTable[OP_PUSH] = sizeof(cell_t); + OpAdvTable[OP_PUSH_S] = sizeof(cell_t); + OpAdvTable[OP_STACK] = sizeof(cell_t); + OpAdvTable[OP_HEAP] = sizeof(cell_t); + OpAdvTable[OP_JREL] = sizeof(cell_t); + OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_ADD_C] = sizeof(cell_t); + OpAdvTable[OP_SMUL_C] = sizeof(cell_t); + OpAdvTable[OP_ZERO] = sizeof(cell_t); + OpAdvTable[OP_ZERO_S] = sizeof(cell_t); + OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t); + OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t); + OpAdvTable[OP_INC] = sizeof(cell_t); + OpAdvTable[OP_INC_S] = sizeof(cell_t); + OpAdvTable[OP_DEC] = sizeof(cell_t); + OpAdvTable[OP_DEC_S] = sizeof(cell_t); + OpAdvTable[OP_MOVS] = sizeof(cell_t); + OpAdvTable[OP_CMPS] = sizeof(cell_t); + OpAdvTable[OP_FILL] = sizeof(cell_t); + OpAdvTable[OP_HALT] = sizeof(cell_t); + OpAdvTable[OP_BOUNDS] = sizeof(cell_t); + OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); + + /* instructions with 0 parameters */ + OpAdvTable[OP_LOAD_I] = 0; + OpAdvTable[OP_STOR_I] = 0; + OpAdvTable[OP_LIDX] = 0; + OpAdvTable[OP_IDXADDR] = 0; + OpAdvTable[OP_MOVE_PRI] = 0; + OpAdvTable[OP_MOVE_ALT] = 0; + OpAdvTable[OP_XCHG] = 0; + OpAdvTable[OP_PUSH_PRI] = 0; + OpAdvTable[OP_PUSH_ALT] = 0; + OpAdvTable[OP_POP_PRI] = 0; + OpAdvTable[OP_POP_ALT] = 0; + OpAdvTable[OP_PROC] = 0; + OpAdvTable[OP_RET] = 0; + OpAdvTable[OP_RETN] = 0; + OpAdvTable[OP_CALL_PRI] = 0; + OpAdvTable[OP_SHL] = 0; + OpAdvTable[OP_SHR] = 0; + OpAdvTable[OP_SSHR] = 0; + OpAdvTable[OP_SMUL] = 0; + OpAdvTable[OP_SDIV] = 0; + OpAdvTable[OP_SDIV_ALT] = 0; + OpAdvTable[OP_UMUL] = 0; + OpAdvTable[OP_UDIV] = 0; + OpAdvTable[OP_UDIV_ALT] = 0; + OpAdvTable[OP_ADD] = 0; + OpAdvTable[OP_SUB] = 0; + OpAdvTable[OP_SUB_ALT] = 0; + OpAdvTable[OP_AND] = 0; + OpAdvTable[OP_OR] = 0; + OpAdvTable[OP_XOR] = 0; + OpAdvTable[OP_NOT] = 0; + OpAdvTable[OP_NEG] = 0; + OpAdvTable[OP_INVERT] = 0; + OpAdvTable[OP_ZERO_PRI] = 0; + OpAdvTable[OP_ZERO_ALT] = 0; + OpAdvTable[OP_SIGN_PRI] = 0; + OpAdvTable[OP_SIGN_ALT] = 0; + OpAdvTable[OP_EQ] = 0; + OpAdvTable[OP_NEQ] = 0; + OpAdvTable[OP_LESS] = 0; + OpAdvTable[OP_LEQ] = 0; + OpAdvTable[OP_GRTR] = 0; + OpAdvTable[OP_GEQ] = 0; + OpAdvTable[OP_SLESS] = 0; + OpAdvTable[OP_SLEQ] = 0; + OpAdvTable[OP_SGRTR] = 0; + OpAdvTable[OP_SGEQ] = 0; + OpAdvTable[OP_INC_PRI] = 0; + OpAdvTable[OP_INC_ALT] = 0; + OpAdvTable[OP_INC_I] = 0; + OpAdvTable[OP_DEC_PRI] = 0; + OpAdvTable[OP_DEC_ALT] = 0; + OpAdvTable[OP_DEC_I] = 0; + OpAdvTable[OP_JUMP_PRI] = 0; + OpAdvTable[OP_SWAP_PRI] = 0; + OpAdvTable[OP_SWAP_ALT] = 0; + OpAdvTable[OP_NOP] = 0; + OpAdvTable[OP_BREAK] = 0; + + /* opcodes that need relocation */ + OpAdvTable[OP_CALL] = -2; + OpAdvTable[OP_JUMP] = -2; + OpAdvTable[OP_JZER] = -2; + OpAdvTable[OP_JNZ] = -2; + OpAdvTable[OP_JEQ] = -2; + OpAdvTable[OP_JNEQ] = -2; + OpAdvTable[OP_JLESS] = -2; + OpAdvTable[OP_JLEQ] = -2; + OpAdvTable[OP_JGRTR] = -2; + OpAdvTable[OP_JGEQ] = -2; + OpAdvTable[OP_JSLESS] = -2; + OpAdvTable[OP_JSLEQ] = -2; + OpAdvTable[OP_JSGRTR] = -2; + OpAdvTable[OP_JSGEQ] = -2; + OpAdvTable[OP_SWITCH] = -2; + + /* opcodes that are totally invalid */ + OpAdvTable[OP_FILE] = -3; + OpAdvTable[OP_SYMBOL] = -3; + OpAdvTable[OP_LINE] = -3; + OpAdvTable[OP_SRANGE] = -3; + OpAdvTable[OP_SYMTAG] = -3; + OpAdvTable[OP_SYSREQ_D] = -3; + OpAdvTable[OP_SYSREQ_ND] = -3; + OpAdvTable[OP_PUSH_R] = -3; +} + diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h new file mode 100644 index 00000000..66dc13d9 --- /dev/null +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -0,0 +1,184 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ +#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ + +#include "..\jit_helpers.h" + +void Macro_PushN_Addr(JitWriter *jit, int i); +void Macro_PushN_S(JitWriter *jit, int i); +void Macro_PushN_C(JitWriter *jit, int i); +void Macro_PushN(JitWriter *jit, int i); + +typedef enum +{ + OP_NONE, /* invalid opcode */ + OP_LOAD_PRI, //DONE + OP_LOAD_ALT, //DONE + OP_LOAD_S_PRI, //DONE + OP_LOAD_S_ALT, //DONE + OP_LREF_PRI, //DONE + OP_LREF_ALT, //DONE + OP_LREF_S_PRI, //DONE + OP_LREF_S_ALT, //DONE + OP_LOAD_I, //DONE + OP_LODB_I, + OP_CONST_PRI, //DONE + OP_CONST_ALT, //DONE + OP_ADDR_PRI, //DONE + OP_ADDR_ALT, //DONE + OP_STOR_PRI, //DONE + OP_STOR_ALT, //DONE + OP_STOR_S_PRI, //DONE + OP_STOR_S_ALT, //DONE + OP_SREF_PRI, //DONE + OP_SREF_ALT, //DONE + OP_SREF_S_PRI, //DONE + OP_SREF_S_ALT, //DONE + OP_STOR_I, //DONE + OP_STRB_I, + OP_LIDX, //DONE + OP_LIDX_B, + OP_IDXADDR, //DONE + OP_IDXADDR_B, + OP_ALIGN_PRI, //DONE + OP_ALIGN_ALT, //DONE + OP_LCTRL, + OP_SCTRL, + OP_MOVE_PRI, //DONE + OP_MOVE_ALT, //DONE + OP_XCHG, //DONE + OP_PUSH_PRI, //DONE + OP_PUSH_ALT, //DONE + OP_PUSH_R, //DONE + OP_PUSH_C, //DONE + OP_PUSH, //DONE + OP_PUSH_S, //DONE + OP_POP_PRI, //DONE + OP_POP_ALT, //DONE + OP_STACK, //DONE + OP_HEAP, //DONE + OP_PROC, //DONE + OP_RET, + OP_RETN, //DONE + OP_CALL, + OP_CALL_PRI, + OP_JUMP, //DONE + OP_JREL, //DONE + OP_JZER, //DONE + OP_JNZ, //DONE + OP_JEQ, //DONE + OP_JNEQ, //DONE + OP_JLESS, //DONE + OP_JLEQ, //DONE + OP_JGRTR, //DONE + OP_JGEQ, //DONE + OP_JSLESS, //DONE + OP_JSLEQ, //DONE + OP_JSGRTR, //DONE + OP_JSGEQ, //DONE + OP_SHL, //DONE + OP_SHR, //DONE + OP_SSHR, //DONE + OP_SHL_C_PRI, //DONE + OP_SHL_C_ALT, //DONE + OP_SHR_C_PRI, //DONE + OP_SHR_C_ALT, //DONE + OP_SMUL, //DONE + OP_SDIV, //DONE + OP_SDIV_ALT, //DONE + OP_UMUL, //DONE + OP_UDIV, //DONE + OP_UDIV_ALT, //DONE + OP_ADD, //DONE + OP_SUB, //DONE + OP_SUB_ALT, //DONE + OP_AND, //DONE + OP_OR, //DONE + OP_XOR, //DONE + OP_NOT, //DONE + OP_NEG, //DONE + OP_INVERT, //DONE + OP_ADD_C, //DONE + OP_SMUL_C, //DONE + OP_ZERO_PRI, //DONE + OP_ZERO_ALT, //DONE + OP_ZERO, //DONE + OP_ZERO_S, //DONE + OP_SIGN_PRI, //DONE + OP_SIGN_ALT, //DONE + OP_EQ, //DONE + OP_NEQ, //DONE + OP_LESS, //DONE + OP_LEQ, //DONE + OP_GRTR, //DONE + OP_GEQ, //DONE + OP_SLESS, //DONE + OP_SLEQ, //DONE + OP_SGRTR, //DONE + OP_SGEQ, //DONE + OP_EQ_C_PRI, //DONE + OP_EQ_C_ALT, //DONE + OP_INC_PRI, //DONE + OP_INC_ALT, //DONE + OP_INC, //DONE + OP_INC_S, //DONE + OP_INC_I, //DONE + OP_DEC_PRI, //DONE + OP_DEC_ALT, //DONE + OP_DEC, //DONE + OP_DEC_S, //DONE + OP_DEC_I, //DONE + OP_MOVS, //DONE + OP_CMPS, //DONE + OP_FILL, //DONE + OP_HALT, //DONE + OP_BOUNDS, + OP_SYSREQ_PRI, + OP_SYSREQ_C, + OP_FILE, + OP_LINE, + OP_SYMBOL, + OP_SRANGE, + OP_JUMP_PRI, + OP_SWITCH, + OP_CASETBL, //DONE + OP_SWAP_PRI, //DONE + OP_SWAP_ALT, //DONE + OP_PUSH_ADR, //DONE + OP_NOP, //DONE + OP_SYSREQ_N, + OP_SYMTAG, + OP_BREAK, + OP_PUSH2_C, //DONE + OP_PUSH2, //DONE + OP_PUSH2_S, //DONE + OP_PUSH2_ADR, //DONE + OP_PUSH3_C, //DONE + OP_PUSH3, //DONE + OP_PUSH3_S, //DONE + OP_PUSH3_ADR, //DONE + OP_PUSH4_C, //DONE + OP_PUSH4, //DONE + OP_PUSH4_S, //DONE + OP_PUSH4_ADR, //DONE + OP_PUSH5_C, //DONE + OP_PUSH5, //DONE + OP_PUSH5_S, //DONE + OP_PUSH5_ADR, //DONE + OP_LOAD_BOTH, + OP_LOAD_S_BOTH, + OP_CONST, + OP_CONST_S, + /* ----- */ + OP_SYSREQ_D, + OP_SYSREQ_ND, + /* ----- */ + OP_HEAP_PRI, + OP_PUSH_HEAP_C, + OP_POP_HEAP_PRI, + /* ----- */ + OP_NUM_OPCODES +} OPCODE; + +extern int OpAdvTable[]; + +#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index ec373613..45ba5d8b 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -1,8 +1,6 @@ #ifndef _INCLUDE_JIT_X86_MACROS_H #define _INCLUDE_JIT_X86_MACROS_H -#include "..\jit_helpers.h" - //MOD R/M #define MOD_MEM_REG 0 #define MOD_DISP8 1 @@ -138,54 +136,54 @@ inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t bas inline void IA32_Inc_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) { - jit->write_ubyte(jit, IA32_INC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, reg)); - jit->write_int32(jit, disp); + jit->write_ubyte(IA32_INC_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, reg)); + jit->write_int32(disp); } inline void IA32_Inc_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) { - jit->write_ubyte(jit, IA32_INC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, reg)); - jit->write_byte(jit, disp); + jit->write_ubyte(IA32_INC_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, reg)); + jit->write_byte(disp); } inline void IA32_Inc_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) { - jit->write_ubyte(jit, IA32_INC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(scale, reg, base)); + jit->write_ubyte(IA32_INC_RM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, reg, base)); } inline void IA32_Inc_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(jit, IA32_INC_REG+reg); + jit->write_ubyte(IA32_INC_REG+reg); } inline void IA32_Dec_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) { - jit->write_ubyte(jit, IA32_DEC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 1, reg)); - jit->write_int32(jit, disp); + jit->write_ubyte(IA32_DEC_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 1, reg)); + jit->write_int32(disp); } inline void IA32_Dec_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) { - jit->write_ubyte(jit, IA32_DEC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 1, reg)); - jit->write_byte(jit, disp); + jit->write_ubyte(IA32_DEC_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, reg)); + jit->write_byte(disp); } inline void IA32_Dec_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) { - jit->write_ubyte(jit, IA32_DEC_RM); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(scale, reg, base)); + jit->write_ubyte(IA32_DEC_RM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, reg, base)); } inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(jit, IA32_DEC_REG+reg); + jit->write_ubyte(IA32_DEC_REG+reg); } /**************** @@ -194,102 +192,102 @@ inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg) inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) { - jit->write_ubyte(jit, IA32_XOR_RM_REG); - jit->write_ubyte(jit, ia32_modrm(dest_mode, src, dest)); + jit->write_ubyte(IA32_XOR_RM_REG); + jit->write_ubyte(ia32_modrm(dest_mode, src, dest)); } inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->write_ubyte(jit, IA32_XOR_EAX_IMM32); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_XOR_EAX_IMM32); + jit->write_int32(value); } inline void IA32_Xor_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) { - jit->write_ubyte(jit, IA32_XOR_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_XOR_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 6, reg)); + jit->write_int32(value); } inline void IA32_Xor_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) { - jit->write_ubyte(jit, IA32_XOR_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); - jit->write_byte(jit, value); + jit->write_ubyte(IA32_XOR_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 6, reg)); + jit->write_byte(value); } inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_NEG_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 3, reg)); + jit->write_ubyte(IA32_NEG_RM); + jit->write_ubyte(ia32_modrm(mode, 3, reg)); } inline void IA32_Or_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_OR_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_OR_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_And_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_AND_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_AND_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_NOT_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 2, reg)); + jit->write_ubyte(IA32_NOT_RM); + jit->write_ubyte(ia32_modrm(mode, 2, reg)); } inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SHR_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 5, dest)); - jit->write_ubyte(jit, value); + jit->write_ubyte(IA32_SHR_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 5, dest)); + jit->write_ubyte(value); } inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SHL_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 4, dest)); - jit->write_ubyte(jit, value); + jit->write_ubyte(IA32_SHL_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 4, dest)); + jit->write_ubyte(value); } inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SAR_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 7, dest)); - jit->write_ubyte(jit, value); + jit->write_ubyte(IA32_SAR_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 7, dest)); + jit->write_ubyte(value); } inline void IA32_Sar_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SAR_RM_CL); - jit->write_ubyte(jit, ia32_modrm(mode, 7, reg)); + jit->write_ubyte(IA32_SAR_RM_CL); + jit->write_ubyte(ia32_modrm(mode, 7, reg)); } inline void IA32_Shr_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SHR_RM_CL); - jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_ubyte(IA32_SHR_RM_CL); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); } inline void IA32_Shl_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SHL_RM_CL); - jit->write_ubyte(jit, ia32_modrm(mode, 4, reg)); + jit->write_ubyte(IA32_SHL_RM_CL); + jit->write_ubyte(ia32_modrm(mode, 4, reg)); } inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(jit, IA32_XCHG_EAX_REG+reg); + jit->write_ubyte(IA32_XCHG_EAX_REG+reg); } inline void IA32_Xchg_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_XCHG_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_XCHG_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } /********************** @@ -298,93 +296,93 @@ inline void IA32_Xchg_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_ADD_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_ADD_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->write_byte(jit, value); + jit->write_ubyte(IA32_ADD_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_byte(value); } inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_ADD_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_int32(value); } inline void IA32_Add_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->write_ubyte(jit, IA32_ADD_EAX_IMM32); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_ADD_EAX_IMM32); + jit->write_int32(value); } inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SUB_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_SUB_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_SUB_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); + jit->write_byte(val); } inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_SUB_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_SUB_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); + jit->write_int32(val); } inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_DIV_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 6, reg)); + jit->write_ubyte(IA32_DIV_RM); + jit->write_ubyte(ia32_modrm(mode, 6, reg)); } inline void IA32_IDiv_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_IDIV_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 7, reg)); + jit->write_ubyte(IA32_IDIV_RM); + jit->write_ubyte(ia32_modrm(mode, 7, reg)); } inline void IA32_Mul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_MUL_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 4, reg)); + jit->write_ubyte(IA32_MUL_RM); + jit->write_ubyte(ia32_modrm(mode, 4, reg)); } inline void IA32_IMul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_IMUL_RM); - jit->write_ubyte(jit, ia32_modrm(mode, 5, reg)); + jit->write_ubyte(IA32_IMUL_RM); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); } inline void IA32_IMul_Reg_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) { - jit->write_ubyte(jit, IA32_IMUL_REG_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->write_byte(jit, value); + jit->write_ubyte(IA32_IMUL_REG_IMM8); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_byte(value); } inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) { - jit->write_ubyte(jit, IA32_IMUL_REG_IMM32); - jit->write_ubyte(jit, ia32_modrm(mode, 0, reg)); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_IMUL_REG_IMM32); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_int32(value); } inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->write_ubyte(jit, IA32_ADD_RM_REG); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); - jit->write_byte(jit, disp); + jit->write_ubyte(IA32_ADD_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(disp); } inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, @@ -392,10 +390,10 @@ inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, jit_int8_t val, jit_int8_t disp8) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(jit, disp8); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_ADD_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(disp8); + jit->write_byte(val); } inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit, @@ -403,10 +401,10 @@ inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit, jit_int32_t val, jit_int8_t disp8) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(jit, disp8); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_ADD_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(disp8); + jit->write_int32(val); } inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, @@ -414,10 +412,10 @@ inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, jit_int8_t val, jit_int32_t disp32) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); - jit->write_int32(jit, disp32); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_ADD_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(disp32); + jit->write_byte(val); } inline void IA32_Add_Rm_Imm8_Disp_Reg(JitWriter *jit, @@ -426,10 +424,10 @@ inline void IA32_Add_Rm_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_scale, jit_int8_t val) { - jit->write_ubyte(jit, IA32_ADD_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_ADD_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(val); } inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit, @@ -437,10 +435,10 @@ inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit, jit_int8_t val, jit_int8_t disp8) { - jit->write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 5, dest)); - jit->write_byte(jit, disp8); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_SUB_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, dest)); + jit->write_byte(disp8); + jit->write_byte(val); } inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit, @@ -448,10 +446,10 @@ inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit, jit_int8_t val, jit_int32_t disp32) { - jit->write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 5, dest)); - jit->write_int32(jit, disp32); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_SUB_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 5, dest)); + jit->write_int32(disp32); + jit->write_byte(val); } inline void IA32_Sub_Rm_Imm8_Disp_Reg(JitWriter *jit, @@ -460,10 +458,10 @@ inline void IA32_Sub_Rm_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_scale, jit_int8_t val) { - jit->write_ubyte(jit, IA32_SUB_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_SUB_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(val); } /** @@ -472,9 +470,9 @@ inline void IA32_Sub_Rm_Imm8_Disp_Reg(JitWriter *jit, inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) { - jit->write_ubyte(jit, IA32_LEA_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(scale, src_index, src_base)); + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); } inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, @@ -484,24 +482,24 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit_uint8_t scale, jit_int8_t val) { - jit->write_ubyte(jit, IA32_LEA_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(scale, src_index, src_base)); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); + jit->write_byte(val); } inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { - jit->write_ubyte(jit, IA32_LEA_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); - jit->write_byte(jit, val); + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); + jit->write_byte(val); } inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) { - jit->write_ubyte(jit, IA32_LEA_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); + jit->write_int32(val); } /** @@ -510,12 +508,12 @@ inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(jit, IA32_POP_REG+reg); + jit->write_ubyte(IA32_POP_REG+reg); } inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(jit, IA32_PUSH_REG+reg); + jit->write_ubyte(IA32_PUSH_REG+reg); } /** @@ -524,22 +522,22 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_MOV_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(mode, dest, src)); + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); } inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->write_ubyte(jit, IA32_MOV_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, dest, src)); - jit->write_byte(jit, disp); + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp); } inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { - jit->write_ubyte(jit, IA32_MOV_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, dest, src)); - jit->write_int32(jit, disp); + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); + jit->write_int32(disp); } inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, @@ -548,9 +546,9 @@ inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t src_index, jit_uint8_t src_scale) { - jit->write_ubyte(jit, IA32_MOV_REG_MEM); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(src_scale, src_index, src_base)); + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); } /** @@ -559,22 +557,22 @@ inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_MOV_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->write_ubyte(jit, IA32_MOV_RM_REG); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, src, dest)); - jit->write_byte(jit, disp); + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(disp); } inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { - jit->write_ubyte(jit, IA32_MOV_RM_REG); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, src, dest)); - jit->write_int32(jit, disp); + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP32, src, dest)); + jit->write_int32(disp); } inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, @@ -583,9 +581,9 @@ inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, jit_uint8_t dest_scale, jit_uint8_t src) { - jit->write_ubyte(jit, IA32_MOV_RM_REG); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, src, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); } /** @@ -594,8 +592,8 @@ inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, inline void IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) { - jit->write_ubyte(jit, IA32_MOV_REG_IMM+dest); - jit->write_int32(jit, num); + jit->write_ubyte(IA32_MOV_REG_IMM+dest); + jit->write_int32(num); } inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, @@ -603,10 +601,10 @@ inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, jit_int32_t val, jit_int8_t disp8) { - jit->write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(jit, disp8); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_MOV_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(disp8); + jit->write_int32(val); } inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, @@ -614,10 +612,10 @@ inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, jit_int32_t val, jit_int32_t disp32) { - jit->write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP32, 0, dest)); - jit->write_int32(jit, disp32); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_MOV_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(disp32); + jit->write_int32(val); } inline void IA32_Mov_Rm_Imm32_Disp_Reg(JitWriter *jit, @@ -626,10 +624,10 @@ inline void IA32_Mov_Rm_Imm32_Disp_Reg(JitWriter *jit, jit_uint8_t dest_scale, jit_int32_t val) { - jit->write_ubyte(jit, IA32_MOV_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->write_ubyte(jit, ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_int32(jit, val); + jit->write_ubyte(IA32_MOV_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_int32(val); } /** @@ -639,37 +637,37 @@ inline void IA32_Mov_Rm_Imm32_Disp_Reg(JitWriter *jit, inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_t disp) { jitoffs_t ptr; - jit->write_ubyte(jit, IA32_JCC_IMM+cond); + jit->write_ubyte(IA32_JCC_IMM+cond); ptr = jit->jit_curpos(); - jit->write_byte(jit, disp); + jit->write_byte(disp); return ptr; } inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; - jit->write_ubyte(jit, IA32_JMP_IMM32); + jit->write_ubyte(IA32_JMP_IMM32); ptr = jit->jit_curpos(); - jit->write_int32(jit, disp); + jit->write_int32(disp); return ptr; } inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp) { jitoffs_t ptr; - jit->write_ubyte(jit, IA32_JCC_IMM32_1); - jit->write_ubyte(jit, IA32_JCC_IMM32_2+cond); + jit->write_ubyte(IA32_JCC_IMM32_1); + jit->write_ubyte(IA32_JCC_IMM32_2+cond); ptr = jit->jit_curpos(); - jit->write_int32(jit, disp); + jit->write_int32(disp); return ptr; } inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; - jit->write_ubyte(jit, IA32_CALL_IMM32); + jit->write_ubyte(IA32_CALL_IMM32); ptr = jit->jit_curpos(); - jit->write_int32(jit, disp); + jit->write_int32(disp); return ptr; } @@ -681,92 +679,92 @@ inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) jit_int8_t diff = (target - (jmp + 1)); //overwrite old value jit->outptr = jit->outbase + jmp; - jit->write_byte(jit, diff); + jit->write_byte(diff); //restore old ptr jit->outptr = oldptr; } inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->jit_curpos(jit); + jitoffs_t curptr = jit->jit_curpos(); IA32_Write_Jump8(jit, jmp, curptr); } inline void IA32_Return(JitWriter *jit) { - jit->write_ubyte(jit, IA32_RET); + jit->write_ubyte(IA32_RET); } inline void IA32_Test_Rm_Reg(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_TEST_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, reg2, reg1)); + jit->write_ubyte(IA32_TEST_RM_REG); + jit->write_ubyte(ia32_modrm(mode, reg2, reg1)); } inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(jit, IA32_CMP_RM_REG); - jit->write_ubyte(jit, ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_CMP_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) { - jit->write_ubyte(jit, IA32_CMP_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(mode, 7, rm)); - jit->write_byte(jit, imm8); + jit->write_ubyte(IA32_CMP_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 7, rm)); + jit->write_byte(imm8); } inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32) { - jit->write_ubyte(jit, IA32_CMP_RM_IMM32); - jit->write_ubyte(jit, ia32_modrm(mode, 7, rm)); - jit->write_int32(jit, imm32); + jit->write_ubyte(IA32_CMP_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 7, rm)); + jit->write_int32(imm32); } inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) { - jit->write_ubyte(jit, IA32_CMP_RM_IMM8); - jit->write_ubyte(jit, ia32_modrm(MOD_DISP8, 7, reg)); - jit->write_byte(jit, disp); - jit->write_byte(jit, imm8); + jit->write_ubyte(IA32_CMP_RM_IMM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg)); + jit->write_byte(disp); + jit->write_byte(imm8); } inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value) { - jit->write_ubyte(jit, IA32_CMP_EAX_IMM32); - jit->write_int32(jit, value); + jit->write_ubyte(IA32_CMP_EAX_IMM32); + jit->write_int32(value); } inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond) { - jit->write_ubyte(jit, IA32_SETCC_RM8_1); - jit->write_ubyte(jit, IA32_SETCC_RM8_2+cond); - jit->write_ubyte(jit, ia32_modrm(MOD_REG, 0, reg)); + jit->write_ubyte(IA32_SETCC_RM8_1); + jit->write_ubyte(IA32_SETCC_RM8_2+cond); + jit->write_ubyte(ia32_modrm(MOD_REG, 0, reg)); } inline void IA32_Rep(JitWriter *jit) { - jit->write_ubyte(jit, IA32_REP); + jit->write_ubyte(IA32_REP); } inline void IA32_Movsd(JitWriter *jit) { - jit->write_ubyte(jit, IA32_MOVSD); + jit->write_ubyte(IA32_MOVSD); } inline void IA32_Movsb(JitWriter *jit) { - jit->write_ubyte(jit, IA32_MOVSB); + jit->write_ubyte(IA32_MOVSB); } inline void IA32_Stosd(JitWriter *jit) { - jit->write_ubyte(jit, IA32_STOSD); + jit->write_ubyte(IA32_STOSD); } inline void IA32_Cld(JitWriter *jit) { - jit->write_ubyte(jit, IA32_CLD); + jit->write_ubyte(IA32_CLD); } #endif //_INCLUDE_JIT_X86_MACROS_H From 7b3530de676b7c700a19402f5e47c95ce19810dd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 03:56:24 +0000 Subject: [PATCH 0046/1664] imported all finished opcodes that do not require jumping/relocation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4076 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 1295 +++++++++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 3 + sourcepawn/vm/jit/x86/opcode_helpers.h | 284 ++--- 3 files changed, 1436 insertions(+), 146 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 0e6bb669..bbffe74c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -19,7 +19,7 @@ inline void WriteOp_Move_Alt(JitWriter *jit) inline void WriteOp_Xchg(JitWriter *jit) { - /* :TODO: change this? */ + /* :TODO: change this? XCHG is bad */ //xchg eax, edx IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT); } @@ -40,6 +40,36 @@ inline void WriteOp_Push(JitWriter *jit) IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } +inline void WriteOp_Push_C(JitWriter *jit) +{ + //push stack + //mov [ebp-4], + //sub ebp, 4 + cell_t val = jit->read_cell(); + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); +} + +inline void WriteOp_Zero(JitWriter *jit) +{ + //mov [edi+], 0 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val); + else + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val); +} + +inline void WriteOp_Zero_S(JitWriter *jit) +{ + //mov [ebx+], 0 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val); + else + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val); +} + inline void WriteOp_Push_S(JitWriter *jit) { //push stack, FRM offset based @@ -56,6 +86,32 @@ inline void WriteOp_Push_S(JitWriter *jit) IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } +inline void WriteOp_Push_Pri(JitWriter *jit) +{ + //mov [ebp-4], eax + //sub ebp, 4 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); +} + +inline void WriteOp_Push_Alt(JitWriter *jit) +{ + //mov [ebp-4], edx + //sub ebp, 4 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); +} + +inline void WriteOp_Push2_C(JitWriter *jit) +{ + Macro_PushN_C(jit, 2); +} + +inline void WriteOp_Push3_C(JitWriter *jit) +{ + Macro_PushN_C(jit, 3); +} + inline void WriteOp_Push4_C(JitWriter *jit) { Macro_PushN_C(jit, 4); @@ -126,6 +182,795 @@ inline void WriteOp_Push2(JitWriter *jit) Macro_PushN(jit, 2); } +inline void WriteOp_Zero_Pri(JitWriter *jit) +{ + //xor eax, eax + IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Zero_Alt(JitWriter *jit) +{ + //xor edx, edx + IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Add(JitWriter *jit) +{ + //add eax, edx + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Sub(JitWriter *jit) +{ + //sub eax, edx + IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Sub_Alt(JitWriter *jit) +{ + //neg eax + //add eax, edx + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Proc(JitWriter *jit) +{ + //push old frame on stack: + //sub ebp, 4 + //mov ecx, frm + //mov [ebp], ecx + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); + //save frame: + //mov frm, ebp - get new frame + //mov ebx, ebp - store frame back + //sub frm, edi - relocate local frame + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_STK, MOD_MEM_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + IA32_Sub_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_DAT, MOD_MEM_REG); +} + +inline void WriteOp_Shl(JitWriter *jit) +{ + //mov ecx, edx + //shl eax, cl + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Shr(JitWriter *jit) +{ + //mov ecx, edx + //shr eax, cl + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Sshr(JitWriter *jit) +{ + //mov ecx, edx + //sar eax, cl + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Shl_C_Pri(JitWriter *jit) +{ + //shl eax, + jit_uint8_t val = (jit_uint8_t)jit->read_cell(); + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); +} + +inline void WriteOp_Shl_C_Alt(JitWriter *jit) +{ + //shl edx, + jit_uint8_t val = (jit_uint8_t)jit->read_cell(); + IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); +} + +inline void WriteOp_Shr_C_Pri(JitWriter *jit) +{ + //shr eax, + jit_uint8_t val = (jit_uint8_t)jit->read_cell(); + IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); +} + +inline void WriteOp_Shr_C_Alt(JitWriter *jit) +{ + //shr edx, + jit_uint8_t val = (jit_uint8_t)jit->read_cell(); + IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); +} + +inline void WriteOp_SMul(JitWriter *jit) +{ + //mov ecx, edx + //imul edx + //mov edx, ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_UMul(JitWriter *jit) +{ + //mov ecx, edx + //mul edx + //mov edx, ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_Not(JitWriter *jit) +{ + //test eax, eax + //mov eax, 0 + //sete al + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); +} + +inline void WriteOp_Neg(JitWriter *jit) +{ + //neg eax + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Xor(JitWriter *jit) +{ + //xor eax, edx + IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Or(JitWriter *jit) +{ + //or eax, edx + IA32_Or_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_And(JitWriter *jit) +{ + //and eax, edx + IA32_And_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + +inline void WriteOp_Invert(JitWriter *jit) +{ + //not eax + IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG); +} + +inline void WriteOp_Add_C(JitWriter *jit) +{ + //add eax, + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); + else + IA32_Add_Eax_Imm32(jit, val); +} + +inline void WriteOp_SMul_C(JitWriter *jit) +{ + //imul eax, + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); + else + IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val); +} + +inline void WriteOp_Sign_Pri(JitWriter *jit) +{ + //shl eax, 24 + //sar eax, 24 + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); + IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); +} + +inline void WriteOp_Sign_Alt(JitWriter *jit) +{ + //shl edx, 24 + //sar edx, 24 + IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); +} + +inline void WriteOp_Eq(JitWriter *jit) +{ + //cmp eax, edx ; PRI == ALT ? + //mov eax, 0 + //sete al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); +} + +inline void WriteOp_Neq(JitWriter *jit) +{ + //cmp eax, edx ; PRI != ALT ? + //mov eax, 0 + //setne al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE); +} + +inline void WriteOp_Less(JitWriter *jit) +{ + //cmp eax, edx ; PRI < ALT ? (unsigned) + //mov eax, 0 + //setb al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B); +} + +inline void WriteOp_Leq(JitWriter *jit) +{ + //cmp eax, edx ; PRI <= ALT ? (unsigned) + //mov eax, 0 + //setbe al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE); +} + +inline void WriteOp_Grtr(JitWriter *jit) +{ + //cmp eax, edx ; PRI > ALT ? (unsigned) + //mov eax, 0 + //seta al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A); +} + +inline void WriteOp_Geq(JitWriter *jit) +{ + //cmp eax, edx ; PRI >= ALT ? (unsigned) + //mov eax, 0 + //setae al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE); +} + +inline void WriteOp_Sless(JitWriter *jit) +{ + //cmp eax, edx ; PRI < ALT ? (signed) + //mov eax, 0 + //setl al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L); +} + +inline void WriteOp_Sleq(JitWriter *jit) +{ + //cmp eax, edx ; PRI <= ALT ? (signed) + //mov eax, 0 + //setle al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE); +} + +inline void WriteOp_Sgrtr(JitWriter *jit) +{ + //cmp eax, edx ; PRI > ALT ? (signed) + //mov eax, 0 + //setg al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G); +} + +inline void WriteOp_Sgeq(JitWriter *jit) +{ + //cmp eax, edx ; PRI >= ALT ? (signed) + //mov eax, 0 + //setge al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE); +} + +inline void WriteOp_Eq_C_Pri(JitWriter *jit) +{ + //cmp eax, ; PRI == value ? + //mov eax, 0 + //sete al + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); + else + IA32_Cmp_Eax_Imm32(jit, val); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); +} + +inline void WriteOp_Eq_C_Alt(JitWriter *jit) +{ + //xor eax, eax + //cmp edx, ; ALT == value ? + //sete al + cell_t val = jit->read_cell(); + IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val); + else + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); +} + +inline void WriteOp_Inc_Pri(JitWriter *jit) +{ + //add eax, 1 + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); +} + +inline void WriteOp_Inc_Alt(JitWriter *jit) +{ + //add edx, 1 + IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); +} + +inline void WriteOp_Inc(JitWriter *jit) +{ + //add [edi+], 1 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); + else + IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); +} + +inline void WriteOp_Inc_S(JitWriter *jit) +{ + //add [ebx+], 1 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); + else + IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); +} + +inline void WriteOp_Inc_I(JitWriter *jit) +{ + //add [edi+eax], 1 + IA32_Add_Rm_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); +} + +inline void WriteOp_Dec_Pri(JitWriter *jit) +{ + //sub eax, 1 + IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); +} + +inline void WriteOp_Dec_Alt(JitWriter *jit) +{ + //sub edx, 1 + IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); +} + +inline void WriteOp_Dec(JitWriter *jit) +{ + //sub [edi+], 1 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); + else + IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); +} + +inline void WriteOp_Dec_S(JitWriter *jit) +{ + //sub [ebx+], 1 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); + else + IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); +} + +inline void WriteOp_Dec_I(JitWriter *jit) +{ + //sub [edi+eax], 1 + IA32_Sub_Rm_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); +} + +inline void WriteOp_Load_Pri(JitWriter *jit) +{ + //mov eax, [edi+] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); +} + +inline void WriteOp_Load_Alt(JitWriter *jit) +{ + //mov edx, [edi+] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); +} + +inline void WriteOp_Load_S_Pri(JitWriter *jit) +{ + //mov eax, [ebx+] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); +} + +inline void WriteOp_Load_S_Alt(JitWriter *jit) +{ + //mov edx, [ebx+] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); +} + +inline void WriteOp_Lref_Pri(JitWriter *jit) +{ + //mov eax, [edi+] + //mov eax, [edi+eax] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} + +inline void WriteOp_Lref_Alt(JitWriter *jit) +{ + //mov edx, [edi+] + //mov edx, [edi+edx] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); +} + +inline void WriteOp_Lref_S_Pri(JitWriter *jit) +{ + //mov eax, [ebx+] + //mov eax, [edi+eax] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} + +inline void WriteOp_Lref_S_Alt(JitWriter *jit) +{ + //mov edx, [ebx+] + //mov edx, [edi+edx] + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); +} + +inline void WriteOp_Const_Pri(JitWriter *jit) +{ + //mov eax, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val); +} + +inline void WriteOp_Const_Alt(JitWriter *jit) +{ + //mov edx, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val); +} + +inline void WriteOp_Addr_Pri(JitWriter *jit) +{ + //mov eax, frm + //add eax, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_INFO_FRM, MOD_MEM_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); + else + IA32_Add_Eax_Imm32(jit, val); +} + +inline void WriteOp_Addr_Alt(JitWriter *jit) +{ + //mov edx, frm + //add edx, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_INFO_FRM, MOD_MEM_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG); + else + IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG); +} + +inline void WriteOp_Stor_Pri(JitWriter *jit) +{ + //mov [edi+], eax + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val); + else + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val); +} + +inline void WriteOp_Stor_Alt(JitWriter *jit) +{ + //mov [edi+], edx + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val); + else + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val); +} + +inline void WriteOp_Stor_S_Pri(JitWriter *jit) +{ + //mov [ebx+], eax + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val); + else + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val); +} + +inline void WriteOp_Stor_S_Alt(JitWriter *jit) +{ + //mov [ebx+], edx + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val); + else + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val); +} + +inline void WriteOp_Idxaddr(JitWriter *jit) +{ + //lea eax, [edx+4*eax] + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); +} + +inline void WriteOp_Sref_Pri(JitWriter *jit) +{ + //mov ecx, [edi+] + //mov [edi+ecx], eax + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); +} + +inline void WriteOp_Sref_Alt(JitWriter *jit) +{ + //mov ecx, [edi+] + //mov [edi+ecx], edx + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); +} + +inline void WriteOp_Sref_S_Pri(JitWriter *jit) +{ + //mov ecx, [ebx+] + //mov [edi+ecx], eax + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); +} + +inline void WriteOp_Sref_S_Alt(JitWriter *jit) +{ + //mov ecx, [ebx+] + //mov [edi+ecx], edx + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); + else + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); +} + +inline void WriteOp_Align_Pri(JitWriter *jit) +{ + //xor eax, + cell_t val = sizeof(cell_t) - jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); + else + IA32_Xor_Eax_Imm32(jit, val); +} + +inline void WriteOp_Align_Alt(JitWriter *jit) +{ + //xor edx, + cell_t val = sizeof(cell_t) - jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val); + else + IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val); +} + +inline void WriteOp_Pop_Pri(JitWriter *jit) +{ + //mov eax, [ebp] + //add ebp, 4 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + +} + +inline void WriteOp_Pop_Alt(JitWriter *jit) +{ + //mov edx, [ebp] + //add ebp, 4 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); +} + +inline void WriteOp_Swap_Pri(JitWriter *jit) +{ + //xchg [ebp], eax // :TODO: change this xchg for another thing (SLOW!! :O ) + IA32_Xchg_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); +} + +inline void WriteOp_Swap_Alt(JitWriter *jit) +{ + //xchg [ebp], edx // :TODO: change this xchg for another thing + IA32_Xchg_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); +} + +inline void WriteOp_PushAddr(JitWriter *jit) +{ + //mov ecx, frm ;get address (offset from frame) + //add ecx, + //mov [ebp-4], ecx + //sub ebp, 4 + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); + else + IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); +} + +inline void WriteOp_Movs(JitWriter *jit) +{ + //cld + //push esi + //lea esi, [edi+eax] + //add edi, edx + //if dword: + // mov ecx, dword + // rep movsd + //if byte: + // mov ecx, byte + // rep movsb + //sub edi, edx + //sub edi, + //pop esi + cell_t val = jit->read_cell(); + unsigned int dwords = val >> 2; + unsigned int bytes = val & 0x3; + + IA32_Cld(jit); + IA32_Push_Reg(jit, REG_ESI); + IA32_Lea_Reg_DispRegMult(jit, REG_ESI, REG_EDI, AMX_REG_PRI, NOSCALE); + IA32_Add_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); + if (dwords) + { + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, dwords); + IA32_Rep(jit); + IA32_Movsd(jit); + } + if (bytes) + { + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, bytes); + IA32_Rep(jit); + IA32_Movsb(jit); + } + IA32_Sub_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Sub_Rm_Imm8(jit, REG_EDI, (jit_uint8_t)val, MOD_REG); + else + IA32_Sub_Rm_Imm32(jit, REG_EDI, val, MOD_REG); + IA32_Pop_Reg(jit, REG_ESI); +} + +inline void WriteOp_Fill(JitWriter *jit) +{ + //add edi, edx + //mov ecx, >> 2 + //cld + //rep stosd + //sub edi, edx + //sub edi, >> 2 + unsigned int val = jit->read_cell() >> 2; + + IA32_Add_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); + IA32_Cld(jit); + IA32_Rep(jit); + IA32_Stosd(jit); + IA32_Sub_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Sub_Rm_Imm8(jit, REG_EDI, (jit_uint8_t)val, MOD_REG); + else + IA32_Sub_Rm_Imm32(jit, REG_EDI, val, MOD_REG); +} + +inline void WriteOp_Heap_Pri(JitWriter *jit) +{ + //mov edx, hea + //add hea, eax + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Add_Rm_Reg_Disp8(jit, AMX_INFO_FRM, AMX_REG_PRI, AMX_INFO_HEAP); +} + +inline void WriteOp_Push_Heap_C(JitWriter *jit) +{ + //mov ecx, hea + //mov [edi+ecx], + //add hea, 4 + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Mov_Rm_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); + IA32_Add_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, 4, AMX_INFO_HEAP); +} + +inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) +{ + //sub hea, 4 + //mov ecx, [hea] + //mov eax, [edi+ecx] + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, 4, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); +} + +/************************************************* + ************************************************* + * JIT PROPER ************************************ + * The rest of the from now on is the JIT engine * + ************************************************* + *************************************************/ + + IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) { CompData *data = (CompData *)co; @@ -192,6 +1037,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) } } + /********************************************* + * SECOND PASS (medium load): writer.outbase is NULL, getting size only + * THIRD PASS (heavy load!!): writer.outbase is valid and output is written + *********************************************/ + JitWriter writer; writer.inptr = (cell_t *)code; @@ -199,9 +1049,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) writer.outbase = NULL; //redo_pass: - /* SECOND PASS (medium load): writer.outbase is NULL, getting size only - * THIRD PASS (heavy load!!): writer.outbase is valid and output is written - */ cell_t *endptr = (cell_t *)(end_cip); JitWriter *jit = &writer; for (; writer.inptr <= endptr;) @@ -234,6 +1081,16 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Push_S(jit); break; } + case OP_PUSH2_C: + { + WriteOp_Push2_C(jit); + break; + } + case OP_PUSH3_C: + { + WriteOp_Push3(jit); + break; + } case OP_PUSH4_C: { WriteOp_Push4_C(jit); @@ -304,6 +1161,436 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Push2(jit); break; } + case OP_ZERO_PRI: + { + WriteOp_Zero_Pri(jit); + break; + } + case OP_ZERO_ALT: + { + WriteOp_Zero_Alt(jit); + break; + } + case OP_PROC: + { + WriteOp_Proc(jit); + break; + } + case OP_SHL: + { + WriteOp_Shl(jit); + break; + } + case OP_SHR: + { + WriteOp_Shr(jit); + break; + } + case OP_SSHR: + { + WriteOp_Sshr(jit); + break; + } + case OP_SHL_C_PRI: + { + WriteOp_Shl_C_Pri(jit); + break; + } + case OP_SHL_C_ALT: + { + WriteOp_Shl_C_Alt(jit); + break; + } + case OP_SHR_C_PRI: + { + WriteOp_Shr_C_Pri(jit); + break; + } + case OP_SHR_C_ALT: + { + WriteOp_Shr_C_Alt(jit); + break; + } + case OP_SMUL: + { + WriteOp_SMul(jit); + break; + } + case OP_UMUL: + { + WriteOp_UMul(jit); + break; + } + case OP_ADD: + { + WriteOp_Add(jit); + break; + } + case OP_SUB: + { + WriteOp_Sub(jit); + break; + } + case OP_SUB_ALT: + { + WriteOp_Sub_Alt(jit); + break; + } + case OP_NOP: + { + /* do nothing */ + break; + } + case OP_NOT: + { + WriteOp_Not(jit); + break; + } + case OP_NEG: + { + WriteOp_Neg(jit); + break; + } + case OP_XOR: + { + WriteOp_Xor(jit); + break; + } + case OP_OR: + { + WriteOp_Or(jit); + break; + } + case OP_AND: + { + WriteOp_And(jit); + break; + } + case OP_INVERT: + { + WriteOp_Invert(jit); + break; + } + case OP_ADD_C: + { + WriteOp_Add_C(jit); + break; + } + case OP_SMUL_C: + { + WriteOp_SMul_C(jit); + break; + } + case OP_SIGN_PRI: + { + WriteOp_Sign_Pri(jit); + break; + } + case OP_SIGN_ALT: + { + WriteOp_Sign_Alt(jit); + break; + } + case OP_EQ: + { + WriteOp_Eq(jit); + break; + } + case OP_NEQ: + { + WriteOp_Neq(jit); + break; + } + case OP_LESS: + { + WriteOp_Less(jit); + break; + } + case OP_LEQ: + { + WriteOp_Leq(jit); + break; + } + case OP_GRTR: + { + WriteOp_Grtr(jit); + break; + } + case OP_GEQ: + { + WriteOp_Geq(jit); + break; + } + case OP_SLESS: + { + WriteOp_Sless(jit); + break; + } + case OP_SLEQ: + { + WriteOp_Sleq(jit); + break; + } + case OP_SGRTR: + { + WriteOp_Sgrtr(jit); + break; + } + case OP_SGEQ: + { + WriteOp_Sgeq(jit); + break; + } + case OP_EQ_C_PRI: + { + WriteOp_Eq_C_Pri(jit); + break; + } + case OP_EQ_C_ALT: + { + WriteOp_Eq_C_Alt(jit); + break; + } + case OP_INC_PRI: + { + WriteOp_Inc_Pri(jit); + break; + } + case OP_INC_ALT: + { + WriteOp_Inc_Alt(jit); + break; + } + case OP_INC: + { + WriteOp_Inc(jit); + break; + } + case OP_INC_S: + { + WriteOp_Inc_S(jit); + break; + } + case OP_INC_I: + { + WriteOp_Inc_I(jit); + break; + } + case OP_DEC_PRI: + { + WriteOp_Dec_Pri(jit); + break; + } + case OP_DEC_ALT: + { + WriteOp_Dec_Alt(jit); + break; + } + case OP_DEC: + { + WriteOp_Dec(jit); + break; + } + case OP_DEC_S: + { + WriteOp_Dec_S(jit); + break; + } + case OP_DEC_I: + { + WriteOp_Dec_I(jit); + break; + } + case OP_LOAD_PRI: + { + WriteOp_Load_Pri(jit); + break; + } + case OP_LOAD_ALT: + { + WriteOp_Load_Alt(jit); + break; + } + case OP_LOAD_S_PRI: + { + WriteOp_Load_S_Pri(jit); + break; + } + case OP_LOAD_S_ALT: + { + WriteOp_Load_S_Alt(jit); + break; + } + case OP_LREF_PRI: + { + WriteOp_Lref_Pri(jit); + break; + } + case OP_LREF_ALT: + { + WriteOp_Lref_Alt(jit); + break; + } + case OP_LREF_S_PRI: + { + WriteOp_Lref_Pri(jit); + break; + } + case OP_LREF_S_ALT: + { + WriteOp_Lref_Alt(jit); + break; + } + case OP_CONST_PRI: + { + WriteOp_Const_Pri(jit); + break; + } + case OP_CONST_ALT: + { + WriteOp_Const_Alt(jit); + break; + } + case OP_ADDR_PRI: + { + WriteOp_Addr_Pri(jit); + break; + } + case OP_ADDR_ALT: + { + WriteOp_Addr_Alt(jit); + break; + } + case OP_STOR_PRI: + { + WriteOp_Stor_Pri(jit); + break; + } + case OP_STOR_ALT: + { + WriteOp_Stor_Alt(jit); + break; + } + case OP_STOR_S_PRI: + { + WriteOp_Stor_S_Pri(jit); + break; + } + case OP_STOR_S_ALT: + { + WriteOp_Stor_S_Alt(jit); + break; + } + case OP_IDXADDR: + { + WriteOp_Idxaddr(jit); + break; + } + case OP_SREF_PRI: + { + WriteOp_Sref_Pri(jit); + break; + } + case OP_SREF_ALT: + { + WriteOp_Sref_Alt(jit); + break; + } + case OP_SREF_S_PRI: + { + WriteOp_Sref_S_Pri(jit); + break; + } + case OP_SREF_S_ALT: + { + WriteOp_Sref_S_Alt(jit); + break; + } + case OP_ALIGN_PRI: + { + WriteOp_Align_Pri(jit); + break; + } + case OP_ALIGN_ALT: + { + WriteOp_Align_Alt(jit); + break; + } + case OP_POP_PRI: + { + WriteOp_Pop_Pri(jit); + break; + } + case OP_POP_ALT: + { + WriteOp_Pop_Alt(jit); + break; + } + case OP_SWAP_PRI: + { + WriteOp_Swap_Pri(jit); + break; + } + case OP_SWAP_ALT: + { + WriteOp_Swap_Alt(jit); + break; + } + case OP_PUSH_ADR: + { + WriteOp_PushAddr(jit); + break; + } + case OP_MOVS: + { + WriteOp_Movs(jit); + break; + } + case OP_FILL: + { + WriteOp_Fill(jit); + break; + } + case OP_HEAP_PRI: + { + WriteOp_Heap_Pri(jit); + break; + } + case OP_PUSH_HEAP_C: + { + WriteOp_Push_Heap_C(jit); + break; + } + case OP_POP_HEAP_PRI: + { + WriteOp_Pop_Heap_Pri(jit); + break; + } + case OP_PUSH_C: + { + WriteOp_Push_C(jit); + break; + } + case OP_ZERO: + { + WriteOp_Zero(jit); + break; + } + case OP_ZERO_S: + { + WriteOp_Zero_S(jit); + break; + } + case OP_PUSH_PRI: + { + WriteOp_Push_Pri(jit); + break; + } + case OP_PUSH_ALT: + { + WriteOp_Push_Alt(jit); + break; + } default: { /* :TODO: error! */ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 879abbf1..b78b3156 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -176,6 +176,7 @@ JITX86::JITX86() OpAdvTable[OP_HALT] = sizeof(cell_t); OpAdvTable[OP_BOUNDS] = sizeof(cell_t); OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); + OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t); /* instructions with 0 parameters */ OpAdvTable[OP_LOAD_I] = 0; @@ -236,6 +237,8 @@ JITX86::JITX86() OpAdvTable[OP_SWAP_ALT] = 0; OpAdvTable[OP_NOP] = 0; OpAdvTable[OP_BREAK] = 0; + OpAdvTable[OP_HEAP_PRI] = 0; + OpAdvTable[OP_POP_HEAP_PRI] = 0; /* opcodes that need relocation */ OpAdvTable[OP_CALL] = -2; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 66dc13d9..e21c4d6a 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -11,170 +11,170 @@ void Macro_PushN(JitWriter *jit, int i); typedef enum { OP_NONE, /* invalid opcode */ - OP_LOAD_PRI, //DONE - OP_LOAD_ALT, //DONE - OP_LOAD_S_PRI, //DONE - OP_LOAD_S_ALT, //DONE - OP_LREF_PRI, //DONE - OP_LREF_ALT, //DONE - OP_LREF_S_PRI, //DONE - OP_LREF_S_ALT, //DONE - OP_LOAD_I, //DONE + OP_LOAD_PRI, //DONE + OP_LOAD_ALT, //DONE + OP_LOAD_S_PRI, //DONE + OP_LOAD_S_ALT, //DONE + OP_LREF_PRI, //DONE + OP_LREF_ALT, //DONE + OP_LREF_S_PRI, //DONE + OP_LREF_S_ALT, //DONE + OP_LOAD_I, OP_LODB_I, - OP_CONST_PRI, //DONE - OP_CONST_ALT, //DONE - OP_ADDR_PRI, //DONE - OP_ADDR_ALT, //DONE - OP_STOR_PRI, //DONE - OP_STOR_ALT, //DONE - OP_STOR_S_PRI, //DONE - OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //DONE - OP_SREF_ALT, //DONE - OP_SREF_S_PRI, //DONE - OP_SREF_S_ALT, //DONE - OP_STOR_I, //DONE + OP_CONST_PRI, //DONE + OP_CONST_ALT, //DONE + OP_ADDR_PRI, //DONE + OP_ADDR_ALT, //DONE + OP_STOR_PRI, //DONE + OP_STOR_ALT, //DONE + OP_STOR_S_PRI, //DONE + OP_STOR_S_ALT, //DONE + OP_SREF_PRI, //DONE + OP_SREF_ALT, //DONE + OP_SREF_S_PRI, //DONE + OP_SREF_S_ALT, //DONE + OP_STOR_I, OP_STRB_I, - OP_LIDX, //DONE + OP_LIDX, OP_LIDX_B, - OP_IDXADDR, //DONE + OP_IDXADDR, //DONE OP_IDXADDR_B, - OP_ALIGN_PRI, //DONE - OP_ALIGN_ALT, //DONE + OP_ALIGN_PRI, //DONE + OP_ALIGN_ALT, //DONE OP_LCTRL, OP_SCTRL, - OP_MOVE_PRI, //DONE - OP_MOVE_ALT, //DONE - OP_XCHG, //DONE - OP_PUSH_PRI, //DONE - OP_PUSH_ALT, //DONE - OP_PUSH_R, //DONE - OP_PUSH_C, //DONE - OP_PUSH, //DONE - OP_PUSH_S, //DONE - OP_POP_PRI, //DONE - OP_POP_ALT, //DONE - OP_STACK, //DONE - OP_HEAP, //DONE - OP_PROC, //DONE + OP_MOVE_PRI, //DONE + OP_MOVE_ALT, //DONE + OP_XCHG, //DONE + OP_PUSH_PRI, //DONE + OP_PUSH_ALT, //DONE + OP_PUSH_R, //DEPRECATED + OP_PUSH_C, //DONE + OP_PUSH, //DONE + OP_PUSH_S, //DONE + OP_POP_PRI, //DONE + OP_POP_ALT, //DONE + OP_STACK, + OP_HEAP, + OP_PROC, //DONE OP_RET, - OP_RETN, //DONE + OP_RETN, OP_CALL, OP_CALL_PRI, - OP_JUMP, //DONE - OP_JREL, //DONE - OP_JZER, //DONE - OP_JNZ, //DONE - OP_JEQ, //DONE - OP_JNEQ, //DONE - OP_JLESS, //DONE - OP_JLEQ, //DONE - OP_JGRTR, //DONE - OP_JGEQ, //DONE - OP_JSLESS, //DONE - OP_JSLEQ, //DONE - OP_JSGRTR, //DONE - OP_JSGEQ, //DONE - OP_SHL, //DONE - OP_SHR, //DONE - OP_SSHR, //DONE - OP_SHL_C_PRI, //DONE - OP_SHL_C_ALT, //DONE - OP_SHR_C_PRI, //DONE - OP_SHR_C_ALT, //DONE - OP_SMUL, //DONE - OP_SDIV, //DONE - OP_SDIV_ALT, //DONE - OP_UMUL, //DONE - OP_UDIV, //DONE - OP_UDIV_ALT, //DONE - OP_ADD, //DONE - OP_SUB, //DONE - OP_SUB_ALT, //DONE - OP_AND, //DONE - OP_OR, //DONE - OP_XOR, //DONE - OP_NOT, //DONE - OP_NEG, //DONE - OP_INVERT, //DONE - OP_ADD_C, //DONE - OP_SMUL_C, //DONE - OP_ZERO_PRI, //DONE - OP_ZERO_ALT, //DONE - OP_ZERO, //DONE - OP_ZERO_S, //DONE - OP_SIGN_PRI, //DONE - OP_SIGN_ALT, //DONE - OP_EQ, //DONE - OP_NEQ, //DONE - OP_LESS, //DONE - OP_LEQ, //DONE - OP_GRTR, //DONE - OP_GEQ, //DONE - OP_SLESS, //DONE - OP_SLEQ, //DONE - OP_SGRTR, //DONE - OP_SGEQ, //DONE - OP_EQ_C_PRI, //DONE - OP_EQ_C_ALT, //DONE - OP_INC_PRI, //DONE - OP_INC_ALT, //DONE - OP_INC, //DONE - OP_INC_S, //DONE - OP_INC_I, //DONE - OP_DEC_PRI, //DONE - OP_DEC_ALT, //DONE - OP_DEC, //DONE - OP_DEC_S, //DONE - OP_DEC_I, //DONE - OP_MOVS, //DONE - OP_CMPS, //DONE - OP_FILL, //DONE - OP_HALT, //DONE + OP_JUMP, + OP_JREL, + OP_JZER, + OP_JNZ, + OP_JEQ, + OP_JNEQ, + OP_JLESS, + OP_JLEQ, + OP_JGRTR, + OP_JGEQ, + OP_JSLESS, + OP_JSLEQ, + OP_JSGRTR, + OP_JSGEQ, + OP_SHL, //DONE + OP_SHR, //DONE + OP_SSHR, //DONE + OP_SHL_C_PRI, //DONE + OP_SHL_C_ALT, //DONE + OP_SHR_C_PRI, //DONE + OP_SHR_C_ALT, //DONE + OP_SMUL, //DONE + OP_SDIV, + OP_SDIV_ALT, + OP_UMUL, //DONE + OP_UDIV, + OP_UDIV_ALT, + OP_ADD, //DONE + OP_SUB, //DONE + OP_SUB_ALT, //DONE + OP_AND, //DONE + OP_OR, //DONE + OP_XOR, //DONE + OP_NOT, //DONE + OP_NEG, //DONE + OP_INVERT, //DONE + OP_ADD_C, //DONE + OP_SMUL_C, //DONE + OP_ZERO_PRI, //DONE + OP_ZERO_ALT, //DONE + OP_ZERO, //DONE + OP_ZERO_S, //DONE + OP_SIGN_PRI, //DONE + OP_SIGN_ALT, //DONE + OP_EQ, //DONE + OP_NEQ, //DONE + OP_LESS, //DONE + OP_LEQ, //DONE + OP_GRTR, //DONE + OP_GEQ, //DONE + OP_SLESS, //DONE + OP_SLEQ, //DONE + OP_SGRTR, //DONE + OP_SGEQ, //DONE + OP_EQ_C_PRI, //DONE + OP_EQ_C_ALT, //DONE + OP_INC_PRI, //DONE + OP_INC_ALT, //DONE + OP_INC, //DONE + OP_INC_S, //DONE + OP_INC_I, //DONE + OP_DEC_PRI, //DONE + OP_DEC_ALT, //DONE + OP_DEC, //DONE + OP_DEC_S, //DONE + OP_DEC_I, //DONE + OP_MOVS, //DONE + OP_CMPS, + OP_FILL, //DONE + OP_HALT, OP_BOUNDS, OP_SYSREQ_PRI, OP_SYSREQ_C, - OP_FILE, - OP_LINE, - OP_SYMBOL, - OP_SRANGE, + OP_FILE, //DEPRECATED + OP_LINE, //DEPRECATED + OP_SYMBOL, //DEPRECATED + OP_SRANGE, //DEPRECATED OP_JUMP_PRI, OP_SWITCH, - OP_CASETBL, //DONE - OP_SWAP_PRI, //DONE - OP_SWAP_ALT, //DONE - OP_PUSH_ADR, //DONE - OP_NOP, //DONE + OP_CASETBL, + OP_SWAP_PRI, //DONE + OP_SWAP_ALT, //DONE + OP_PUSH_ADR, + OP_NOP, //DONE OP_SYSREQ_N, - OP_SYMTAG, + OP_SYMTAG, //DEPRECATED OP_BREAK, - OP_PUSH2_C, //DONE - OP_PUSH2, //DONE - OP_PUSH2_S, //DONE - OP_PUSH2_ADR, //DONE - OP_PUSH3_C, //DONE - OP_PUSH3, //DONE - OP_PUSH3_S, //DONE - OP_PUSH3_ADR, //DONE - OP_PUSH4_C, //DONE - OP_PUSH4, //DONE - OP_PUSH4_S, //DONE - OP_PUSH4_ADR, //DONE - OP_PUSH5_C, //DONE - OP_PUSH5, //DONE - OP_PUSH5_S, //DONE - OP_PUSH5_ADR, //DONE + OP_PUSH2_C, //DONE + OP_PUSH2, //DONE + OP_PUSH2_S, //DONE + OP_PUSH2_ADR, //DONE + OP_PUSH3_C, //DONE + OP_PUSH3, //DONE + OP_PUSH3_S, //DONE + OP_PUSH3_ADR, //DONE + OP_PUSH4_C, //DONE + OP_PUSH4, //DONE + OP_PUSH4_S, //DONE + OP_PUSH4_ADR, //DONE + OP_PUSH5_C, //DONE + OP_PUSH5, //DONE + OP_PUSH5_S, //DONE + OP_PUSH5_ADR, //DONE OP_LOAD_BOTH, OP_LOAD_S_BOTH, OP_CONST, OP_CONST_S, /* ----- */ - OP_SYSREQ_D, - OP_SYSREQ_ND, + OP_SYSREQ_D, //UNSUPPORTED + OP_SYSREQ_ND, //UNSUPPORTED /* ----- */ - OP_HEAP_PRI, - OP_PUSH_HEAP_C, - OP_POP_HEAP_PRI, + OP_HEAP_PRI, //DONE + OP_PUSH_HEAP_C, //DONE + OP_POP_HEAP_PRI, //DONE /* ----- */ OP_NUM_OPCODES } OPCODE; From 7d0bb148488450235145a327869057604be31eb0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 04:14:53 +0000 Subject: [PATCH 0047/1664] added some more macro opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4077 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 65 +++++++++++++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.h | 10 ++-- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index bbffe74c..4f178a64 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -963,6 +963,46 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); } +inline void WriteOp_Load_Both(JitWriter *jit) +{ + WriteOp_Const_Pri(jit); + WriteOp_Const_Alt(jit); +} + +inline void WriteOp_Load_S_Both(JitWriter *jit) +{ + WriteOp_Load_S_Pri(jit); + WriteOp_Load_S_Alt(jit); +} + +inline void WriteOp_Const(JitWriter *jit) +{ + //mov [edi+], + cell_t addr = jit->read_cell(); + cell_t val = jit->read_cell(); + if (addr < SCHAR_MAX && addr > SCHAR_MIN) + { + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr); + } else { + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr); + } +} + +inline void WriteOp_Const_S(JitWriter *jit) +{ + //mov [ebx+], + cell_t offs = jit->read_cell(); + cell_t val = jit->read_cell(); + + if (offs < SCHAR_MAX && offs > SCHAR_MIN) + { + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs); + } else { + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs); + } +} + + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1591,10 +1631,31 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Push_Alt(jit); break; } + case OP_LOAD_BOTH: + { + WriteOp_Load_Both(jit); + break; + } + case OP_LOAD_S_BOTH: + { + WriteOp_Load_S_Both(jit); + break; + } + case OP_CONST: + { + WriteOp_Const(jit); + break; + } + case OP_CONST_S: + { + WriteOp_Const_S(jit); + break; + } default: { - /* :TODO: error! */ - break; + AbortCompilation(co); + *err = SP_ERR_INVALID_INSTRUCTION; + return NULL; } } } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index e21c4d6a..bfd86db9 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -143,7 +143,7 @@ typedef enum OP_CASETBL, OP_SWAP_PRI, //DONE OP_SWAP_ALT, //DONE - OP_PUSH_ADR, + OP_PUSH_ADR, //DONE OP_NOP, //DONE OP_SYSREQ_N, OP_SYMTAG, //DEPRECATED @@ -164,10 +164,10 @@ typedef enum OP_PUSH5, //DONE OP_PUSH5_S, //DONE OP_PUSH5_ADR, //DONE - OP_LOAD_BOTH, - OP_LOAD_S_BOTH, - OP_CONST, - OP_CONST_S, + OP_LOAD_BOTH, //DONE + OP_LOAD_S_BOTH, //DONE + OP_CONST, //DONE + OP_CONST_S, //DONE /* ----- */ OP_SYSREQ_D, //UNSUPPORTED OP_SYSREQ_ND, //UNSUPPORTED From 3cdf54e7e967128f2c8e079c4b666d754cc4045a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 04:52:13 +0000 Subject: [PATCH 0048/1664] fixed AMX_INFO_FRM being used instead of AMX_REG_INFO --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4078 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 32 ++++++++++++------------ sourcepawn/vm/jit/x86/jit_x86.h | 6 ++--- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 22 ++++++++++++++++ 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 4f178a64..693890d5 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -218,16 +218,16 @@ inline void WriteOp_Proc(JitWriter *jit) { //push old frame on stack: //sub ebp, 4 - //mov ecx, frm + //mov ecx, [frm] //mov [ebp], ecx IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); //save frame: - //mov frm, ebp - get new frame - //mov ebx, ebp - store frame back - //sub frm, edi - relocate local frame - IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_STK, MOD_MEM_REG); + //mov [frm], ebp - get new frame + //mov ebx, ebp - store frame back + //sub [frm], edi - relocate local frame + IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_STK, MOD_MEM_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); IA32_Sub_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_DAT, MOD_MEM_REG); } @@ -936,30 +936,30 @@ inline void WriteOp_Fill(JitWriter *jit) inline void WriteOp_Heap_Pri(JitWriter *jit) { - //mov edx, hea - //add hea, eax - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_INFO_FRM, AMX_INFO_HEAP); - IA32_Add_Rm_Reg_Disp8(jit, AMX_INFO_FRM, AMX_REG_PRI, AMX_INFO_HEAP); + //mov edx, [hea] + //add [hea], eax + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); } inline void WriteOp_Push_Heap_C(JitWriter *jit) { - //mov ecx, hea + //mov ecx, [hea] //mov [edi+ecx], - //add hea, 4 + //add [hea], 4 cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Rm_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); - IA32_Add_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, 4, AMX_INFO_HEAP); + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); } inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) { - //sub hea, 4 + //sub [hea], 4 //mov ecx, [hea] //mov eax, [edi+ecx] - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, 4, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index b78ca8a2..7fa56ce2 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -40,8 +40,8 @@ public: #define AMX_REG_INFO REG_ESI #define AMX_REG_FRM REG_EBX -#define AMX_INFO_FRM AMX_REG_INFO -#define AMX_INFO_HEAP 4 -#define AMX_INFO_RETVAL 12 +#define AMX_INFO_FRM AMX_REG_INFO +#define AMX_INFO_HEAP 4 +#define AMX_INFO_RETVAL 8 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index b78b3156..012f3a05 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -6,6 +6,28 @@ int OpAdvTable[OP_NUM_OPCODES]; +void Write_Prologue(JitWriter *jit) +{ + /** + * The state expected by our plugin is: + * #define AMX_REG_PRI REG_EAX + #define AMX_REG_ALT REG_EDX + #define AMX_REG_STK REG_EBP + #define AMX_REG_DAT REG_EDI + #define AMX_REG_TMP REG_ECX + #define AMX_REG_INFO REG_ESI + #define AMX_REG_FRM REG_EBX + #define AMX_INFO_FRM AMX_REG_INFO + #define AMX_INFO_HEAP 4 + #define AMX_INFO_RETVAL 12 + * + * The variables we're passed in: + * sp_context_t *ctx, uint32_t code_idx, cell_t *result + */ + + +} + void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax From 824beee935112abb731738064e58bdbf747e84fb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 07:07:49 +0000 Subject: [PATCH 0049/1664] Wrote the JIT execution function Solidified some more code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4079 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 33 +++--- sourcepawn/vm/jit/x86/jit_x86.h | 5 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 128 +++++++++++++++++++++-- sourcepawn/vm/jit/x86/opcode_helpers.h | 13 +++ sourcepawn/vm/jit/x86/x86_macros.h | 25 +++++ sourcepawn/vm/msvc8/vm.vcproj | 8 +- sourcepawn/vm/sp_vm_basecontext.cpp | 13 ++- 7 files changed, 193 insertions(+), 32 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 693890d5..ca58068b 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -830,7 +830,6 @@ inline void WriteOp_Pop_Pri(JitWriter *jit) //add ebp, 4 IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - } inline void WriteOp_Pop_Alt(JitWriter *jit) @@ -1049,16 +1048,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) } else if (op_c == -1) { switch (op) { - case OP_SYSREQ_C: - case OP_SYSREQ_PRI: - case OP_SYSREQ_N: - { - if (!data->always_inline) - { - reloc_count++; - } - break; - } case OP_CASETBL: { ucell_t num = *(ucell_t *)cip; @@ -1083,14 +1072,30 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) *********************************************/ JitWriter writer; + JitWriter *jit = &writer; + cell_t *endptr = (cell_t *)(end_cip); + jitoffs_t jit_return; + /* Initial code is written "blank," + * so we can check the exact memory usage. + */ writer.inptr = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; -//redo_pass: - cell_t *endptr = (cell_t *)(end_cip); - JitWriter *jit = &writer; + /* Get inlining level */ + int inline_level = data->inline_level; + bool never_inline = false; + + if (inline_level == 0) + { + never_inline = true; + } + +//:TODO: Jump back here once finished! + /* Start writing the actual code */ + jit_return = Write_Execute_Function(jit, never_inline); + for (; writer.inptr <= endptr;) { op = (OPCODE)writer.read_cell(); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 7fa56ce2..b3ba2e8d 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,12 +9,12 @@ using namespace SourcePawn; class CompData : public ICompilation { public: - CompData() : plugin(NULL), debug(false), always_inline(true) + CompData() : plugin(NULL), debug(false), inline_level(2) { }; public: sp_plugin_t *plugin; - bool always_inline; + int inline_level; bool debug; }; @@ -43,5 +43,6 @@ public: #define AMX_INFO_FRM AMX_REG_INFO #define AMX_INFO_HEAP 4 #define AMX_INFO_RETVAL 8 +#define AMX_INFO_CONTEXT 12 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 012f3a05..43e39e77 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -6,26 +6,129 @@ int OpAdvTable[OP_NUM_OPCODES]; -void Write_Prologue(JitWriter *jit) +jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) { /** * The state expected by our plugin is: - * #define AMX_REG_PRI REG_EAX - #define AMX_REG_ALT REG_EDX - #define AMX_REG_STK REG_EBP - #define AMX_REG_DAT REG_EDI - #define AMX_REG_TMP REG_ECX - #define AMX_REG_INFO REG_ESI - #define AMX_REG_FRM REG_EBX - #define AMX_INFO_FRM AMX_REG_INFO - #define AMX_INFO_HEAP 4 - #define AMX_INFO_RETVAL 12 + * #define AMX_REG_PRI REG_EAX (done) + #define AMX_REG_ALT REG_EDX (done) + #define AMX_REG_STK REG_EBP (done) + #define AMX_REG_DAT REG_EDI (done) + #define AMX_REG_TMP REG_ECX (nothing) + #define AMX_REG_INFO REG_ESI (done) + #define AMX_REG_FRM REG_EBX (done) + #define AMX_INFO_FRM AMX_REG_INFO (done) + #define AMX_INFO_HEAP 4 (done) + #define AMX_INFO_RETVAL 8 (done) + #define AMX_INFO_CONTEXT 12 (done) * * The variables we're passed in: * sp_context_t *ctx, uint32_t code_idx, cell_t *result */ + /** + * !NOTE! + * Currently, we do not accept ctx->frm as the new frame pointer. + * Instead, we copy the frame from the stack pointer. + * This is because we do not support resuming or sleeping! + */ + //push ebp + //mov ebp, esp + IA32_Push_Reg(jit, REG_EBP); + IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG); + + //push esi + //push edi + //push ebx + IA32_Push_Reg(jit, REG_ESI); + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_EBX); + + //sub esp, 4*4 - allocate info array + //mov esi, esp - save info pointer + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); + + //mov eax, [ebp+16] - get result pointer + //mov [esi+8], eax - store into info pointer + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_RETVAL); + + //mov eax, [ebp+8] - get context + //mov [esi+12], eax - store context into info pointer + //mov ecx, [eax+] - get heap pointer + //mov [esi+4], ecx - store heap into info pointer + //mov edi, [eax+] - get data pointer + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); + + //mov ebp, [eax+] - get stack pointer + //add ebp, edi - relocate to data section + //mov ebx, ebp - copy sp to frm + //mov ecx, [ebp+12] - get code index + //add ecx, [eax+] - add code base to index + //mov edx, [eax+] - get alt + //mov eax, [eax+] - get pri + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); + IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri)); + + /* by now, everything is set up, so we can call into the plugin */ + + //call ecx + IA32_Call_Rm(jit, REG_ECX); + + /* if the code flow gets to here, there was a normal return */ + //mov ebp, [esi+8] - get retval pointer + //mov [ebp], eax - store retval from PRI + //mov eax, SP_ERR_NONE - set no error + IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL); + IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG); + IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE); + + /* where error checking/return functions should go to */ + jitoffs_t offs_return; + if (never_inline) + { + /* We have to write code assume we're breaking out of a call */ + //jmp [past the next instruction] + //add esp, 4 + jitoffs_t offs = IA32_Jump_Imm8(jit, 0); + offs_return = jit->jit_curpos(); + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); + IA32_Send_Jump8_Here(jit, offs); + } else { + offs_return = jit->jit_curpos(); + } + + /* _FOR NOW_ ... + * We are _not_ going to restore anything that was on the stack. + * This is a tiny, useless optimization based on the fact that + * BaseContext::Execute() automatically restores our values anyway. + */ + + //add esp, 4*4 + //pop ebx + //pop edi + //pop esi + //pop ebp + //ret + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Pop_Reg(jit, REG_EBX); + IA32_Pop_Reg(jit, REG_EDI); + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EBP); + IA32_Return(jit); + + return offs_return; } void Macro_PushN_Addr(JitWriter *jit, int i) @@ -142,6 +245,7 @@ JITX86::JITX86() OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; OpAdvTable[OP_CONST] = sizeof(cell_t)*2; OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; + OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2; /* instructions with 1 parameter */ OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); @@ -199,6 +303,7 @@ JITX86::JITX86() OpAdvTable[OP_BOUNDS] = sizeof(cell_t); OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t); + OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t); /* instructions with 0 parameters */ OpAdvTable[OP_LOAD_I] = 0; @@ -261,6 +366,7 @@ JITX86::JITX86() OpAdvTable[OP_BREAK] = 0; OpAdvTable[OP_HEAP_PRI] = 0; OpAdvTable[OP_POP_HEAP_PRI] = 0; + OpAdvTable[OP_SYSREQ_PRI] = 0; /* opcodes that need relocation */ OpAdvTable[OP_CALL] = -2; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index bfd86db9..64a753c6 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -3,6 +3,19 @@ #include "..\jit_helpers.h" +/** + * This outputs the execution function for a plugin. + * It also returns the 'return' offset, which is used for + * breaking out of the JIT during runtime. + * + * If 'never_inline' is true, it outputs slightly different code used for + * inlining the error checking routines. + */ +jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline); + +/** + * These are for writing the PushN opcodes. + */ void Macro_PushN_Addr(JitWriter *jit, int i); void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 45ba5d8b..7d0d5a0a 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -53,6 +53,7 @@ #define IA32_XOR_RM_IMM32 0x81 // encoding is /6 #define IA32_XOR_RM_IMM8 0x83 // encoding is /6 #define IA32_ADD_RM_REG 0x01 // encoding is /r +#define IA32_ADD_REG_RM 0x03 // encoding is /r #define IA32_ADD_RM_IMM32 0x81 // encoding is /0 #define IA32_ADD_RM_IMM8 0x83 // encoding is /0 #define IA32_ADD_EAX_IMM32 0x05 // no extra encoding @@ -60,7 +61,9 @@ #define IA32_SUB_RM_IMM8 0x83 // encoding is /5 #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 #define IA32_JMP_IMM32 0xE9 // encoding is imm32 +#define IA32_JMP_IMM8 0xEB // encoding is imm8 #define IA32_CALL_IMM32 0xE8 // relative call, +#define IA32_CALL_RM 0xFF // encoding is /2 #define IA32_MOV_REG_IMM 0xB8 // encoding is +r #define IA32_MOV_RM_REG 0x89 // encoding is /r #define IA32_MOV_REG_MEM 0x8B // encoding is /r @@ -385,6 +388,13 @@ inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->write_ubyte(IA32_ADD_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp); +} + inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, @@ -652,6 +662,15 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } +inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp) +{ + jitoffs_t ptr; + jit->write_ubyte(IA32_JMP_IMM8); + ptr = jit->jit_curpos(); + jit->write_byte(disp); + return ptr; +} + inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp) { jitoffs_t ptr; @@ -671,6 +690,12 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } +inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg) +{ + jit->write_ubyte(IA32_CALL_RM); + jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg)); +} + inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) { //save old ptr diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 4e53d0b5..3bd93d34 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -189,10 +189,6 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - @@ -319,6 +315,10 @@ RelativePath="..\..\include\sp_vm_api.h" > + + diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index bc38cc82..d64680f1 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -58,7 +58,18 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) return err; } - return vm->ContextExecute(ctx, pubfunc->offs, result); + PushCell(ctx->pushcount); + ctx->pushcount = 0; + + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + + err = vm->ContextExecute(ctx, pubfunc->offs, result); + + ctx->sp = save_sp; + ctx->hp = save_hp; + + return err; } int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) From 15778979255df85735ad1aea87dd93523d4debb0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 08:44:21 +0000 Subject: [PATCH 0050/1664] I'm proud to present the first non-backpatched error checking routine! all of this is untested --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4080 --- sourcepawn/vm/jit/jit_helpers.h | 2 + sourcepawn/vm/jit/x86/jit_x86.cpp | 29 +++++-- sourcepawn/vm/jit/x86/jit_x86.h | 10 ++- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 105 ++++++++++++++++++----- sourcepawn/vm/jit/x86/opcode_helpers.h | 19 ++-- sourcepawn/vm/jit/x86/x86_macros.h | 36 ++++++++ 6 files changed, 166 insertions(+), 35 deletions(-) diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index bbfda1ec..5b74ce65 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -2,6 +2,7 @@ #define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ #include +#include #if defined HAVE_STDINT_H && !defined WIN32 #include @@ -70,6 +71,7 @@ public: cell_t *inptr; /* input pointer */ jitcode_t outbase; /* output pointer */ jitcode_t outptr; /* output base */ + SourcePawn::ICompilation *data; /* compiler live info */ }; #endif //_INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index ca58068b..e7cc2885 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1,7 +1,6 @@ #include #include #include "jit_x86.h" -#include "..\jit_helpers.h" #include "opcode_helpers.h" #include "x86_macros.h" @@ -1001,6 +1000,13 @@ inline void WriteOp_Const_S(JitWriter *jit) } } +inline void WriteOp_Load_I(JitWriter *jit) +{ + //mov eax, [edi+eax] + Write_Check_VerifyAddr(jit, REG_EAX, false); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} + /************************************************* ************************************************* @@ -1074,7 +1080,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); - jitoffs_t jit_return; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1085,16 +1090,17 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) /* Get inlining level */ int inline_level = data->inline_level; - bool never_inline = false; - - if (inline_level == 0) - { - never_inline = true; - } //:TODO: Jump back here once finished! + /* Start writing the actual code */ - jit_return = Write_Execute_Function(jit, never_inline); + data->jit_return = Write_Execute_Function(jit); + + /* Write error checking routines in case they are needed */ + data->jit_verify_addr_eax = jit->jit_curpos(); + Write_Check_VerifyAddr(jit, REG_EAX, true); + data->jit_verify_addr_edx = jit->jit_curpos(); + Write_Check_VerifyAddr(jit, REG_EDX, true); for (; writer.inptr <= endptr;) { @@ -1656,6 +1662,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Const_S(jit); break; } + case OP_LOAD_I: + { + WriteOp_Load_I(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index b3ba2e8d..0eb22f8f 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -3,17 +3,24 @@ #include #include +#include "..\jit_helpers.h" using namespace SourcePawn; +#define JIT_INLINE_ERRORCHECKS (1<<0) +#define JIT_INLINE_NATIVES (1<<1) + class CompData : public ICompilation { public: - CompData() : plugin(NULL), debug(false), inline_level(2) + CompData() : plugin(NULL), debug(false), inline_level(3) { }; public: sp_plugin_t *plugin; + jitoffs_t jit_return; + jitoffs_t jit_verify_addr_eax; + jitoffs_t jit_verify_addr_edx; int inline_level; bool debug; }; @@ -44,5 +51,6 @@ public: #define AMX_INFO_HEAP 4 #define AMX_INFO_RETVAL 8 #define AMX_INFO_CONTEXT 12 +#define AMX_INFO_STACKTOP 16 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 43e39e77..0b5180f9 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -9,19 +9,6 @@ int OpAdvTable[OP_NUM_OPCODES]; jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) { /** - * The state expected by our plugin is: - * #define AMX_REG_PRI REG_EAX (done) - #define AMX_REG_ALT REG_EDX (done) - #define AMX_REG_STK REG_EBP (done) - #define AMX_REG_DAT REG_EDI (done) - #define AMX_REG_TMP REG_ECX (nothing) - #define AMX_REG_INFO REG_ESI (done) - #define AMX_REG_FRM REG_EBX (done) - #define AMX_INFO_FRM AMX_REG_INFO (done) - #define AMX_INFO_HEAP 4 (done) - #define AMX_INFO_RETVAL 8 (done) - #define AMX_INFO_CONTEXT 12 (done) - * * The variables we're passed in: * sp_context_t *ctx, uint32_t code_idx, cell_t *result */ @@ -45,7 +32,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); - //sub esp, 4*4 - allocate info array + //sub esp, 4*5 - allocate info array //mov esi, esp - save info pointer IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); @@ -69,13 +56,21 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) //mov ebp, [eax+] - get stack pointer //add ebp, edi - relocate to data section //mov ebx, ebp - copy sp to frm + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); + IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + + //mov ecx, edi - copy base of data to temp var + //add ecx, [eax+] - add memsize to get stack top + //mov [esi+16], ecx - store stack top into info pointer + IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG); + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_STACKTOP); + //mov ecx, [ebp+12] - get code index //add ecx, [eax+] - add code base to index //mov edx, [eax+] - get alt //mov eax, [eax+] - get pri - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); - IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base)); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt)); @@ -94,9 +89,10 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG); IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE); - /* where error checking/return functions should go to */ + /* save where error checking/halting functions should go to */ jitoffs_t offs_return; - if (never_inline) + CompData *data = (CompData *)jit->data; + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { /* We have to write code assume we're breaking out of a call */ //jmp [past the next instruction] @@ -121,7 +117,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) //pop esi //pop ebp //ret - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*5, MOD_REG); IA32_Pop_Reg(jit, REG_EBX); IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); @@ -131,6 +127,75 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) return offs_return; } +void Write_Error(JitWriter *jit, int error) +{ + CompData *data = (CompData *)jit->data; + + /* These are so small that we always inline them! */ + //mov eax, + //jmp [...jit_return] + IA32_Mov_Reg_Imm32(jit, REG_EAX, error); + jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); + IA32_Write_Jump32(jit, jmp, data->jit_return); +} + +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) +{ + CompData *data = (CompData *)jit->data; + + /* :TODO: Should this be checking for below heaplow? + * The old JIT did not. + */ + + bool call = false; + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) + { + /* If we're not in the initial generation phase, + * Write a call to the actual routine instead. + */ + if (!firstcall) + { + jitoffs_t call = IA32_Call_Imm32(jit, 0); + if (reg == REG_EAX) + { + IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); + } else if (reg == REG_EDX) { + IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); + } + return; + } + call = true; + } else if (firstcall) { + /* Inline + initial gen == no code */ + return; + } + + //cmp reg, [stp] + //jae memaccess + //cmp reg, [hea] + //jb continue + //lea ecx, [reg+edi] + //cmp ecx, ebp + //jae continue + //memaccess: (write error) + //continue: + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP); + jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); + jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0); + IA32_Lea_DispRegReg(jit, REG_ECX, reg, REG_EDI); + IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); + jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); + IA32_Send_Jump8_Here(jit, jmp1); + Write_Error(jit, SP_ERR_MEMACCESS); + IA32_Send_Jump8_Here(jit, jmp2); + IA32_Send_Jump8_Here(jit, jmp3); + if (call) + { + IA32_Return(jit); + } +} + void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 64a753c6..7cb8efd5 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -7,11 +7,20 @@ * This outputs the execution function for a plugin. * It also returns the 'return' offset, which is used for * breaking out of the JIT during runtime. - * - * If 'never_inline' is true, it outputs slightly different code used for - * inlining the error checking routines. */ -jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline); +jitoffs_t Write_Execute_Function(JitWriter *jit); + +/** + * Generates code to set an error state in the VM and return. + * Note that this should only be called from inside an error + * checking function. + */ +void Write_Error(JitWriter *jit, int error); + +/** + * Verifies an address by register. + */ +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); /** * These are for writing the PushN opcodes. @@ -32,7 +41,7 @@ typedef enum OP_LREF_ALT, //DONE OP_LREF_S_PRI, //DONE OP_LREF_S_ALT, //DONE - OP_LOAD_I, + OP_LOAD_I, //DONE OP_LODB_I, OP_CONST_PRI, //DONE OP_CONST_ALT, //DONE diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 7d0d5a0a..067e6620 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -97,6 +97,7 @@ #define IA32_SHL_RM_CL 0xD3 // encoding is /4 #define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 #define IA32_CMP_RM_REG 0x39 // encoding is /r +#define IA32_CMP_REG_RM 0x3B // encoding is /r #define IA32_SETCC_RM8_1 0x0F // opcode part 1 #define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits) #define IA32_XCHG_EAX_REG 0x90 // encoding is +r @@ -498,8 +499,16 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit->write_byte(val); } +inline void IA32_Lea_DispRegReg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t dispreg) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, dispreg, src_base)); +} + inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { + /* :TODO: - why does this take in src_base? */ jit->write_ubyte(IA32_LEA_REG_MEM); jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); jit->write_byte(val); @@ -507,6 +516,7 @@ inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t s inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) { + /* :TODO: - why does this take in src_base? */ jit->write_ubyte(IA32_LEA_REG_MEM); jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); jit->write_int32(val); @@ -709,12 +719,31 @@ inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) jit->outptr = oldptr; } +inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) +{ + //save old ptr + jitcode_t oldptr = jit->outptr; + //get relative difference + jit_int32_t diff = (target - (jmp + 1)); + //overwrite old value + jit->outptr = jit->outbase + jmp; + jit->write_int32(diff); + //restore old ptr + jit->outptr = oldptr; +} + inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { jitoffs_t curptr = jit->jit_curpos(); IA32_Write_Jump8(jit, jmp, curptr); } +inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp) +{ + jitoffs_t curptr = jit->jit_curpos(); + IA32_Write_Jump32(jit, jmp, curptr); +} + inline void IA32_Return(JitWriter *jit) { jit->write_ubyte(IA32_RET); @@ -732,6 +761,13 @@ inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_CMP_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2)); + jit->write_byte(disp8); +} + inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) { jit->write_ubyte(IA32_CMP_RM_IMM8); From 0503ac73b7e4c9ca254f1b4c43660915e63a476f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 15:51:05 +0000 Subject: [PATCH 0051/1664] implemented some more opcode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4081 --- sourcepawn/vm/jit/jit_helpers.h | 8 ++ sourcepawn/vm/jit/x86/jit_x86.cpp | 117 ++++++++++++++++++++++- sourcepawn/vm/jit/x86/jit_x86.h | 4 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 5 + sourcepawn/vm/jit/x86/opcode_helpers.h | 12 +-- sourcepawn/vm/jit/x86/x86_macros.h | 40 ++++++++ 6 files changed, 178 insertions(+), 8 deletions(-) diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index 5b74ce65..e7d79084 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -63,6 +63,14 @@ public: } outptr += sizeof(jit_int32_t); } + inline void write_uint32(jit_uint32_t c) + { + if (outptr) + { + *(jit_uint32_t *)outptr = c; + } + outptr += sizeof(jit_uint32_t); + } inline jitoffs_t jit_curpos() { return (outptr - outbase); diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e7cc2885..ba292178 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -755,6 +755,15 @@ inline void WriteOp_Idxaddr(JitWriter *jit) IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); } +inline void WriteOp_Idxaddr_B(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + //shl eax, + //add eax, edx + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + inline void WriteOp_Sref_Pri(JitWriter *jit) { //mov ecx, [edi+] @@ -1003,10 +1012,86 @@ inline void WriteOp_Const_S(JitWriter *jit) inline void WriteOp_Load_I(JitWriter *jit) { //mov eax, [edi+eax] - Write_Check_VerifyAddr(jit, REG_EAX, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +inline void WriteOp_Lodb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + + //mov eax, [edi+eax] + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + + //and eax, + cell_t val = jit->read_cell(); + switch(val) + { + case 1: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF); + break; + } + case 2: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF); + break; + } + } +} + +inline void WriteOp_Stor_I(JitWriter *jit) +{ + //mov [edi+edx], eax + Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); +} + +inline void WriteOp_Strb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + //mov [edi+edx], eax + cell_t val = jit->read_cell(); + switch (val) + { + case 1: + { + IA32_Mov_Rm8_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 2: + { + IA32_Mov_Rm16_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 3: + { + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + } +} + +inline void WriteOp_Lidx(JitWriter *jit) +{ + //lea eax, [edx+4*eax] + //mov eax, [edi+eax] + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} + +inline void WriteOp_Lidx_B(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + //shl eax, + //add eax, edx + //mov eax, [edi+eax] + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} /************************************************* ************************************************* @@ -1667,6 +1752,36 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Load_I(jit); break; } + case OP_LODB_I: + { + WriteOp_Lodb_I(jit); + break; + } + case OP_STOR_I: + { + WriteOp_Stor_I(jit); + break; + } + case OP_STRB_I: + { + WriteOp_Strb_I(jit); + break; + } + case OP_LIDX: + { + WriteOp_Lidx(jit); + break; + } + case OP_LIDX_B: + { + WriteOp_Lidx_B(jit); + break; + } + case OP_IDXADDR_B: + { + WriteOp_Idxaddr_B(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 0eb22f8f..5e53ee33 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -13,7 +13,8 @@ using namespace SourcePawn; class CompData : public ICompilation { public: - CompData() : plugin(NULL), debug(false), inline_level(3) + CompData() : plugin(NULL), + debug(false), inline_level(3), checks(true) { }; public: @@ -22,6 +23,7 @@ public: jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; int inline_level; + bool checks; bool debug; }; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 0b5180f9..df8bde71 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -147,6 +147,11 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) * The old JIT did not. */ + if (!data->checks) + { + return; + } + bool call = false; if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 7cb8efd5..3fbc6801 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -42,7 +42,7 @@ typedef enum OP_LREF_S_PRI, //DONE OP_LREF_S_ALT, //DONE OP_LOAD_I, //DONE - OP_LODB_I, + OP_LODB_I, //DONE OP_CONST_PRI, //DONE OP_CONST_ALT, //DONE OP_ADDR_PRI, //DONE @@ -55,12 +55,12 @@ typedef enum OP_SREF_ALT, //DONE OP_SREF_S_PRI, //DONE OP_SREF_S_ALT, //DONE - OP_STOR_I, - OP_STRB_I, - OP_LIDX, - OP_LIDX_B, + OP_STOR_I, //DONE + OP_STRB_I, //DONE + OP_LIDX, //DONE + OP_LIDX_B, //DONE OP_IDXADDR, //DONE - OP_IDXADDR_B, + OP_IDXADDR_B, //DONE OP_ALIGN_PRI, //DONE OP_ALIGN_ALT, //DONE OP_LCTRL, diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 067e6620..d12b86df 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -25,6 +25,8 @@ #define REG_ESI 6 #define REG_EDI 7 +#define IA32_16BIT_PREFIX 0x66 + //condition codes (for example, Jcc opcodes) #define CC_B 0x2 #define CC_NAE CC_B @@ -65,6 +67,7 @@ #define IA32_CALL_IMM32 0xE8 // relative call, #define IA32_CALL_RM 0xFF // encoding is /2 #define IA32_MOV_REG_IMM 0xB8 // encoding is +r +#define IA32_MOV_RM8_REG 0x88 // encoding is /r #define IA32_MOV_RM_REG 0x89 // encoding is /r #define IA32_MOV_REG_MEM 0x8B // encoding is /r #define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 @@ -83,6 +86,8 @@ #define IA32_DEC_RM 0xFF // encoding is /1 #define IA32_OR_RM_REG 0x09 // encoding is /r #define IA32_AND_RM_REG 0x21 // encoding is /r +#define IA32_AND_EAX_IMM32 0x25 // encoding is +#define IA32_AND_RM_IMM32 0x81 // encoding is /4 #define IA32_NOT_RM 0xF7 // encoding is /2 #define IA32_DIV_RM 0xF7 // encoding is /6 #define IA32_MUL_RM 0xF7 // encoding is /4 @@ -238,6 +243,18 @@ inline void IA32_And_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint32_t c) +{ + if (reg == REG_EAX) + { + jit->write_ubyte(IA32_AND_EAX_IMM32); + } else { + jit->write_ubyte(IA32_AND_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg)); + } + jit->write_uint32(c); +} + inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { jit->write_ubyte(IA32_NOT_RM); @@ -606,6 +623,29 @@ inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); } +inline void IA32_Mov_Rm8_Reg_Disp_Reg(JitWriter *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_uint8_t src) +{ + jit->write_ubyte(IA32_MOV_RM8_REG); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + +inline void IA32_Mov_Rm16_Reg_Disp_Reg(JitWriter *jit, + jit_uint8_t dest_base, + jit_uint8_t dest_index, + jit_uint8_t dest_scale, + jit_uint8_t src) +{ + jit->write_ubyte(IA32_16BIT_PREFIX); + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + /** * Moving from IMMEDIATE to REGISTER */ From 6e15ece9549b15ae926a917c18ce90fcedc03ec0 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 20 Sep 2006 18:19:31 +0000 Subject: [PATCH 0052/1664] bye to the slow xchg --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4082 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 27 +++++++++++++++++++-------- sourcepawn/vm/jit/x86/x86_macros.h | 14 +++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index ba292178..4a9fd689 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -18,7 +18,6 @@ inline void WriteOp_Move_Alt(JitWriter *jit) inline void WriteOp_Xchg(JitWriter *jit) { - /* :TODO: change this? XCHG is bad */ //xchg eax, edx IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT); } @@ -757,10 +756,10 @@ inline void WriteOp_Idxaddr(JitWriter *jit) inline void WriteOp_Idxaddr_B(JitWriter *jit) { - cell_t val = jit->read_cell(); //shl eax, //add eax, edx - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + cell_t val = jit->read_cell(); + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } @@ -850,14 +849,26 @@ inline void WriteOp_Pop_Alt(JitWriter *jit) inline void WriteOp_Swap_Pri(JitWriter *jit) { - //xchg [ebp], eax // :TODO: change this xchg for another thing (SLOW!! :O ) - IA32_Xchg_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); + //add [ebp], eax + //sub eax, [ebp] + //add [ebp], eax + //neg eax + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); } inline void WriteOp_Swap_Alt(JitWriter *jit) { - //xchg [ebp], edx // :TODO: change this xchg for another thing - IA32_Xchg_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); + //add [ebp], edx + //sub edx, [ebp] + //add [ebp], edx + //neg edx + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); + IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG); } inline void WriteOp_PushAddr(JitWriter *jit) @@ -1087,7 +1098,7 @@ inline void WriteOp_Lidx_B(JitWriter *jit) //shl eax, //add eax, edx //mov eax, [edi+eax] - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index d12b86df..835a4cd8 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -60,6 +60,7 @@ #define IA32_ADD_RM_IMM8 0x83 // encoding is /0 #define IA32_ADD_EAX_IMM32 0x05 // no extra encoding #define IA32_SUB_RM_REG 0x29 // encoding is /r +#define IA32_SUB_REG_RM 0x2B // encoding is /r #define IA32_SUB_RM_IMM8 0x83 // encoding is /5 #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 #define IA32_JMP_IMM32 0xE9 // encoding is imm32 @@ -106,7 +107,6 @@ #define IA32_SETCC_RM8_1 0x0F // opcode part 1 #define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits) #define IA32_XCHG_EAX_REG 0x90 // encoding is +r -#define IA32_XCHG_RM_REG 0x87 // encoding is /r #define IA32_LEA_REG_MEM 0x8D // encoding is /r #define IA32_POP_REG 0x58 // encoding is +r #define IA32_PUSH_REG 0x50 // encoding is +r @@ -305,12 +305,6 @@ inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(IA32_XCHG_EAX_REG+reg); } -inline void IA32_Xchg_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_XCHG_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - /********************** * ARITHMETIC (BASIC) * **********************/ @@ -347,6 +341,12 @@ inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_SUB_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_RM_IMM8); From 240d29846cc959da84fb8ef709b7e8a0bf29da71 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 20:11:02 +0000 Subject: [PATCH 0053/1664] committed OP_LCTRL for some reason added setpos() to JIT helpers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4083 --- sourcepawn/vm/jit/jit_helpers.h | 4 ++ sourcepawn/vm/jit/x86/jit_x86.cpp | 65 ++++++++++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 2 +- sourcepawn/vm/jit/x86/x86_macros.h | 5 +- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index e7d79084..43e6bd58 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -75,6 +75,10 @@ public: { return (outptr - outbase); } + inline void setpos(jitoffs_t offs) + { + outptr = outbase + offs; + } public: cell_t *inptr; /* input pointer */ jitcode_t outbase; /* output pointer */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 4a9fd689..85e58322 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1104,6 +1104,66 @@ inline void WriteOp_Lidx_B(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +inline void WriteOp_Lctrl(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + switch (val) + { + case 0: + { + //mov ecx, [esi+ctx] + //mov eax, [ecx+] + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_ECX, offsetof(sp_context_t, base)); + break; + } + case 1: + { + //mov eax, edi + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); + break; + } + case 2: + { + //mov eax, [esi+hea] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP); + break; + } + case 3: + { + //mov ecx, [esi+ctx] + //mov eax, [ecx+ctx.memory] + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_ECX, offsetof(sp_context_t, memory)); + break; + } + case 4: + { + //mov eax, ebp + //sub eax, edi - unrelocate + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG); + IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); + break; + } + case 5: + { + //mov eax, [esi+frm] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_FRM); + break; + } + case 6: + { + //mov eax, [cip] + jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + jitoffs_t save = jit->jit_curpos(); + jit->setpos(imm32); + jit->write_int32((uint32_t)(jit->outbase + save)); + jit->setpos(save); + break; + } + } +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1793,6 +1853,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Idxaddr_B(jit); break; } + case OP_LCTRL: + { + WriteOp_Lctrl(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 3fbc6801..7ecfe8f9 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -63,7 +63,7 @@ typedef enum OP_IDXADDR_B, //DONE OP_ALIGN_PRI, //DONE OP_ALIGN_ALT, //DONE - OP_LCTRL, + OP_LCTRL, //DONE OP_SCTRL, OP_MOVE_PRI, //DONE OP_MOVE_ALT, //DONE diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 835a4cd8..5b93e10c 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -650,10 +650,13 @@ inline void IA32_Mov_Rm16_Reg_Disp_Reg(JitWriter *jit, * Moving from IMMEDIATE to REGISTER */ -inline void IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) +inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) { + jitoffs_t offs; jit->write_ubyte(IA32_MOV_REG_IMM+dest); + offs = jit->jit_curpos(); jit->write_int32(num); + return offs; } inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, From ae9c2187cb53b036fd28ff8bb613e4dc7f1be0c4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 20:29:28 +0000 Subject: [PATCH 0054/1664] implemented op.sctrl --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4084 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 40 ++++++++++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 2 +- sourcepawn/vm/jit/x86/x86_macros.h | 7 +++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 85e58322..cd791b91 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1164,6 +1164,41 @@ inline void WriteOp_Lctrl(JitWriter *jit) } } +inline void WriteOp_Sctrl(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + switch (val) + { + case 2: + { + //mov [esi+hea], eax + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, AMX_REG_PRI); + break; + } + case 4: + { + //lea ebp, [edi+eax] + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + break; + } + case 5: + { + //mov ebx, eax - overwrite frm + //mov frm, eax - overwrite stacked frame + //add ebx, edi - relocate local frm + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_PRI, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_PRI, MOD_MEM_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + break; + } + case 6: + { + IA32_Jump_Reg(jit, AMX_REG_PRI); + break; + } + } +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1858,6 +1893,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Lctrl(jit); break; } + case OP_SCTRL: + { + WriteOp_Sctrl(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 7ecfe8f9..01942b03 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -64,7 +64,7 @@ typedef enum OP_ALIGN_PRI, //DONE OP_ALIGN_ALT, //DONE OP_LCTRL, //DONE - OP_SCTRL, + OP_SCTRL, //DONE OP_MOVE_PRI, //DONE OP_MOVE_ALT, //DONE OP_XCHG, //DONE diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 5b93e10c..dc86e62f 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -65,6 +65,7 @@ #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 #define IA32_JMP_IMM32 0xE9 // encoding is imm32 #define IA32_JMP_IMM8 0xEB // encoding is imm8 +#define IA32_JMP_RM 0xFF // encoding is /4 #define IA32_CALL_IMM32 0xE8 // relative call, #define IA32_CALL_RM 0xFF // encoding is /2 #define IA32_MOV_REG_IMM 0xB8 // encoding is +r @@ -734,6 +735,12 @@ inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int3 return ptr; } +inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg) +{ + jit->write_ubyte(IA32_JMP_RM); + jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg)); +} + inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; From fb39f34d4b8328e445990564f8d6cbcc2978c7b4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 21:23:48 +0000 Subject: [PATCH 0055/1664] committed op.stack --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4085 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 21 +++++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.cpp | 18 ++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 8 +++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index cd791b91..10e6c32c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1199,6 +1199,22 @@ inline void WriteOp_Sctrl(JitWriter *jit) } } +inline void WriteOp_Stack(JitWriter *jit) +{ + //mov edx, ebp + //add ebp, + //sub edx, edi + cell_t val = jit->read_cell(); + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); + else + IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); + IA32_Sub_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); + + Write_CheckMargin_Stack(jit); +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1898,6 +1914,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Sctrl(jit); break; } + case OP_STACK: + { + WriteOp_Stack(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index df8bde71..204aabf4 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -201,6 +201,24 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } +void Write_CheckMargin_Stack(JitWriter *jit) +{ + /* this is small, so we always inline it. + */ + //cmp ebp, [esi+stp] + //jle :continue + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); + if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) + { + //sub esp, 4 - correct stack for returning to non-inlined JIT + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); + } + Write_Error(jit, SP_ERR_STACKMIN); + //continue: + IA32_Send_Jump8_Here(jit, jmp); +} + void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 01942b03..d740d41f 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -22,6 +22,12 @@ void Write_Error(JitWriter *jit, int error); */ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); +/** + * Verifies stack margins. + */ +void Write_CheckMargin_Stack(JitWriter *jit); + + /** * These are for writing the PushN opcodes. */ @@ -76,7 +82,7 @@ typedef enum OP_PUSH_S, //DONE OP_POP_PRI, //DONE OP_POP_ALT, //DONE - OP_STACK, + OP_STACK, //DONE OP_HEAP, OP_PROC, //DONE OP_RET, From 82cb24e40b66c9057abda784b0942afd7b5afbd0 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 20 Sep 2006 22:12:55 +0000 Subject: [PATCH 0056/1664] div opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4086 --- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 40 +++++++++++++----------- sourcepawn/vm/jit/x86/opcode_helpers.h | 13 +++++--- sourcepawn/vm/jit/x86/x86_macros.h | 7 ----- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 204aabf4..f4136eb7 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -139,6 +139,26 @@ void Write_Error(JitWriter *jit, int error) IA32_Write_Jump32(jit, jmp, data->jit_return); } +void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) +{ + CompData *data = (CompData *)jit->data; + + //test reg, reg + //jnz :continue + //divzero: (write error) + IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) + { + //sub esp, 4 - correct stack for returning to non-inlined JIT + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); + } + Write_Error(jit, SP_ERR_DIVZERO); + //continue: + IA32_Send_Jump8_Here(jit, jmp); + +} + void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) { CompData *data = (CompData *)jit->data; @@ -188,7 +208,7 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0); - IA32_Lea_DispRegReg(jit, REG_ECX, reg, REG_EDI); + IA32_Lea_Reg_DispRegMult(jit, REG_ECX, reg, REG_EDI, NOSCALE); IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Send_Jump8_Here(jit, jmp1); @@ -201,24 +221,6 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } -void Write_CheckMargin_Stack(JitWriter *jit) -{ - /* this is small, so we always inline it. - */ - //cmp ebp, [esi+stp] - //jle :continue - IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); - if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) - { - //sub esp, 4 - correct stack for returning to non-inlined JIT - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - } - Write_Error(jit, SP_ERR_STACKMIN); - //continue: - IA32_Send_Jump8_Here(jit, jmp); -} - void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index d740d41f..9a56da08 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -27,6 +27,11 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); */ void Write_CheckMargin_Stack(JitWriter *jit); +/** +* Checks for division by zero. +*/ +void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg); + /** * These are for writing the PushN opcodes. @@ -111,11 +116,11 @@ typedef enum OP_SHR_C_PRI, //DONE OP_SHR_C_ALT, //DONE OP_SMUL, //DONE - OP_SDIV, - OP_SDIV_ALT, + OP_SDIV, //DONE + OP_SDIV_ALT, //DONE OP_UMUL, //DONE - OP_UDIV, - OP_UDIV_ALT, + OP_UDIV, //DONE + OP_UDIV_ALT, //DONE OP_ADD, //DONE OP_SUB, //DONE OP_SUB_ALT, //DONE diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index dc86e62f..66e22138 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -517,13 +517,6 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit->write_byte(val); } -inline void IA32_Lea_DispRegReg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t dispreg) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, dispreg, src_base)); -} - inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { /* :TODO: - why does this take in src_base? */ From fa759036422f10bd239dde96bb41b207a5bf3b06 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 20 Sep 2006 22:17:52 +0000 Subject: [PATCH 0057/1664] more div stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4087 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 71 ++++++++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.cpp | 19 +++++++ 2 files changed, 90 insertions(+) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 10e6c32c..a916da7d 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1215,6 +1215,57 @@ inline void WriteOp_Stack(JitWriter *jit) Write_CheckMargin_Stack(jit); } +inline void WriteOp_SDiv(JitWriter *jit) +{ + //mov ecx, edx + //mov edx, eax + //sar edx, 31 + //idiv ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); + IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); +} + + +inline void WriteOp_SDiv_Alt(JitWriter *jit) +{ + //mov ecx, eax + //mov eax, edx + //sar edx, 31 + //idiv ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); + IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_UDiv(JitWriter *jit) +{ + //mov ecx, edx + //xor edx, edx + //div ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_UDiv_Alt(JitWriter *jit) +{ + //mov ecx, eax + //mov eax, edx + //xor edx, edx + //div ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1919,6 +1970,26 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Stack(jit); break; } + case OP_SDIV: + { + WriteOp_SDiv(jit); + break; + } + case OP_SDIV_ALT: + { + WriteOp_SDiv_Alt(jit); + break; + } + case OP_UDIV: + { + WriteOp_UDiv(jit); + break; + } + case OP_UDIV_ALT: + { + WriteOp_UDiv_Alt(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index f4136eb7..795502d1 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -221,6 +221,25 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } +void Write_CheckMargin_Stack(JitWriter *jit) +{ + /* this is small, so we always inline it. + */ + //cmp ebp, [esi+stp] + //jle :continue + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); + if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) + { + //sub esp, 4 - correct stack for returning to non-inlined JIT + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); + } + Write_Error(jit, SP_ERR_STACKMIN); + //continue: + IA32_Send_Jump8_Here(jit, jmp); +} + + void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax From 894ac3c5135a29951009be9fc09fa5f444bac096 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Sep 2006 23:33:40 +0000 Subject: [PATCH 0058/1664] added heap opcode and check function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4088 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 47 ++++++++++++-- sourcepawn/vm/jit/x86/jit_x86.h | 13 ++-- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 79 ++++++++++++++++++++---- sourcepawn/vm/jit/x86/opcode_helpers.h | 7 ++- 4 files changed, 122 insertions(+), 24 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index a916da7d..7318ccfe 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -958,6 +958,8 @@ inline void WriteOp_Heap_Pri(JitWriter *jit) //add [hea], eax IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Push_Heap_C(JitWriter *jit) @@ -969,6 +971,8 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Rm_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) @@ -979,6 +983,8 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Load_Both(JitWriter *jit) @@ -1215,6 +1221,20 @@ inline void WriteOp_Stack(JitWriter *jit) Write_CheckMargin_Stack(jit); } +inline void WriteOp_Heap(JitWriter *jit) +{ + //mov edx, hea + //add hea, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_INFO_FRM, AMX_INFO_HEAP); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, (jit_int8_t)val, AMX_INFO_HEAP); + else + IA32_Add_Rm_Imm32_Disp8(jit, AMX_INFO_FRM, val, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); +} + inline void WriteOp_SDiv(JitWriter *jit) { //mov ecx, edx @@ -1338,6 +1358,7 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); + cell_t jitpos; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1346,19 +1367,30 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) writer.outptr = NULL; writer.outbase = NULL; - /* Get inlining level */ - int inline_level = data->inline_level; - //:TODO: Jump back here once finished! + /* Initialize pass vars */ + data->jit_chkmargin_heap = 0; + data->jit_verify_addr_eax = 0; + data->jit_verify_addr_edx = 0; + /* Start writing the actual code */ data->jit_return = Write_Execute_Function(jit); /* Write error checking routines in case they are needed */ - data->jit_verify_addr_eax = jit->jit_curpos(); + jitpos = jit->jit_curpos(); Write_Check_VerifyAddr(jit, REG_EAX, true); - data->jit_verify_addr_edx = jit->jit_curpos(); + data->jit_verify_addr_eax = jitpos; + + jitpos = jit->jit_curpos(); Write_Check_VerifyAddr(jit, REG_EDX, true); + data->jit_verify_addr_edx = jitpos; + + jitpos = jit->jit_curpos(); + Write_CheckMargin_Heap(jit); + data->jit_chkmargin_heap = jitpos; + + /* Begin opcode browsing */ for (; writer.inptr <= endptr;) { @@ -1970,6 +2002,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Stack(jit); break; } + case OP_HEAP: + { + WriteOp_Heap(jit); + break; + } case OP_SDIV: { WriteOp_SDiv(jit); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 5e53ee33..704367c9 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,6 +9,7 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) +#define STACK_MARGIN 16 class CompData : public ICompilation { @@ -22,6 +23,7 @@ public: jitoffs_t jit_return; jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; + jitoffs_t jit_chkmargin_heap; int inline_level; bool checks; bool debug; @@ -49,10 +51,11 @@ public: #define AMX_REG_INFO REG_ESI #define AMX_REG_FRM REG_EBX -#define AMX_INFO_FRM AMX_REG_INFO -#define AMX_INFO_HEAP 4 -#define AMX_INFO_RETVAL 8 -#define AMX_INFO_CONTEXT 12 -#define AMX_INFO_STACKTOP 16 +#define AMX_INFO_FRM AMX_REG_INFO //not relocated +#define AMX_INFO_HEAP 4 //not relocated +#define AMX_INFO_RETVAL 8 //physical +#define AMX_INFO_CONTEXT 12 //physical +#define AMX_INFO_STACKTOP 16 //relocated +#define AMX_INFO_HEAPLOW 20 //not relocated #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 795502d1..026b6611 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -32,27 +32,28 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); - //sub esp, 4*5 - allocate info array + //sub esp, 4*6 - allocate info array //mov esi, esp - save info pointer - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); - //mov eax, [ebp+16] - get result pointer - //mov [esi+8], eax - store into info pointer - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_RETVAL); - + /* Initial memory setup */ + //mov eax, [ebp+16] - get result pointer + //mov [esi+8], eax - store into info pointer //mov eax, [ebp+8] - get context //mov [esi+12], eax - store context into info pointer //mov ecx, [eax+] - get heap pointer //mov [esi+4], ecx - store heap into info pointer //mov edi, [eax+] - get data pointer + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_HEAP); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); + /* Frame setup */ //mov ebp, [eax+] - get stack pointer //add ebp, edi - relocate to data section //mov ebx, ebp - copy sp to frm @@ -60,13 +61,19 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + /* Info memory setup */ //mov ecx, edi - copy base of data to temp var //add ecx, [eax+] - add memsize to get stack top //mov [esi+16], ecx - store stack top into info pointer + //mov ecx, [eax+] - get heap low + //mov [esi+20], ecx - store heap low into info pointer IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG); IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_STACKTOP); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase)); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW); + /* Remaining needed vars */ //mov ecx, [ebp+12] - get code index //add ecx, [eax+] - add code base to index //mov edx, [eax+] - get alt @@ -77,7 +84,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri)); /* by now, everything is set up, so we can call into the plugin */ - //call ecx IA32_Call_Rm(jit, REG_ECX); @@ -111,13 +117,13 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) * BaseContext::Execute() automatically restores our values anyway. */ - //add esp, 4*4 + //add esp, 4*6 //pop ebx //pop edi //pop esi //pop ebp //ret - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*5, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); IA32_Pop_Reg(jit, REG_EBX); IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); @@ -221,6 +227,53 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } +void Write_CheckMargin_Heap(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + + bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); + + if (always_inline && data->jit_chkmargin_heap) + { + /* just generate the call */ + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, data->jit_chkmargin_heap); + } else { + //mov ecx, [esi+hea] + //cmp ecx, [esi+hlw] + //jl :error_heapmin + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Cmp_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAPLOW); + jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); + //lea ecx, [edi+ecx+STACK_MARGIN] + //cmp ecx, ebp + // jg :error_heaplow + //OR + // ret + IA32_Lea_Reg_DispRegMultImm8(jit, REG_ECX, AMX_REG_DAT, REG_ECX, NOSCALE, STACK_MARGIN); + IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); + jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0); + jitoffs_t cont; + if (always_inline) + { + cont = IA32_Jump_Imm8(jit, 0); + } else { + IA32_Return(jit); + } + //:error_heapmin + IA32_Send_Jump8_Here(jit, hm); + Write_Error(jit, SP_ERR_HEAPMIN); + //:error_heaplow + IA32_Send_Jump8_Here(jit, hl); + Write_Error(jit, SP_ERR_HEAPLOW); + //:continue + if (!always_inline) + { + IA32_Send_Jump8_Here(jit, cont); + } + } +} + void Write_CheckMargin_Stack(JitWriter *jit) { /* this is small, so we always inline it. diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 9a56da08..51f8619c 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -19,6 +19,7 @@ void Write_Error(JitWriter *jit, int error); /** * Verifies an address by register. + * :TODO: optimize and make it look like the heap checkfunction! */ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); @@ -27,6 +28,10 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); */ void Write_CheckMargin_Stack(JitWriter *jit); +/** + * Verifies heap margins. + */ +void Write_CheckMargin_Heap(JitWriter *jit); /** * Checks for division by zero. */ @@ -88,7 +93,7 @@ typedef enum OP_POP_PRI, //DONE OP_POP_ALT, //DONE OP_STACK, //DONE - OP_HEAP, + OP_HEAP, //DONE OP_PROC, //DONE OP_RET, OP_RETN, From 2ada76752870beb1ac4b0fb92aae840f8f8673d8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 21 Sep 2006 01:48:19 +0000 Subject: [PATCH 0059/1664] committed ret/retn --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4089 --- sourcepawn/include/sp_vm_types.h | 5 +++ sourcepawn/vm/jit/x86/jit_x86.cpp | 46 ++++++++++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 4 +-- sourcepawn/vm/jit/x86/x86_macros.h | 13 ++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 8de64699..3866174a 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -21,6 +21,10 @@ typedef int32_t cell_t; #define SP_ERR_STACKERR 9 /* Stack/Heap collision */ #define SP_ERR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ #define SP_ERR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ +#define SP_ERR_MEMACCESS 12 /* Invalid memory access */ +#define SP_ERR_STACKMIN 13 /* Stack went beyond its minimum value */ +#define SP_ERR_HEAPMIN 14 /* Heap went beyond its minimum value */ +#define SP_ERR_DIVIDE_BY_ZERO 15 /* Division by zero */ /********************************************** *** The following structures are reference structures. @@ -203,6 +207,7 @@ typedef struct sp_context_s cell_t alt; /* ALT register */ cell_t hp; /* heap pointer */ cell_t sp; /* stack pointer */ + cell_t frm; /* frame pointer */ int32_t err; /* error code */ uint32_t pushcount; /* push count */ /* context rebased database */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 7318ccfe..e9577a60 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1286,6 +1286,42 @@ inline void WriteOp_UDiv_Alt(JitWriter *jit) IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } +inline void WriteOp_Ret(JitWriter *jit) +{ + //mov ebx, [ebp] - get old FRM + //add ebp, 4 - pop stack + //mov [esi+frm], ebx - restore + //add ebx, edi - relocate + //ret + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM); + IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + IA32_Return(jit); +} + +inline void WriteOp_Retn(JitWriter *jit) +{ + //mov ebx, [ebp] - get old frm + //mov ecx, [ebp+4] - get return eip + //add ebp, 8 - pop stack + //mov [esi+frm], ebx - restore frame pointer + //add ebx, edi - relocate + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM); + IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + + //add ebp, [ebp] - reduce by this # of params + //add ebp, 4 - pop one extra for the # itself + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + + //jmp ecx - jump to return eip + IA32_Jump_Reg(jit, AMX_REG_TMP); +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -2027,6 +2063,16 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_UDiv_Alt(jit); break; } + case OP_RET: + { + WriteOp_Ret(jit); + break; + } + case OP_RETN: + { + WriteOp_Retn(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 51f8619c..0629a032 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -95,8 +95,8 @@ typedef enum OP_STACK, //DONE OP_HEAP, //DONE OP_PROC, //DONE - OP_RET, - OP_RETN, + OP_RET, //DONE + OP_RETN, //DONE OP_CALL, OP_CALL_PRI, OP_JUMP, diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 66e22138..b5fcc8f1 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -407,6 +407,12 @@ inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_ADD_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_ADD_REG_RM); @@ -664,6 +670,13 @@ inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, jit->write_int32(val); } +inline void IA32_Mov_Rm_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_MOV_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 0, dest)); + jit->write_int32(val); +} + inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, From 9ba07e4b2893922fbf14f31dfc327a82b9b06310 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 21 Sep 2006 02:58:59 +0000 Subject: [PATCH 0060/1664] added cmps, bounds, halt, and other fixes/additions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4090 --- sourcepawn/include/sp_vm_types.h | 1 + sourcepawn/vm/jit/x86/jit_x86.cpp | 82 +++++++++++++++++++++++- sourcepawn/vm/jit/x86/jit_x86.h | 1 + sourcepawn/vm/jit/x86/opcode_helpers.cpp | 57 +++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.h | 15 +++-- sourcepawn/vm/jit/x86/x86_macros.h | 20 ++++++ 6 files changed, 168 insertions(+), 8 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 3866174a..f89a5be4 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -25,6 +25,7 @@ typedef int32_t cell_t; #define SP_ERR_STACKMIN 13 /* Stack went beyond its minimum value */ #define SP_ERR_HEAPMIN 14 /* Heap went beyond its minimum value */ #define SP_ERR_DIVIDE_BY_ZERO 15 /* Division by zero */ +#define SP_ERR_ARRAY_BOUNDS 16 /* Array index is out of bounds */ /********************************************** *** The following structures are reference structures. diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e9577a60..932e74e4 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -930,6 +930,37 @@ inline void WriteOp_Movs(JitWriter *jit) IA32_Pop_Reg(jit, REG_ESI); } +inline void WriteOp_Cmps(JitWriter *jit) +{ + //push edi + //push esi + //lea esi, [edi+edx] + //lea edi, [edi+eax] + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_ESI); + IA32_Lea_Reg_DispRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Lea_Reg_DispRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + + //xor eax, eax + //repe cmpsb + //je :cmps1 + IA32_Xor_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Cmpsb(jit); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0); + + //sbb eax, eax + //sbb eax, -1 + IA32_Sbb_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Sbb_Eax_Imm32(jit, -1); + + //:cmps1 + //pop esi + //pop edi + IA32_Send_Jump8_Here(jit, jmp); + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EDI); +} + inline void WriteOp_Fill(JitWriter *jit) { //add edi, edx @@ -1322,6 +1353,36 @@ inline void WriteOp_Retn(JitWriter *jit) IA32_Jump_Reg(jit, AMX_REG_TMP); } +inline void WriteOp_Bounds(JitWriter *jit) +{ + Write_BoundsCheck(jit); +} + +inline void WriteOp_Halt(JitWriter *jit) +{ + //mov ecx, [esi+ret] + //mov [ecx], eax + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL); + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG); + + /* :TODO: + * We don't support sleeping or halting with weird values. + * So we're omitting the mov eax that was here. + */ + jit->read_cell(); + + CompData *data = (CompData *)jit->data; + jitoffs_t reloc; + if (data->inline_level & JIT_INLINE_ERRORCHECKS) + { + reloc = IA32_Jump_Imm32(jit, 0); + } else { + reloc = IA32_Call_Imm32(jit, 0); + } + IA32_Write_Jump32(jit, reloc, data->jit_return); +} + + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1409,6 +1470,7 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) data->jit_chkmargin_heap = 0; data->jit_verify_addr_eax = 0; data->jit_verify_addr_edx = 0; + data->jit_bounds = 0; /* Start writing the actual code */ data->jit_return = Write_Execute_Function(jit); @@ -1426,8 +1488,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) Write_CheckMargin_Heap(jit); data->jit_chkmargin_heap = jitpos; - /* Begin opcode browsing */ + jitpos = jit->jit_curpos(); + Write_BoundsCheck(jit); + data->jit_bounds = jitpos; + /* Begin opcode browsing */ for (; writer.inptr <= endptr;) { op = (OPCODE)writer.read_cell(); @@ -2073,6 +2138,21 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Retn(jit); break; } + case OP_CMPS: + { + WriteOp_Cmps(jit); + break; + } + case OP_BOUNDS: + { + WriteOp_Bounds(jit); + break; + } + case OP_HALT: + { + WriteOp_Halt(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 704367c9..edcb212f 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -24,6 +24,7 @@ public: jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; jitoffs_t jit_chkmargin_heap; + jitoffs_t jit_bounds; int inline_level; bool checks; bool debug; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 026b6611..18ffa95d 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -159,7 +159,7 @@ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) //sub esp, 4 - correct stack for returning to non-inlined JIT IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); } - Write_Error(jit, SP_ERR_DIVZERO); + Write_Error(jit, SP_ERR_DIVIDE_BY_ZERO); //continue: IA32_Send_Jump8_Here(jit, jmp); @@ -227,13 +227,66 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } +void Write_BoundsCheck(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); + + /* :TODO: break out on high -O level? */ + + if (!always_inline) + { + if (data->jit_bounds) + { + /* just generate the call */ + //mov ecx, + //call + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit->read_cell()); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, data->jit_bounds); + } else { + //cmp eax, 0 + //jl :err_bounds + //cmp eax, ecx + //jg :err_bounds + //ret + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0); + jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); + //:TODO: make sure this is right order + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); + jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); + IA32_Return(jit); + IA32_Send_Jump8_Here(jit, jmp1); + IA32_Send_Jump8_Here(jit, jmp2); + Write_Error(jit, SP_ERR_ARRAY_BOUNDS); + } + } else { + //cmp eax, 0 + //jl :err_bounds + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0); + jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); + //cmp eax, + //jg :err_bounds + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, jit->read_cell()); + jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); + //jmp :continue + jitoffs_t cont = IA32_Jump_Imm8(jit, 0); + //:err_bounds + IA32_Send_Jump8_Here(jit, jmp1); + IA32_Send_Jump8_Here(jit, jmp2); + Write_Error(jit, SP_ERR_ARRAY_BOUNDS); + //:continue + IA32_Send_Jump8_Here(jit, cont); + } +} + void Write_CheckMargin_Heap(JitWriter *jit) { CompData *data = (CompData *)jit->data; bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); - if (always_inline && data->jit_chkmargin_heap) + if (!always_inline && data->jit_chkmargin_heap) { /* just generate the call */ jitoffs_t call = IA32_Call_Imm32(jit, 0); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 0629a032..23f66eab 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -32,11 +32,16 @@ void Write_CheckMargin_Stack(JitWriter *jit); * Verifies heap margins. */ void Write_CheckMargin_Heap(JitWriter *jit); + /** -* Checks for division by zero. -*/ + * Checks for division by zero. + */ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg); +/** + * Writes a bounds check. + */ +void Write_BoundsCheck(JitWriter *jit); /** * These are for writing the PushN opcodes. @@ -166,10 +171,10 @@ typedef enum OP_DEC_S, //DONE OP_DEC_I, //DONE OP_MOVS, //DONE - OP_CMPS, + OP_CMPS, //DONE OP_FILL, //DONE - OP_HALT, - OP_BOUNDS, + OP_HALT, //DONE + OP_BOUNDS, //DONE OP_SYSREQ_PRI, OP_SYSREQ_C, OP_FILE, //DEPRECATED diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index b5fcc8f1..bf62a38b 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -63,6 +63,8 @@ #define IA32_SUB_REG_RM 0x2B // encoding is /r #define IA32_SUB_RM_IMM8 0x83 // encoding is /5 #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 +#define IA32_SBB_RM_REG 0x19 // encoding is /r +#define IA32_SBB_EAX_IMM32 0x1D // encoding is #define IA32_JMP_IMM32 0xE9 // encoding is imm32 #define IA32_JMP_IMM8 0xEB // encoding is imm8 #define IA32_JMP_RM 0xFF // encoding is /4 @@ -76,6 +78,7 @@ #define IA32_CMP_RM_IMM32 0x81 // encoding is /7 #define IA32_CMP_RM_IMM8 0x83 // encoding is /7 #define IA32_CMP_EAX_IMM32 0x3D // no extra encoding +#define IA32_CMPSB 0xA6 // no extra encoding #define IA32_TEST_RM_REG 0x85 // encoding is /r #define IA32_JCC_IMM 0x70 // encoding is +cc #define IA32_JCC_IMM32_1 0x0F // opcode part 1 @@ -342,6 +345,12 @@ inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Sbb_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_SBB_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); +} + inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_REG_RM); @@ -362,6 +371,12 @@ inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit->write_int32(val); } +inline void IA32_Sbb_Eax_Imm32(JitWriter *jit, jit_int32_t value) +{ + jit->write_ubyte(IA32_SBB_EAX_IMM32); + jit->write_int32(value); +} + inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) { jit->write_ubyte(IA32_DIV_RM); @@ -859,6 +874,11 @@ inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond) jit->write_ubyte(ia32_modrm(MOD_REG, 0, reg)); } +inline void IA32_Cmpsb(JitWriter *jit) +{ + jit->write_ubyte(IA32_CMPSB); +} + inline void IA32_Rep(JitWriter *jit) { jit->write_ubyte(IA32_REP); From 1bf17b05bb8e09bd37990362892c34a5857ec2c2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 21 Sep 2006 05:04:51 +0000 Subject: [PATCH 0061/1664] sketched out break opcode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4091 --- sourcepawn/include/sp_vm_types.h | 16 ++++++-- sourcepawn/vm/jit/x86/jit_x86.cpp | 51 ++++++++++++++++++------ sourcepawn/vm/jit/x86/jit_x86.h | 2 + sourcepawn/vm/jit/x86/opcode_helpers.cpp | 35 +++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.h | 7 +++- sourcepawn/vm/jit/x86/x86_macros.h | 30 +++++++++++++- 6 files changed, 122 insertions(+), 19 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index f89a5be4..95434180 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -175,10 +175,20 @@ typedef struct sp_debug_symbol_s sp_fdbg_symbol_t *sym; /* pointer to original symbol */ } sp_debug_symbol_t; +namespace SourcePawn +{ + class IPluginContext; + class IVirtualMachine; +}; + /** * Breaks into a debugger + * Params: + * [0] - plugin context + * [1] - frm + * [2] - cip */ -typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *); +typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t); #define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ @@ -193,8 +203,8 @@ typedef struct sp_context_s /* general/parent information */ void *base; /* base of generated code and memory */ sp_plugin_t *plugin; /* pointer back to parent information */ - void *context; /* pointer to IPluginContext */ - void *vmbase; /* pointer to IVirtualMachine */ + SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ + SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ void *user[4]; /* user specific pointers */ void *vm[4]; /* VM specific pointers */ uint32_t flags; /* compilation flags */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 932e74e4..2c80df62 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1382,6 +1382,23 @@ inline void WriteOp_Halt(JitWriter *jit) IA32_Write_Jump32(jit, reloc, data->jit_return); } +inline void WriteOp_Break(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + if (data->debug) + { + //mov ecx, + jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); + jitoffs_t save = jit->jit_curpos(); + jit->setpos(wr); + jit->write_uint32((uint32_t)(jit->outbase + wr)); + jit->setpos(save); + + wr = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, wr, data->jit_break); + } +} + /************************************************* ************************************************* @@ -1476,21 +1493,24 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) data->jit_return = Write_Execute_Function(jit); /* Write error checking routines in case they are needed */ - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EAX, true); - data->jit_verify_addr_eax = jitpos; + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) + { + jitpos = jit->jit_curpos(); + Write_Check_VerifyAddr(jit, REG_EAX, true); + data->jit_verify_addr_eax = jitpos; + + jitpos = jit->jit_curpos(); + Write_Check_VerifyAddr(jit, REG_EDX, true); + data->jit_verify_addr_edx = jitpos; - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EDX, true); - data->jit_verify_addr_edx = jitpos; + jitpos = jit->jit_curpos(); + Write_CheckMargin_Heap(jit); + data->jit_chkmargin_heap = jitpos; - jitpos = jit->jit_curpos(); - Write_CheckMargin_Heap(jit); - data->jit_chkmargin_heap = jitpos; - - jitpos = jit->jit_curpos(); - Write_BoundsCheck(jit); - data->jit_bounds = jitpos; + jitpos = jit->jit_curpos(); + Write_BoundsCheck(jit); + data->jit_bounds = jitpos; + } /* Begin opcode browsing */ for (; writer.inptr <= endptr;) @@ -2153,6 +2173,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Halt(jit); break; } + case OP_BREAK: + { + WriteOp_Break(jit); + break; + } default: { AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index edcb212f..dd619892 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -25,6 +25,7 @@ public: jitoffs_t jit_verify_addr_edx; jitoffs_t jit_chkmargin_heap; jitoffs_t jit_bounds; + jitoffs_t jit_break; int inline_level; bool checks; bool debug; @@ -53,6 +54,7 @@ public: #define AMX_REG_FRM REG_EBX #define AMX_INFO_FRM AMX_REG_INFO //not relocated +#define AMX_INFO_FRAME 0 //(same thing as above) #define AMX_INFO_HEAP 4 //not relocated #define AMX_INFO_RETVAL 8 //physical #define AMX_INFO_CONTEXT 12 //physical diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 18ffa95d..f35b7c5e 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -85,7 +85,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) /* by now, everything is set up, so we can call into the plugin */ //call ecx - IA32_Call_Rm(jit, REG_ECX); + IA32_Call_Reg(jit, REG_ECX); /* if the code flow gets to here, there was a normal return */ //mov ebp, [esi+8] - get retval pointer @@ -133,6 +133,39 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) return offs_return; } +void Write_BreakDebug(JitWriter *jit) +{ + //push ecx + //mov ecx, [esi+ctx] + //cmp [ecx+dbreak], 0 + //jnz :nocall + IA32_Push_Reg(jit, AMX_REG_TMP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); + + //pushad + IA32_Pushad(jit); + + //push [esi+frm] + //push [ecx+context] + //mov ecx, [ecx+dbreak] + //call ecx + //add esp, 8 + //popad + IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); + IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); + IA32_Call_Reg(jit, AMX_REG_TMP); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG); + IA32_Popad(jit); + + //:nocall + IA32_Send_Jump8_Here(jit, jmp); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG); + IA32_Return(jit); +} + void Write_Error(JitWriter *jit, int error) { CompData *data = (CompData *)jit->data; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 23f66eab..6417ea8a 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -43,6 +43,11 @@ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg); */ void Write_BoundsCheck(JitWriter *jit); +/** + * Writes the break debug function. + */ +void Write_BreakDebug(JitWriter *jit); + /** * These are for writing the PushN opcodes. */ @@ -190,7 +195,7 @@ typedef enum OP_NOP, //DONE OP_SYSREQ_N, OP_SYMTAG, //DEPRECATED - OP_BREAK, + OP_BREAK, //DONE OP_PUSH2_C, //DONE OP_PUSH2, //DONE OP_PUSH2_S, //DONE diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index bf62a38b..2994042a 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -114,11 +114,14 @@ #define IA32_LEA_REG_MEM 0x8D // encoding is /r #define IA32_POP_REG 0x58 // encoding is +r #define IA32_PUSH_REG 0x50 // encoding is +r +#define IA32_PUSH_RM 0xFF // encoding is /6 #define IA32_REP 0xF3 // no extra encoding #define IA32_MOVSD 0xA5 // no extra encoding #define IA32_MOVSB 0xA4 // no extra encoding #define IA32_STOSD 0xAB // no extra encoding #define IA32_CLD 0xFC // no extra encoding +#define IA32_PUSHAD 0x60 // no extra encoding +#define IA32_POPAD 0x61 // no extra encoding inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -568,6 +571,23 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(IA32_PUSH_REG+reg); } +inline void IA32_Pushad(JitWriter *jit) +{ + jit->write_ubyte(IA32_PUSHAD); +} + +inline void IA32_Popad(JitWriter *jit) +{ + jit->write_ubyte(IA32_POPAD); +} + +inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t disp8) +{ + jit->write_ubyte(IA32_PUSH_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg)); + jit->write_ubyte(disp8); +} + /** * Moving from REGISTER/MEMORY to REGISTER */ @@ -771,7 +791,7 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } -inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg) +inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg) { jit->write_ubyte(IA32_CALL_RM); jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg)); @@ -853,6 +873,14 @@ inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit->write_int32(imm32); } +inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t disp8, jit_int32_t imm32) +{ + jit->write_ubyte(IA32_CMP_RM_IMM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg)); + jit->write_ubyte(disp8); + jit->write_int32(imm32); +} + inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) { jit->write_ubyte(IA32_CMP_RM_IMM8); From 80688365a282b3ade802d00f2bd12d93433bae29 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 22 Sep 2006 11:52:19 +0000 Subject: [PATCH 0062/1664] organising stuff s bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4092 --- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 12 +++++----- sourcepawn/vm/jit/x86/x86_macros.h | 28 ++++++++++++------------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index f35b7c5e..b1ce1b45 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -247,8 +247,8 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0); - IA32_Lea_Reg_DispRegMult(jit, REG_ECX, reg, REG_EDI, NOSCALE); - IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_TMP, reg, AMX_REG_DAT, NOSCALE); + IA32_Cmp_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Send_Jump8_Here(jit, jmp1); Write_Error(jit, SP_ERR_MEMACCESS); @@ -328,15 +328,15 @@ void Write_CheckMargin_Heap(JitWriter *jit) //mov ecx, [esi+hea] //cmp ecx, [esi+hlw] //jl :error_heapmin - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Cmp_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAPLOW); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW); jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); //lea ecx, [edi+ecx+STACK_MARGIN] //cmp ecx, ebp // jg :error_heaplow //OR // ret - IA32_Lea_Reg_DispRegMultImm8(jit, REG_ECX, AMX_REG_DAT, REG_ECX, NOSCALE, STACK_MARGIN); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0); jitoffs_t cont; @@ -378,7 +378,6 @@ void Write_CheckMargin_Stack(JitWriter *jit) IA32_Send_Jump8_Here(jit, jmp); } - void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax @@ -643,4 +642,3 @@ JITX86::JITX86() OpAdvTable[OP_SYSREQ_ND] = -3; OpAdvTable[OP_PUSH_R] = -3; } - diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 2994042a..48cc660b 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -250,7 +250,7 @@ inline void IA32_And_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } -inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint32_t c) +inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t c) { if (reg == REG_EAX) { @@ -259,7 +259,7 @@ inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint32_t c) jit->write_ubyte(IA32_AND_RM_IMM32); jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg)); } - jit->write_uint32(c); + jit->write_int32(c); } inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) @@ -322,6 +322,12 @@ inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_ADD_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) { jit->write_ubyte(IA32_ADD_RM_IMM8); @@ -348,12 +354,6 @@ inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } -inline void IA32_Sbb_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SBB_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_REG_RM); @@ -374,6 +374,12 @@ inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit->write_int32(val); } +inline void IA32_Sbb_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_SBB_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); +} + inline void IA32_Sbb_Eax_Imm32(JitWriter *jit, jit_int32_t value) { jit->write_ubyte(IA32_SBB_EAX_IMM32); @@ -425,12 +431,6 @@ inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } -inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_ADD_REG_RM); From f454b114cb83b430cb61281fbbfadea5e24ea849 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 22 Sep 2006 11:52:48 +0000 Subject: [PATCH 0063/1664] organising stuff a bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4093 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 2c80df62..604578da 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1150,8 +1150,8 @@ inline void WriteOp_Lctrl(JitWriter *jit) { //mov ecx, [esi+ctx] //mov eax, [ecx+] - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_ECX, offsetof(sp_context_t, base)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, base)); break; } case 1: @@ -1170,8 +1170,8 @@ inline void WriteOp_Lctrl(JitWriter *jit) { //mov ecx, [esi+ctx] //mov eax, [ecx+ctx.memory] - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_ECX, offsetof(sp_context_t, memory)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory)); break; } case 4: @@ -1273,13 +1273,12 @@ inline void WriteOp_SDiv(JitWriter *jit) //sar edx, 31 //idiv ecx IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); } - inline void WriteOp_SDiv_Alt(JitWriter *jit) { //mov ecx, eax @@ -1287,9 +1286,9 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) //sar edx, 31 //idiv ecx IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); } @@ -1299,8 +1298,8 @@ inline void WriteOp_UDiv(JitWriter *jit) //xor edx, edx //div ecx IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } @@ -1311,9 +1310,9 @@ inline void WriteOp_UDiv_Alt(JitWriter *jit) //xor edx, edx //div ecx IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } From 96505c8e607a0a08c69ddef4a09b7949021d271b Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 22 Sep 2006 12:41:08 +0000 Subject: [PATCH 0064/1664] fixed a LEA macro --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4094 --- sourcepawn/vm/jit/x86/x86_macros.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 48cc660b..9d69db42 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -543,17 +543,15 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { - /* :TODO: - why does this take in src_base? */ jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base)); jit->write_byte(val); } inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) { - /* :TODO: - why does this take in src_base? */ jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG)); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base)); jit->write_int32(val); } @@ -585,7 +583,7 @@ inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t disp { jit->write_ubyte(IA32_PUSH_RM); jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg)); - jit->write_ubyte(disp8); + jit->write_ubyte(disp8); // :TODO: is it ubyte or byte?? } /** From 845ae657974604cd9313e3b122403a3d081c609f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 22 Sep 2006 21:38:58 +0000 Subject: [PATCH 0065/1664] fixes here and there --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4095 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 14 +++++++------- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 6 +++--- sourcepawn/vm/jit/x86/x86_macros.h | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 604578da..1a302586 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -951,7 +951,7 @@ inline void WriteOp_Cmps(JitWriter *jit) //sbb eax, eax //sbb eax, -1 IA32_Sbb_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Sbb_Eax_Imm32(jit, -1); + IA32_Sbb_Eax_Imm32(jit, -1);//:TODO: use imm8 here //:cmps1 //pop esi @@ -1077,12 +1077,12 @@ inline void WriteOp_Lodb_I(JitWriter *jit) { case 1: { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF); + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);//:TODO: replace with AND EAX, imm32 break; } case 2: { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF); + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);//:TODO: replace with AND EAX, imm32 break; } } @@ -1112,7 +1112,7 @@ inline void WriteOp_Strb_I(JitWriter *jit) IA32_Mov_Rm16_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); break; } - case 3: + case 4: { IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); break; @@ -1222,7 +1222,7 @@ inline void WriteOp_Sctrl(JitWriter *jit) { //mov ebx, eax - overwrite frm //mov frm, eax - overwrite stacked frame - //add ebx, edi - relocate local frm + //add ebx, edi - relocate local frm //:TODO: use LEA here!!! IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_PRI, MOD_REG); IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_PRI, MOD_MEM_REG); IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); @@ -1325,7 +1325,7 @@ inline void WriteOp_Ret(JitWriter *jit) //ret IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); IA32_Return(jit); } @@ -1340,7 +1340,7 @@ inline void WriteOp_Retn(JitWriter *jit) IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); //add ebp, [ebp] - reduce by this # of params diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index b1ce1b45..f6c2d3ff 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -283,7 +283,7 @@ void Write_BoundsCheck(JitWriter *jit) //cmp eax, ecx //jg :err_bounds //ret - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0);//:TODO: use imm8 jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); //:TODO: make sure this is right order IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); @@ -296,11 +296,11 @@ void Write_BoundsCheck(JitWriter *jit) } else { //cmp eax, 0 //jl :err_bounds - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0);//:TODO: use imm8 jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); //cmp eax, //jg :err_bounds - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, jit->read_cell()); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, jit->read_cell());//:TODO:check val size and use cmp eax or imm8 jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); //jmp :continue jitoffs_t cont = IA32_Jump_Imm8(jit, 0); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 9d69db42..8083ee95 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -579,11 +579,11 @@ inline void IA32_Popad(JitWriter *jit) jit->write_ubyte(IA32_POPAD); } -inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t disp8) +inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8) { jit->write_ubyte(IA32_PUSH_RM); jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg)); - jit->write_ubyte(disp8); // :TODO: is it ubyte or byte?? + jit->write_byte(disp8); } /** @@ -871,11 +871,11 @@ inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit->write_int32(imm32); } -inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t disp8, jit_int32_t imm32) +inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8, jit_int32_t imm32) { jit->write_ubyte(IA32_CMP_RM_IMM32); jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg)); - jit->write_ubyte(disp8); + jit->write_byte(disp8); jit->write_int32(imm32); } From 968692755bbc4ad0cbdad0a46b436582cf55c03b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 23 Sep 2006 04:11:01 +0000 Subject: [PATCH 0066/1664] merged in the easy relocation requiring opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4096 --- sourcepawn/vm/jit/jit_helpers.h | 6 + sourcepawn/vm/jit/x86/jit_x86.cpp | 892 +++++---------------- sourcepawn/vm/jit/x86/jit_x86.h | 9 +- sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 4 + sourcepawn/vm/jit/x86/opcode_helpers.h | 28 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 724 +++++++++++++++++ sourcepawn/vm/jit/x86/x86_macros.h | 20 +- 7 files changed, 990 insertions(+), 693 deletions(-) create mode 100644 sourcepawn/vm/jit/x86/opcode_switch.inc diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index 43e6bd58..d0bf929d 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -23,6 +23,7 @@ typedef unsigned __int64 jit_uint64_t; typedef char * jitcode_t; typedef unsigned int jitoffs_t; +typedef signed int jitrel_t; class JitWriter { @@ -79,8 +80,13 @@ public: { outptr = outbase + offs; } + inline jitoffs_t inputrel() + { + return (jitoffs_t)((char *)inptr - (char *)inbase); + } public: cell_t *inptr; /* input pointer */ + cell_t *inbase; /* input base */ jitcode_t outbase; /* output pointer */ jitcode_t outptr; /* output base */ SourcePawn::ICompilation *data; /* compiler live info */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 1a302586..b69ea6d5 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "jit_x86.h" #include "opcode_helpers.h" #include "x86_macros.h" @@ -1398,15 +1399,165 @@ inline void WriteOp_Break(JitWriter *jit) } } +inline void WriteOp_JRel(JitWriter *jit) +{ + //jmp ;relative jump + cell_t cip_offs = jit->read_cell(); + + /* Note that since code size calculation has to be done in the same + * phase as building relocation information, we cannot know the jump size + * beforehand. Thus, we always write full 32bit jumps for safety. + */ + jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); + IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs)); +} + +inline void WriteOp_Jump(JitWriter *jit) +{ + //jmp + cell_t amx_offs = jit->read_cell(); + + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false)); +} + +inline void WriteOp_Jzer(JitWriter *jit) +{ + //test eax, eax + //jz + cell_t target = jit->read_cell(); + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jnz(JitWriter *jit) +{ + //test eax, eax + //jnz + cell_t target = jit->read_cell(); + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jeq(JitWriter *jit) +{ + //cmp eax, edx + //je + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jneq(JitWriter *jit) +{ + //cmp eax, edx + //jne + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jless(JitWriter *jit) +{ + //cmp eax, edx + //jb + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jleq(JitWriter *jit) +{ + //cmp eax, edx + //jbe + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jgrtr(JitWriter *jit) +{ + //cmp eax, edx + //ja + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jgeq(JitWriter *jit) +{ + //cmp eax, edx + //jae + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jsless(JitWriter *jit) +{ + //cmp eax, edx + //jl + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_L, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jsleq(JitWriter *jit) +{ + //cmp eax, edx + //jle + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_LE, RelocLookup(jit, target, false)); +} + +inline void WriteOp_JsGrtr(JitWriter *jit) +{ + //cmp eax, edx + //jg + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_G, RelocLookup(jit, target, false)); +} + +inline void WriteOp_JsGeq(JitWriter *jit) +{ + //cmp eax, edx + //jge + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false)); +} /************************************************* ************************************************* * JIT PROPER ************************************ - * The rest of the from now on is the JIT engine * + * The rest from now on is the JIT engine * ************************************************* *************************************************/ +jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) +{ + if (jit->outptr) + { + CompData *data = (CompData *)jit->data; + if (relative) + { + /* The actual offset is EIP relative. We need to relocate it. + * Note that this assumes that we're pointing to the next op. + */ + pcode_offs += jit->inputrel(); + } + /* Offset must always be 1)positive and 2)less than the codesize */ + assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize); + /* Do the lookup in the native dictionary. */ + return *(jitoffs_t *)(data->rebase + pcode_offs); + } else { + return 0; + } +} + IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) { CompData *data = (CompData *)co; @@ -1418,7 +1569,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) uint8_t *end_cip = plugin->pcode + plugin->pcode_size; OPCODE op; int op_c; - uint32_t reloc_count = 0; /* FIRST PASS (light load) - Get initial opcode information */ for (cip = code; cip < end_cip;) @@ -1440,7 +1590,7 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) *err = SP_ERR_INVALID_INSTRUCTION; return NULL; } else if (op_c == -2) { - reloc_count++; + /* :TODO: get rid of this block */ cip += sizeof(cell_t); } else if (op_c == -1) { switch (op) @@ -1449,7 +1599,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) { ucell_t num = *(ucell_t *)cip; cip += sizeof(cell_t); - reloc_count += (num + 1); cip += ((2*num) + 1) * sizeof(cell_t); break; } @@ -1476,13 +1625,16 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) /* Initial code is written "blank," * so we can check the exact memory usage. */ - writer.inptr = (cell_t *)code; + data->codesize = plugin->pcode_size; + writer.inbase = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; + data->rebase = (jitcode_t *)engine->BaseAlloc(plugin->pcode_size); -//:TODO: Jump back here once finished! - + /* Jump back here for second pass */ +jit_rewind: /* Initialize pass vars */ + writer.inptr = writer.inbase; data->jit_chkmargin_heap = 0; data->jit_verify_addr_eax = 0; data->jit_verify_addr_edx = 0; @@ -1511,684 +1663,70 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) data->jit_bounds = jitpos; } - /* Begin opcode browsing */ - for (; writer.inptr <= endptr;) + if (writer.outbase == NULL) { - op = (OPCODE)writer.read_cell(); - switch (op) + /******* + * SECOND PASS - get opcode sizes+info + *******/ + jitoffs_t pcode_offs; + jitoffs_t native_offs; + + for (; writer.inptr <= endptr;) { - case OP_MOVE_PRI: - { - WriteOp_Move_Pri(jit); - break; - } - case OP_MOVE_ALT: - { - WriteOp_Move_Alt(jit); - break; - } - case OP_XCHG: - { - WriteOp_Xchg(jit); - break; - } - case OP_PUSH: - { - WriteOp_Push(jit); - break; - } - case OP_PUSH_S: - { - WriteOp_Push_S(jit); - break; - } - case OP_PUSH2_C: - { - WriteOp_Push2_C(jit); - break; - } - case OP_PUSH3_C: - { - WriteOp_Push3(jit); - break; - } - case OP_PUSH4_C: - { - WriteOp_Push4_C(jit); - break; - } - case OP_PUSH5_C: - { - WriteOp_Push5_C(jit); - break; - } - case OP_PUSH2_ADR: - { - WriteOp_Push2_Adr(jit); - break; - } - case OP_PUSH3_ADR: - { - WriteOp_Push3_Adr(jit); - break; - } - case OP_PUSH4_ADR: - { - WriteOp_Push4_Adr(jit); - break; - } - case OP_PUSH5_ADR: - { - WriteOp_Push5_Adr(jit); - break; - } - case OP_PUSH2_S: - { - WriteOp_Push2_S(jit); - break; - } - case OP_PUSH3_S: - { - WriteOp_Push3_S(jit); - break; - } - case OP_PUSH4_S: - { - WriteOp_Push4_S(jit); - break; - } - case OP_PUSH5_S: - { - WriteOp_Push5_S(jit); - break; - } - case OP_PUSH5: - { - WriteOp_Push5(jit); - break; - } - case OP_PUSH4: - { - WriteOp_Push4(jit); - break; - } - case OP_PUSH3: - { - WriteOp_Push3(jit); - break; - } - case OP_PUSH2: - { - WriteOp_Push2(jit); - break; - } - case OP_ZERO_PRI: - { - WriteOp_Zero_Pri(jit); - break; - } - case OP_ZERO_ALT: - { - WriteOp_Zero_Alt(jit); - break; - } - case OP_PROC: - { - WriteOp_Proc(jit); - break; - } - case OP_SHL: - { - WriteOp_Shl(jit); - break; - } - case OP_SHR: - { - WriteOp_Shr(jit); - break; - } - case OP_SSHR: - { - WriteOp_Sshr(jit); - break; - } - case OP_SHL_C_PRI: - { - WriteOp_Shl_C_Pri(jit); - break; - } - case OP_SHL_C_ALT: - { - WriteOp_Shl_C_Alt(jit); - break; - } - case OP_SHR_C_PRI: - { - WriteOp_Shr_C_Pri(jit); - break; - } - case OP_SHR_C_ALT: - { - WriteOp_Shr_C_Alt(jit); - break; - } - case OP_SMUL: - { - WriteOp_SMul(jit); - break; - } - case OP_UMUL: - { - WriteOp_UMul(jit); - break; - } - case OP_ADD: - { - WriteOp_Add(jit); - break; - } - case OP_SUB: - { - WriteOp_Sub(jit); - break; - } - case OP_SUB_ALT: - { - WriteOp_Sub_Alt(jit); - break; - } - case OP_NOP: - { - /* do nothing */ - break; - } - case OP_NOT: - { - WriteOp_Not(jit); - break; - } - case OP_NEG: - { - WriteOp_Neg(jit); - break; - } - case OP_XOR: - { - WriteOp_Xor(jit); - break; - } - case OP_OR: - { - WriteOp_Or(jit); - break; - } - case OP_AND: - { - WriteOp_And(jit); - break; - } - case OP_INVERT: - { - WriteOp_Invert(jit); - break; - } - case OP_ADD_C: - { - WriteOp_Add_C(jit); - break; - } - case OP_SMUL_C: - { - WriteOp_SMul_C(jit); - break; - } - case OP_SIGN_PRI: - { - WriteOp_Sign_Pri(jit); - break; - } - case OP_SIGN_ALT: - { - WriteOp_Sign_Alt(jit); - break; - } - case OP_EQ: - { - WriteOp_Eq(jit); - break; - } - case OP_NEQ: - { - WriteOp_Neq(jit); - break; - } - case OP_LESS: - { - WriteOp_Less(jit); - break; - } - case OP_LEQ: - { - WriteOp_Leq(jit); - break; - } - case OP_GRTR: - { - WriteOp_Grtr(jit); - break; - } - case OP_GEQ: - { - WriteOp_Geq(jit); - break; - } - case OP_SLESS: - { - WriteOp_Sless(jit); - break; - } - case OP_SLEQ: - { - WriteOp_Sleq(jit); - break; - } - case OP_SGRTR: - { - WriteOp_Sgrtr(jit); - break; - } - case OP_SGEQ: - { - WriteOp_Sgeq(jit); - break; - } - case OP_EQ_C_PRI: - { - WriteOp_Eq_C_Pri(jit); - break; - } - case OP_EQ_C_ALT: - { - WriteOp_Eq_C_Alt(jit); - break; - } - case OP_INC_PRI: - { - WriteOp_Inc_Pri(jit); - break; - } - case OP_INC_ALT: - { - WriteOp_Inc_Alt(jit); - break; - } - case OP_INC: - { - WriteOp_Inc(jit); - break; - } - case OP_INC_S: - { - WriteOp_Inc_S(jit); - break; - } - case OP_INC_I: - { - WriteOp_Inc_I(jit); - break; - } - case OP_DEC_PRI: - { - WriteOp_Dec_Pri(jit); - break; - } - case OP_DEC_ALT: - { - WriteOp_Dec_Alt(jit); - break; - } - case OP_DEC: - { - WriteOp_Dec(jit); - break; - } - case OP_DEC_S: - { - WriteOp_Dec_S(jit); - break; - } - case OP_DEC_I: - { - WriteOp_Dec_I(jit); - break; - } - case OP_LOAD_PRI: - { - WriteOp_Load_Pri(jit); - break; - } - case OP_LOAD_ALT: - { - WriteOp_Load_Alt(jit); - break; - } - case OP_LOAD_S_PRI: - { - WriteOp_Load_S_Pri(jit); - break; - } - case OP_LOAD_S_ALT: - { - WriteOp_Load_S_Alt(jit); - break; - } - case OP_LREF_PRI: - { - WriteOp_Lref_Pri(jit); - break; - } - case OP_LREF_ALT: - { - WriteOp_Lref_Alt(jit); - break; - } - case OP_LREF_S_PRI: - { - WriteOp_Lref_Pri(jit); - break; - } - case OP_LREF_S_ALT: - { - WriteOp_Lref_Alt(jit); - break; - } - case OP_CONST_PRI: - { - WriteOp_Const_Pri(jit); - break; - } - case OP_CONST_ALT: - { - WriteOp_Const_Alt(jit); - break; - } - case OP_ADDR_PRI: - { - WriteOp_Addr_Pri(jit); - break; - } - case OP_ADDR_ALT: - { - WriteOp_Addr_Alt(jit); - break; - } - case OP_STOR_PRI: - { - WriteOp_Stor_Pri(jit); - break; - } - case OP_STOR_ALT: - { - WriteOp_Stor_Alt(jit); - break; - } - case OP_STOR_S_PRI: - { - WriteOp_Stor_S_Pri(jit); - break; - } - case OP_STOR_S_ALT: - { - WriteOp_Stor_S_Alt(jit); - break; - } - case OP_IDXADDR: - { - WriteOp_Idxaddr(jit); - break; - } - case OP_SREF_PRI: - { - WriteOp_Sref_Pri(jit); - break; - } - case OP_SREF_ALT: - { - WriteOp_Sref_Alt(jit); - break; - } - case OP_SREF_S_PRI: - { - WriteOp_Sref_S_Pri(jit); - break; - } - case OP_SREF_S_ALT: - { - WriteOp_Sref_S_Alt(jit); - break; - } - case OP_ALIGN_PRI: - { - WriteOp_Align_Pri(jit); - break; - } - case OP_ALIGN_ALT: - { - WriteOp_Align_Alt(jit); - break; - } - case OP_POP_PRI: - { - WriteOp_Pop_Pri(jit); - break; - } - case OP_POP_ALT: - { - WriteOp_Pop_Alt(jit); - break; - } - case OP_SWAP_PRI: - { - WriteOp_Swap_Pri(jit); - break; - } - case OP_SWAP_ALT: - { - WriteOp_Swap_Alt(jit); - break; - } - case OP_PUSH_ADR: - { - WriteOp_PushAddr(jit); - break; - } - case OP_MOVS: - { - WriteOp_Movs(jit); - break; - } - case OP_FILL: - { - WriteOp_Fill(jit); - break; - } - case OP_HEAP_PRI: - { - WriteOp_Heap_Pri(jit); - break; - } - case OP_PUSH_HEAP_C: - { - WriteOp_Push_Heap_C(jit); - break; - } - case OP_POP_HEAP_PRI: - { - WriteOp_Pop_Heap_Pri(jit); - break; - } - case OP_PUSH_C: - { - WriteOp_Push_C(jit); - break; - } - case OP_ZERO: - { - WriteOp_Zero(jit); - break; - } - case OP_ZERO_S: - { - WriteOp_Zero_S(jit); - break; - } - case OP_PUSH_PRI: - { - WriteOp_Push_Pri(jit); - break; - } - case OP_PUSH_ALT: - { - WriteOp_Push_Alt(jit); - break; - } - case OP_LOAD_BOTH: - { - WriteOp_Load_Both(jit); - break; - } - case OP_LOAD_S_BOTH: - { - WriteOp_Load_S_Both(jit); - break; - } - case OP_CONST: - { - WriteOp_Const(jit); - break; - } - case OP_CONST_S: - { - WriteOp_Const_S(jit); - break; - } - case OP_LOAD_I: - { - WriteOp_Load_I(jit); - break; - } - case OP_LODB_I: - { - WriteOp_Lodb_I(jit); - break; - } - case OP_STOR_I: - { - WriteOp_Stor_I(jit); - break; - } - case OP_STRB_I: - { - WriteOp_Strb_I(jit); - break; - } - case OP_LIDX: - { - WriteOp_Lidx(jit); - break; - } - case OP_LIDX_B: - { - WriteOp_Lidx_B(jit); - break; - } - case OP_IDXADDR_B: - { - WriteOp_Idxaddr_B(jit); - break; - } - case OP_LCTRL: - { - WriteOp_Lctrl(jit); - break; - } - case OP_SCTRL: - { - WriteOp_Sctrl(jit); - break; - } - case OP_STACK: - { - WriteOp_Stack(jit); - break; - } - case OP_HEAP: - { - WriteOp_Heap(jit); - break; - } - case OP_SDIV: - { - WriteOp_SDiv(jit); - break; - } - case OP_SDIV_ALT: - { - WriteOp_SDiv_Alt(jit); - break; - } - case OP_UDIV: - { - WriteOp_UDiv(jit); - break; - } - case OP_UDIV_ALT: - { - WriteOp_UDiv_Alt(jit); - break; - } - case OP_RET: - { - WriteOp_Ret(jit); - break; - } - case OP_RETN: - { - WriteOp_Retn(jit); - break; - } - case OP_CMPS: - { - WriteOp_Cmps(jit); - break; - } - case OP_BOUNDS: - { - WriteOp_Bounds(jit); - break; - } - case OP_HALT: - { - WriteOp_Halt(jit); - break; - } - case OP_BREAK: - { - WriteOp_Break(jit); - break; - } - default: - { - AbortCompilation(co); - *err = SP_ERR_INVALID_INSTRUCTION; - return NULL; + /* Store the native offset into the rebase memory. + * This large chunk of memory lets us do an instant lookup + * based on an original pcode offset. + */ + pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); + native_offs = jit->jit_curpos(); + *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; + + /* Now read the opcode and continue. */ + op = (OPCODE)writer.read_cell(); + switch (op) + { + #include "opcode_switch.inc" + } + } + + /* the total codesize is now known! */ + uint32_t mem = writer.jit_curpos(); + writer.outbase = new char[mem]; + writer.outptr = writer.outbase; + /* go back for third pass */ + goto jit_rewind; + } else { + /******* + * THIRD PASS - write opcode info + *******/ + for (; writer.inptr <= endptr;) + { + op = (OPCODE)writer.read_cell(); + switch (op) + { + #include "opcode_switch.inc" } } } + sp_context_t *ctx = new sp_context_t; + memset(ctx, 0, sizeof(sp_context_t)); + + ctx->context = engine->CreateBaseContext(ctx); + ctx->data = new uint8_t[plugin->memory]; + memcpy(ctx->data, plugin->data, plugin->data_size); + ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); + ctx->heapbase = plugin->data_size; + ctx->hp = ctx->heapbase; + ctx->memory = plugin->memory; + ctx->plugin = plugin; + ctx->vmbase = this; + + /* :TODO: the rest of this */ + *err = SP_ERR_NONE; - return NULL; + return ctx->context; } const char *JITX86::GetVMName() diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index dd619892..01febc4f 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -15,17 +15,20 @@ class CompData : public ICompilation { public: CompData() : plugin(NULL), - debug(false), inline_level(3), checks(true) + debug(false), inline_level(3), checks(true), + rebase(NULL) { }; public: sp_plugin_t *plugin; + jitcode_t *rebase; jitoffs_t jit_return; jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; jitoffs_t jit_chkmargin_heap; jitoffs_t jit_bounds; jitoffs_t jit_break; + uint32_t codesize; int inline_level; bool checks; bool debug; @@ -45,6 +48,8 @@ public: int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; +jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); + #define AMX_REG_PRI REG_EAX #define AMX_REG_ALT REG_EDX #define AMX_REG_STK REG_EBP @@ -61,4 +66,6 @@ public: #define AMX_INFO_STACKTOP 16 //relocated #define AMX_INFO_HEAPLOW 20 //not relocated +extern ISourcePawnEngine *engine; + #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj index f5607836..1f3f4973 100644 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj @@ -223,6 +223,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + outptr; //get relative difference - jit_int32_t diff = (target - (jmp + 1)); + jit_int32_t diff = (target - (jmp + 4)); //overwrite old value jit->outptr = jit->outbase + jmp; jit->write_int32(diff); @@ -821,6 +821,24 @@ inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) jit->outptr = oldptr; } +/* For writing and auto-calculating an absolute target */ +inline void IA32_Jump_Imm32_Abs(JitWriter *jit, jitoffs_t target) +{ + /* :TODO: this should work, but does it? */ + jit->write_ubyte(IA32_JMP_IMM32); + IA32_Write_Jump32(jit, jit->jit_curpos(), target); + jit->outptr += 4; +} + +inline void IA32_Jump_Cond_Imm32_Abs(JitWriter *jit, jit_uint8_t cond, jitoffs_t target) +{ + /* :TODO: this should work, but does it? */ + jit->write_ubyte(IA32_JCC_IMM32_1); + jit->write_ubyte(IA32_JCC_IMM32_2+cond); + IA32_Write_Jump32(jit, jit->jit_curpos(), target); + jit->outptr += 4; +} + inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { jitoffs_t curptr = jit->jit_curpos(); From b1c6a06d15f1f85e8c762ea818038fd4818a9c16 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 23 Sep 2006 23:37:40 +0000 Subject: [PATCH 0067/1664] added UNSUPPORTED defines and context setup code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4097 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 162 +++++++++++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.h | 60 ++++----- sourcepawn/vm/jit/x86/opcode_switch.inc | 60 +++++++++ 3 files changed, 245 insertions(+), 37 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index b69ea6d5..57da1767 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -293,6 +293,7 @@ inline void WriteOp_SMul(JitWriter *jit) IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); } +#ifdef UNSUPPORTED inline void WriteOp_UMul(JitWriter *jit) { //mov ecx, edx @@ -302,6 +303,7 @@ inline void WriteOp_UMul(JitWriter *jit) IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); } +#endif inline void WriteOp_Not(JitWriter *jit) { @@ -399,6 +401,7 @@ inline void WriteOp_Neq(JitWriter *jit) IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE); } +#ifdef UNSUPPORTED inline void WriteOp_Less(JitWriter *jit) { //cmp eax, edx ; PRI < ALT ? (unsigned) @@ -408,7 +411,9 @@ inline void WriteOp_Less(JitWriter *jit) IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Leq(JitWriter *jit) { //cmp eax, edx ; PRI <= ALT ? (unsigned) @@ -418,7 +423,9 @@ inline void WriteOp_Leq(JitWriter *jit) IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Grtr(JitWriter *jit) { //cmp eax, edx ; PRI > ALT ? (unsigned) @@ -428,7 +435,9 @@ inline void WriteOp_Grtr(JitWriter *jit) IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Geq(JitWriter *jit) { //cmp eax, edx ; PRI >= ALT ? (unsigned) @@ -438,6 +447,7 @@ inline void WriteOp_Geq(JitWriter *jit) IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE); } +#endif inline void WriteOp_Sless(JitWriter *jit) { @@ -623,6 +633,7 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); } +#ifdef UNSUPPORTED inline void WriteOp_Lref_Pri(JitWriter *jit) { //mov eax, [edi+] @@ -634,7 +645,9 @@ inline void WriteOp_Lref_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Lref_Alt(JitWriter *jit) { //mov edx, [edi+] @@ -646,7 +659,9 @@ inline void WriteOp_Lref_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Lref_S_Pri(JitWriter *jit) { //mov eax, [ebx+] @@ -658,7 +673,9 @@ inline void WriteOp_Lref_S_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Lref_S_Alt(JitWriter *jit) { //mov edx, [ebx+] @@ -670,6 +687,7 @@ inline void WriteOp_Lref_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } +#endif inline void WriteOp_Const_Pri(JitWriter *jit) { @@ -755,6 +773,7 @@ inline void WriteOp_Idxaddr(JitWriter *jit) IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); } +#ifdef UNSUPPORTED inline void WriteOp_Idxaddr_B(JitWriter *jit) { //shl eax, @@ -763,7 +782,9 @@ inline void WriteOp_Idxaddr_B(JitWriter *jit) IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Sref_Pri(JitWriter *jit) { //mov ecx, [edi+] @@ -775,7 +796,9 @@ inline void WriteOp_Sref_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Sref_Alt(JitWriter *jit) { //mov ecx, [edi+] @@ -787,7 +810,9 @@ inline void WriteOp_Sref_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Sref_S_Pri(JitWriter *jit) { //mov ecx, [ebx+] @@ -799,7 +824,9 @@ inline void WriteOp_Sref_S_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Sref_S_Alt(JitWriter *jit) { //mov ecx, [ebx+] @@ -811,7 +838,9 @@ inline void WriteOp_Sref_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Align_Pri(JitWriter *jit) { //xor eax, @@ -821,7 +850,9 @@ inline void WriteOp_Align_Pri(JitWriter *jit) else IA32_Xor_Eax_Imm32(jit, val); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Align_Alt(JitWriter *jit) { //xor edx, @@ -831,6 +862,7 @@ inline void WriteOp_Align_Alt(JitWriter *jit) else IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val); } +#endif inline void WriteOp_Pop_Pri(JitWriter *jit) { @@ -931,6 +963,7 @@ inline void WriteOp_Movs(JitWriter *jit) IA32_Pop_Reg(jit, REG_ESI); } +#ifdef UNSUPPORTED inline void WriteOp_Cmps(JitWriter *jit) { //push edi @@ -961,6 +994,7 @@ inline void WriteOp_Cmps(JitWriter *jit) IA32_Pop_Reg(jit, REG_ESI); IA32_Pop_Reg(jit, REG_EDI); } +#endif inline void WriteOp_Fill(JitWriter *jit) { @@ -1065,6 +1099,7 @@ inline void WriteOp_Load_I(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +#ifdef UNSUPPORTED inline void WriteOp_Lodb_I(JitWriter *jit) { Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); @@ -1088,6 +1123,7 @@ inline void WriteOp_Lodb_I(JitWriter *jit) } } } +#endif inline void WriteOp_Stor_I(JitWriter *jit) { @@ -1096,6 +1132,7 @@ inline void WriteOp_Stor_I(JitWriter *jit) IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } +#ifdef UNSUPPORTED inline void WriteOp_Strb_I(JitWriter *jit) { Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); @@ -1120,6 +1157,7 @@ inline void WriteOp_Strb_I(JitWriter *jit) } } } +#endif inline void WriteOp_Lidx(JitWriter *jit) { @@ -1130,6 +1168,7 @@ inline void WriteOp_Lidx(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +#ifdef UNSUPPORTED inline void WriteOp_Lidx_B(JitWriter *jit) { cell_t val = jit->read_cell(); @@ -1141,7 +1180,9 @@ inline void WriteOp_Lidx_B(JitWriter *jit) Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Lctrl(JitWriter *jit) { cell_t val = jit->read_cell(); @@ -1201,7 +1242,9 @@ inline void WriteOp_Lctrl(JitWriter *jit) } } } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Sctrl(JitWriter *jit) { cell_t val = jit->read_cell(); @@ -1236,6 +1279,7 @@ inline void WriteOp_Sctrl(JitWriter *jit) } } } +#endif inline void WriteOp_Stack(JitWriter *jit) { @@ -1293,6 +1337,7 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); } +#ifdef UNSUPPORTED inline void WriteOp_UDiv(JitWriter *jit) { //mov ecx, edx @@ -1303,7 +1348,9 @@ inline void WriteOp_UDiv(JitWriter *jit) Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_UDiv_Alt(JitWriter *jit) { //mov ecx, eax @@ -1316,7 +1363,9 @@ inline void WriteOp_UDiv_Alt(JitWriter *jit) Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Ret(JitWriter *jit) { //mov ebx, [ebp] - get old FRM @@ -1330,6 +1379,7 @@ inline void WriteOp_Ret(JitWriter *jit) IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); IA32_Return(jit); } +#endif inline void WriteOp_Retn(JitWriter *jit) { @@ -1399,6 +1449,7 @@ inline void WriteOp_Break(JitWriter *jit) } } +#ifdef UNSUPPORTED inline void WriteOp_JRel(JitWriter *jit) { //jmp ;relative jump @@ -1411,6 +1462,7 @@ inline void WriteOp_JRel(JitWriter *jit) jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs)); } +#endif inline void WriteOp_Jump(JitWriter *jit) { @@ -1447,7 +1499,6 @@ inline void WriteOp_Jeq(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false)); } - inline void WriteOp_Jneq(JitWriter *jit) { //cmp eax, edx @@ -1457,6 +1508,7 @@ inline void WriteOp_Jneq(JitWriter *jit) IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); } +#ifdef UNSUPPORTED inline void WriteOp_Jless(JitWriter *jit) { //cmp eax, edx @@ -1465,7 +1517,9 @@ inline void WriteOp_Jless(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false)); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Jleq(JitWriter *jit) { //cmp eax, edx @@ -1474,7 +1528,9 @@ inline void WriteOp_Jleq(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false)); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Jgrtr(JitWriter *jit) { //cmp eax, edx @@ -1483,7 +1539,9 @@ inline void WriteOp_Jgrtr(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false)); } +#endif +#ifdef UNSUPPORTED inline void WriteOp_Jgeq(JitWriter *jit) { //cmp eax, edx @@ -1492,6 +1550,7 @@ inline void WriteOp_Jgeq(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false)); } +#endif inline void WriteOp_Jsless(JitWriter *jit) { @@ -1709,20 +1768,109 @@ jit_rewind: } } + /******* + * Context Setup + *******/ sp_context_t *ctx = new sp_context_t; memset(ctx, 0, sizeof(sp_context_t)); + ctx->base = plugin->base; + ctx->plugin = plugin; ctx->context = engine->CreateBaseContext(ctx); + ctx->vmbase = this; + ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); + ctx->data = new uint8_t[plugin->memory]; memcpy(ctx->data, plugin->data, plugin->data_size); - ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); - ctx->heapbase = plugin->data_size; - ctx->hp = ctx->heapbase; ctx->memory = plugin->memory; - ctx->plugin = plugin; - ctx->vmbase = this; + ctx->heapbase = plugin->data_size; - /* :TODO: the rest of this */ + ctx->hp = ctx->heapbase; + ctx->sp = ctx->memory - sizeof(cell_t); + + const char *strbase = plugin->info.stringbase; + uint32_t max, iter; + + if ((max = plugin->info.publics_num)) + { + ctx->publics = new sp_public_t[max]; + for (iter=0; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; + ctx->publics[iter].offs = RelocLookup(jit, plugin->info.publics[iter].address, false); + } + } + + if ((max = plugin->info.pubvars_num)) + { + uint8_t *dat = ctx->data; + ctx->pubvars = new sp_pubvar_t[max]; + for (iter=0; iterpubvars[iter].name = strbase + plugin->info.pubvars[iter].name; + ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); + } + } + + if ((max = plugin->info.natives_num)) + { + ctx->natives = new sp_native_t[max]; + for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; + //ctx->natives[iter].pfn = SP_NoExecNative; :TODO: + ctx->natives[iter].status = SP_NATIVE_NONE; + } + } + + strbase = plugin->debug.stringbase; + + if (plugin->flags & SP_FLAG_DEBUG) + { + max = plugin->debug.files_num; + ctx->files = new sp_debug_file_t[max]; + for (iter=0; iterfiles[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false); + ctx->files[iter].name = strbase + plugin->debug.files[iter].name; + } + + max = plugin->debug.lines_num; + ctx->lines = new sp_debug_line_t[max]; + for (iter=0; iterlines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false); + ctx->lines[iter].line = plugin->debug.lines[iter].line; + } + + sp_fdbg_symbol_t *sym; + sp_fdbg_arraydim_t *arr; + uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); + + max = plugin->debug.syms_num; + ctx->symbols = new sp_debug_symbol_t[max]; + for (iter=0; itersymbols[iter].codestart = RelocLookup(jit, sym->codestart, false); + ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false); + ctx->symbols[iter].name = strbase + sym->name; + ctx->symbols[iter].sym = sym; + + if (sym->dimcount > 0) + { + cursor += sizeof(sp_fdbg_symbol_t); + arr = (sp_fdbg_arraydim_t *)cursor; + ctx->symbols[iter].dims = arr; + cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; + continue; + } + + ctx->symbols[iter].dims = NULL; + cursor += sizeof(sp_fdbg_symbol_t); + } + } *err = SP_ERR_NONE; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 657d2f38..d5b024c5 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -63,12 +63,12 @@ typedef enum OP_LOAD_ALT, //DONE OP_LOAD_S_PRI, //DONE OP_LOAD_S_ALT, //DONE - OP_LREF_PRI, //DONE - OP_LREF_ALT, //DONE - OP_LREF_S_PRI, //DONE - OP_LREF_S_ALT, //DONE + OP_LREF_PRI, //UNSUPPORTED + OP_LREF_ALT, //UNSUPPORTED + OP_LREF_S_PRI, //UNSUPPORTED + OP_LREF_S_ALT, //UNSUPPORTED OP_LOAD_I, //DONE - OP_LODB_I, //DONE + OP_LODB_I, //UNSUPPORTED OP_CONST_PRI, //DONE OP_CONST_ALT, //DONE OP_ADDR_PRI, //DONE @@ -77,20 +77,20 @@ typedef enum OP_STOR_ALT, //DONE OP_STOR_S_PRI, //DONE OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //DONE - OP_SREF_ALT, //DONE - OP_SREF_S_PRI, //DONE - OP_SREF_S_ALT, //DONE + OP_SREF_PRI, //UNSUPPORTED + OP_SREF_ALT, //UNSUPPORTED + OP_SREF_S_PRI, //UNSUPPORTED + OP_SREF_S_ALT, //UNSUPPORTED OP_STOR_I, //DONE - OP_STRB_I, //DONE + OP_STRB_I, //UNSUPPORTED OP_LIDX, //DONE - OP_LIDX_B, //DONE + OP_LIDX_B, //UNSUPPORTED OP_IDXADDR, //DONE - OP_IDXADDR_B, //DONE - OP_ALIGN_PRI, //DONE - OP_ALIGN_ALT, //DONE - OP_LCTRL, //DONE - OP_SCTRL, //DONE + OP_IDXADDR_B, //UNSUPPORTED + OP_ALIGN_PRI, //UNSUPPORTED + OP_ALIGN_ALT, //UNSUPPORTED + OP_LCTRL, //UNSUPPORTED + OP_SCTRL, //UNSUPPORTED OP_MOVE_PRI, //DONE OP_MOVE_ALT, //DONE OP_XCHG, //DONE @@ -105,20 +105,20 @@ typedef enum OP_STACK, //DONE OP_HEAP, //DONE OP_PROC, //DONE - OP_RET, //DONE + OP_RET, //UNSUPPORTED OP_RETN, //DONE OP_CALL, OP_CALL_PRI, OP_JUMP, //DONE - OP_JREL, //DONE + OP_JREL, //UNSUPPORTED OP_JZER, //DONE OP_JNZ, //DONE OP_JEQ, //DONE OP_JNEQ, //DONE - OP_JLESS, //DONE - OP_JLEQ, //DONE - OP_JGRTR, //DONE - OP_JGEQ, //DONE + OP_JLESS, //UNSUPPORTED + OP_JLEQ, //UNSUPPORTED + OP_JGRTR, //UNSUPPORTED + OP_JGEQ, //UNSUPPORTED OP_JSLESS, //DONE OP_JSLEQ, //DONE OP_JSGRTR, //DONE @@ -133,9 +133,9 @@ typedef enum OP_SMUL, //DONE OP_SDIV, //DONE OP_SDIV_ALT, //DONE - OP_UMUL, //DONE - OP_UDIV, //DONE - OP_UDIV_ALT, //DONE + OP_UMUL, //UNSUPPORTED + OP_UDIV, //UNSUPPORTED + OP_UDIV_ALT, //UNSUPPORTED OP_ADD, //DONE OP_SUB, //DONE OP_SUB_ALT, //DONE @@ -155,10 +155,10 @@ typedef enum OP_SIGN_ALT, //DONE OP_EQ, //DONE OP_NEQ, //DONE - OP_LESS, //DONE - OP_LEQ, //DONE - OP_GRTR, //DONE - OP_GEQ, //DONE + OP_LESS, //UNSUPPORTED + OP_LEQ, //UNSUPPORTED + OP_GRTR, //UNSUPPORTED + OP_GEQ, //UNSUPPORTED OP_SLESS, //DONE OP_SLEQ, //DONE OP_SGRTR, //DONE @@ -176,7 +176,7 @@ typedef enum OP_DEC_S, //DONE OP_DEC_I, //DONE OP_MOVS, //DONE - OP_CMPS, //DONE + OP_CMPS, //UNSUPPORTED OP_FILL, //DONE OP_HALT, //DONE OP_BOUNDS, //DONE diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index 6918ac4c..e34bfb93 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -158,11 +158,13 @@ WriteOp_SMul(jit); break; } +#ifdef UNSUPPORTED case OP_UMUL: { WriteOp_UMul(jit); break; } +#endif case OP_ADD: { WriteOp_Add(jit); @@ -243,26 +245,34 @@ WriteOp_Neq(jit); break; } +#ifdef UNSUPPORTED case OP_LESS: { WriteOp_Less(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_LEQ: { WriteOp_Leq(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_GRTR: { WriteOp_Grtr(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_GEQ: { WriteOp_Geq(jit); break; } +#endif case OP_SLESS: { WriteOp_Sless(jit); @@ -363,26 +373,34 @@ WriteOp_Load_S_Alt(jit); break; } +#ifdef UNSUPPORTED case OP_LREF_PRI: { WriteOp_Lref_Pri(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_LREF_ALT: { WriteOp_Lref_Alt(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_LREF_S_PRI: { WriteOp_Lref_Pri(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_LREF_S_ALT: { WriteOp_Lref_Alt(jit); break; } +#endif case OP_CONST_PRI: { WriteOp_Const_Pri(jit); @@ -428,36 +446,48 @@ WriteOp_Idxaddr(jit); break; } +#ifdef UNSUPPORTED case OP_SREF_PRI: { WriteOp_Sref_Pri(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_SREF_ALT: { WriteOp_Sref_Alt(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_SREF_S_PRI: { WriteOp_Sref_S_Pri(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_SREF_S_ALT: { WriteOp_Sref_S_Alt(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_ALIGN_PRI: { WriteOp_Align_Pri(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_ALIGN_ALT: { WriteOp_Align_Alt(jit); break; } +#endif case OP_POP_PRI: { WriteOp_Pop_Pri(jit); @@ -558,46 +588,58 @@ WriteOp_Load_I(jit); break; } +#ifdef UNSUPPORTED case OP_LODB_I: { WriteOp_Lodb_I(jit); break; } +#endif case OP_STOR_I: { WriteOp_Stor_I(jit); break; } +#ifdef UNSUPPORTED case OP_STRB_I: { WriteOp_Strb_I(jit); break; } +#endif case OP_LIDX: { WriteOp_Lidx(jit); break; } +#ifdef UNSUPPORTED case OP_LIDX_B: { WriteOp_Lidx_B(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_IDXADDR_B: { WriteOp_Idxaddr_B(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_LCTRL: { WriteOp_Lctrl(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_SCTRL: { WriteOp_Sctrl(jit); break; } +#endif case OP_STACK: { WriteOp_Stack(jit); @@ -618,31 +660,39 @@ WriteOp_SDiv_Alt(jit); break; } +#ifdef UNSUPPORTED case OP_UDIV: { WriteOp_UDiv(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_UDIV_ALT: { WriteOp_UDiv_Alt(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_RET: { WriteOp_Ret(jit); break; } +#endif case OP_RETN: { WriteOp_Retn(jit); break; } +#ifdef UNSUPPORTED case OP_CMPS: { WriteOp_Cmps(jit); break; } +#endif case OP_BOUNDS: { WriteOp_Bounds(jit); @@ -658,11 +708,13 @@ WriteOp_Break(jit); break; } +#ifdef UNSUPPORTED case OP_JREL: { WriteOp_JRel(jit); break; } +#endif case OP_JUMP: { WriteOp_Jump(jit); @@ -688,26 +740,34 @@ WriteOp_Jneq(jit); break; } +#ifdef UNSUPPORTED case OP_JLESS: { WriteOp_Jless(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_JLEQ: { WriteOp_Jeq(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_JGRTR: { WriteOp_Jgrtr(jit); break; } +#endif +#ifdef UNSUPPORTED case OP_JGEQ: { WriteOp_Jgeq(jit); break; } +#endif case OP_JSLESS: { WriteOp_Jsless(jit); From 55b590cb8ed7710fd218190f33c414c5734c82d0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 24 Sep 2006 06:17:10 +0000 Subject: [PATCH 0068/1664] reorganized ungen opcode stuff fixed mislabeled ungen ops, then added appropriate notes added executable memory functions to API compilation results in an sp_context_t, not a BaseContext now renamed FreeContextVars() to FreeContext() other minor changes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4098 --- sourcepawn/include/sp_vm_api.h | 23 +- sourcepawn/include/sp_vm_types.h | 2 +- sourcepawn/vm/jit/x86/jit_x86.cpp | 498 +++--------------- sourcepawn/vm/jit/x86/jit_x86.h | 4 +- sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 8 + sourcepawn/vm/jit/x86/opcode_helpers.cpp | 44 +- sourcepawn/vm/jit/x86/opcode_helpers.h | 84 +-- sourcepawn/vm/jit/x86/opcode_switch.inc | 163 +----- sourcepawn/vm/jit/x86/ungen_opcode_switch.inc | 100 ++++ sourcepawn/vm/jit/x86/ungen_opcodes.h | 336 ++++++++++++ sourcepawn/vm/sp_vm_engine.cpp | 33 +- sourcepawn/vm/sp_vm_engine.h | 16 + 12 files changed, 654 insertions(+), 657 deletions(-) create mode 100644 sourcepawn/vm/jit/x86/ungen_opcode_switch.inc create mode 100644 sourcepawn/vm/jit/x86/ungen_opcodes.h diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 8c6e7589..c07248d8 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -59,7 +59,7 @@ namespace SourcePawn virtual void FreeBaseContext(IPluginContext *ctx) =0; /** - * Allocates memory. + * Allocates large blocks of temporary memory. * * @param size Size of memory to allocate. * @return Pointer to memory, NULL if allocation failed. @@ -72,6 +72,21 @@ namespace SourcePawn * @param mem Memory address to free. */ virtual void BaseFree(void *memory) =0; + + /** + * Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *ExecAlloc(size_t size) =0; + + /** + * Frees executable memory. + * + * @param mem Address to free. + */ + virtual void ExecFree(void *address) =0; }; class ICompilation @@ -107,14 +122,14 @@ namespace SourcePawn virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; /** - * Finalizes a compilation into a new IContext. + * Finalizes a compilation into a new sp_context_t. * Note: This will free the ICompilation pointer. * * @param co Compilation pointer. * @param err Filled with error code on exit. * @return New plugin context. */ - virtual IPluginContext *CompileToContext(ICompilation *co, int *err) =0; + virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; /** * Aborts a compilation and frees the ICompilation pointer. @@ -128,7 +143,7 @@ namespace SourcePawn * * @param ctx Context structure pointer. */ - virtual void FreeContextVars(sp_context_t *ctx) =0; + virtual void FreeContext(sp_context_t *ctx) =0; /** * Calls the "execute" function on a context. diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 95434180..e81802d1 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -201,7 +201,7 @@ typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t) typedef struct sp_context_s { /* general/parent information */ - void *base; /* base of generated code and memory */ + void *codebase; /* base of generated code and memory */ sp_plugin_t *plugin; /* pointer back to parent information */ SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 57da1767..1835acea 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -5,6 +5,10 @@ #include "opcode_helpers.h" #include "x86_macros.h" +#if defined USE_UNGEN_OPCODES +#include "ungen_opcodes.h" +#endif + inline void WriteOp_Move_Pri(JitWriter *jit) { //mov eax, edx @@ -231,6 +235,27 @@ inline void WriteOp_Proc(JitWriter *jit) IA32_Sub_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_DAT, MOD_MEM_REG); } +inline void WriteOp_Lidx_B(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + //shl eax, + //add eax, edx + //mov eax, [edi+eax] + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); +} + +inline void WriteOp_Idxaddr_B(JitWriter *jit) +{ + //shl eax, + //add eax, edx + cell_t val = jit->read_cell(); + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); +} + inline void WriteOp_Shl(JitWriter *jit) { //mov ecx, edx @@ -293,18 +318,6 @@ inline void WriteOp_SMul(JitWriter *jit) IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); } -#ifdef UNSUPPORTED -inline void WriteOp_UMul(JitWriter *jit) -{ - //mov ecx, edx - //mul edx - //mov edx, ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); -} -#endif - inline void WriteOp_Not(JitWriter *jit) { //test eax, eax @@ -401,54 +414,6 @@ inline void WriteOp_Neq(JitWriter *jit) IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE); } -#ifdef UNSUPPORTED -inline void WriteOp_Less(JitWriter *jit) -{ - //cmp eax, edx ; PRI < ALT ? (unsigned) - //mov eax, 0 - //setb al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Leq(JitWriter *jit) -{ - //cmp eax, edx ; PRI <= ALT ? (unsigned) - //mov eax, 0 - //setbe al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Grtr(JitWriter *jit) -{ - //cmp eax, edx ; PRI > ALT ? (unsigned) - //mov eax, 0 - //seta al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Geq(JitWriter *jit) -{ - //cmp eax, edx ; PRI >= ALT ? (unsigned) - //mov eax, 0 - //setae al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE); -} -#endif - inline void WriteOp_Sless(JitWriter *jit) { //cmp eax, edx ; PRI < ALT ? (signed) @@ -633,7 +598,6 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); } -#ifdef UNSUPPORTED inline void WriteOp_Lref_Pri(JitWriter *jit) { //mov eax, [edi+] @@ -645,9 +609,7 @@ inline void WriteOp_Lref_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Lref_Alt(JitWriter *jit) { //mov edx, [edi+] @@ -659,9 +621,7 @@ inline void WriteOp_Lref_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Lref_S_Pri(JitWriter *jit) { //mov eax, [ebx+] @@ -673,9 +633,7 @@ inline void WriteOp_Lref_S_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Lref_S_Alt(JitWriter *jit) { //mov edx, [ebx+] @@ -687,7 +645,6 @@ inline void WriteOp_Lref_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } -#endif inline void WriteOp_Const_Pri(JitWriter *jit) { @@ -773,18 +730,6 @@ inline void WriteOp_Idxaddr(JitWriter *jit) IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); } -#ifdef UNSUPPORTED -inline void WriteOp_Idxaddr_B(JitWriter *jit) -{ - //shl eax, - //add eax, edx - cell_t val = jit->read_cell(); - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} -#endif - -#ifdef UNSUPPORTED inline void WriteOp_Sref_Pri(JitWriter *jit) { //mov ecx, [edi+] @@ -796,9 +741,7 @@ inline void WriteOp_Sref_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Sref_Alt(JitWriter *jit) { //mov ecx, [edi+] @@ -810,9 +753,7 @@ inline void WriteOp_Sref_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Sref_S_Pri(JitWriter *jit) { //mov ecx, [ebx+] @@ -824,9 +765,7 @@ inline void WriteOp_Sref_S_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } -#endif -#ifdef UNSUPPORTED inline void WriteOp_Sref_S_Alt(JitWriter *jit) { //mov ecx, [ebx+] @@ -838,31 +777,6 @@ inline void WriteOp_Sref_S_Alt(JitWriter *jit) IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Align_Pri(JitWriter *jit) -{ - //xor eax, - cell_t val = sizeof(cell_t) - jit->read_cell(); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); - else - IA32_Xor_Eax_Imm32(jit, val); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Align_Alt(JitWriter *jit) -{ - //xor edx, - cell_t val = sizeof(cell_t) - jit->read_cell(); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val); - else - IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val); -} -#endif inline void WriteOp_Pop_Pri(JitWriter *jit) { @@ -963,39 +877,6 @@ inline void WriteOp_Movs(JitWriter *jit) IA32_Pop_Reg(jit, REG_ESI); } -#ifdef UNSUPPORTED -inline void WriteOp_Cmps(JitWriter *jit) -{ - //push edi - //push esi - //lea esi, [edi+edx] - //lea edi, [edi+eax] - IA32_Push_Reg(jit, REG_EDI); - IA32_Push_Reg(jit, REG_ESI); - IA32_Lea_Reg_DispRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - IA32_Lea_Reg_DispRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - - //xor eax, eax - //repe cmpsb - //je :cmps1 - IA32_Xor_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Cmpsb(jit); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0); - - //sbb eax, eax - //sbb eax, -1 - IA32_Sbb_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Sbb_Eax_Imm32(jit, -1);//:TODO: use imm8 here - - //:cmps1 - //pop esi - //pop edi - IA32_Send_Jump8_Here(jit, jmp); - IA32_Pop_Reg(jit, REG_ESI); - IA32_Pop_Reg(jit, REG_EDI); -} -#endif - inline void WriteOp_Fill(JitWriter *jit) { //add edi, edx @@ -1099,32 +980,6 @@ inline void WriteOp_Load_I(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } -#ifdef UNSUPPORTED -inline void WriteOp_Lodb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - - //mov eax, [edi+eax] - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - - //and eax, - cell_t val = jit->read_cell(); - switch(val) - { - case 1: - { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);//:TODO: replace with AND EAX, imm32 - break; - } - case 2: - { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);//:TODO: replace with AND EAX, imm32 - break; - } - } -} -#endif - inline void WriteOp_Stor_I(JitWriter *jit) { //mov [edi+edx], eax @@ -1132,33 +987,6 @@ inline void WriteOp_Stor_I(JitWriter *jit) IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } -#ifdef UNSUPPORTED -inline void WriteOp_Strb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); - //mov [edi+edx], eax - cell_t val = jit->read_cell(); - switch (val) - { - case 1: - { - IA32_Mov_Rm8_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 2: - { - IA32_Mov_Rm16_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 4: - { - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - } -} -#endif - inline void WriteOp_Lidx(JitWriter *jit) { //lea eax, [edx+4*eax] @@ -1168,119 +996,6 @@ inline void WriteOp_Lidx(JitWriter *jit) IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } -#ifdef UNSUPPORTED -inline void WriteOp_Lidx_B(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - //shl eax, - //add eax, edx - //mov eax, [edi+eax] - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Lctrl(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - switch (val) - { - case 0: - { - //mov ecx, [esi+ctx] - //mov eax, [ecx+] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, base)); - break; - } - case 1: - { - //mov eax, edi - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); - break; - } - case 2: - { - //mov eax, [esi+hea] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP); - break; - } - case 3: - { - //mov ecx, [esi+ctx] - //mov eax, [ecx+ctx.memory] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory)); - break; - } - case 4: - { - //mov eax, ebp - //sub eax, edi - unrelocate - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG); - IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); - break; - } - case 5: - { - //mov eax, [esi+frm] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_FRM); - break; - } - case 6: - { - //mov eax, [cip] - jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - jitoffs_t save = jit->jit_curpos(); - jit->setpos(imm32); - jit->write_int32((uint32_t)(jit->outbase + save)); - jit->setpos(save); - break; - } - } -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Sctrl(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - switch (val) - { - case 2: - { - //mov [esi+hea], eax - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, AMX_REG_PRI); - break; - } - case 4: - { - //lea ebp, [edi+eax] - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - break; - } - case 5: - { - //mov ebx, eax - overwrite frm - //mov frm, eax - overwrite stacked frame - //add ebx, edi - relocate local frm //:TODO: use LEA here!!! - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_PRI, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_PRI, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); - break; - } - case 6: - { - IA32_Jump_Reg(jit, AMX_REG_PRI); - break; - } - } -} -#endif - inline void WriteOp_Stack(JitWriter *jit) { //mov edx, ebp @@ -1337,50 +1052,6 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); } -#ifdef UNSUPPORTED -inline void WriteOp_UDiv(JitWriter *jit) -{ - //mov ecx, edx - //xor edx, edx - //div ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_UDiv_Alt(JitWriter *jit) -{ - //mov ecx, eax - //mov eax, edx - //xor edx, edx - //div ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Ret(JitWriter *jit) -{ - //mov ebx, [ebp] - get old FRM - //add ebp, 4 - pop stack - //mov [esi+frm], ebx - restore - //add ebx, edi - relocate - //ret - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! - IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); - IA32_Return(jit); -} -#endif - inline void WriteOp_Retn(JitWriter *jit) { //mov ebx, [ebp] - get old frm @@ -1449,21 +1120,6 @@ inline void WriteOp_Break(JitWriter *jit) } } -#ifdef UNSUPPORTED -inline void WriteOp_JRel(JitWriter *jit) -{ - //jmp ;relative jump - cell_t cip_offs = jit->read_cell(); - - /* Note that since code size calculation has to be done in the same - * phase as building relocation information, we cannot know the jump size - * beforehand. Thus, we always write full 32bit jumps for safety. - */ - jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); - IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs)); -} -#endif - inline void WriteOp_Jump(JitWriter *jit) { //jmp @@ -1508,50 +1164,6 @@ inline void WriteOp_Jneq(JitWriter *jit) IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); } -#ifdef UNSUPPORTED -inline void WriteOp_Jless(JitWriter *jit) -{ - //cmp eax, edx - //jb - cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false)); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Jleq(JitWriter *jit) -{ - //cmp eax, edx - //jbe - cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false)); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Jgrtr(JitWriter *jit) -{ - //cmp eax, edx - //ja - cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false)); -} -#endif - -#ifdef UNSUPPORTED -inline void WriteOp_Jgeq(JitWriter *jit) -{ - //cmp eax, edx - //jae - cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false)); -} -#endif - inline void WriteOp_Jsless(JitWriter *jit) { //cmp eax, edx @@ -1617,7 +1229,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) } } -IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) +sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) { CompData *data = (CompData *)co; sp_plugin_t *plugin = data->plugin; @@ -1750,7 +1362,7 @@ jit_rewind: /* the total codesize is now known! */ uint32_t mem = writer.jit_curpos(); - writer.outbase = new char[mem]; + writer.outbase = (jitcode_t)engine->ExecAlloc(mem); writer.outptr = writer.outbase; /* go back for third pass */ goto jit_rewind; @@ -1768,29 +1380,31 @@ jit_rewind: } } - /******* - * Context Setup - *******/ + /************* + * FOURTH PASS - Context Setup + *************/ + sp_context_t *ctx = new sp_context_t; memset(ctx, 0, sizeof(sp_context_t)); - ctx->base = plugin->base; + /* setup basics */ + ctx->codebase = writer.outbase; ctx->plugin = plugin; - ctx->context = engine->CreateBaseContext(ctx); ctx->vmbase = this; ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); + /* setup memory */ ctx->data = new uint8_t[plugin->memory]; memcpy(ctx->data, plugin->data, plugin->data_size); ctx->memory = plugin->memory; ctx->heapbase = plugin->data_size; - ctx->hp = ctx->heapbase; ctx->sp = ctx->memory - sizeof(cell_t); const char *strbase = plugin->info.stringbase; uint32_t max, iter; + /* relocate public info */ if ((max = plugin->info.publics_num)) { ctx->publics = new sp_public_t[max]; @@ -1801,6 +1415,7 @@ jit_rewind: } } + /* relocate pubvar info */ if ((max = plugin->info.pubvars_num)) { uint8_t *dat = ctx->data; @@ -1812,21 +1427,26 @@ jit_rewind: } } + /* relocate native info */ if ((max = plugin->info.natives_num)) { ctx->natives = new sp_native_t[max]; for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; - //ctx->natives[iter].pfn = SP_NoExecNative; :TODO: + ctx->natives[iter].pfn = NULL; ctx->natives[iter].status = SP_NATIVE_NONE; } } - strbase = plugin->debug.stringbase; - - if (plugin->flags & SP_FLAG_DEBUG) + /** + * If we're debugging, make sure we copy the necessary info. + */ + if (data->debug) { + strbase = plugin->debug.stringbase; + + /* relocate files */ max = plugin->debug.files_num; ctx->files = new sp_debug_file_t[max]; for (iter=0; iterfiles[iter].name = strbase + plugin->debug.files[iter].name; } + /* relocate lines */ max = plugin->debug.lines_num; ctx->lines = new sp_debug_line_t[max]; for (iter=0; iterlines[iter].line = plugin->debug.lines[iter].line; } + /* relocate arrays */ sp_fdbg_symbol_t *sym; sp_fdbg_arraydim_t *arr; uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); @@ -1872,9 +1494,13 @@ jit_rewind: } } + /* clean up relocation+compilation memory */ + engine->BaseFree(data->rebase); + delete data; + *err = SP_ERR_NONE; - return ctx->context; + return ctx; } const char *JITX86::GetVMName() @@ -1882,6 +1508,26 @@ const char *JITX86::GetVMName() return "JIT (x86)"; } +int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) +{ + typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *); + CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; + return fn(ctx, code_idx, result); +} + +void JITX86::FreeContext(sp_context_t *ctx) +{ + engine->ExecFree(ctx->codebase); + delete [] ctx->data; + delete [] ctx->files; + delete [] ctx->lines; + delete [] ctx->natives; + delete [] ctx->publics; + delete [] ctx->pubvars; + delete [] ctx->symbols; + delete ctx; +} + ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) { CompData *data = new CompData; diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 01febc4f..a3a08322 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -42,9 +42,9 @@ public: const char *GetVMName() =0; ICompilation *StartCompilation(sp_plugin_t *plugin); bool SetCompilationOption(ICompilation *co, const char *key, const char *val) ; - IPluginContext *CompileToContext(ICompilation *co, int *err); + sp_context_t *CompileToContext(ICompilation *co, int *err); void AbortCompilation(ICompilation *co); - void FreeContextVars(sp_context_t *ctx); + void FreeContext(sp_context_t *ctx); int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj index 1f3f4973..f7e0b79c 100644 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj @@ -213,6 +213,10 @@ RelativePath="..\opcode_helpers.h" > + + @@ -227,6 +231,10 @@ RelativePath="..\opcode_switch.inc" > + + ] - get alt //mov eax, [eax+] - get pri IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); - IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base)); + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase)); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt)); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri)); @@ -503,7 +503,6 @@ JITX86::JITX86() OpAdvTable[OP_LREF_ALT] = sizeof(cell_t); OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t); OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_LODB_I] = sizeof(cell_t); OpAdvTable[OP_CONST_PRI] = sizeof(cell_t); OpAdvTable[OP_CONST_ALT] = sizeof(cell_t); OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t); @@ -516,19 +515,13 @@ JITX86::JITX86() OpAdvTable[OP_SREF_ALT] = sizeof(cell_t); OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t); OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_STRB_I] = sizeof(cell_t); OpAdvTable[OP_LIDX_B] = sizeof(cell_t); OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t); - OpAdvTable[OP_ALIGN_PRI] = sizeof(cell_t); - OpAdvTable[OP_ALIGN_ALT] = sizeof(cell_t); - OpAdvTable[OP_LCTRL] = sizeof(cell_t); - OpAdvTable[OP_SCTRL] = sizeof(cell_t); OpAdvTable[OP_PUSH_C] = sizeof(cell_t); OpAdvTable[OP_PUSH] = sizeof(cell_t); OpAdvTable[OP_PUSH_S] = sizeof(cell_t); OpAdvTable[OP_STACK] = sizeof(cell_t); OpAdvTable[OP_HEAP] = sizeof(cell_t); - OpAdvTable[OP_JREL] = sizeof(cell_t); OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t); OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t); OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t); @@ -544,7 +537,6 @@ JITX86::JITX86() OpAdvTable[OP_DEC] = sizeof(cell_t); OpAdvTable[OP_DEC_S] = sizeof(cell_t); OpAdvTable[OP_MOVS] = sizeof(cell_t); - OpAdvTable[OP_CMPS] = sizeof(cell_t); OpAdvTable[OP_FILL] = sizeof(cell_t); OpAdvTable[OP_HALT] = sizeof(cell_t); OpAdvTable[OP_BOUNDS] = sizeof(cell_t); @@ -574,9 +566,6 @@ JITX86::JITX86() OpAdvTable[OP_SMUL] = 0; OpAdvTable[OP_SDIV] = 0; OpAdvTable[OP_SDIV_ALT] = 0; - OpAdvTable[OP_UMUL] = 0; - OpAdvTable[OP_UDIV] = 0; - OpAdvTable[OP_UDIV_ALT] = 0; OpAdvTable[OP_ADD] = 0; OpAdvTable[OP_SUB] = 0; OpAdvTable[OP_SUB_ALT] = 0; @@ -592,10 +581,6 @@ JITX86::JITX86() OpAdvTable[OP_SIGN_ALT] = 0; OpAdvTable[OP_EQ] = 0; OpAdvTable[OP_NEQ] = 0; - OpAdvTable[OP_LESS] = 0; - OpAdvTable[OP_LEQ] = 0; - OpAdvTable[OP_GRTR] = 0; - OpAdvTable[OP_GEQ] = 0; OpAdvTable[OP_SLESS] = 0; OpAdvTable[OP_SLEQ] = 0; OpAdvTable[OP_SGRTR] = 0; @@ -622,10 +607,6 @@ JITX86::JITX86() OpAdvTable[OP_JNZ] = -2; OpAdvTable[OP_JEQ] = -2; OpAdvTable[OP_JNEQ] = -2; - OpAdvTable[OP_JLESS] = -2; - OpAdvTable[OP_JLEQ] = -2; - OpAdvTable[OP_JGRTR] = -2; - OpAdvTable[OP_JGEQ] = -2; OpAdvTable[OP_JSLESS] = -2; OpAdvTable[OP_JSLEQ] = -2; OpAdvTable[OP_JSGRTR] = -2; @@ -633,6 +614,7 @@ JITX86::JITX86() OpAdvTable[OP_SWITCH] = -2; /* opcodes that are totally invalid */ + /* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */ OpAdvTable[OP_FILE] = -3; OpAdvTable[OP_SYMBOL] = -3; OpAdvTable[OP_LINE] = -3; @@ -641,4 +623,24 @@ JITX86::JITX86() OpAdvTable[OP_SYSREQ_D] = -3; OpAdvTable[OP_SYSREQ_ND] = -3; OpAdvTable[OP_PUSH_R] = -3; + OpAdvTable[OP_LODB_I] = -3; + OpAdvTable[OP_STRB_I] = -3; + OpAdvTable[OP_LCTRL] = -3; + OpAdvTable[OP_SCTRL] = -3; + OpAdvTable[OP_ALIGN_PRI] = -3; + OpAdvTable[OP_ALIGN_ALT] = -3; + OpAdvTable[OP_JREL] = -3; + OpAdvTable[OP_CMPS] = -3; + OpAdvTable[OP_UMUL] = -3; + OpAdvTable[OP_UDIV] = -3; + OpAdvTable[OP_UDIV_ALT] = -3; + OpAdvTable[OP_LESS] = -3; + OpAdvTable[OP_LEQ] = -3; + OpAdvTable[OP_GRTR] = -3; + OpAdvTable[OP_GEQ] = -3; + OpAdvTable[OP_JLESS] = -3; + OpAdvTable[OP_JLEQ] = -3; + OpAdvTable[OP_JGRTR] = -3; + OpAdvTable[OP_JGEQ] = -3; + } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index d5b024c5..20388dd2 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -63,12 +63,12 @@ typedef enum OP_LOAD_ALT, //DONE OP_LOAD_S_PRI, //DONE OP_LOAD_S_ALT, //DONE - OP_LREF_PRI, //UNSUPPORTED - OP_LREF_ALT, //UNSUPPORTED - OP_LREF_S_PRI, //UNSUPPORTED - OP_LREF_S_ALT, //UNSUPPORTED + OP_LREF_PRI, // !GEN :TODO: we will need this for dynarrays + OP_LREF_ALT, // !GEN :TODO: we will need this for dynarrays + OP_LREF_S_PRI, //DONE + OP_LREF_S_ALT, //DONE OP_LOAD_I, //DONE - OP_LODB_I, //UNSUPPORTED + OP_LODB_I, // !GEN :TODO: - only used for pack access - drop support in compiler first OP_CONST_PRI, //DONE OP_CONST_ALT, //DONE OP_ADDR_PRI, //DONE @@ -77,26 +77,26 @@ typedef enum OP_STOR_ALT, //DONE OP_STOR_S_PRI, //DONE OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //UNSUPPORTED - OP_SREF_ALT, //UNSUPPORTED - OP_SREF_S_PRI, //UNSUPPORTED - OP_SREF_S_ALT, //UNSUPPORTED + OP_SREF_PRI, //DONE + OP_SREF_ALT, //DONE + OP_SREF_S_PRI, // !GEN :TODO: we will need this for dynarrays + OP_SREF_S_ALT, // !GEN :TODO: we will need this for dynarrays OP_STOR_I, //DONE - OP_STRB_I, //UNSUPPORTED + OP_STRB_I, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_LIDX, //DONE - OP_LIDX_B, //UNSUPPORTED + OP_LIDX_B, //DONE OP_IDXADDR, //DONE - OP_IDXADDR_B, //UNSUPPORTED - OP_ALIGN_PRI, //UNSUPPORTED - OP_ALIGN_ALT, //UNSUPPORTED - OP_LCTRL, //UNSUPPORTED - OP_SCTRL, //UNSUPPORTED + OP_IDXADDR_B, //DONE + OP_ALIGN_PRI, // !GEN :TODO: - only used for pack access, drop support in compiler first + OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first + OP_LCTRL, // !GEN + OP_SCTRL, // !GEN OP_MOVE_PRI, //DONE OP_MOVE_ALT, //DONE OP_XCHG, //DONE OP_PUSH_PRI, //DONE OP_PUSH_ALT, //DONE - OP_PUSH_R, //DEPRECATED + OP_PUSH_R, // !GEN DEPRECATED OP_PUSH_C, //DONE OP_PUSH, //DONE OP_PUSH_S, //DONE @@ -105,20 +105,20 @@ typedef enum OP_STACK, //DONE OP_HEAP, //DONE OP_PROC, //DONE - OP_RET, //UNSUPPORTED + OP_RET, // !GEN OP_RETN, //DONE OP_CALL, - OP_CALL_PRI, + OP_CALL_PRI, // !GEN OP_JUMP, //DONE - OP_JREL, //UNSUPPORTED + OP_JREL, // !GEN OP_JZER, //DONE OP_JNZ, //DONE OP_JEQ, //DONE OP_JNEQ, //DONE - OP_JLESS, //UNSUPPORTED - OP_JLEQ, //UNSUPPORTED - OP_JGRTR, //UNSUPPORTED - OP_JGEQ, //UNSUPPORTED + OP_JLESS, // !GEN + OP_JLEQ, // !GEN + OP_JGRTR, // !GEN + OP_JGEQ, // !GEN OP_JSLESS, //DONE OP_JSLEQ, //DONE OP_JSGRTR, //DONE @@ -133,9 +133,9 @@ typedef enum OP_SMUL, //DONE OP_SDIV, //DONE OP_SDIV_ALT, //DONE - OP_UMUL, //UNSUPPORTED - OP_UDIV, //UNSUPPORTED - OP_UDIV_ALT, //UNSUPPORTED + OP_UMUL, // !GEN + OP_UDIV, // !GEN + OP_UDIV_ALT, // !GEN OP_ADD, //DONE OP_SUB, //DONE OP_SUB_ALT, //DONE @@ -155,10 +155,10 @@ typedef enum OP_SIGN_ALT, //DONE OP_EQ, //DONE OP_NEQ, //DONE - OP_LESS, //UNSUPPORTED - OP_LEQ, //UNSUPPORTED - OP_GRTR, //UNSUPPORTED - OP_GEQ, //UNSUPPORTED + OP_LESS, // !GEN + OP_LEQ, // !GEN + OP_GRTR, // !GEN + OP_GEQ, // !GEN OP_SLESS, //DONE OP_SLEQ, //DONE OP_SGRTR, //DONE @@ -176,17 +176,17 @@ typedef enum OP_DEC_S, //DONE OP_DEC_I, //DONE OP_MOVS, //DONE - OP_CMPS, //UNSUPPORTED + OP_CMPS, // !GEN OP_FILL, //DONE OP_HALT, //DONE OP_BOUNDS, //DONE - OP_SYSREQ_PRI, - OP_SYSREQ_C, - OP_FILE, //DEPRECATED - OP_LINE, //DEPRECATED - OP_SYMBOL, //DEPRECATED - OP_SRANGE, //DEPRECATED - OP_JUMP_PRI, + OP_SYSREQ_PRI, // !GEN + OP_SYSREQ_C, + OP_FILE, // !GEN DEPRECATED + OP_LINE, // !GEN DEPRECATED + OP_SYMBOL, // !GEN DEPRECATED + OP_SRANGE, // !GEN DEPRECATED + OP_JUMP_PRI, // !GEN OP_SWITCH, OP_CASETBL, OP_SWAP_PRI, //DONE @@ -194,7 +194,7 @@ typedef enum OP_PUSH_ADR, //DONE OP_NOP, //DONE OP_SYSREQ_N, - OP_SYMTAG, //DEPRECATED + OP_SYMTAG, // !GEN DEPRECATED OP_BREAK, //DONE OP_PUSH2_C, //DONE OP_PUSH2, //DONE @@ -217,8 +217,8 @@ typedef enum OP_CONST, //DONE OP_CONST_S, //DONE /* ----- */ - OP_SYSREQ_D, //UNSUPPORTED - OP_SYSREQ_ND, //UNSUPPORTED + OP_SYSREQ_D, // !GEN UNSUPPORT + OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ OP_HEAP_PRI, //DONE OP_PUSH_HEAP_C, //DONE diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index e34bfb93..4ea20788 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -158,13 +158,6 @@ WriteOp_SMul(jit); break; } -#ifdef UNSUPPORTED - case OP_UMUL: - { - WriteOp_UMul(jit); - break; - } -#endif case OP_ADD: { WriteOp_Add(jit); @@ -245,34 +238,6 @@ WriteOp_Neq(jit); break; } -#ifdef UNSUPPORTED - case OP_LESS: - { - WriteOp_Less(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_LEQ: - { - WriteOp_Leq(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_GRTR: - { - WriteOp_Grtr(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_GEQ: - { - WriteOp_Geq(jit); - break; - } -#endif case OP_SLESS: { WriteOp_Sless(jit); @@ -373,34 +338,26 @@ WriteOp_Load_S_Alt(jit); break; } -#ifdef UNSUPPORTED case OP_LREF_PRI: { WriteOp_Lref_Pri(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_LREF_ALT: { WriteOp_Lref_Alt(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_LREF_S_PRI: { WriteOp_Lref_Pri(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_LREF_S_ALT: { WriteOp_Lref_Alt(jit); break; } -#endif case OP_CONST_PRI: { WriteOp_Const_Pri(jit); @@ -446,48 +403,26 @@ WriteOp_Idxaddr(jit); break; } -#ifdef UNSUPPORTED case OP_SREF_PRI: { WriteOp_Sref_Pri(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_SREF_ALT: { WriteOp_Sref_Alt(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_SREF_S_PRI: { WriteOp_Sref_S_Pri(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_SREF_S_ALT: { WriteOp_Sref_S_Alt(jit); break; } -#endif -#ifdef UNSUPPORTED - case OP_ALIGN_PRI: - { - WriteOp_Align_Pri(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_ALIGN_ALT: - { - WriteOp_Align_Alt(jit); - break; - } -#endif case OP_POP_PRI: { WriteOp_Pop_Pri(jit); @@ -588,58 +523,26 @@ WriteOp_Load_I(jit); break; } -#ifdef UNSUPPORTED - case OP_LODB_I: - { - WriteOp_Lodb_I(jit); - break; - } -#endif case OP_STOR_I: { WriteOp_Stor_I(jit); break; } -#ifdef UNSUPPORTED - case OP_STRB_I: - { - WriteOp_Strb_I(jit); - break; - } -#endif case OP_LIDX: { WriteOp_Lidx(jit); break; } -#ifdef UNSUPPORTED case OP_LIDX_B: { WriteOp_Lidx_B(jit); break; } -#endif -#ifdef UNSUPPORTED case OP_IDXADDR_B: { WriteOp_Idxaddr_B(jit); break; } -#endif -#ifdef UNSUPPORTED - case OP_LCTRL: - { - WriteOp_Lctrl(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_SCTRL: - { - WriteOp_Sctrl(jit); - break; - } -#endif case OP_STACK: { WriteOp_Stack(jit); @@ -660,39 +563,11 @@ WriteOp_SDiv_Alt(jit); break; } -#ifdef UNSUPPORTED - case OP_UDIV: - { - WriteOp_UDiv(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_UDIV_ALT: - { - WriteOp_UDiv_Alt(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_RET: - { - WriteOp_Ret(jit); - break; - } -#endif case OP_RETN: { WriteOp_Retn(jit); break; } -#ifdef UNSUPPORTED - case OP_CMPS: - { - WriteOp_Cmps(jit); - break; - } -#endif case OP_BOUNDS: { WriteOp_Bounds(jit); @@ -708,13 +583,6 @@ WriteOp_Break(jit); break; } -#ifdef UNSUPPORTED - case OP_JREL: - { - WriteOp_JRel(jit); - break; - } -#endif case OP_JUMP: { WriteOp_Jump(jit); @@ -740,34 +608,6 @@ WriteOp_Jneq(jit); break; } -#ifdef UNSUPPORTED - case OP_JLESS: - { - WriteOp_Jless(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_JLEQ: - { - WriteOp_Jeq(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_JGRTR: - { - WriteOp_Jgrtr(jit); - break; - } -#endif -#ifdef UNSUPPORTED - case OP_JGEQ: - { - WriteOp_Jgeq(jit); - break; - } -#endif case OP_JSLESS: { WriteOp_Jsless(jit); @@ -778,6 +618,9 @@ WriteOp_Jsleq(jit); break; } +#if defined USE_UNGEN_OPCODES + #include "ungen_opcode_switch.inc" +#endif default: { assert(0); diff --git a/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc b/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc new file mode 100644 index 00000000..0f9ba552 --- /dev/null +++ b/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc @@ -0,0 +1,100 @@ + case OP_UMUL: + { + WriteOp_UMul(jit); + break; + } + case OP_LESS: + { + WriteOp_Less(jit); + break; + } + case OP_LEQ: + { + WriteOp_Leq(jit); + break; + } + case OP_GRTR: + { + WriteOp_Grtr(jit); + break; + } + case OP_GEQ: + { + WriteOp_Geq(jit); + break; + } + case OP_ALIGN_PRI: + { + WriteOp_Align_Pri(jit); + break; + } + case OP_ALIGN_ALT: + { + WriteOp_Align_Alt(jit); + break; + } + case OP_LODB_I: + { + WriteOp_Lodb_I(jit); + break; + } + case OP_STRB_I: + { + WriteOp_Strb_I(jit); + break; + } + case OP_LCTRL: + { + WriteOp_Lctrl(jit); + break; + } + case OP_SCTRL: + { + WriteOp_Sctrl(jit); + break; + } + case OP_UDIV: + { + WriteOp_UDiv(jit); + break; + } + case OP_UDIV_ALT: + { + WriteOp_UDiv_Alt(jit); + break; + } + case OP_RET: + { + WriteOp_Ret(jit); + break; + } + case OP_CMPS: + { + WriteOp_Cmps(jit); + break; + } + case OP_JREL: + { + WriteOp_JRel(jit); + break; + } + case OP_JLESS: + { + WriteOp_Jless(jit); + break; + } + case OP_JLEQ: + { + WriteOp_Jeq(jit); + break; + } + case OP_JGRTR: + { + WriteOp_Jgrtr(jit); + break; + } + case OP_JGEQ: + { + WriteOp_Jgeq(jit); + break; + } \ No newline at end of file diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h new file mode 100644 index 00000000..3072db28 --- /dev/null +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -0,0 +1,336 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_ +#define _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_ + +inline void WriteOp_UMul(JitWriter *jit) +{ + //mov ecx, edx + //mul edx + //mov edx, ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_Less(JitWriter *jit) +{ + //cmp eax, edx ; PRI < ALT ? (unsigned) + //mov eax, 0 + //setb al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B); +} + +inline void WriteOp_Leq(JitWriter *jit) +{ + //cmp eax, edx ; PRI <= ALT ? (unsigned) + //mov eax, 0 + //setbe al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE); +} + +inline void WriteOp_Grtr(JitWriter *jit) +{ + //cmp eax, edx ; PRI > ALT ? (unsigned) + //mov eax, 0 + //seta al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A); +} + +inline void WriteOp_Geq(JitWriter *jit) +{ + //cmp eax, edx ; PRI >= ALT ? (unsigned) + //mov eax, 0 + //setae al + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE); +} + +inline void WriteOp_Align_Pri(JitWriter *jit) +{ + //xor eax, + cell_t val = sizeof(cell_t) - jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); + else + IA32_Xor_Eax_Imm32(jit, val); +} + +inline void WriteOp_Align_Alt(JitWriter *jit) +{ + //xor edx, + cell_t val = sizeof(cell_t) - jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val); + else + IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val); +} + +inline void WriteOp_Cmps(JitWriter *jit) +{ + //push edi + //push esi + //lea esi, [edi+edx] + //lea edi, [edi+eax] + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_ESI); + IA32_Lea_Reg_DispRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Lea_Reg_DispRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + + //xor eax, eax + //repe cmpsb + //je :cmps1 + IA32_Xor_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Cmpsb(jit); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0); + + //sbb eax, eax + //sbb eax, -1 + IA32_Sbb_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Sbb_Eax_Imm32(jit, -1);//:TODO: use imm8 here + + //:cmps1 + //pop esi + //pop edi + IA32_Send_Jump8_Here(jit, jmp); + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EDI); +} + +inline void WriteOp_Lodb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + + //mov eax, [edi+eax] + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + + //and eax, + cell_t val = jit->read_cell(); + switch(val) + { + case 1: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);//:TODO: replace with AND EAX, imm32 + break; + } + case 2: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);//:TODO: replace with AND EAX, imm32 + break; + } + } +} + +inline void WriteOp_Strb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + //mov [edi+edx], eax + cell_t val = jit->read_cell(); + switch (val) + { + case 1: + { + IA32_Mov_Rm8_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 2: + { + IA32_Mov_Rm16_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 4: + { + IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + } +} + +inline void WriteOp_Lctrl(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + switch (val) + { + case 0: + { + //mov ecx, [esi+ctx] + //mov eax, [ecx+] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, base)); + break; + } + case 1: + { + //mov eax, edi + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); + break; + } + case 2: + { + //mov eax, [esi+hea] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP); + break; + } + case 3: + { + //mov ecx, [esi+ctx] + //mov eax, [ecx+ctx.memory] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory)); + break; + } + case 4: + { + //mov eax, ebp + //sub eax, edi - unrelocate + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG); + IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); + break; + } + case 5: + { + //mov eax, [esi+frm] + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_FRM); + break; + } + case 6: + { + //mov eax, [cip] + jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); + jitoffs_t save = jit->jit_curpos(); + jit->setpos(imm32); + jit->write_int32((uint32_t)(jit->outbase + save)); + jit->setpos(save); + break; + } + } +} + +inline void WriteOp_Sctrl(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + switch (val) + { + case 2: + { + //mov [esi+hea], eax + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, AMX_REG_PRI); + break; + } + case 4: + { + //lea ebp, [edi+eax] + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + break; + } + case 5: + { + //mov ebx, eax - overwrite frm + //mov frm, eax - overwrite stacked frame + //add ebx, edi - relocate local frm //:TODO: use LEA here!!! + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_PRI, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_PRI, MOD_MEM_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + break; + } + case 6: + { + IA32_Jump_Reg(jit, AMX_REG_PRI); + break; + } + } +} + +inline void WriteOp_UDiv(JitWriter *jit) +{ + //mov ecx, edx + //xor edx, edx + //div ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_UDiv_Alt(JitWriter *jit) +{ + //mov ecx, eax + //mov eax, edx + //xor edx, edx + //div ecx + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + Write_Check_DivZero(jit, AMX_REG_TMP); + IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); +} + +inline void WriteOp_Ret(JitWriter *jit) +{ + //mov ebx, [ebp] - get old FRM + //add ebp, 4 - pop stack + //mov [esi+frm], ebx - restore + //add ebx, edi - relocate + //ret + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! + IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + IA32_Return(jit); +} + +inline void WriteOp_JRel(JitWriter *jit) +{ + //jmp ;relative jump + cell_t cip_offs = jit->read_cell(); + + /* Note that since code size calculation has to be done in the same + * phase as building relocation information, we cannot know the jump size + * beforehand. Thus, we always write full 32bit jumps for safety. + */ + jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); + IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs)); +} + +inline void WriteOp_Jless(JitWriter *jit) +{ + //cmp eax, edx + //jb + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jleq(JitWriter *jit) +{ + //cmp eax, edx + //jbe + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jgrtr(JitWriter *jit) +{ + //cmp eax, edx + //ja + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false)); +} + +inline void WriteOp_Jgeq(JitWriter *jit) +{ + //cmp eax, edx + //jae + cell_t target = jit->read_cell(); + IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false)); +} + +#endif //_INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_ diff --git a/sourcepawn/vm/sp_vm_engine.cpp b/sourcepawn/vm/sp_vm_engine.cpp index 5bae6220..fa3d2a79 100644 --- a/sourcepawn/vm/sp_vm_engine.cpp +++ b/sourcepawn/vm/sp_vm_engine.cpp @@ -6,8 +6,39 @@ #include "zlib/zlib.h" #include "sp_vm_basecontext.h" +#if defined WIN32 + #define WIN32_LEAN_AND_MEAN + #include +#else if defined __GNUC__ + #include +#endif + using namespace SourcePawn; +void *SourcePawnEngine::ExecAlloc(size_t size) +{ +#if defined WIN32 + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else if defined __GNUC__ + void *base = memalign(sysconf(_SC_PAGESIZE), size); + if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + { + free(base); + return NULL; + } + return base; +#endif +} + +void SourcePawnEngine::ExecFree(void *address) +{ +#if defined WIN32 + VirtualFree(address, 0, MEM_RELEASE); +#else if defined __GNUC__ + free(address); +#endif +} + void *SourcePawnEngine::BaseAlloc(size_t size) { return malloc(size); @@ -28,7 +59,7 @@ void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx) sp_context_t *_ctx = ctx->GetContext(); IVirtualMachine *vm = ctx->GetVirtualMachine(); - vm->FreeContextVars(_ctx); + vm->FreeContext(_ctx); delete ctx; } diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h index 13b18557..66b38e6c 100644 --- a/sourcepawn/vm/sp_vm_engine.h +++ b/sourcepawn/vm/sp_vm_engine.h @@ -67,6 +67,22 @@ namespace SourcePawn * @param mem Memory address to free. */ void BaseFree(void *memory); + + + /** + * Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + void *ExecAlloc(size_t size); + + /** + * Frees executable memory. + * + * @param mem Address to free. + */ + void ExecFree(void *address); }; }; From 8669bbd4a8de138fe61e82432d3c831e88417fb8 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 24 Sep 2006 18:04:18 +0000 Subject: [PATCH 0069/1664] compilation errors --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4099 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 1 + sourcepawn/vm/jit/x86/jit_x86.h | 4 ++-- sourcepawn/vm/jit/x86/ungen_opcodes.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 1835acea..991ec658 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1155,6 +1155,7 @@ inline void WriteOp_Jeq(JitWriter *jit) IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false)); } + inline void WriteOp_Jneq(JitWriter *jit) { //cmp eax, edx diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index a3a08322..9004dd6b 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -39,9 +39,9 @@ class JITX86 : public IVirtualMachine public: JITX86(); public: - const char *GetVMName() =0; + const char *GetVMName(); ICompilation *StartCompilation(sp_plugin_t *plugin); - bool SetCompilationOption(ICompilation *co, const char *key, const char *val) ; + bool SetCompilationOption(ICompilation *co, const char *key, const char *val); sp_context_t *CompileToContext(ICompilation *co, int *err); void AbortCompilation(ICompilation *co); void FreeContext(sp_context_t *ctx); diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h index 3072db28..2a9dc9d3 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcodes.h +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -161,7 +161,7 @@ inline void WriteOp_Lctrl(JitWriter *jit) //mov ecx, [esi+ctx] //mov eax, [ecx+] IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, base)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, codebase)); break; } case 1: From 0b9cdfeddd526ca3ba0a9735b3b6c61f6b033c38 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 28 Sep 2006 11:21:45 +0000 Subject: [PATCH 0070/1664] switched DAT and STK registers fixed the EBP encoding mess (more to come for ungen opcodes and helpers) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40100 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 326 ++++++++++++++--------------- sourcepawn/vm/jit/x86/jit_x86.h | 4 +- sourcepawn/vm/jit/x86/x86_macros.h | 69 ++++-- 3 files changed, 215 insertions(+), 184 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 991ec658..96f753f6 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -12,13 +12,13 @@ inline void WriteOp_Move_Pri(JitWriter *jit) { //mov eax, edx - IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Move_Alt(JitWriter *jit) { //mov edx, eax - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); } inline void WriteOp_Xchg(JitWriter *jit) @@ -30,9 +30,9 @@ inline void WriteOp_Xchg(JitWriter *jit) inline void WriteOp_Push(JitWriter *jit) { //push stack, DAT offset based - //sub ebp, 4 - //mov ecx, [edi+] - //mov [ebp], ecx + //sub edi, 4 + //mov ecx, [ebp+] + //mov [edi], ecx cell_t val = jit->read_cell(); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); //optimize encoding a bit... @@ -46,8 +46,8 @@ inline void WriteOp_Push(JitWriter *jit) inline void WriteOp_Push_C(JitWriter *jit) { //push stack - //mov [ebp-4], - //sub ebp, 4 + //mov [edi-4], + //sub edi, 4 cell_t val = jit->read_cell(); IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); @@ -55,7 +55,7 @@ inline void WriteOp_Push_C(JitWriter *jit) inline void WriteOp_Zero(JitWriter *jit) { - //mov [edi+], 0 + //mov [ebp+], 0 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val); @@ -76,9 +76,9 @@ inline void WriteOp_Zero_S(JitWriter *jit) inline void WriteOp_Push_S(JitWriter *jit) { //push stack, FRM offset based - //sub ebp, 4 + //sub edi, 4 //mov ecx, [ebx+] - //mov [ebp], ecx + //mov [edi], ecx cell_t val = jit->read_cell(); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); //optimize encoding a bit... @@ -91,16 +91,16 @@ inline void WriteOp_Push_S(JitWriter *jit) inline void WriteOp_Push_Pri(JitWriter *jit) { - //mov [ebp-4], eax - //sub ebp, 4 + //mov [edi-4], eax + //sub edi, 4 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); } inline void WriteOp_Push_Alt(JitWriter *jit) { - //mov [ebp-4], edx - //sub ebp, 4 + //mov [edi-4], edx + //sub edi, 4 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); } @@ -188,25 +188,25 @@ inline void WriteOp_Push2(JitWriter *jit) inline void WriteOp_Zero_Pri(JitWriter *jit) { //xor eax, eax - IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); } inline void WriteOp_Zero_Alt(JitWriter *jit) { //xor edx, edx - IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Add(JitWriter *jit) { //add eax, edx - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Sub(JitWriter *jit) { //sub eax, edx - IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Sub_Alt(JitWriter *jit) @@ -214,25 +214,26 @@ inline void WriteOp_Sub_Alt(JitWriter *jit) //neg eax //add eax, edx IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Proc(JitWriter *jit) { //push old frame on stack: - //sub ebp, 4 - //mov ecx, [frm] - //mov [ebp], ecx + //sub edi, 4 + //mov ecx, [esi+frm] + //mov [edi], ecx IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); //save frame: - //mov [frm], ebp - get new frame - //mov ebx, ebp - store frame back - //sub [frm], edi - relocate local frame - IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_STK, MOD_MEM_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); - IA32_Sub_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_DAT, MOD_MEM_REG); + //:TODO: move to a temp reg, subtract and then move to mem, faster?? + //mov [esi+frm], edi - get new frame + //mov ebx, edi - store frame back + //sub [esi+frm], ebp - relocate local frame + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_STK, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + IA32_Sub_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_DAT, MOD_MEM_REG); } inline void WriteOp_Lidx_B(JitWriter *jit) @@ -240,11 +241,11 @@ inline void WriteOp_Lidx_B(JitWriter *jit) cell_t val = jit->read_cell(); //shl eax, //add eax, edx - //mov eax, [edi+eax] + //mov eax, [ebp+eax] IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Idxaddr_B(JitWriter *jit) @@ -253,14 +254,14 @@ inline void WriteOp_Idxaddr_B(JitWriter *jit) //add eax, edx cell_t val = jit->read_cell(); IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Shl(JitWriter *jit) { //mov ecx, edx //shl eax, cl - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG); } @@ -268,7 +269,7 @@ inline void WriteOp_Shr(JitWriter *jit) { //mov ecx, edx //shr eax, cl - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG); } @@ -276,7 +277,7 @@ inline void WriteOp_Sshr(JitWriter *jit) { //mov ecx, edx //sar eax, cl - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG); } @@ -313,9 +314,9 @@ inline void WriteOp_SMul(JitWriter *jit) //mov ecx, edx //imul edx //mov edx, ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); } inline void WriteOp_Not(JitWriter *jit) @@ -337,19 +338,19 @@ inline void WriteOp_Neg(JitWriter *jit) inline void WriteOp_Xor(JitWriter *jit) { //xor eax, edx - IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Or(JitWriter *jit) { //or eax, edx - IA32_Or_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_And(JitWriter *jit) { //and eax, edx - IA32_And_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); } inline void WriteOp_Invert(JitWriter *jit) @@ -399,7 +400,7 @@ inline void WriteOp_Eq(JitWriter *jit) //cmp eax, edx ; PRI == ALT ? //mov eax, 0 //sete al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); } @@ -409,7 +410,7 @@ inline void WriteOp_Neq(JitWriter *jit) //cmp eax, edx ; PRI != ALT ? //mov eax, 0 //setne al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE); } @@ -419,7 +420,7 @@ inline void WriteOp_Sless(JitWriter *jit) //cmp eax, edx ; PRI < ALT ? (signed) //mov eax, 0 //setl al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L); } @@ -429,7 +430,7 @@ inline void WriteOp_Sleq(JitWriter *jit) //cmp eax, edx ; PRI <= ALT ? (signed) //mov eax, 0 //setle al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE); } @@ -439,7 +440,7 @@ inline void WriteOp_Sgrtr(JitWriter *jit) //cmp eax, edx ; PRI > ALT ? (signed) //mov eax, 0 //setg al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G); } @@ -449,7 +450,7 @@ inline void WriteOp_Sgeq(JitWriter *jit) //cmp eax, edx ; PRI >= ALT ? (signed) //mov eax, 0 //setge al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE); } @@ -474,7 +475,7 @@ inline void WriteOp_Eq_C_Alt(JitWriter *jit) //cmp edx, ; ALT == value ? //sete al cell_t val = jit->read_cell(); - IA32_Xor_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val); else @@ -496,7 +497,7 @@ inline void WriteOp_Inc_Alt(JitWriter *jit) inline void WriteOp_Inc(JitWriter *jit) { - //add [edi+], 1 + //add [ebp+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); @@ -516,8 +517,8 @@ inline void WriteOp_Inc_S(JitWriter *jit) inline void WriteOp_Inc_I(JitWriter *jit) { - //add [edi+eax], 1 - IA32_Add_Rm_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); + //add [ebp+eax], 1 + IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); } inline void WriteOp_Dec_Pri(JitWriter *jit) @@ -534,7 +535,7 @@ inline void WriteOp_Dec_Alt(JitWriter *jit) inline void WriteOp_Dec(JitWriter *jit) { - //sub [edi+], 1 + //sub [ebp+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); @@ -554,13 +555,13 @@ inline void WriteOp_Dec_S(JitWriter *jit) inline void WriteOp_Dec_I(JitWriter *jit) { - //sub [edi+eax], 1 - IA32_Sub_Rm_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); + //sub [ebp+eax], 1 + IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); } inline void WriteOp_Load_Pri(JitWriter *jit) { - //mov eax, [edi+] + //mov eax, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); @@ -570,7 +571,7 @@ inline void WriteOp_Load_Pri(JitWriter *jit) inline void WriteOp_Load_Alt(JitWriter *jit) { - //mov edx, [edi+] + //mov edx, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); @@ -600,50 +601,50 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit) inline void WriteOp_Lref_Pri(JitWriter *jit) { - //mov eax, [edi+] - //mov eax, [edi+eax] + //mov eax, [ebp+] + //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Lref_Alt(JitWriter *jit) { - //mov edx, [edi+] - //mov edx, [edi+edx] + //mov edx, [ebp+] + //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } inline void WriteOp_Lref_S_Pri(JitWriter *jit) { //mov eax, [ebx+] - //mov eax, [edi+eax] + //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Lref_S_Alt(JitWriter *jit) { //mov edx, [ebx+] - //mov edx, [edi+edx] + //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } inline void WriteOp_Const_Pri(JitWriter *jit) @@ -662,10 +663,10 @@ inline void WriteOp_Const_Alt(JitWriter *jit) inline void WriteOp_Addr_Pri(JitWriter *jit) { - //mov eax, frm + //mov eax, [esi+frm] //add eax, cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); else @@ -674,10 +675,10 @@ inline void WriteOp_Addr_Pri(JitWriter *jit) inline void WriteOp_Addr_Alt(JitWriter *jit) { - //mov edx, frm + //mov edx, [esi+frm] //add edx, cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG); else @@ -686,7 +687,7 @@ inline void WriteOp_Addr_Alt(JitWriter *jit) inline void WriteOp_Stor_Pri(JitWriter *jit) { - //mov [edi+], eax + //mov [ebp+], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val); @@ -696,7 +697,7 @@ inline void WriteOp_Stor_Pri(JitWriter *jit) inline void WriteOp_Stor_Alt(JitWriter *jit) { - //mov [edi+], edx + //mov [ebp+], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val); @@ -732,73 +733,73 @@ inline void WriteOp_Idxaddr(JitWriter *jit) inline void WriteOp_Sref_Pri(JitWriter *jit) { - //mov ecx, [edi+] - //mov [edi+ecx], eax + //mov ecx, [ebp+] + //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } inline void WriteOp_Sref_Alt(JitWriter *jit) { - //mov ecx, [edi+] - //mov [edi+ecx], edx + //mov ecx, [ebp+] + //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } inline void WriteOp_Sref_S_Pri(JitWriter *jit) { //mov ecx, [ebx+] - //mov [edi+ecx], eax + //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } inline void WriteOp_Sref_S_Alt(JitWriter *jit) { //mov ecx, [ebx+] - //mov [edi+ecx], edx + //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); else IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } inline void WriteOp_Pop_Pri(JitWriter *jit) { - //mov eax, [ebp] - //add ebp, 4 + //mov eax, [edi] + //add edi, 4 IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); } inline void WriteOp_Pop_Alt(JitWriter *jit) { - //mov edx, [ebp] - //add ebp, 4 + //mov edx, [edi] + //add edi, 4 IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); } inline void WriteOp_Swap_Pri(JitWriter *jit) { - //add [ebp], eax - //sub eax, [ebp] - //add [ebp], eax + //add [edi], eax + //sub eax, [edi] + //add [edi], eax //neg eax IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); @@ -808,9 +809,9 @@ inline void WriteOp_Swap_Pri(JitWriter *jit) inline void WriteOp_Swap_Alt(JitWriter *jit) { - //add [ebp], edx - //sub edx, [ebp] - //add [ebp], edx + //add [edi], edx + //sub edx, [edi] + //add [edi], edx //neg edx IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); @@ -820,12 +821,12 @@ inline void WriteOp_Swap_Alt(JitWriter *jit) inline void WriteOp_PushAddr(JitWriter *jit) { - //mov ecx, frm ;get address (offset from frame) + //mov ecx, [esi+frm] ;get address (offset from frame) //add ecx, - //mov [ebp-4], ecx - //sub ebp, 4 + //mov [edi-4], ecx + //sub edi, 4 cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); else @@ -838,16 +839,16 @@ inline void WriteOp_Movs(JitWriter *jit) { //cld //push esi - //lea esi, [edi+eax] - //add edi, edx + //push edi + //lea esi, [ebp+eax] + //lea edi, [ebp+edx] //if dword: // mov ecx, dword // rep movsd //if byte: // mov ecx, byte // rep movsb - //sub edi, edx - //sub edi, + //pop edi //pop esi cell_t val = jit->read_cell(); unsigned int dwords = val >> 2; @@ -855,54 +856,48 @@ inline void WriteOp_Movs(JitWriter *jit) IA32_Cld(jit); IA32_Push_Reg(jit, REG_ESI); - IA32_Lea_Reg_DispRegMult(jit, REG_ESI, REG_EDI, AMX_REG_PRI, NOSCALE); - IA32_Add_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); + IA32_Push_Reg(jit, REG_EDI); + IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); if (dwords) { - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, dwords); + IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords); IA32_Rep(jit); IA32_Movsd(jit); } if (bytes) { - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, bytes); + IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes); IA32_Rep(jit); IA32_Movsb(jit); } - IA32_Sub_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Sub_Rm_Imm8(jit, REG_EDI, (jit_uint8_t)val, MOD_REG); - else - IA32_Sub_Rm_Imm32(jit, REG_EDI, val, MOD_REG); + IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); } inline void WriteOp_Fill(JitWriter *jit) { - //add edi, edx + //push edi + //lea edi, [ebp+edx] //mov ecx, >> 2 //cld //rep stosd - //sub edi, edx - //sub edi, >> 2 + //pop edi unsigned int val = jit->read_cell() >> 2; - IA32_Add_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); + IA32_Push_Reg(jit, REG_EDI); + IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Mov_Reg_Imm32(jit, REG_ECX, val); IA32_Cld(jit); IA32_Rep(jit); IA32_Stosd(jit); - IA32_Sub_Rm_Reg(jit, REG_EDI, AMX_REG_ALT, MOD_REG); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Sub_Rm_Imm8(jit, REG_EDI, (jit_uint8_t)val, MOD_REG); - else - IA32_Sub_Rm_Imm32(jit, REG_EDI, val, MOD_REG); + IA32_Pop_Reg(jit, REG_EDI); } inline void WriteOp_Heap_Pri(JitWriter *jit) { - //mov edx, [hea] - //add [hea], eax + //mov edx, [esi+hea] + //add [esi+hea], eax IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); @@ -911,12 +906,12 @@ inline void WriteOp_Heap_Pri(JitWriter *jit) inline void WriteOp_Push_Heap_C(JitWriter *jit) { - //mov ecx, [hea] - //mov [edi+ecx], - //add [hea], 4 + //mov ecx, [esi+hea] + //mov [ebp+ecx], + //add [esi+hea], 4 cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Rm_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); + IA32_Mov_RmEBP_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); Write_CheckMargin_Heap(jit); @@ -924,12 +919,12 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) { - //sub [hea], 4 - //mov ecx, [hea] - //mov eax, [edi+ecx] + //sub [esi+hea], 4 + //mov ecx, [esi+hea] + //mov eax, [ebp+ecx] IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); Write_CheckMargin_Heap(jit); } @@ -948,7 +943,7 @@ inline void WriteOp_Load_S_Both(JitWriter *jit) inline void WriteOp_Const(JitWriter *jit) { - //mov [edi+], + //mov [ebp+], cell_t addr = jit->read_cell(); cell_t val = jit->read_cell(); if (addr < SCHAR_MAX && addr > SCHAR_MIN) @@ -964,7 +959,6 @@ inline void WriteOp_Const_S(JitWriter *jit) //mov [ebx+], cell_t offs = jit->read_cell(); cell_t val = jit->read_cell(); - if (offs < SCHAR_MAX && offs > SCHAR_MIN) { IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs); @@ -975,53 +969,53 @@ inline void WriteOp_Const_S(JitWriter *jit) inline void WriteOp_Load_I(JitWriter *jit) { - //mov eax, [edi+eax] + //mov eax, [ebp+eax] Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stor_I(JitWriter *jit) { - //mov [edi+edx], eax + //mov [ebp+edx], eax Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } inline void WriteOp_Lidx(JitWriter *jit) { //lea eax, [edx+4*eax] - //mov eax, [edi+eax] + //mov eax, [ebp+eax] IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stack(JitWriter *jit) { - //mov edx, ebp - //add ebp, - //sub edx, edi + //mov edx, edi + //add edi, + //sub edx, ebp cell_t val = jit->read_cell(); - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); else IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); - IA32_Sub_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); Write_CheckMargin_Stack(jit); } inline void WriteOp_Heap(JitWriter *jit) { - //mov edx, hea - //add hea, + //mov edx, [esi+hea] + //add [esi+hea], cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_INFO_FRM, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Add_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, (jit_int8_t)val, AMX_INFO_HEAP); + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP); else - IA32_Add_Rm_Imm32_Disp8(jit, AMX_INFO_FRM, val, AMX_INFO_HEAP); + IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP); Write_CheckMargin_Heap(jit); } @@ -1032,8 +1026,8 @@ inline void WriteOp_SDiv(JitWriter *jit) //mov edx, eax //sar edx, 31 //idiv ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); Write_Check_DivZero(jit, AMX_REG_TMP); IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); @@ -1045,8 +1039,8 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) //mov eax, edx //sar edx, 31 //idiv ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); Write_Check_DivZero(jit, AMX_REG_TMP); IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); @@ -1054,19 +1048,19 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) inline void WriteOp_Retn(JitWriter *jit) { - //mov ebx, [ebp] - get old frm - //mov ecx, [ebp+4] - get return eip - //add ebp, 8 - pop stack + //mov ebx, [edi] - get old frm + //mov ecx, [edi+4] - get return eip + //add edi, 8 - pop stack //mov [esi+frm], ebx - restore frame pointer - //add ebx, edi - relocate + //add ebx, ebp - relocate IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! - IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); - - //add ebp, [ebp] - reduce by this # of params - //add ebp, 4 - pop one extra for the # itself + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + + //add edi, [edi] - reduce by this # of params + //add edi, 4 - pop one extra for the # itself IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); @@ -1152,7 +1146,7 @@ inline void WriteOp_Jeq(JitWriter *jit) //cmp eax, edx //je cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false)); } @@ -1161,7 +1155,7 @@ inline void WriteOp_Jneq(JitWriter *jit) //cmp eax, edx //jne cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); } @@ -1170,7 +1164,7 @@ inline void WriteOp_Jsless(JitWriter *jit) //cmp eax, edx //jl cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_L, RelocLookup(jit, target, false)); } @@ -1179,7 +1173,7 @@ inline void WriteOp_Jsleq(JitWriter *jit) //cmp eax, edx //jle cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_LE, RelocLookup(jit, target, false)); } @@ -1188,7 +1182,7 @@ inline void WriteOp_JsGrtr(JitWriter *jit) //cmp eax, edx //jg cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_G, RelocLookup(jit, target, false)); } @@ -1197,7 +1191,7 @@ inline void WriteOp_JsGeq(JitWriter *jit) //cmp eax, edx //jge cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false)); } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 9004dd6b..13f63f7a 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -52,8 +52,8 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_REG_PRI REG_EAX #define AMX_REG_ALT REG_EDX -#define AMX_REG_STK REG_EBP -#define AMX_REG_DAT REG_EDI +#define AMX_REG_STK REG_EDI +#define AMX_REG_DAT REG_EBP #define AMX_REG_TMP REG_ECX #define AMX_REG_INFO REG_ESI #define AMX_REG_FRM REG_EBX diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 13650dd7..0eeb5d6f 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -51,6 +51,7 @@ //Opcodes with encoding information #define IA32_XOR_RM_REG 0x31 // encoding is /r +#define IA32_XOR_REG_RM 0x33 // encoding is /r #define IA32_XOR_EAX_IMM32 0x35 // encoding is /r #define IA32_XOR_RM_IMM32 0x81 // encoding is /6 #define IA32_XOR_RM_IMM8 0x83 // encoding is /6 @@ -89,8 +90,8 @@ #define IA32_INC_RM 0xFF // encoding is /0 #define IA32_DEC_REG 0x48 // encoding is +r #define IA32_DEC_RM 0xFF // encoding is /1 -#define IA32_OR_RM_REG 0x09 // encoding is /r -#define IA32_AND_RM_REG 0x21 // encoding is /r +#define IA32_OR_REG_RM 0x0B // encoding is /r +#define IA32_AND_REG_RM 0x23 // encoding is /r #define IA32_AND_EAX_IMM32 0x25 // encoding is #define IA32_AND_RM_IMM32 0x81 // encoding is /4 #define IA32_NOT_RM 0xF7 // encoding is /2 @@ -212,6 +213,12 @@ inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(dest_mode, src, dest)); } +inline void IA32_Xor_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) +{ + jit->write_ubyte(IA32_XOR_REG_RM); + jit->write_ubyte(ia32_modrm(dest_mode, dest, src)); +} + inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value) { jit->write_ubyte(IA32_XOR_EAX_IMM32); @@ -238,16 +245,16 @@ inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) jit->write_ubyte(ia32_modrm(mode, 3, reg)); } -inline void IA32_Or_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Or_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(IA32_OR_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_OR_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); } -inline void IA32_And_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_And_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(IA32_AND_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_AND_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); } inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t c) @@ -471,15 +478,16 @@ inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, jit->write_byte(val); } -inline void IA32_Add_Rm_Imm8_Disp_Reg(JitWriter *jit, +inline void IA32_Add_RmEBP_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int8_t val) { jit->write_ubyte(IA32_ADD_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); jit->write_byte(val); } @@ -505,15 +513,16 @@ inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit, jit->write_byte(val); } -inline void IA32_Sub_Rm_Imm8_Disp_Reg(JitWriter *jit, +inline void IA32_Sub_RmEBP_Imm8_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int8_t val) { jit->write_ubyte(IA32_SUB_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); jit->write_byte(val); } @@ -528,6 +537,14 @@ inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8 jit->write_ubyte(ia32_sib(scale, src_index, src_base)); } +inline void IA32_Lea_Reg_DispEBPRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); + jit->write_byte(0); +} + inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, @@ -621,6 +638,18 @@ inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); } +inline void IA32_Mov_Reg_RmEBP_Disp_Reg(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t src_scale) +{ + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); + jit->write_byte(0); +} + /** * Moving from REGISTER to REGISTER/MEMORY */ @@ -645,15 +674,16 @@ inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_int32(disp); } -inline void IA32_Mov_Rm_Reg_Disp_Reg(JitWriter *jit, +inline void IA32_Mov_RmEBP_Reg_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_uint8_t src) { jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); } inline void IA32_Mov_Rm8_Reg_Disp_Reg(JitWriter *jit, @@ -721,15 +751,16 @@ inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, jit->write_int32(val); } -inline void IA32_Mov_Rm_Imm32_Disp_Reg(JitWriter *jit, +inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_int32_t val) { jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); jit->write_int32(val); } @@ -868,6 +899,12 @@ inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Cmp_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_CMP_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8) { jit->write_ubyte(IA32_CMP_REG_RM); From 84a75be487a7e0a813f1fb425267f889a701a960 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 28 Sep 2006 15:11:41 +0000 Subject: [PATCH 0071/1664] fixed the EBP bug in ungen opcodes and fixed other code generation bugs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40101 --- sourcepawn/vm/jit/x86/ungen_opcodes.h | 103 +++++++++++++------------- sourcepawn/vm/jit/x86/x86_macros.h | 27 ++++--- 2 files changed, 68 insertions(+), 62 deletions(-) diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h index 2a9dc9d3..466ff54c 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcodes.h +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -6,9 +6,9 @@ inline void WriteOp_UMul(JitWriter *jit) //mov ecx, edx //mul edx //mov edx, ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); } inline void WriteOp_Less(JitWriter *jit) @@ -16,7 +16,7 @@ inline void WriteOp_Less(JitWriter *jit) //cmp eax, edx ; PRI < ALT ? (unsigned) //mov eax, 0 //setb al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B); } @@ -26,7 +26,7 @@ inline void WriteOp_Leq(JitWriter *jit) //cmp eax, edx ; PRI <= ALT ? (unsigned) //mov eax, 0 //setbe al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE); } @@ -36,7 +36,7 @@ inline void WriteOp_Grtr(JitWriter *jit) //cmp eax, edx ; PRI > ALT ? (unsigned) //mov eax, 0 //seta al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A); } @@ -46,7 +46,7 @@ inline void WriteOp_Geq(JitWriter *jit) //cmp eax, edx ; PRI >= ALT ? (unsigned) //mov eax, 0 //setae al - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE); } @@ -75,24 +75,29 @@ inline void WriteOp_Cmps(JitWriter *jit) { //push edi //push esi - //lea esi, [edi+edx] - //lea edi, [edi+eax] + //lea esi, [ebp+edx] + //lea edi, [ebp+eax] + //mov ecx, + unsigned int val = jit->read_cell(); + IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_ESI); - IA32_Lea_Reg_DispRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - IA32_Lea_Reg_DispRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); + IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Reg_Imm32(jit, REG_ECX, val); //xor eax, eax //repe cmpsb //je :cmps1 - IA32_Xor_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Rep(jit); IA32_Cmpsb(jit); jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0); //sbb eax, eax //sbb eax, -1 - IA32_Sbb_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Sbb_Eax_Imm32(jit, -1);//:TODO: use imm8 here + IA32_Sbb_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); + IA32_Sbb_Rm_Imm8(jit, AMX_REG_PRI, -1, MOD_REG); //:cmps1 //pop esi @@ -106,8 +111,8 @@ inline void WriteOp_Lodb_I(JitWriter *jit) { Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); - //mov eax, [edi+eax] - IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + //mov eax, [ebp+eax] + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); //and eax, cell_t val = jit->read_cell(); @@ -115,12 +120,12 @@ inline void WriteOp_Lodb_I(JitWriter *jit) { case 1: { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);//:TODO: replace with AND EAX, imm32 + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF); break; } case 2: { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);//:TODO: replace with AND EAX, imm32 + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF); break; } } @@ -129,23 +134,23 @@ inline void WriteOp_Lodb_I(JitWriter *jit) inline void WriteOp_Strb_I(JitWriter *jit) { Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); - //mov [edi+edx], eax + //mov [ebp+edx], eax cell_t val = jit->read_cell(); switch (val) { case 1: { - IA32_Mov_Rm8_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); break; } case 2: { - IA32_Mov_Rm16_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); break; } case 4: { - IA32_Mov_Rm_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); break; } } @@ -159,14 +164,14 @@ inline void WriteOp_Lctrl(JitWriter *jit) case 0: { //mov ecx, [esi+ctx] - //mov eax, [ecx+] + //mov eax, [ecx+ctx.codebase] IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, codebase)); break; } case 1: { - //mov eax, edi + //mov eax, ebp IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); break; } @@ -186,16 +191,16 @@ inline void WriteOp_Lctrl(JitWriter *jit) } case 4: { - //mov eax, ebp - //sub eax, edi - unrelocate + //mov eax, edi + //sub eax, ebp - unrelocate IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG); - IA32_Sub_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG); break; } case 5: { //mov eax, [esi+frm] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_FRM); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); break; } case 6: @@ -219,23 +224,21 @@ inline void WriteOp_Sctrl(JitWriter *jit) case 2: { //mov [esi+hea], eax - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, AMX_REG_PRI); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); break; } case 4: { - //lea ebp, [edi+eax] - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + //lea edi, [ebp+eax] + IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); break; } case 5: { - //mov ebx, eax - overwrite frm - //mov frm, eax - overwrite stacked frame - //add ebx, edi - relocate local frm //:TODO: use LEA here!!! - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_PRI, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_INFO_FRM, AMX_REG_PRI, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + //lea ebx, [ebp+eax] - overwrite frm + //mov [esi+frm], eax - overwrite stacked frame + IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_FRM, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_PRI, MOD_MEM_REG); break; } case 6: @@ -251,8 +254,8 @@ inline void WriteOp_UDiv(JitWriter *jit) //mov ecx, edx //xor edx, edx //div ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } @@ -263,24 +266,24 @@ inline void WriteOp_UDiv_Alt(JitWriter *jit) //mov eax, edx //xor edx, edx //div ecx - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Xor_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); Write_Check_DivZero(jit, AMX_REG_TMP); IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG); } inline void WriteOp_Ret(JitWriter *jit) { - //mov ebx, [ebp] - get old FRM - //add ebp, 4 - pop stack + //mov ebx, [edi] - get old FRM + //add edi, 4 - pop stack //mov [esi+frm], ebx - restore - //add ebx, edi - relocate + //add ebx, ebp - relocate //ret IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_INFO, AMX_REG_FRM, AMX_INFO_FRM);//:TODO: this is wrong! - IA32_Add_Rm_Reg(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); IA32_Return(jit); } @@ -302,7 +305,7 @@ inline void WriteOp_Jless(JitWriter *jit) //cmp eax, edx //jb cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false)); } @@ -311,7 +314,7 @@ inline void WriteOp_Jleq(JitWriter *jit) //cmp eax, edx //jbe cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false)); } @@ -320,7 +323,7 @@ inline void WriteOp_Jgrtr(JitWriter *jit) //cmp eax, edx //ja cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false)); } @@ -329,7 +332,7 @@ inline void WriteOp_Jgeq(JitWriter *jit) //cmp eax, edx //jae cell_t target = jit->read_cell(); - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false)); } diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 0eeb5d6f..ea2977b7 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -64,8 +64,8 @@ #define IA32_SUB_REG_RM 0x2B // encoding is /r #define IA32_SUB_RM_IMM8 0x83 // encoding is /5 #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 -#define IA32_SBB_RM_REG 0x19 // encoding is /r -#define IA32_SBB_EAX_IMM32 0x1D // encoding is +#define IA32_SBB_REG_RM 0x1B // encoding is /r +#define IA32_SBB_RM_IMM8 0x83 // encoding is #define IA32_JMP_IMM32 0xE9 // encoding is imm32 #define IA32_JMP_IMM8 0xEB // encoding is imm8 #define IA32_JMP_RM 0xFF // encoding is /4 @@ -381,16 +381,17 @@ inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit->write_int32(val); } -inline void IA32_Sbb_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Sbb_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(IA32_SBB_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_SBB_REG_RM); + jit->write_ubyte(ia32_modrm(mode, dest, src)); } -inline void IA32_Sbb_Eax_Imm32(JitWriter *jit, jit_int32_t value) +inline void IA32_Sbb_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_int8_t value, jit_uint8_t mode) { - jit->write_ubyte(IA32_SBB_EAX_IMM32); - jit->write_int32(value); + jit->write_ubyte(IA32_SBB_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 3, dest)); + jit->write_byte(value); } inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) @@ -686,18 +687,19 @@ inline void IA32_Mov_RmEBP_Reg_Disp_Reg(JitWriter *jit, jit->write_byte(0); } -inline void IA32_Mov_Rm8_Reg_Disp_Reg(JitWriter *jit, +inline void IA32_Mov_Rm8EBP_Reg_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, jit_uint8_t src) { jit->write_ubyte(IA32_MOV_RM8_REG); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); } -inline void IA32_Mov_Rm16_Reg_Disp_Reg(JitWriter *jit, +inline void IA32_Mov_Rm16EBP_Reg_Disp_Reg(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale, @@ -705,8 +707,9 @@ inline void IA32_Mov_Rm16_Reg_Disp_Reg(JitWriter *jit, { jit->write_ubyte(IA32_16BIT_PREFIX); jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_SIB)); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); + jit->write_byte(0); } /** From 39abe7776da426af134b78c2df762409f615e9d0 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 28 Sep 2006 19:33:58 +0000 Subject: [PATCH 0072/1664] helper functions turn --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40102 --- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 53 +++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 809567bf..30dfafba 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -20,6 +20,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) * This is because we do not support resuming or sleeping! */ + //:TODO: FIX THIS FOR THE EBP AND EDI SWITCHING //push ebp //mov ebp, esp IA32_Push_Reg(jit, REG_EBP); @@ -141,7 +142,7 @@ void Write_BreakDebug(JitWriter *jit) //jnz :nocall IA32_Push_Reg(jit, AMX_REG_TMP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0); jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); //pushad @@ -153,7 +154,7 @@ void Write_BreakDebug(JitWriter *jit) //call ecx //add esp, 8 //popad - IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); + IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0 IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context)); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); IA32_Call_Reg(jit, AMX_REG_TMP); @@ -180,14 +181,12 @@ void Write_Error(JitWriter *jit, int error) void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) { - CompData *data = (CompData *)jit->data; - //test reg, reg //jnz :continue //divzero: (write error) IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG); jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); - if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) + if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) { //sub esp, 4 - correct stack for returning to non-inlined JIT IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); @@ -197,7 +196,7 @@ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) IA32_Send_Jump8_Here(jit, jmp); } - +//:TODO: FIX THIS FOR NEW EBP STUFF void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) { CompData *data = (CompData *)jit->data; @@ -283,10 +282,10 @@ void Write_BoundsCheck(JitWriter *jit) //cmp eax, ecx //jg :err_bounds //ret - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0);//:TODO: use imm8 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); //:TODO: make sure this is right order - IA32_Cmp_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); IA32_Return(jit); IA32_Send_Jump8_Here(jit, jmp1); @@ -296,11 +295,15 @@ void Write_BoundsCheck(JitWriter *jit) } else { //cmp eax, 0 //jl :err_bounds - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, 0);//:TODO: use imm8 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); //cmp eax, //jg :err_bounds - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, jit->read_cell());//:TODO:check val size and use cmp eax or imm8 + cell_t val = jit->read_cell(); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); + else + IA32_Cmp_Eax_Imm32(jit, val); jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); //jmp :continue jitoffs_t cont = IA32_Jump_Imm8(jit, 0); @@ -331,13 +334,13 @@ void Write_CheckMargin_Heap(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW); jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //lea ecx, [edi+ecx+STACK_MARGIN] - //cmp ecx, ebp + //lea ecx, [ebp+ecx+STACK_MARGIN] + //cmp ecx, edi // jg :error_heaplow //OR // ret IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); - IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0); jitoffs_t cont; if (always_inline) @@ -364,7 +367,7 @@ void Write_CheckMargin_Stack(JitWriter *jit) { /* this is small, so we always inline it. */ - //cmp ebp, [esi+stp] + //cmp edi, [esi+stp] //jle :continue IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); @@ -381,17 +384,17 @@ void Write_CheckMargin_Stack(JitWriter *jit) void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax - //mov eax, frm + //mov eax, [esi+frm] //loop i times: // lea ecx, [eax+] - // mov [ebp-4*i], ecx - //sub ebp, 4*N + // mov [edi-4*i], ecx + //sub edi, 4*N //pop eax cell_t val; int n = 1; IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_INFO_FRM, MOD_MEM_REG); + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); do { val = jit->read_cell(); @@ -409,8 +412,8 @@ void Macro_PushN_S(JitWriter *jit, int i) { //loop i times: // mov ecx, [ebx+] - // mov [ebp-4*i], ecx - //sub ebp, 4*N + // mov [edi-4*i], ecx + //sub edi, 4*N cell_t val; int n = 1; @@ -429,8 +432,8 @@ void Macro_PushN_S(JitWriter *jit, int i) void Macro_PushN_C(JitWriter *jit, int i) { //loop i times: - // mov [ebp-4*i], - //sub ebp, 4*N + // mov [edi-4*i], + //sub edi, 4*N int n = 1; do @@ -443,9 +446,9 @@ void Macro_PushN_C(JitWriter *jit, int i) void Macro_PushN(JitWriter *jit, int i) { //loop i times: - // mov ecx, [edi+] - // mov [ebp-4*i], ecx - //sub ebp, 4*N + // mov ecx, [ebp+] + // mov [edi-4*i], ecx + //sub edi, 4*N cell_t val; int n = 1; From 47dadb6cd6923b3c57c3764b8678706eff9dac1a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 1 Oct 2006 21:05:07 +0000 Subject: [PATCH 0073/1664] added experimental implementation of switch --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40103 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 122 ++++++++++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 24 ++--- sourcepawn/vm/jit/x86/opcode_helpers.h | 4 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 10 ++ sourcepawn/vm/jit/x86/x86_macros.h | 24 +++++ 5 files changed, 165 insertions(+), 19 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 96f753f6..d6d473ce 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1128,7 +1128,6 @@ inline void WriteOp_Jzer(JitWriter *jit) //jz cell_t target = jit->read_cell(); IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, target, false)); IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false)); } @@ -1195,6 +1194,124 @@ inline void WriteOp_JsGeq(JitWriter *jit) IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false)); } +inline void WriteOp_Switch(JitWriter *jit) +{ + cell_t offs = jit->read_cell(); + cell_t *tbl = (cell_t *)((char *)jit->inbase + offs); + + struct casetbl + { + cell_t val; + cell_t offs; + }; + + /* Read the number of cases, then advance by one */ + cell_t num_cases = *tbl++; + if (!num_cases) + { + /* Special treatment for 0 cases */ + } else { + /* Check if the case layout is fully sequential */ + casetbl *iter = (casetbl *)(tbl + 1); + casetbl *cases = iter; + cell_t first = iter[0].val; + cell_t last = first; + bool sequential = true; + for (cell_t i=1; i HIGH) + * This check is valid for both sequential and non-sequential. + */ + cell_t low_bound = cases[0].val; + if (low_bound != 0) + { + /* negate it so we'll get a lower bound of 0 */ + //lea ecx, [eax-] + low_bound = -low_bound; + if (low_bound > SCHAR_MIN && low_bound < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); + } else { + IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); + } + } + cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val); + //cmp ecx, + if (high_bound > SCHAR_MIN && high_bound < SCHAR_MAX) + { + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound); + } else { + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound); + } + //ja + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, RelocLookup(jit, *tbl, false)); + + /** + * Now we've taken the default case out of the way, it's time to do the + * full check, which is different for sequential vs. non-sequential. + */ + if (sequential) + { + /* we're now theoretically guaranteed to be jumping to a correct offset. + * ECX still has the correctly bound offset in it, luckily! + * thus, we simply need to relocate ECX and store the cases. + */ + //shr ecx, 2 + //add ecx, + IA32_Shr_Rm_Imm8(jit, AMX_REG_TMP, 2, MOD_REG); + jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); + IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); + /* The case table starts here. Go back and write the output pointer. */ + jitoffs_t cur_pos = jit->jit_curpos(); + jit->setpos(tbl_offs); + jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos)); + jit->setpos(cur_pos); + //now we can write the case table, finally! + jit_uint32_t base = (jit_uint32_t)jit->outbase; + for (cell_t i=0; iwrite_uint32(base + RelocLookup(jit, cases[i].offs, false)); + } + } else { + /* The slow version. Go through each case and generate a check. + * In the future we should replace case tables of more than ~8 cases with a + * hash table lookup. + */ + cell_t val; + for (cell_t i=0; i OR cmp al, + if (val > SCHAR_MIN && val < SCHAR_MAX) + { + IA32_Cmp_Al_Imm8(jit, val); + } else { + IA32_Cmp_Eax_Imm32(jit, cases[i].val); + } + IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false)); + } + } + } +} + +inline void WriteOp_Casetbl(JitWriter *jit) +{ + /* do nothing here, switch does all ze work */ + cell_t num_cases = jit->read_cell(); + + /* Two cells per case, one extra case for the default jump */ + num_cases = (num_cases * 2) + 1; + jit->inptr += num_cases; +} + + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1255,9 +1372,6 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) AbortCompilation(co); *err = SP_ERR_INVALID_INSTRUCTION; return NULL; - } else if (op_c == -2) { - /* :TODO: get rid of this block */ - cip += sizeof(cell_t); } else if (op_c == -1) { switch (op) { diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 30dfafba..1bd33902 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -546,6 +546,17 @@ JITX86::JITX86() OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t); OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t); + OpAdvTable[OP_CALL] = sizeof(cell_t); + OpAdvTable[OP_JUMP] = sizeof(cell_t); + OpAdvTable[OP_JZER] = sizeof(cell_t); + OpAdvTable[OP_JNZ] = sizeof(cell_t); + OpAdvTable[OP_JEQ] = sizeof(cell_t); + OpAdvTable[OP_JNEQ] = sizeof(cell_t); + OpAdvTable[OP_JSLESS] = sizeof(cell_t); + OpAdvTable[OP_JSLEQ] = sizeof(cell_t); + OpAdvTable[OP_JSGRTR] = sizeof(cell_t); + OpAdvTable[OP_JSGEQ] = sizeof(cell_t); + OpAdvTable[OP_SWITCH] = sizeof(cell_t); /* instructions with 0 parameters */ OpAdvTable[OP_LOAD_I] = 0; @@ -603,19 +614,6 @@ JITX86::JITX86() OpAdvTable[OP_POP_HEAP_PRI] = 0; OpAdvTable[OP_SYSREQ_PRI] = 0; - /* opcodes that need relocation */ - OpAdvTable[OP_CALL] = -2; - OpAdvTable[OP_JUMP] = -2; - OpAdvTable[OP_JZER] = -2; - OpAdvTable[OP_JNZ] = -2; - OpAdvTable[OP_JEQ] = -2; - OpAdvTable[OP_JNEQ] = -2; - OpAdvTable[OP_JSLESS] = -2; - OpAdvTable[OP_JSLEQ] = -2; - OpAdvTable[OP_JSGRTR] = -2; - OpAdvTable[OP_JSGEQ] = -2; - OpAdvTable[OP_SWITCH] = -2; - /* opcodes that are totally invalid */ /* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */ OpAdvTable[OP_FILE] = -3; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 20388dd2..7df128bc 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -187,8 +187,8 @@ typedef enum OP_SYMBOL, // !GEN DEPRECATED OP_SRANGE, // !GEN DEPRECATED OP_JUMP_PRI, // !GEN - OP_SWITCH, - OP_CASETBL, + OP_SWITCH, //DONE + OP_CASETBL, //DONE OP_SWAP_PRI, //DONE OP_SWAP_ALT, //DONE OP_PUSH_ADR, //DONE diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index 4ea20788..e3551f5c 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -618,6 +618,16 @@ WriteOp_Jsleq(jit); break; } + case OP_SWITCH: + { + WriteOp_Switch(jit); + break; + } + case OP_CASETBL: + { + WriteOp_Casetbl(jit); + break; + } #if defined USE_UNGEN_OPCODES #include "ungen_opcode_switch.inc" #endif diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index ea2977b7..e423b596 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -78,6 +78,7 @@ #define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 #define IA32_CMP_RM_IMM32 0x81 // encoding is /7 #define IA32_CMP_RM_IMM8 0x83 // encoding is /7 +#define IA32_CMP_AL_IMM32 0x3C // no extra encoding #define IA32_CMP_EAX_IMM32 0x3D // no extra encoding #define IA32_CMPSB 0xA6 // no extra encoding #define IA32_TEST_RM_REG 0x85 // encoding is /r @@ -468,6 +469,17 @@ inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit, jit->write_int32(val); } +inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t mode) +{ + jit->write_ubyte(IA32_ADD_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 0, dest)); + jitoffs_t ptr = jit->jit_curpos(); + jit->write_int32(0); + return ptr; +} + inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, @@ -814,6 +826,12 @@ inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg)); } +inline void IA32_Jump_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_JMP_RM); + jit->write_ubyte(ia32_modrm(mode, 4, reg)); +} + inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; @@ -945,6 +963,12 @@ inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t d jit->write_byte(imm8); } +inline void IA32_Cmp_Al_Imm8(JitWriter *jit, jit_int8_t value) +{ + jit->write_ubyte(IA32_CMP_AL_IMM32); + jit->write_byte(value); +} + inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value) { jit->write_ubyte(IA32_CMP_EAX_IMM32); From ea6c73dcb32704c7a71fd76d9691f7e07f487c5b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 1 Oct 2006 21:06:50 +0000 Subject: [PATCH 0074/1664] added jump for zero cases --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40104 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index d6d473ce..b4b39f59 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1210,6 +1210,8 @@ inline void WriteOp_Switch(JitWriter *jit) if (!num_cases) { /* Special treatment for 0 cases */ + //jmp + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false)); } else { /* Check if the case layout is fully sequential */ casetbl *iter = (casetbl *)(tbl + 1); From c6f60dbd6c56dd2b082ef84aa8dce59dd287b010 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Oct 2006 01:03:54 +0000 Subject: [PATCH 0075/1664] added op.call --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40105 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 8 ++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 2 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index b4b39f59..e4b77213 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1068,6 +1068,14 @@ inline void WriteOp_Retn(JitWriter *jit) IA32_Jump_Reg(jit, AMX_REG_TMP); } +inline void WriteOp_Call(JitWriter *jit) +{ + cell_t offs = jit->read_cell(); + + jitoffs_t jmp = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false)); +} + inline void WriteOp_Bounds(JitWriter *jit) { Write_BoundsCheck(jit); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 7df128bc..c0b502e8 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -107,7 +107,7 @@ typedef enum OP_PROC, //DONE OP_RET, // !GEN OP_RETN, //DONE - OP_CALL, + OP_CALL, //DONE OP_CALL_PRI, // !GEN OP_JUMP, //DONE OP_JREL, // !GEN diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index e3551f5c..f4b49b5a 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -628,6 +628,11 @@ WriteOp_Casetbl(jit); break; } + case OP_CALL: + { + WriteOp_Call(jit); + break; + } #if defined USE_UNGEN_OPCODES #include "ungen_opcode_switch.inc" #endif From cfcb4d288bbff2f078816abad9351f34fcd05a01 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 6 Oct 2006 17:03:33 +0000 Subject: [PATCH 0076/1664] - param count pushed is now cell based, not byte based - removed .. for cases --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40106 --- sourcepawn/compiler/sc1.c | 20 ++------------------ sourcepawn/compiler/sc3.c | 6 +++--- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 96d38eee..189fe7fc 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -4459,7 +4459,7 @@ static void destructsymbols(symbol *root,int level) address(sym,sPRI); addconst(offset); /* add offset to array data to the address */ pushreg(sPRI); - pushval(2*sizeof(cell));/* 2 parameters */ + pushval(2 /* *sizeof(cell)*/ );/* 2 parameters */ assert(opsym->ident==iFUNCTN); ffcall(opsym,NULL,1); if (sc_status!=statSKIP) @@ -5231,23 +5231,7 @@ static void doswitch(void) assert(csp->next==cse); insert_constval(csp,cse,itoh(lbl_case),val,0); if (matchtoken(tDBLDOT)) { - cell end; - constexpr(&end,NULL,NULL); - if (end<=val) - error(50); /* invalid range */ - while (++val<=end) { - casecount++; - /* find the new insertion point */ - for (csp=&caselist, cse=caselist.next; - cse!=NULL && cse->valuenext) - /* nothing */; - if (cse!=NULL && cse->value==val) - error(40,val); /* duplicate "case" label */ - assert(csp!=NULL); - assert(csp->next==cse); - insert_constval(csp,cse,itoh(lbl_case),val,0); - } /* if */ + error(1, ":", ".."); } /* if */ } while (matchtoken(',')); needtoken(':'); /* ':' ends the case */ diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index a8124de6..b169df5c 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -13,7 +13,7 @@ * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in * a product, an acknowledgment in the product documentation would be - * appreciated but is not required. + * appreciated but is not reeq;quired. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. @@ -354,7 +354,7 @@ static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec }; assert(0); } /* switch */ markexpr(sPARM,NULL,0); /* mark the end of a sub-expression */ - pushval((cell)paramspassed*sizeof(cell)); + pushval((cell)paramspassed /* *sizeof(cell)*/ ); assert(sym->ident==iFUNCTN); ffcall(sym,NULL,paramspassed); if (sc_status!=statSKIP) @@ -2453,7 +2453,7 @@ static int nesting=0; arglist[argidx]=ARG_DONE; } /* for */ stgmark(sENDREORDER); /* mark end of reversed evaluation */ - pushval((cell)nargs*sizeof(cell)); + pushval((cell)nargs /* *sizeof(cell)*/ ); nest_stkusage++; ffcall(sym,NULL,nargs); if (sc_status!=statSKIP) From fb9234eb86400e1f5d27fe77c3a350b6e5a38814 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 6 Oct 2006 17:05:07 +0000 Subject: [PATCH 0077/1664] oh --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40107 --- sourcepawn/include/sp_vm_types.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index e81802d1..94cce17a 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -190,6 +190,7 @@ namespace SourcePawn */ typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t); + #define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ /** @@ -214,8 +215,6 @@ typedef struct sp_context_s uint8_t *data; /* data chunk */ cell_t heapbase; /* heap base */ /* execution specific data */ - cell_t pri; /* PRI register */ - cell_t alt; /* ALT register */ cell_t hp; /* heap pointer */ cell_t sp; /* stack pointer */ cell_t frm; /* frame pointer */ From 5eec9f6dff8ed25376c308c4db1e5191d00a867b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 00:39:19 +0000 Subject: [PATCH 0078/1664] moved # of params error message back to an actual error fixed a bug in the peephole optimizer --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40108 --- sourcepawn/compiler/sc1.c | 2 +- sourcepawn/compiler/sc3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 189fe7fc..73a5bc8a 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -5391,7 +5391,7 @@ static void doreturn(void) /* "return " */ if ((rettype & uRETNONE)!=0) error(78); /* mix "return;" and "return value;" */ - ident=doexpr(TRUE,FALSE,TRUE,TRUE,&tag,&sym,TRUE); + ident=doexpr(TRUE,FALSE,TRUE,FALSE,&tag,&sym,TRUE); needtoken(tTERM); /* see if this function already has a sub type (an array attached) */ sub=finddepend(curfunc); diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index b169df5c..c9b2e467 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -2402,7 +2402,7 @@ static int nesting=0; markexpr(sPARM,NULL,0); /* mark the end of a sub-expression */ nest_stkusage++; } else { - error(202,argidx); /* argument count mismatch */ + error(92,argidx); /* argument count mismatch */ } /* if */ if (arglist[argidx]==ARG_UNHANDLED) nargs++; From bc22a3bc845424b380666bf626f44e60489ed320 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 00:39:45 +0000 Subject: [PATCH 0079/1664] finalized structures I think --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40109 --- sourcepawn/include/sp_vm_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 94cce17a..c0bfb5cb 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -18,7 +18,7 @@ typedef int32_t cell_t; #define SP_ERR_NOT_FOUND 6 /* The object in question was not found */ #define SP_ERR_INDEX 7 /* Invalid index parameter */ #define SP_ERR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ -#define SP_ERR_STACKERR 9 /* Stack/Heap collision */ +#define SP_ERR_STACKLOW 9 /* Nnot enough space left on the stack */ #define SP_ERR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ #define SP_ERR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ #define SP_ERR_MEMACCESS 12 /* Invalid memory access */ From 4b6c4f11af12b97cbd6b4eb573ebbcd78da8c456 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 01:55:08 +0000 Subject: [PATCH 0080/1664] added DLL exports (it builds now!) rewrote error checking mechanism fixed some opcode cases not being right fixed various opcode and codegen bugs fixed stack alignment problems made proc aligned to a dword fixed up helpers naming scheme started marking opcodes as either working or not working probably more -- too much to list --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40110 --- sourcepawn/vm/jit/jit_helpers.h | 14 +- sourcepawn/vm/jit/x86/dll_exports.cpp | 32 ++ sourcepawn/vm/jit/x86/dll_exports.h | 10 +- sourcepawn/vm/jit/x86/jit_x86.cpp | 374 +++++++++++++++----- sourcepawn/vm/jit/x86/jit_x86.h | 20 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 427 +++++++++++------------ sourcepawn/vm/jit/x86/opcode_helpers.h | 249 +++++++------ sourcepawn/vm/jit/x86/opcode_switch.inc | 16 +- sourcepawn/vm/jit/x86/x86_macros.h | 46 ++- 9 files changed, 736 insertions(+), 452 deletions(-) diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index d0bf929d..d6b4b810 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -42,7 +42,7 @@ public: } inline void write_ubyte(jit_uint8_t c) { - if (outptr) + if (outbase) { *outptr = c; } @@ -50,7 +50,7 @@ public: } inline void write_byte(jit_int8_t c) { - if (outptr) + if (outbase) { *outptr = c; } @@ -58,7 +58,7 @@ public: } inline void write_int32(jit_int32_t c) { - if (outptr) + if (outbase) { *(jit_int32_t *)outptr = c; } @@ -66,21 +66,21 @@ public: } inline void write_uint32(jit_uint32_t c) { - if (outptr) + if (outbase) { *(jit_uint32_t *)outptr = c; } outptr += sizeof(jit_uint32_t); } - inline jitoffs_t jit_curpos() + inline jitoffs_t get_outputpos() { return (outptr - outbase); } - inline void setpos(jitoffs_t offs) + inline void set_outputpos(jitoffs_t offs) { outptr = outbase + offs; } - inline jitoffs_t inputrel() + inline jitoffs_t get_inputpos() { return (jitoffs_t)((char *)inptr - (char *)inbase); } diff --git a/sourcepawn/vm/jit/x86/dll_exports.cpp b/sourcepawn/vm/jit/x86/dll_exports.cpp index e1723f9e..db593b19 100644 --- a/sourcepawn/vm/jit/x86/dll_exports.cpp +++ b/sourcepawn/vm/jit/x86/dll_exports.cpp @@ -1 +1,33 @@ #include +#include "jit_x86.h" +#include "dll_exports.h" + +SourcePawn::ISourcePawnEngine *engine = NULL; +JITX86 jit; + +EXPORTFUNC void GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) +{ + engine = engine_p; +} + +EXPORTFUNC unsigned int GetExportCount() +{ + return 0; +} + +EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum) +{ + /* Don't return anything if we're not initialized yet */ + if (!engine) + { + return NULL; + } + + /* We only have one export - 0 */ + if (exportnum) + { + return NULL; + } + + return &jit; +} diff --git a/sourcepawn/vm/jit/x86/dll_exports.h b/sourcepawn/vm/jit/x86/dll_exports.h index 568ecd92..653773f6 100644 --- a/sourcepawn/vm/jit/x86/dll_exports.h +++ b/sourcepawn/vm/jit/x86/dll_exports.h @@ -3,6 +3,14 @@ #include - +#if defined WIN32 +#define EXPORTFUNC extern "C" __declspec(dllexport) +#elif defined __GNUC__ +#if __GNUC__ >= 3 +#define EXPORTFUNC extern "C" __attribute__((visibility("default"))) +#else +#define EXPORTFUNC extern "C" +#endif //__GNUC__ >= 3 +#endif //defined __GNUC__ #endif //_INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e4b77213..b28619f9 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -37,9 +37,11 @@ inline void WriteOp_Push(JitWriter *jit) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); //optimize encoding a bit... if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } @@ -219,13 +221,31 @@ inline void WriteOp_Sub_Alt(JitWriter *jit) inline void WriteOp_Proc(JitWriter *jit) { + /* align this to four byte boundaries! + * This is a decent optimization - x86 likes calls to be properly aligned, otherwise there's an alignment exception + * Since all calls are jumped to by relocation, the nops/garbage will never be hit by the runtime process. + * Just in case, we guard this memory with INT3 to break into the debugger. + */ + jitoffs_t cur_offs = jit->get_outputpos(); + if (cur_offs % 4) + { + cur_offs = 4 - (cur_offs % 4); + for (unsigned int i=0; iwrite_ubyte(IA32_INT3); + } + /* add this amt to the offset we relocated */ + jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t); + jitcode_t rebase = ((CompData *)jit->data)->rebase; + *(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos(); + } //push old frame on stack: - //sub edi, 4 //mov ecx, [esi+frm] - //mov [edi], ecx - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + //mov [edi-4], ecx + //sub edi, 8 ;extra un-used slot for non-existant CIP IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); //save frame: //:TODO: move to a temp reg, subtract and then move to mem, faster?? //mov [esi+frm], edi - get new frame @@ -244,7 +264,7 @@ inline void WriteOp_Lidx_B(JitWriter *jit) //mov eax, [ebp+eax] IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -538,9 +558,11 @@ inline void WriteOp_Dec(JitWriter *jit) //sub [ebp+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); - else + } else { IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); + } } inline void WriteOp_Dec_S(JitWriter *jit) @@ -548,9 +570,11 @@ inline void WriteOp_Dec_S(JitWriter *jit) //sub [ebx+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); - else + } else { IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); + } } inline void WriteOp_Dec_I(JitWriter *jit) @@ -564,9 +588,11 @@ inline void WriteOp_Load_Pri(JitWriter *jit) //mov eax, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); + } } inline void WriteOp_Load_Alt(JitWriter *jit) @@ -574,9 +600,11 @@ inline void WriteOp_Load_Alt(JitWriter *jit) //mov edx, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); + } } inline void WriteOp_Load_S_Pri(JitWriter *jit) @@ -584,9 +612,11 @@ inline void WriteOp_Load_S_Pri(JitWriter *jit) //mov eax, [ebx+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); + } } inline void WriteOp_Load_S_Alt(JitWriter *jit) @@ -594,9 +624,11 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit) //mov edx, [ebx+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); + } } inline void WriteOp_Lref_Pri(JitWriter *jit) @@ -605,9 +637,11 @@ inline void WriteOp_Lref_Pri(JitWriter *jit) //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -617,9 +651,11 @@ inline void WriteOp_Lref_Alt(JitWriter *jit) //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } @@ -629,9 +665,11 @@ inline void WriteOp_Lref_S_Pri(JitWriter *jit) //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -641,9 +679,11 @@ inline void WriteOp_Lref_S_Alt(JitWriter *jit) //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } @@ -668,9 +708,11 @@ inline void WriteOp_Addr_Pri(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Eax_Imm32(jit, val); + } } inline void WriteOp_Addr_Alt(JitWriter *jit) @@ -680,9 +722,11 @@ inline void WriteOp_Addr_Alt(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG); + } } inline void WriteOp_Stor_Pri(JitWriter *jit) @@ -690,9 +734,11 @@ inline void WriteOp_Stor_Pri(JitWriter *jit) //mov [ebp+], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val); + } } inline void WriteOp_Stor_Alt(JitWriter *jit) @@ -700,9 +746,11 @@ inline void WriteOp_Stor_Alt(JitWriter *jit) //mov [ebp+], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val); + } } inline void WriteOp_Stor_S_Pri(JitWriter *jit) @@ -710,9 +758,11 @@ inline void WriteOp_Stor_S_Pri(JitWriter *jit) //mov [ebx+], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val); + } } inline void WriteOp_Stor_S_Alt(JitWriter *jit) @@ -720,9 +770,11 @@ inline void WriteOp_Stor_S_Alt(JitWriter *jit) //mov [ebx+], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val); + } } inline void WriteOp_Idxaddr(JitWriter *jit) @@ -737,9 +789,11 @@ inline void WriteOp_Sref_Pri(JitWriter *jit) //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } @@ -749,9 +803,11 @@ inline void WriteOp_Sref_Alt(JitWriter *jit) //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } @@ -761,9 +817,11 @@ inline void WriteOp_Sref_S_Pri(JitWriter *jit) //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } @@ -773,9 +831,11 @@ inline void WriteOp_Sref_S_Alt(JitWriter *jit) //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } @@ -901,7 +961,8 @@ inline void WriteOp_Heap_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); - Write_CheckMargin_Heap(jit); + /* :TODO: should we do a full bounds check here? */ + Write_CheckHeap_Min(jit); } inline void WriteOp_Push_Heap_C(JitWriter *jit) @@ -914,7 +975,7 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) IA32_Mov_RmEBP_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - Write_CheckMargin_Heap(jit); + Write_CheckHeap_Low(jit); } inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) @@ -926,13 +987,13 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); - Write_CheckMargin_Heap(jit); + Write_CheckHeap_Min(jit); } inline void WriteOp_Load_Both(JitWriter *jit) { - WriteOp_Const_Pri(jit); - WriteOp_Const_Alt(jit); + WriteOp_Load_Pri(jit); + WriteOp_Load_Alt(jit); } inline void WriteOp_Load_S_Both(JitWriter *jit) @@ -970,14 +1031,14 @@ inline void WriteOp_Const_S(JitWriter *jit) inline void WriteOp_Load_I(JitWriter *jit) { //mov eax, [ebp+eax] - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stor_I(JitWriter *jit) { //mov [ebp+edx], eax - Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + Write_Check_VerifyAddr(jit, AMX_REG_ALT); IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } @@ -986,24 +1047,34 @@ inline void WriteOp_Lidx(JitWriter *jit) //lea eax, [edx+4*eax] //mov eax, [ebp+eax] IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stack(JitWriter *jit) { + /* :TODO: Find an instance in the compiler where + * the ALT value from STACK is actually used! + */ //mov edx, edi //add edi, //sub edx, ebp cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); + } IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); - Write_CheckMargin_Stack(jit); + if (val > 0) + { + Write_CheckStack_Min(jit); + } else if (val < 0) { + Write_CheckStack_Low(jit); + } } inline void WriteOp_Heap(JitWriter *jit) @@ -1013,11 +1084,19 @@ inline void WriteOp_Heap(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP); - else + } else { IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP); + } - Write_CheckMargin_Heap(jit); + /* NOTE: Backwards from op.stack */ + if (val > 0) + { + Write_CheckHeap_Low(jit); + } else if (val < 0) { + Write_CheckHeap_Min(jit); + } } inline void WriteOp_SDiv(JitWriter *jit) @@ -1048,24 +1127,23 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) inline void WriteOp_Retn(JitWriter *jit) { - //mov ebx, [edi] - get old frm - //mov ecx, [edi+4] - get return eip + //mov ebx, [edi+4] - get old frm //add edi, 8 - pop stack //mov [esi+frm], ebx - restore frame pointer //add ebx, ebp - relocate - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG); IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); - //add edi, [edi] - reduce by this # of params - //add edi, 4 - pop one extra for the # itself - IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + /* pop params */ + //mov ecx, [edi] + //lea edi, [edi+edi*4+4] + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4); - //jmp ecx - jump to return eip - IA32_Jump_Reg(jit, AMX_REG_TMP); + //ret - return (EIP on real stack!) + IA32_Return(jit); } inline void WriteOp_Call(JitWriter *jit) @@ -1078,7 +1156,12 @@ inline void WriteOp_Call(JitWriter *jit) inline void WriteOp_Bounds(JitWriter *jit) { - Write_BoundsCheck(jit); + cell_t val = jit->read_cell(); + + //cmp eax, + //ja :error + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, val); + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds); } inline void WriteOp_Halt(JitWriter *jit) @@ -1095,14 +1178,7 @@ inline void WriteOp_Halt(JitWriter *jit) jit->read_cell(); CompData *data = (CompData *)jit->data; - jitoffs_t reloc; - if (data->inline_level & JIT_INLINE_ERRORCHECKS) - { - reloc = IA32_Jump_Imm32(jit, 0); - } else { - reloc = IA32_Call_Imm32(jit, 0); - } - IA32_Write_Jump32(jit, reloc, data->jit_return); + IA32_Jump_Imm32_Abs(jit, data->jit_return); } inline void WriteOp_Break(JitWriter *jit) @@ -1112,10 +1188,10 @@ inline void WriteOp_Break(JitWriter *jit) { //mov ecx, jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); - jitoffs_t save = jit->jit_curpos(); - jit->setpos(wr); + jitoffs_t save = jit->get_outputpos(); + jit->set_outputpos(wr); jit->write_uint32((uint32_t)(jit->outbase + wr)); - jit->setpos(save); + jit->set_outputpos(save); wr = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32(jit, wr, data->jit_break); @@ -1126,7 +1202,6 @@ inline void WriteOp_Jump(JitWriter *jit) { //jmp cell_t amx_offs = jit->read_cell(); - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false)); } @@ -1163,7 +1238,7 @@ inline void WriteOp_Jneq(JitWriter *jit) //jne cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false)); } inline void WriteOp_Jsless(JitWriter *jit) @@ -1172,7 +1247,7 @@ inline void WriteOp_Jsless(JitWriter *jit) //jl cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_L, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false)); } inline void WriteOp_Jsleq(JitWriter *jit) @@ -1181,7 +1256,7 @@ inline void WriteOp_Jsleq(JitWriter *jit) //jle cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_LE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false)); } inline void WriteOp_JsGrtr(JitWriter *jit) @@ -1190,7 +1265,7 @@ inline void WriteOp_JsGrtr(JitWriter *jit) //jg cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_G, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false)); } inline void WriteOp_JsGeq(JitWriter *jit) @@ -1199,7 +1274,7 @@ inline void WriteOp_JsGeq(JitWriter *jit) //jge cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false)); } inline void WriteOp_Switch(JitWriter *jit) @@ -1279,10 +1354,10 @@ inline void WriteOp_Switch(JitWriter *jit) jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); /* The case table starts here. Go back and write the output pointer. */ - jitoffs_t cur_pos = jit->jit_curpos(); - jit->setpos(tbl_offs); + jitoffs_t cur_pos = jit->get_outputpos(); + jit->set_outputpos(tbl_offs); jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos)); - jit->setpos(cur_pos); + jit->set_outputpos(cur_pos); //now we can write the case table, finally! jit_uint32_t base = (jit_uint32_t)jit->outbase; for (cell_t i=0; iwrite_ubyte(IA32_INT3); } } @@ -1321,6 +1398,98 @@ inline void WriteOp_Casetbl(JitWriter *jit) jit->inptr += num_cases; } +inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) +{ + /* store the number of parameters on the stack, + * and store the native index as well. + */ + cell_t num_params = jit->read_cell(); + cell_t native_index = jit->read_cell(); + + //mov eax, + //mov ecx, + IA32_Mov_Rm_Imm32(jit, REG_EAX, num_params, MOD_REG); + IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG); + + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n); +} + +inline void WriteOp_Sysreq_N(JitWriter *jit) +{ + /* The big daddy of opcodes. */ + cell_t num_params = jit->read_cell(); + cell_t native_index = jit->read_cell(); + CompData *data = (CompData *)jit->data; + + /* store the number of parameters on the stack */ + //mov [edi-4], num_params + //sub edi, 4 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + + /* save registers we will need */ + //push edx + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* push some callback stuff */ + //push edi ; stack + //push ; native index + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Push_Imm32(jit, native_index); + + /* Relocate stack, heap, frm information, then store back */ + //sub edi, ebp + //mov ecx, [esi+hea] + //mov eax, [esi+context] + //mov [eax+hp], ecx + //mov [eax+sp], edi + //mov ecx, [esi+frm] + //mov [eax+frm], ecx + IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); + + /* finally, push the last parameter and make the call */ + //push eax ; context + //mov eax, [eax+context] + //call NativeCallback + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + + /* restore what we damaged */ + //add esp, 4*3 + //add edi, ebp + //pop edx + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_ALT); + + /* check for errors */ + //test eax, eax + //jne :error + IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); + + /* pop the stack. do not check the margins. + * Note that this is not a true macro - we don't bother to + * set ALT here because nothing will be using it. + */ + num_params++; + num_params *= 4; + //add edi, + if (num_params < SCHAR_MAX && num_params > SCHAR_MIN) + { + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG); + } else { + IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG); + } +} /************************************************* ************************************************* @@ -1329,6 +1498,12 @@ inline void WriteOp_Casetbl(JitWriter *jit) ************************************************* *************************************************/ +cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) +{ + /* :TODO: fill this out... */ + + return 0; +} jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) { @@ -1340,7 +1515,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) /* The actual offset is EIP relative. We need to relocate it. * Note that this assumes that we're pointing to the next op. */ - pcode_offs += jit->inputrel(); + pcode_offs += jit->get_inputpos(); } /* Offset must always be 1)positive and 2)less than the codesize */ assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize); @@ -1416,43 +1591,59 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) * so we can check the exact memory usage. */ data->codesize = plugin->pcode_size; + writer.data = data; writer.inbase = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; - data->rebase = (jitcode_t *)engine->BaseAlloc(plugin->pcode_size); + data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size); /* Jump back here for second pass */ jit_rewind: /* Initialize pass vars */ writer.inptr = writer.inbase; - data->jit_chkmargin_heap = 0; data->jit_verify_addr_eax = 0; data->jit_verify_addr_edx = 0; - data->jit_bounds = 0; /* Start writing the actual code */ data->jit_return = Write_Execute_Function(jit); - /* Write error checking routines in case they are needed */ + /* Write error checking routines that are jumped to */ if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EAX, true); + jitpos = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EAX); data->jit_verify_addr_eax = jitpos; - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EDX, true); + jitpos = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EDX); data->jit_verify_addr_edx = jitpos; - - jitpos = jit->jit_curpos(); - Write_CheckMargin_Heap(jit); - data->jit_chkmargin_heap = jitpos; - - jitpos = jit->jit_curpos(); - Write_BoundsCheck(jit); - data->jit_bounds = jitpos; } + /* Write error codes we need */ + { + data->jit_error_divzero = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_DIVIDE_BY_ZERO); + + data->jit_error_stacklow = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_STACKLOW); + + data->jit_error_stackmin = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_STACKMIN); + + data->jit_error_bounds = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_ARRAY_BOUNDS); + + data->jit_error_memaccess = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_MEMACCESS); + + data->jit_error_heaplow = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_HEAPLOW); + + data->jit_error_heapmin = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_HEAPMIN); + } + + /* Actual code generation! */ if (writer.outbase == NULL) { /******* @@ -1461,14 +1652,14 @@ jit_rewind: jitoffs_t pcode_offs; jitoffs_t native_offs; - for (; writer.inptr <= endptr;) + for (; writer.inptr < endptr;) { /* Store the native offset into the rebase memory. * This large chunk of memory lets us do an instant lookup * based on an original pcode offset. */ pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); - native_offs = jit->jit_curpos(); + native_offs = jit->get_outputpos(); *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; /* Now read the opcode and continue. */ @@ -1480,7 +1671,7 @@ jit_rewind: } /* the total codesize is now known! */ - uint32_t mem = writer.jit_curpos(); + uint32_t mem = writer.get_outputpos(); writer.outbase = (jitcode_t)engine->ExecAlloc(mem); writer.outptr = writer.outbase; /* go back for third pass */ @@ -1489,7 +1680,7 @@ jit_rewind: /******* * THIRD PASS - write opcode info *******/ - for (; writer.inptr <= endptr;) + for (; writer.inptr < endptr;) { op = (OPCODE)writer.read_cell(); switch (op) @@ -1630,7 +1821,7 @@ const char *JITX86::GetVMName() int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) { typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *); - CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; + CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; return fn(ctx, code_idx, result); } @@ -1652,6 +1843,7 @@ ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) CompData *data = new CompData; data->plugin = plugin; + data->inline_level = JIT_INLINE_ERRORCHECKS; return data; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 13f63f7a..ee0e0524 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,28 +9,32 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) -#define STACK_MARGIN 16 +#define STACK_MARGIN 64 //8 parameters of safety, I guess class CompData : public ICompilation { public: CompData() : plugin(NULL), - debug(false), inline_level(3), checks(true), - rebase(NULL) + debug(false), inline_level(0), rebase(NULL) { }; public: sp_plugin_t *plugin; - jitcode_t *rebase; + jitcode_t rebase; jitoffs_t jit_return; jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; - jitoffs_t jit_chkmargin_heap; - jitoffs_t jit_bounds; jitoffs_t jit_break; + jitoffs_t jit_sysreq_n; + jitoffs_t jit_error_bounds; + jitoffs_t jit_error_divzero; + jitoffs_t jit_error_stacklow; + jitoffs_t jit_error_stackmin; + jitoffs_t jit_error_memaccess; + jitoffs_t jit_error_heaplow; + jitoffs_t jit_error_heapmin; uint32_t codesize; int inline_level; - bool checks; bool debug; }; @@ -48,6 +52,7 @@ public: int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; +cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_REG_PRI REG_EAX @@ -65,6 +70,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_STACKTOP 16 //relocated #define AMX_INFO_HEAPLOW 20 //not relocated +#define AMX_INFO_STACKTOP_U 24 //not relocated extern ISourcePawnEngine *engine; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 1bd33902..a218ff82 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -6,6 +6,8 @@ int OpAdvTable[OP_NUM_OPCODES]; +#define NUM_INFO_PARAMS 7 + jitoffs_t Write_Execute_Function(JitWriter *jit) { /** @@ -20,7 +22,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) * This is because we do not support resuming or sleeping! */ - //:TODO: FIX THIS FOR THE EBP AND EDI SWITCHING //push ebp //mov ebp, esp IA32_Push_Reg(jit, REG_EBP); @@ -33,9 +34,9 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); - //sub esp, 4*6 - allocate info array + //sub esp, 4*n - reserve info array //mov esi, esp - save info pointer - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); /* Initial memory setup */ @@ -45,7 +46,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) //mov [esi+12], eax - store context into info pointer //mov ecx, [eax+] - get heap pointer //mov [esi+4], ecx - store heap into info pointer - //mov edi, [eax+] - get data pointer + //mov ebp, [eax+] - get data pointer IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); @@ -55,76 +56,73 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); /* Frame setup */ - //mov ebp, [eax+] - get stack pointer - //add ebp, edi - relocate to data section - //mov ebx, ebp - copy sp to frm + //mov edi, [eax+] - get stack pointer + //add edi, ebp - relocate to data section + //mov ebx, edi - copy sp to frm IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); - IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); /* Info memory setup */ - //mov ecx, edi - copy base of data to temp var - //add ecx, [eax+] - add memsize to get stack top - //mov [esi+16], ecx - store stack top into info pointer + //mov ecx, [eax+] - copy memsize to temp var + //mov [esi+x], ecx - store unrelocated + //add ecx, ebp - relocate + //mov [esi+x], ecx - store relocated //mov ecx, [eax+] - get heap low //mov [esi+20], ecx - store heap low into info pointer - IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG); - IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U); + IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase)); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW); /* Remaining needed vars */ - //mov ecx, [ebp+12] - get code index - //add ecx, [eax+] - add code base to index - //mov edx, [eax+] - get alt - //mov eax, [eax+] - get pri - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); + //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack) + //add ecx, [eax+] - add code base to index + IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3))); IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase)); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt)); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri)); /* by now, everything is set up, so we can call into the plugin */ //call ecx IA32_Call_Reg(jit, REG_ECX); /* if the code flow gets to here, there was a normal return */ - //mov ebp, [esi+8] - get retval pointer - //mov [ebp], eax - store retval from PRI + //mov ecx, [esi+8] - get retval pointer + //mov [ecx], eax - store retval from PRI //mov eax, SP_ERR_NONE - set no error - IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL); - IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL); + IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG); IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE); /* save where error checking/halting functions should go to */ - jitoffs_t offs_return; - CompData *data = (CompData *)jit->data; - if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) - { - /* We have to write code assume we're breaking out of a call */ - //jmp [past the next instruction] - //add esp, 4 - jitoffs_t offs = IA32_Jump_Imm8(jit, 0); - offs_return = jit->jit_curpos(); - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - IA32_Send_Jump8_Here(jit, offs); - } else { - offs_return = jit->jit_curpos(); - } + jitoffs_t offs_return = jit->get_outputpos(); + //mov esp, esi - restore stack pointer + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG); - /* _FOR NOW_ ... - * We are _not_ going to restore anything that was on the stack. - * This is a tiny, useless optimization based on the fact that - * BaseContext::Execute() automatically restores our values anyway. + /* _FOR NOW_ ... + * We are going to restore SP, HP, and FRM for now. This is for + * debugging only, to check for alignment errors. As such: + * :TODO: probably remove this. */ + //mov ecx, [esi+context] + //sub edi, ebp + //mov edx, [esi+heap] + //mov [ecx+sp], edi + //mov [ecx+hp], edx + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT); + IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp)); + IA32_Mov_Rm_Reg(jit, REG_ECX, REG_EDX, MOD_REG); - //add esp, 4*6 + //add esp, 4*NUM_INFO_PARAMS //pop ebx //pop edi //pop esi //pop ebp //ret - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); IA32_Pop_Reg(jit, REG_EBX); IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); @@ -167,7 +165,7 @@ void Write_BreakDebug(JitWriter *jit) IA32_Return(jit); } -void Write_Error(JitWriter *jit, int error) +void Write_SetError(JitWriter *jit, bool always_inline, int error) { CompData *data = (CompData *)jit->data; @@ -182,22 +180,67 @@ void Write_Error(JitWriter *jit, int error) void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) { //test reg, reg - //jnz :continue - //divzero: (write error) + //jz :error IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); - if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) - { - //sub esp, 4 - correct stack for returning to non-inlined JIT - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - } - Write_Error(jit, SP_ERR_DIVIDE_BY_ZERO); - //continue: - IA32_Send_Jump8_Here(jit, jmp); - + IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero); } -//:TODO: FIX THIS FOR NEW EBP STUFF -void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) + +void Write_CheckHeap_Min(JitWriter *jit) +{ + /* Check if the stack went beyond the heap low. + * This usually means there was a compiler error. + * NOTE: Special optimization here. + * The heap low is always known ahead of time! :) + */ + CompData *data = (CompData *)jit->data; + //cmp [esi+info.heap], + //jb :error + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin); +} + +void Write_CheckHeap_Low(JitWriter *jit) +{ + /* Check if the heap is trying to grow beyond the stack. + */ + //mov ecx, [esi+info.heap] + //lea ecx, [ebp+ecx+STACK_MARGIN] + //cmp ecx, edi + //ja :error ; I think this is right + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow); +} + +void Write_CheckStack_Min(JitWriter *jit) +{ + /* Check if the stack went beyond the stack top + * This usually means there was a compiler error. + */ + //cmp edi, [esi+info.stacktop] + //jae :error + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin); +} + +void Write_CheckStack_Low(JitWriter *jit) +{ + /* Check if the stack went beyond the heap boundary. + * Unfortunately this one isn't as quick as the other check. + * The stack margin check is important for sysreq.n having space. + */ + //mov ecx, [esi+info.heap] + //lea ecx, [ebp+ecx+STACK_MARGIN] + //cmp edi, ecx + //jb :error ; I think this is right + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); + IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow); +} + +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg) { CompData *data = (CompData *)jit->data; @@ -205,182 +248,57 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) * The old JIT did not. */ - if (!data->checks) - { - return; - } - bool call = false; if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { /* If we're not in the initial generation phase, * Write a call to the actual routine instead. */ - if (!firstcall) + if ((reg == REG_EAX) && data->jit_verify_addr_eax) { jitoffs_t call = IA32_Call_Imm32(jit, 0); - if (reg == REG_EAX) - { - IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); - } else if (reg == REG_EDX) { - IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); - } + IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); + return; + } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) { + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); return; } call = true; - } else if (firstcall) { - /* Inline + initial gen == no code */ - return; } - //cmp reg, [stp] - //jae memaccess - //cmp reg, [hea] - //jb continue - //lea ecx, [reg+edi] - //cmp ecx, ebp - //jae continue - //memaccess: (write error) - //continue: - IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); + /** + * :TODO: If we can't find a nicer way of doing this, + * then scrap it on high optimizations. The second portion is not needed at all! + */ + + /* Part 1: Check if we're in the memory bounds */ + //cmp , [esi+info.stpu] + //jae :error + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP_U); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess); + + /* Part 2: Check if we're in the invalid region between HP and SP */ + jitoffs_t jmp; + //cmp , [esi+info.heap] + //jb :continue + //lea ecx, [ebp+] + //cmp edi, ecx + //jb :error + //:continue IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0); - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_TMP, reg, AMX_REG_DAT, NOSCALE); - IA32_Cmp_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); - jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); - IA32_Send_Jump8_Here(jit, jmp1); - Write_Error(jit, SP_ERR_MEMACCESS); - IA32_Send_Jump8_Here(jit, jmp2); - IA32_Send_Jump8_Here(jit, jmp3); + jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0); + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess); + IA32_Send_Jump8_Here(jit, jmp); + if (call) { IA32_Return(jit); } } -void Write_BoundsCheck(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); - - /* :TODO: break out on high -O level? */ - - if (!always_inline) - { - if (data->jit_bounds) - { - /* just generate the call */ - //mov ecx, - //call - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit->read_cell()); - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, data->jit_bounds); - } else { - //cmp eax, 0 - //jl :err_bounds - //cmp eax, ecx - //jg :err_bounds - //ret - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //:TODO: make sure this is right order - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); - IA32_Return(jit); - IA32_Send_Jump8_Here(jit, jmp1); - IA32_Send_Jump8_Here(jit, jmp2); - Write_Error(jit, SP_ERR_ARRAY_BOUNDS); - } - } else { - //cmp eax, 0 - //jl :err_bounds - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //cmp eax, - //jg :err_bounds - cell_t val = jit->read_cell(); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); - else - IA32_Cmp_Eax_Imm32(jit, val); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); - //jmp :continue - jitoffs_t cont = IA32_Jump_Imm8(jit, 0); - //:err_bounds - IA32_Send_Jump8_Here(jit, jmp1); - IA32_Send_Jump8_Here(jit, jmp2); - Write_Error(jit, SP_ERR_ARRAY_BOUNDS); - //:continue - IA32_Send_Jump8_Here(jit, cont); - } -} - -void Write_CheckMargin_Heap(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - - bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); - - if (!always_inline && data->jit_chkmargin_heap) - { - /* just generate the call */ - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, data->jit_chkmargin_heap); - } else { - //mov ecx, [esi+hea] - //cmp ecx, [esi+hlw] - //jl :error_heapmin - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW); - jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //lea ecx, [ebp+ecx+STACK_MARGIN] - //cmp ecx, edi - // jg :error_heaplow - //OR - // ret - IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); - IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); - jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0); - jitoffs_t cont; - if (always_inline) - { - cont = IA32_Jump_Imm8(jit, 0); - } else { - IA32_Return(jit); - } - //:error_heapmin - IA32_Send_Jump8_Here(jit, hm); - Write_Error(jit, SP_ERR_HEAPMIN); - //:error_heaplow - IA32_Send_Jump8_Here(jit, hl); - Write_Error(jit, SP_ERR_HEAPLOW); - //:continue - if (!always_inline) - { - IA32_Send_Jump8_Here(jit, cont); - } - } -} - -void Write_CheckMargin_Stack(JitWriter *jit) -{ - /* this is small, so we always inline it. - */ - //cmp edi, [esi+stp] - //jle :continue - IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); - if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) - { - //sub esp, 4 - correct stack for returning to non-inlined JIT - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - } - Write_Error(jit, SP_ERR_STACKMIN); - //continue: - IA32_Send_Jump8_Here(jit, jmp); -} - void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax @@ -404,6 +322,7 @@ void Macro_PushN_Addr(JitWriter *jit, int i) IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); } while (n++ < i); + //:TODO: fix the case of this size > imm8! IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_PRI); } @@ -464,6 +383,83 @@ void Macro_PushN(JitWriter *jit, int i) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); } +void WriteOp_Sysreq_N_Function(JitWriter *jit) +{ + /* The big daddy of opcodes. + * eax - num_params + * ecx - native index + */ + CompData *data = (CompData *)jit->data; + + /* store the number of parameters on the stack */ + //mov [edi-4], eax + //sub edi, 4 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + + /* save registers we will need */ + //push eax ; num_params for stack popping + //push edx + IA32_Push_Reg(jit, REG_EAX); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* push some callback stuff */ + //push edi ; stack + //push ecx ; native index + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Push_Reg(jit, REG_ECX); + + /* Relocate stack, heap, frm information, then store back */ + //sub edi, ebp + //mov ecx, [esi+hea] + //mov eax, [esi+context] + //mov [eax+hp], ecx + //mov [eax+sp], edi + //mov ecx, [esi+frm] + //mov [eax+frm], ecx + IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); + + /* finally, push the last parameter and make the call */ + //push eax ; context + //mov eax, [eax+context] + //call NativeCallback + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + + /* restore what we damaged */ + //add esp, 4*3 + //add edi, ebp + //pop edx + //pop ecx ; num_params + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, REG_ECX); + + //Note: always safe, we're in a call + //test eax, eax + //jne :error + IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); + + /* pop the AMX stack. do not check the margins. + * Note that this is not a true macro - we don't bother to + * set ALT here because nothing will be using it. + */ + //lea edi, [edi+ecx*4+4] + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4); + + //ret + IA32_Return(jit); +} + JITX86::JITX86() { memset(OpAdvTable, -1, sizeof(OpAdvTable)); @@ -643,5 +639,4 @@ JITX86::JITX86() OpAdvTable[OP_JLEQ] = -3; OpAdvTable[OP_JGRTR] = -3; OpAdvTable[OP_JGEQ] = -3; - } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index c0b502e8..b5d192dc 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -10,39 +10,41 @@ */ jitoffs_t Write_Execute_Function(JitWriter *jit); +/** + * Writes the Sysreq.n opcode as a function call. + */ +void WriteOp_Sysreq_N_Function(JitWriter *jit); + /** * Generates code to set an error state in the VM and return. - * Note that this should only be called from inside an error - * checking function. + * This is used for generating the error set points in the VM. */ -void Write_Error(JitWriter *jit, int error); +void Write_SetError(JitWriter *jit, bool always_inline, int error); /** - * Verifies an address by register. - * :TODO: optimize and make it look like the heap checkfunction! + * Checks the stacks for min and low errors. + * :TODO: Should a variation of this go in the pushN opcodes? */ -void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); +void Write_CheckStack_Min(JitWriter *jit); +void Write_CheckStack_Low(JitWriter *jit); /** - * Verifies stack margins. + * Checks the heap for min and low errors. */ -void Write_CheckMargin_Stack(JitWriter *jit); +void Write_CheckHeap_Min(JitWriter *jit); +void Write_CheckHeap_Low(JitWriter *jit); -/** - * Verifies heap margins. +/** + * Verifies an address by register. The address must reside + * between DAT and HP and SP and STP. */ -void Write_CheckMargin_Heap(JitWriter *jit); +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg); /** * Checks for division by zero. */ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg); -/** - * Writes a bounds check. - */ -void Write_BoundsCheck(JitWriter *jit); - /** * Writes the break debug function. */ @@ -56,132 +58,147 @@ void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); void Macro_PushN(JitWriter *jit, int i); +/** + * Legend for Statuses: + * ****** *** ******** + * DONE -> code generation is done + * !GEN -> code generation is deliberate skipped because: + * (default): compiler does not generate + * DEPRECATED: this feature no longer exists/supported + * UNSUPPORTED: this opcode is not supported + * TODO: done in case needed + * VERIFIED -> code generation is checked as run-time working. prefixes: + * ! errors are not checked yet. + * - non-inline errors are not checked yet. + * ~ assumed checked because of related variation, but not actually checked + */ + typedef enum { OP_NONE, /* invalid opcode */ - OP_LOAD_PRI, //DONE - OP_LOAD_ALT, //DONE - OP_LOAD_S_PRI, //DONE - OP_LOAD_S_ALT, //DONE + OP_LOAD_PRI, //!VERIFIED + OP_LOAD_ALT, //~!VERIFIED (load.pri) + OP_LOAD_S_PRI, //VERIFIED + OP_LOAD_S_ALT, //VERIFIED OP_LREF_PRI, // !GEN :TODO: we will need this for dynarrays OP_LREF_ALT, // !GEN :TODO: we will need this for dynarrays - OP_LREF_S_PRI, //DONE - OP_LREF_S_ALT, //DONE - OP_LOAD_I, //DONE + OP_LREF_S_PRI, //VERIFIED + OP_LREF_S_ALT, //~VERIFIED (lref.s.pri) + OP_LOAD_I, //VERIFIED OP_LODB_I, // !GEN :TODO: - only used for pack access - drop support in compiler first - OP_CONST_PRI, //DONE - OP_CONST_ALT, //DONE - OP_ADDR_PRI, //DONE - OP_ADDR_ALT, //DONE - OP_STOR_PRI, //DONE - OP_STOR_ALT, //DONE - OP_STOR_S_PRI, //DONE - OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //DONE - OP_SREF_ALT, //DONE - OP_SREF_S_PRI, // !GEN :TODO: we will need this for dynarrays - OP_SREF_S_ALT, // !GEN :TODO: we will need this for dynarrays - OP_STOR_I, //DONE + OP_CONST_PRI, //VERIFIED + OP_CONST_ALT, //~VERIFIED (const.pri) + OP_ADDR_PRI, //VERIFIED + OP_ADDR_ALT, //VERIFIED + OP_STOR_PRI, //VERIFIED + OP_STOR_ALT, //~VERIFIED (stor.pri) + OP_STOR_S_PRI, //VERIFIED + OP_STOR_S_ALT, //~VERIFIED (stor.s.pri) + OP_SREF_PRI, // !GEN :TODO: we will need this for dynarrays + OP_SREF_ALT, // !GEN :TODO: we will need this for dynarrays + OP_SREF_S_PRI, //VERIFIED + OP_SREF_S_ALT, //~VERIFIED (stor.s.alt) + OP_STOR_I, //VERIFIED OP_STRB_I, // !GEN :TODO: - only used for pack access, drop support in compiler first - OP_LIDX, //DONE + OP_LIDX, //VERIFIED OP_LIDX_B, //DONE - OP_IDXADDR, //DONE + OP_IDXADDR, //VERIFIED OP_IDXADDR_B, //DONE OP_ALIGN_PRI, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_LCTRL, // !GEN OP_SCTRL, // !GEN OP_MOVE_PRI, //DONE - OP_MOVE_ALT, //DONE + OP_MOVE_ALT, //VERIFIED OP_XCHG, //DONE OP_PUSH_PRI, //DONE OP_PUSH_ALT, //DONE OP_PUSH_R, // !GEN DEPRECATED - OP_PUSH_C, //DONE + OP_PUSH_C, //VERIFIED OP_PUSH, //DONE - OP_PUSH_S, //DONE - OP_POP_PRI, //DONE - OP_POP_ALT, //DONE - OP_STACK, //DONE + OP_PUSH_S, //VERIFIED + OP_POP_PRI, //VERIFIED + OP_POP_ALT, //VERIFIED + OP_STACK, //VERIFIED OP_HEAP, //DONE - OP_PROC, //DONE + OP_PROC, //VERIFIED OP_RET, // !GEN - OP_RETN, //DONE - OP_CALL, //DONE + OP_RETN, //VERIFIED + OP_CALL, //VERIFIED OP_CALL_PRI, // !GEN - OP_JUMP, //DONE + OP_JUMP, //VERIFIED OP_JREL, // !GEN - OP_JZER, //DONE + OP_JZER, //VERIFIED OP_JNZ, //DONE - OP_JEQ, //DONE - OP_JNEQ, //DONE + OP_JEQ, //VERIFIED + OP_JNEQ, //VERIFIED OP_JLESS, // !GEN OP_JLEQ, // !GEN OP_JGRTR, // !GEN OP_JGEQ, // !GEN - OP_JSLESS, //DONE - OP_JSLEQ, //DONE - OP_JSGRTR, //DONE - OP_JSGEQ, //DONE - OP_SHL, //DONE - OP_SHR, //DONE - OP_SSHR, //DONE + OP_JSLESS, //VERIFIED + OP_JSLEQ, //VERIFIED + OP_JSGRTR, //VERIFIED + OP_JSGEQ, //VERIFIED + OP_SHL, //VERIFIED + OP_SHR, //VERIFIED (Note: operator >>>) + OP_SSHR, //VERIFIED (Note: operator >>) OP_SHL_C_PRI, //DONE OP_SHL_C_ALT, //DONE OP_SHR_C_PRI, //DONE OP_SHR_C_ALT, //DONE - OP_SMUL, //DONE + OP_SMUL, //VERIFIED OP_SDIV, //DONE - OP_SDIV_ALT, //DONE + OP_SDIV_ALT, //VERIFIED OP_UMUL, // !GEN OP_UDIV, // !GEN OP_UDIV_ALT, // !GEN - OP_ADD, //DONE + OP_ADD, //VERIFIED OP_SUB, //DONE - OP_SUB_ALT, //DONE - OP_AND, //DONE - OP_OR, //DONE - OP_XOR, //DONE - OP_NOT, //DONE - OP_NEG, //DONE - OP_INVERT, //DONE - OP_ADD_C, //DONE - OP_SMUL_C, //DONE - OP_ZERO_PRI, //DONE - OP_ZERO_ALT, //DONE - OP_ZERO, //DONE - OP_ZERO_S, //DONE + OP_SUB_ALT, //VERIFIED + OP_AND, //VERIFIED + OP_OR, //VERIFIED + OP_XOR, //VERIFIED + OP_NOT, //VERIFIED + OP_NEG, //VERIFIED + OP_INVERT, //VERIFIED + OP_ADD_C, //VERIFIED + OP_SMUL_C, //VERIFIED + OP_ZERO_PRI, //VERIFIED + OP_ZERO_ALT, //~VERIFIED + OP_ZERO, //VERIFIED + OP_ZERO_S, //VERIFIED OP_SIGN_PRI, //DONE OP_SIGN_ALT, //DONE - OP_EQ, //DONE - OP_NEQ, //DONE + OP_EQ, //VERIFIED + OP_NEQ, //VERIFIED OP_LESS, // !GEN OP_LEQ, // !GEN OP_GRTR, // !GEN OP_GEQ, // !GEN - OP_SLESS, //DONE - OP_SLEQ, //DONE - OP_SGRTR, //DONE - OP_SGEQ, //DONE + OP_SLESS, //VERIFIED + OP_SLEQ, //VERIFIED + OP_SGRTR, //VERIFIED + OP_SGEQ, //VERIFIED OP_EQ_C_PRI, //DONE OP_EQ_C_ALT, //DONE - OP_INC_PRI, //DONE - OP_INC_ALT, //DONE - OP_INC, //DONE - OP_INC_S, //DONE - OP_INC_I, //DONE - OP_DEC_PRI, //DONE - OP_DEC_ALT, //DONE - OP_DEC, //DONE - OP_DEC_S, //DONE - OP_DEC_I, //DONE + OP_INC_PRI, //VERIFIED + OP_INC_ALT, //~VERIFIED (inc.pri) + OP_INC, //VERIFIED + OP_INC_S, //VERIFIED + OP_INC_I, //VERIFIED + OP_DEC_PRI, //VERIFIED + OP_DEC_ALT, //~VERIFIED (dec.pri) + OP_DEC, //VERIFIED + OP_DEC_S, //VERIFIED + OP_DEC_I, //VERIFIED OP_MOVS, //DONE OP_CMPS, // !GEN - OP_FILL, //DONE + OP_FILL, //VERIFIED OP_HALT, //DONE - OP_BOUNDS, //DONE + OP_BOUNDS, //VERIFIED OP_SYSREQ_PRI, // !GEN - OP_SYSREQ_C, + OP_SYSREQ_C, // !GEN DEPRECATED OP_FILE, // !GEN DEPRECATED OP_LINE, // !GEN DEPRECATED OP_SYMBOL, // !GEN DEPRECATED @@ -189,32 +206,32 @@ typedef enum OP_JUMP_PRI, // !GEN OP_SWITCH, //DONE OP_CASETBL, //DONE - OP_SWAP_PRI, //DONE - OP_SWAP_ALT, //DONE - OP_PUSH_ADR, //DONE - OP_NOP, //DONE + OP_SWAP_PRI, //VERIFIED + OP_SWAP_ALT, //~VERIFIED (swap.alt) + OP_PUSH_ADR, //VERIFIED + OP_NOP, //VERIFIED (lol) OP_SYSREQ_N, OP_SYMTAG, // !GEN DEPRECATED OP_BREAK, //DONE - OP_PUSH2_C, //DONE - OP_PUSH2, //DONE - OP_PUSH2_S, //DONE - OP_PUSH2_ADR, //DONE - OP_PUSH3_C, //DONE - OP_PUSH3, //DONE - OP_PUSH3_S, //DONE - OP_PUSH3_ADR, //DONE - OP_PUSH4_C, //DONE - OP_PUSH4, //DONE - OP_PUSH4_S, //DONE - OP_PUSH4_ADR, //DONE - OP_PUSH5_C, //DONE - OP_PUSH5, //DONE - OP_PUSH5_S, //DONE - OP_PUSH5_ADR, //DONE - OP_LOAD_BOTH, //DONE - OP_LOAD_S_BOTH, //DONE - OP_CONST, //DONE + OP_PUSH2_C, //~VERIFIED (push3.c) + OP_PUSH2, //VERIFIED + OP_PUSH2_S, //VERIFIED + OP_PUSH2_ADR, //VERIFIED + OP_PUSH3_C, //VERIFIED + OP_PUSH3, //~VERIFIED (push2) + OP_PUSH3_S, //~VERIFIED (push2.s) + OP_PUSH3_ADR, //~VERIFIED (push2.adr) + OP_PUSH4_C, //~VERIFIED (push3.c) + OP_PUSH4, //~VERIFIED (push2) + OP_PUSH4_S, //~VERIFIED (push2.s) + OP_PUSH4_ADR, //~VERIFIED (push2.adr) + OP_PUSH5_C, //~VERIFIED (push3.c) + OP_PUSH5, //~VERIFIED (push2) + OP_PUSH5_S, //~VERIFIED (push2.s) + OP_PUSH5_ADR, //~VERIFIED (push2.adr) + OP_LOAD_BOTH, //VERIFIED + OP_LOAD_S_BOTH, //VERIFIED + OP_CONST, //VERIFIED OP_CONST_S, //DONE /* ----- */ OP_SYSREQ_D, // !GEN UNSUPPORT diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index f4b49b5a..fde04a9d 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -30,7 +30,7 @@ } case OP_PUSH3_C: { - WriteOp_Push3(jit); + WriteOp_Push3_C(jit); break; } case OP_PUSH4_C: @@ -350,12 +350,12 @@ } case OP_LREF_S_PRI: { - WriteOp_Lref_Pri(jit); + WriteOp_Lref_S_Pri(jit); break; } case OP_LREF_S_ALT: { - WriteOp_Lref_Alt(jit); + WriteOp_Lref_S_Alt(jit); break; } case OP_CONST_PRI: @@ -613,6 +613,16 @@ WriteOp_Jsless(jit); break; } + case OP_JSGRTR: + { + WriteOp_JsGrtr(jit); + break; + } + case OP_JSGEQ: + { + WriteOp_JsGeq(jit); + break; + } case OP_JSLEQ: { WriteOp_Jsleq(jit); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index e423b596..0a733d0a 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -117,6 +117,7 @@ #define IA32_POP_REG 0x58 // encoding is +r #define IA32_PUSH_REG 0x50 // encoding is +r #define IA32_PUSH_RM 0xFF // encoding is /6 +#define IA32_PUSH_IMM32 0x68 // encoding is #define IA32_REP 0xF3 // no extra encoding #define IA32_MOVSD 0xA5 // no extra encoding #define IA32_MOVSB 0xA4 // no extra encoding @@ -124,6 +125,8 @@ #define IA32_CLD 0xFC // no extra encoding #define IA32_PUSHAD 0x60 // no extra encoding #define IA32_POPAD 0x61 // no extra encoding +#define IA32_NOP 0x90 // no extra encoding +#define IA32_INT3 0xCC // no extra encoding inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -368,6 +371,13 @@ inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } +inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_SUB_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp8); +} + inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_RM_IMM8); @@ -475,7 +485,7 @@ inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit, { jit->write_ubyte(IA32_ADD_RM_IMM32); jit->write_ubyte(ia32_modrm(mode, 0, dest)); - jitoffs_t ptr = jit->jit_curpos(); + jitoffs_t ptr = jit->get_outputpos(); jit->write_int32(0); return ptr; } @@ -599,6 +609,12 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(IA32_PUSH_REG+reg); } +inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val) +{ + jit->write_ubyte(IA32_PUSH_IMM32); + jit->write_int32(val); +} + inline void IA32_Pushad(JitWriter *jit) { jit->write_ubyte(IA32_PUSHAD); @@ -633,6 +649,14 @@ inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp) +{ + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); + jit->write_byte(disp); +} + inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -732,7 +756,7 @@ inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_ { jitoffs_t offs; jit->write_ubyte(IA32_MOV_REG_IMM+dest); - offs = jit->jit_curpos(); + offs = jit->get_outputpos(); jit->write_int32(num); return offs; } @@ -787,7 +811,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_ { jitoffs_t ptr; jit->write_ubyte(IA32_JCC_IMM+cond); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_byte(disp); return ptr; } @@ -796,7 +820,7 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_JMP_IMM32); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -805,7 +829,7 @@ inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_JMP_IMM8); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_byte(disp); return ptr; } @@ -815,7 +839,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int3 jitoffs_t ptr; jit->write_ubyte(IA32_JCC_IMM32_1); jit->write_ubyte(IA32_JCC_IMM32_2+cond); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -836,7 +860,7 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_CALL_IMM32); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -878,7 +902,7 @@ inline void IA32_Jump_Imm32_Abs(JitWriter *jit, jitoffs_t target) { /* :TODO: this should work, but does it? */ jit->write_ubyte(IA32_JMP_IMM32); - IA32_Write_Jump32(jit, jit->jit_curpos(), target); + IA32_Write_Jump32(jit, jit->get_outputpos(), target); jit->outptr += 4; } @@ -887,19 +911,19 @@ inline void IA32_Jump_Cond_Imm32_Abs(JitWriter *jit, jit_uint8_t cond, jitoffs_t /* :TODO: this should work, but does it? */ jit->write_ubyte(IA32_JCC_IMM32_1); jit->write_ubyte(IA32_JCC_IMM32_2+cond); - IA32_Write_Jump32(jit, jit->jit_curpos(), target); + IA32_Write_Jump32(jit, jit->get_outputpos(), target); jit->outptr += 4; } inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->jit_curpos(); + jitoffs_t curptr = jit->get_outputpos(); IA32_Write_Jump8(jit, jmp, curptr); } inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->jit_curpos(); + jitoffs_t curptr = jit->get_outputpos(); IA32_Write_Jump32(jit, jmp, curptr); } From d2cb27e20c93bd76869258cc4318e94e73b8109a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 02:06:50 +0000 Subject: [PATCH 0081/1664] added simple test procedure to VM and updated some context stuff for stack checking --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40111 --- sourcepawn/vm/msvc8/vm.vcproj | 8 +++- sourcepawn/vm/sp_vm_basecontext.cpp | 28 ++++++++--- sourcepawn/vm/sp_vm_engine.h | 18 ++++---- sourcepawn/vm/test_main.cpp | 72 +++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 sourcepawn/vm/test_main.cpp diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 3bd93d34..c57a6b54 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -20,7 +20,7 @@ OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" - CharacterSet="1" + CharacterSet="2" > + + vmbase; + uint32_t pushcount = ctx->pushcount; + int err; sp_public_t *pubfunc; if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERR_NONE) @@ -58,16 +60,30 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) return err; } - PushCell(ctx->pushcount); + PushCell(pushcount++); ctx->pushcount = 0; cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; err = vm->ContextExecute(ctx, pubfunc->offs, result); + + /** + * :TODO: turn this into an error check + */ - ctx->sp = save_sp; - ctx->hp = save_hp; +#if defined _DEBUG + if (err == SP_ERR_NONE) + { + assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); + assert(ctx->hp == save_hp); + } +#endif + if (err != SP_ERR_NONE) + { + ctx->sp = save_sp; + ctx->hp = save_hp; + } return err; } @@ -89,8 +105,8 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys realmem = cells * sizeof(cell_t); /** - * Check if the space between the heap and stack is sufficient. - */ + * Check if the space between the heap and stack is sufficient. + */ if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) { return SP_ERR_HEAPLOW; @@ -394,7 +410,7 @@ int BaseContext::PushCell(cell_t value) { if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) { - return SP_ERR_STACKERR; + return SP_ERR_STACKLOW; } ctx->sp -= sizeof(cell_t); diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h index 66b38e6c..9a181c26 100644 --- a/sourcepawn/vm/sp_vm_engine.h +++ b/sourcepawn/vm/sp_vm_engine.h @@ -70,18 +70,18 @@ namespace SourcePawn /** - * Allocates executable memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ + * Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ void *ExecAlloc(size_t size); /** - * Frees executable memory. - * - * @param mem Address to free. - */ + * Frees executable memory. + * + * @param mem Address to free. + */ void ExecFree(void *address); }; }; diff --git a/sourcepawn/vm/test_main.cpp b/sourcepawn/vm/test_main.cpp new file mode 100644 index 00000000..b6094321 --- /dev/null +++ b/sourcepawn/vm/test_main.cpp @@ -0,0 +1,72 @@ +#include +#include +#include "sp_vm_engine.h" +#include "sp_vm_basecontext.h" +#define WINDOWS_LEAN_AND_MEAN +#include + +using namespace SourcePawn; + +typedef void (*GIVEENGINE)(ISourcePawnEngine *); +typedef IVirtualMachine *(*GETEXPORT)(unsigned int); + +int main() +{ + SourcePawnEngine engine; + IVirtualMachine *vm; + ICompilation *co; + sp_plugin_t *plugin = NULL; + sp_context_t *ctx = NULL; + cell_t result; + int err; + + /* Note: for now this is hardcoded for testing purposes! + * The ..\ should be one above msvc8. + */ + + FILE *fp = fopen("..\\test.smx", "rb"); + if (!fp) + { + return 0; + } + plugin = engine.LoadFromFilePointer(fp, &err); + if (err != SP_ERR_NONE) + { + printf("Error loading: %d", err); + return 0; + } + HMODULE dll = LoadLibrary("..\\jit\\x86\\msvc8\\Debug\\jit-x86.dll"); + if (dll == NULL) + { + printf("Error loading DLL: %d\n", GetLastError()); + return 0; + } + GIVEENGINE give_eng = (GIVEENGINE)GetProcAddress(dll, "GiveEnginePointer"); + if (!give_eng) + { + printf("Error getting \"GiveEnginePointer!\"!\n"); + return 0; + } + give_eng(&engine); + GETEXPORT getex = (GETEXPORT)GetProcAddress(dll, "GetExport"); + if ((vm=getex(0)) == NULL) + { + printf("GetExport() returned no VM!\n"); + return 0; + } + + co = vm->StartCompilation(plugin); + ctx = vm->CompileToContext(co, &err); + + IPluginContext *base = engine.CreateBaseContext(ctx); + + base->PushCell(1); + base->PushCell(5); + err = base->Execute(0, &result); + printf("Result: %d Error: %d\n", result, err); + + engine.FreeBaseContext(base); + + fclose(fp); + FreeLibrary(dll); +} From f62af67279e65de3be025de22894a08acfeb4260 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 16:39:55 +0000 Subject: [PATCH 0082/1664] small touch-ups --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40112 --- sourcepawn/vm/jit/x86/dll_exports.cpp | 2 +- sourcepawn/vm/jit/x86/jit_x86.cpp | 6 ++++-- sourcepawn/vm/jit/x86/jit_x86.h | 2 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 1 - sourcepawn/vm/jit/x86/ungen_opcodes.h | 8 ++++++-- sourcepawn/vm/jit/x86/x86_macros.h | 2 ++ 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sourcepawn/vm/jit/x86/dll_exports.cpp b/sourcepawn/vm/jit/x86/dll_exports.cpp index db593b19..1cbaa90a 100644 --- a/sourcepawn/vm/jit/x86/dll_exports.cpp +++ b/sourcepawn/vm/jit/x86/dll_exports.cpp @@ -12,7 +12,7 @@ EXPORTFUNC void GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) EXPORTFUNC unsigned int GetExportCount() { - return 0; + return 1; } EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index b28619f9..8e6e4e6e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1138,7 +1138,7 @@ inline void WriteOp_Retn(JitWriter *jit) /* pop params */ //mov ecx, [edi] - //lea edi, [edi+edi*4+4] + //lea edi, [edi+ecx*4+4] IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4); @@ -1538,7 +1538,9 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) OPCODE op; int op_c; - /* FIRST PASS (light load) - Get initial opcode information */ + /* FIRST PASS (light load) - Get initial opcode information + * :TODO: remove this pass soon, it's not needed anymore! + */ for (cip = code; cip < end_cip;) { op = (OPCODE)*(ucell_t *)cip; diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index ee0e0524..cf720dc3 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -69,7 +69,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_INFO_RETVAL 8 //physical #define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_STACKTOP 16 //relocated -#define AMX_INFO_HEAPLOW 20 //not relocated +#define AMX_INFO_HEAPLOW 20 //not relocated. currently unused #define AMX_INFO_STACKTOP_U 24 //not relocated extern ISourcePawnEngine *engine; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index a218ff82..a02032a3 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -322,7 +322,6 @@ void Macro_PushN_Addr(JitWriter *jit, int i) IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); } while (n++ < i); - //:TODO: fix the case of this size > imm8! IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_PRI); } diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h index 466ff54c..94836acf 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcodes.h +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -56,9 +56,11 @@ inline void WriteOp_Align_Pri(JitWriter *jit) //xor eax, cell_t val = sizeof(cell_t) - jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); - else + } else { IA32_Xor_Eax_Imm32(jit, val); + } } inline void WriteOp_Align_Alt(JitWriter *jit) @@ -66,9 +68,11 @@ inline void WriteOp_Align_Alt(JitWriter *jit) //xor edx, cell_t val = sizeof(cell_t) - jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val); - else + } else { IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val); + } } inline void WriteOp_Cmps(JitWriter *jit) diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 0a733d0a..1a8d957d 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -1,6 +1,8 @@ #ifndef _INCLUDE_JIT_X86_MACROS_H #define _INCLUDE_JIT_X86_MACROS_H +#include + //MOD R/M #define MOD_MEM_REG 0 #define MOD_DISP8 1 From 9bc1279af19385159303ae143c4ec05f84922e6d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 17:22:28 +0000 Subject: [PATCH 0083/1664] fixed casetbl not being aligned correctly fixed bitshifting the wrong way (oops!) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40113 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 8e6e4e6e..ee7120ce 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1280,7 +1280,7 @@ inline void WriteOp_JsGeq(JitWriter *jit) inline void WriteOp_Switch(JitWriter *jit) { cell_t offs = jit->read_cell(); - cell_t *tbl = (cell_t *)((char *)jit->inbase + offs); + cell_t *tbl = (cell_t *)((char *)jit->inbase + offs + sizeof(cell_t)); struct casetbl { @@ -1348,9 +1348,9 @@ inline void WriteOp_Switch(JitWriter *jit) * ECX still has the correctly bound offset in it, luckily! * thus, we simply need to relocate ECX and store the cases. */ - //shr ecx, 2 + //shl ecx, 2 //add ecx, - IA32_Shr_Rm_Imm8(jit, AMX_REG_TMP, 2, MOD_REG); + IA32_Shl_Rm_Imm8(jit, AMX_REG_TMP, 2, MOD_REG); jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); /* The case table starts here. Go back and write the output pointer. */ From 8fe4440b10689b018ac3958d61499c918f147870 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 17:32:09 +0000 Subject: [PATCH 0084/1664] fixed non-sequential not having a correct default case --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40114 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index ee7120ce..038cb3de 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1364,10 +1364,15 @@ inline void WriteOp_Switch(JitWriter *jit) { jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false)); } + //if we get here, there was a bug in the JIT, so we should break into the debugger + jit->write_ubyte(IA32_INT3); } else { /* The slow version. Go through each case and generate a check. * In the future we should replace case tables of more than ~8 cases with a * hash table lookup. + * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case, + * but only if we're under N cases or so! + * :THOUGHT: Write out a static btree lookup :) */ cell_t val; for (cell_t i=0; iwrite_ubyte(IA32_INT3); } } From d328933cc5f19dce46b0687ee23c3d563a8d65df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 10 Oct 2006 17:33:05 +0000 Subject: [PATCH 0085/1664] marked switch and casetbl as verified --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40115 --- sourcepawn/vm/jit/x86/opcode_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index b5d192dc..b1c600ac 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -204,8 +204,8 @@ typedef enum OP_SYMBOL, // !GEN DEPRECATED OP_SRANGE, // !GEN DEPRECATED OP_JUMP_PRI, // !GEN - OP_SWITCH, //DONE - OP_CASETBL, //DONE + OP_SWITCH, //VERIFIED + OP_CASETBL, //VERIFIED OP_SWAP_PRI, //VERIFIED OP_SWAP_ALT, //~VERIFIED (swap.alt) OP_PUSH_ADR, //VERIFIED From c06a526165d564818cce6392fcb04a32d077c4f5 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 10 Oct 2006 17:53:42 +0000 Subject: [PATCH 0086/1664] not needed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40116 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 038cb3de..1a4d763c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1364,8 +1364,6 @@ inline void WriteOp_Switch(JitWriter *jit) { jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false)); } - //if we get here, there was a bug in the JIT, so we should break into the debugger - jit->write_ubyte(IA32_INT3); } else { /* The slow version. Go through each case and generate a check. * In the future we should replace case tables of more than ~8 cases with a From fb7942ee4dc2bc6792071e9ed39781bd2cddbe6d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Oct 2006 23:47:04 +0000 Subject: [PATCH 0087/1664] and you thought you'd never see the day.. sysreq.n verified! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40117 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 198 ++++++++++---------- sourcepawn/vm/jit/x86/jit_x86.h | 4 +- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 219 +++-------------------- sourcepawn/vm/jit/x86/opcode_helpers.h | 8 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 16 +- sourcepawn/vm/jit/x86/x86_macros.h | 16 ++ sourcepawn/vm/sp_vm_basecontext.cpp | 1 + 7 files changed, 162 insertions(+), 300 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 1a4d763c..5ef91c9d 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -60,9 +60,11 @@ inline void WriteOp_Zero(JitWriter *jit) //mov [ebp+], 0 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val); + } } inline void WriteOp_Zero_S(JitWriter *jit) @@ -70,9 +72,11 @@ inline void WriteOp_Zero_S(JitWriter *jit) //mov [ebx+], 0 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val); + } } inline void WriteOp_Push_S(JitWriter *jit) @@ -85,9 +89,11 @@ inline void WriteOp_Push_S(JitWriter *jit) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); //optimize encoding a bit... if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + } IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } @@ -1406,8 +1412,14 @@ inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) /* store the number of parameters on the stack, * and store the native index as well. */ - cell_t num_params = jit->read_cell(); cell_t native_index = jit->read_cell(); + cell_t num_params = jit->read_cell(); + + if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num) + { + ((CompData *)jit->data)->error_set = SP_ERR_INSTRUCTION_PARAM; + return; + } //mov eax, //mov ecx, @@ -1421,10 +1433,16 @@ inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) inline void WriteOp_Sysreq_N(JitWriter *jit) { /* The big daddy of opcodes. */ - cell_t num_params = jit->read_cell(); cell_t native_index = jit->read_cell(); + cell_t num_params = jit->read_cell(); CompData *data = (CompData *)jit->data; + if ((uint32_t)native_index >= data->plugin->info.natives_num) + { + data->error_set = SP_ERR_INSTRUCTION_PARAM; + return; + } + /* store the number of parameters on the stack */ //mov [edi-4], num_params //sub edi, 4 @@ -1463,7 +1481,15 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //call NativeCallback IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + IA32_Write_Jump32_Abs(jit, call, NativeCallback); + + /* check for errors */ + //mov ecx, [esi+context] + //cmp [ecx+err], 0 + //jnz :error + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ //add esp, 4*3 @@ -1473,12 +1499,6 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_ALT); - /* check for errors */ - //test eax, eax - //jne :error - IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); - /* pop the stack. do not check the margins. * Note that this is not a true macro - we don't bother to * set ALT here because nothing will be using it. @@ -1503,9 +1523,16 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) { - /* :TODO: fill this out... */ + sp_native_t *native = &ctx->natives[native_idx]; + + /* Technically both aren't needed, I guess */ + if (native->status == SP_NATIVE_NONE) + { + ctx->err = SP_ERR_NATIVE_PENDING; + return 0; + } - return 0; + return native->pfn(ctx, params); } jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) @@ -1529,6 +1556,33 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) } } +void WriteErrorRoutines(CompData *data, JitWriter *jit) +{ + data->jit_error_divzero = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_DIVIDE_BY_ZERO); + + data->jit_error_stacklow = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_STACKLOW); + + data->jit_error_stackmin = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_STACKMIN); + + data->jit_error_bounds = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_ARRAY_BOUNDS); + + data->jit_error_memaccess = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_MEMACCESS); + + data->jit_error_heaplow = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_HEAPLOW); + + data->jit_error_heapmin = jit->get_outputpos(); + Write_SetError(jit, SP_ERR_HEAPMIN); + + data->jit_extern_error = jit->get_outputpos(); + Write_GetError(jit); +} + sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) { CompData *data = (CompData *)co; @@ -1536,61 +1590,17 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) /* The first phase is to browse */ uint8_t *code = plugin->pcode; - uint8_t *cip; uint8_t *end_cip = plugin->pcode + plugin->pcode_size; OPCODE op; - int op_c; - - /* FIRST PASS (light load) - Get initial opcode information - * :TODO: remove this pass soon, it's not needed anymore! - */ - for (cip = code; cip < end_cip;) - { - op = (OPCODE)*(ucell_t *)cip; - if ((unsigned)op >= OP_NUM_OPCODES) - { - AbortCompilation(co); - *err = SP_ERR_INVALID_INSTRUCTION; - return NULL; - } - cip += sizeof(cell_t); - op_c = OpAdvTable[op]; - if (op_c >= 0) - { - cip += op_c; - } else if (op_c == -3) { - AbortCompilation(co); - *err = SP_ERR_INVALID_INSTRUCTION; - return NULL; - } else if (op_c == -1) { - switch (op) - { - case OP_CASETBL: - { - ucell_t num = *(ucell_t *)cip; - cip += sizeof(cell_t); - cip += ((2*num) + 1) * sizeof(cell_t); - break; - } - default: - { - AbortCompilation(co); - *err = SP_ERR_INVALID_INSTRUCTION; - return NULL; - } - } - } - } /********************************************* - * SECOND PASS (medium load): writer.outbase is NULL, getting size only - * THIRD PASS (heavy load!!): writer.outbase is valid and output is written + * FIRST PASS (medium load): writer.outbase is NULL, getting size only + * SECOND PASS (heavy load!!): writer.outbase is valid and output is written *********************************************/ JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); - cell_t jitpos; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1602,58 +1612,37 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) writer.outbase = NULL; data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size); - /* Jump back here for second pass */ + /* We will jump back here for second pass */ jit_rewind: /* Initialize pass vars */ writer.inptr = writer.inbase; data->jit_verify_addr_eax = 0; data->jit_verify_addr_edx = 0; - /* Start writing the actual code */ + /* Write the prologue of the JIT */ data->jit_return = Write_Execute_Function(jit); - /* Write error checking routines that are jumped to */ - if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) + /* Write the SYSREQ.N opcode if we need to */ + if (!(data->inline_level & JIT_INLINE_NATIVES)) { - jitpos = jit->get_outputpos(); - Write_Check_VerifyAddr(jit, REG_EAX); - data->jit_verify_addr_eax = jitpos; - - jitpos = jit->get_outputpos(); - Write_Check_VerifyAddr(jit, REG_EDX); - data->jit_verify_addr_edx = jitpos; + data->jit_sysreq_n = jit->get_outputpos(); + WriteOp_Sysreq_N_Function(jit); } - /* Write error codes we need */ + /* Write error checking routines that are called to */ + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { - data->jit_error_divzero = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_DIVIDE_BY_ZERO); + data->jit_verify_addr_eax = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EAX); - data->jit_error_stacklow = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_STACKLOW); - - data->jit_error_stackmin = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_STACKMIN); - - data->jit_error_bounds = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_ARRAY_BOUNDS); - - data->jit_error_memaccess = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_MEMACCESS); - - data->jit_error_heaplow = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_HEAPLOW); - - data->jit_error_heapmin = jit->get_outputpos(); - Write_SetError(jit, true, SP_ERR_HEAPMIN); + data->jit_verify_addr_edx = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EDX); } /* Actual code generation! */ if (writer.outbase == NULL) { - /******* - * SECOND PASS - get opcode sizes+info - *******/ + /* First Pass - find codesize and resolve relocation */ jitoffs_t pcode_offs; jitoffs_t native_offs; @@ -1673,7 +1662,16 @@ jit_rewind: { #include "opcode_switch.inc" } + /* Check for errors. This should only happen in the first pass. */ + if (data->error_set != SP_ERR_NONE) + { + *err = data->error_set; + AbortCompilation(co); + return NULL; + } } + /* Write these last because error jumps should be unpredicted, and thus forward */ + WriteErrorRoutines(data, jit); /* the total codesize is now known! */ uint32_t mem = writer.get_outputpos(); @@ -1693,6 +1691,8 @@ jit_rewind: #include "opcode_switch.inc" } } + /* Write these last because error jumps should be unpredicted, and thus forward */ + WriteErrorRoutines(data, jit); } /************* @@ -1810,8 +1810,7 @@ jit_rewind: } /* clean up relocation+compilation memory */ - engine->BaseFree(data->rebase); - delete data; + AbortCompilation(co); *err = SP_ERR_NONE; @@ -1848,13 +1847,18 @@ ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) CompData *data = new CompData; data->plugin = plugin; - data->inline_level = JIT_INLINE_ERRORCHECKS; + data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES; + data->error_set = SP_ERR_NONE; return data; } void JITX86::AbortCompilation(ICompilation *co) { + if (((CompData *)co)->rebase) + { + engine->BaseFree(((CompData *)co)->rebase); + } delete (CompData *)co; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index cf720dc3..49198999 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -33,15 +33,15 @@ public: jitoffs_t jit_error_memaccess; jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; + jitoffs_t jit_extern_error; uint32_t codesize; int inline_level; + int error_set; bool debug; }; class JITX86 : public IVirtualMachine { -public: - JITX86(); public: const char *GetVMName(); ICompilation *StartCompilation(sp_plugin_t *plugin); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index a02032a3..92cea6e1 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -4,8 +4,6 @@ #include "opcode_helpers.h" #include "x86_macros.h" -int OpAdvTable[OP_NUM_OPCODES]; - #define NUM_INFO_PARAMS 7 jitoffs_t Write_Execute_Function(JitWriter *jit) @@ -165,16 +163,26 @@ void Write_BreakDebug(JitWriter *jit) IA32_Return(jit); } -void Write_SetError(JitWriter *jit, bool always_inline, int error) +void Write_GetError(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + + //mov eax, [esi+info.context] + //mov eax, [eax+ctx.error] + //jmp [jit_return] + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, err)); + IA32_Jump_Imm32_Abs(jit, data->jit_return); +} + +void Write_SetError(JitWriter *jit, int error) { CompData *data = (CompData *)jit->data; - /* These are so small that we always inline them! */ //mov eax, - //jmp [...jit_return] + //jmp [jit_return] IA32_Mov_Reg_Imm32(jit, REG_EAX, error); - jitoffs_t jmp = IA32_Jump_Imm32(jit, 0); - IA32_Write_Jump32(jit, jmp, data->jit_return); + IA32_Jump_Imm32_Abs(jit, data->jit_return); } void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) @@ -426,11 +434,18 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) /* finally, push the last parameter and make the call */ //push eax ; context - //mov eax, [eax+context] //call NativeCallback IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + IA32_Write_Jump32_Abs(jit, call, (void *)&NativeCallback); + + /* Test for error */ + //mov ecx, [esi+context] + //cmp [ecx+err], 0 + //jnz :error + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ //add esp, 4*3 @@ -442,12 +457,6 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Pop_Reg(jit, AMX_REG_ALT); IA32_Pop_Reg(jit, REG_ECX); - //Note: always safe, we're in a call - //test eax, eax - //jne :error - IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); - /* pop the AMX stack. do not check the margins. * Note that this is not a true macro - we don't bother to * set ALT here because nothing will be using it. @@ -459,183 +468,3 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Return(jit); } -JITX86::JITX86() -{ - memset(OpAdvTable, -1, sizeof(OpAdvTable)); - - /* instructions with 5 parameters */ - OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5; - OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5; - - /* instructions with 4 parameters */ - OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4; - OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4; - - /* instructions with 3 parameters */ - OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3; - OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3; - - /* instructions with 2 parameters */ - OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2; - OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2; - OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2; - OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; - OpAdvTable[OP_CONST] = sizeof(cell_t)*2; - OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; - OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2; - - /* instructions with 1 parameter */ - OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); - OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t); - OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_LREF_PRI] = sizeof(cell_t); - OpAdvTable[OP_LREF_ALT] = sizeof(cell_t); - OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_CONST_PRI] = sizeof(cell_t); - OpAdvTable[OP_CONST_ALT] = sizeof(cell_t); - OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t); - OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t); - OpAdvTable[OP_STOR_PRI] = sizeof(cell_t); - OpAdvTable[OP_STOR_ALT] = sizeof(cell_t); - OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_SREF_PRI] = sizeof(cell_t); - OpAdvTable[OP_SREF_ALT] = sizeof(cell_t); - OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t); - OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t); - OpAdvTable[OP_LIDX_B] = sizeof(cell_t); - OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t); - OpAdvTable[OP_PUSH_C] = sizeof(cell_t); - OpAdvTable[OP_PUSH] = sizeof(cell_t); - OpAdvTable[OP_PUSH_S] = sizeof(cell_t); - OpAdvTable[OP_STACK] = sizeof(cell_t); - OpAdvTable[OP_HEAP] = sizeof(cell_t); - OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_ADD_C] = sizeof(cell_t); - OpAdvTable[OP_SMUL_C] = sizeof(cell_t); - OpAdvTable[OP_ZERO] = sizeof(cell_t); - OpAdvTable[OP_ZERO_S] = sizeof(cell_t); - OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t); - OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t); - OpAdvTable[OP_INC] = sizeof(cell_t); - OpAdvTable[OP_INC_S] = sizeof(cell_t); - OpAdvTable[OP_DEC] = sizeof(cell_t); - OpAdvTable[OP_DEC_S] = sizeof(cell_t); - OpAdvTable[OP_MOVS] = sizeof(cell_t); - OpAdvTable[OP_FILL] = sizeof(cell_t); - OpAdvTable[OP_HALT] = sizeof(cell_t); - OpAdvTable[OP_BOUNDS] = sizeof(cell_t); - OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); - OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t); - OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t); - OpAdvTable[OP_CALL] = sizeof(cell_t); - OpAdvTable[OP_JUMP] = sizeof(cell_t); - OpAdvTable[OP_JZER] = sizeof(cell_t); - OpAdvTable[OP_JNZ] = sizeof(cell_t); - OpAdvTable[OP_JEQ] = sizeof(cell_t); - OpAdvTable[OP_JNEQ] = sizeof(cell_t); - OpAdvTable[OP_JSLESS] = sizeof(cell_t); - OpAdvTable[OP_JSLEQ] = sizeof(cell_t); - OpAdvTable[OP_JSGRTR] = sizeof(cell_t); - OpAdvTable[OP_JSGEQ] = sizeof(cell_t); - OpAdvTable[OP_SWITCH] = sizeof(cell_t); - - /* instructions with 0 parameters */ - OpAdvTable[OP_LOAD_I] = 0; - OpAdvTable[OP_STOR_I] = 0; - OpAdvTable[OP_LIDX] = 0; - OpAdvTable[OP_IDXADDR] = 0; - OpAdvTable[OP_MOVE_PRI] = 0; - OpAdvTable[OP_MOVE_ALT] = 0; - OpAdvTable[OP_XCHG] = 0; - OpAdvTable[OP_PUSH_PRI] = 0; - OpAdvTable[OP_PUSH_ALT] = 0; - OpAdvTable[OP_POP_PRI] = 0; - OpAdvTable[OP_POP_ALT] = 0; - OpAdvTable[OP_PROC] = 0; - OpAdvTable[OP_RET] = 0; - OpAdvTable[OP_RETN] = 0; - OpAdvTable[OP_CALL_PRI] = 0; - OpAdvTable[OP_SHL] = 0; - OpAdvTable[OP_SHR] = 0; - OpAdvTable[OP_SSHR] = 0; - OpAdvTable[OP_SMUL] = 0; - OpAdvTable[OP_SDIV] = 0; - OpAdvTable[OP_SDIV_ALT] = 0; - OpAdvTable[OP_ADD] = 0; - OpAdvTable[OP_SUB] = 0; - OpAdvTable[OP_SUB_ALT] = 0; - OpAdvTable[OP_AND] = 0; - OpAdvTable[OP_OR] = 0; - OpAdvTable[OP_XOR] = 0; - OpAdvTable[OP_NOT] = 0; - OpAdvTable[OP_NEG] = 0; - OpAdvTable[OP_INVERT] = 0; - OpAdvTable[OP_ZERO_PRI] = 0; - OpAdvTable[OP_ZERO_ALT] = 0; - OpAdvTable[OP_SIGN_PRI] = 0; - OpAdvTable[OP_SIGN_ALT] = 0; - OpAdvTable[OP_EQ] = 0; - OpAdvTable[OP_NEQ] = 0; - OpAdvTable[OP_SLESS] = 0; - OpAdvTable[OP_SLEQ] = 0; - OpAdvTable[OP_SGRTR] = 0; - OpAdvTable[OP_SGEQ] = 0; - OpAdvTable[OP_INC_PRI] = 0; - OpAdvTable[OP_INC_ALT] = 0; - OpAdvTable[OP_INC_I] = 0; - OpAdvTable[OP_DEC_PRI] = 0; - OpAdvTable[OP_DEC_ALT] = 0; - OpAdvTable[OP_DEC_I] = 0; - OpAdvTable[OP_JUMP_PRI] = 0; - OpAdvTable[OP_SWAP_PRI] = 0; - OpAdvTable[OP_SWAP_ALT] = 0; - OpAdvTable[OP_NOP] = 0; - OpAdvTable[OP_BREAK] = 0; - OpAdvTable[OP_HEAP_PRI] = 0; - OpAdvTable[OP_POP_HEAP_PRI] = 0; - OpAdvTable[OP_SYSREQ_PRI] = 0; - - /* opcodes that are totally invalid */ - /* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */ - OpAdvTable[OP_FILE] = -3; - OpAdvTable[OP_SYMBOL] = -3; - OpAdvTable[OP_LINE] = -3; - OpAdvTable[OP_SRANGE] = -3; - OpAdvTable[OP_SYMTAG] = -3; - OpAdvTable[OP_SYSREQ_D] = -3; - OpAdvTable[OP_SYSREQ_ND] = -3; - OpAdvTable[OP_PUSH_R] = -3; - OpAdvTable[OP_LODB_I] = -3; - OpAdvTable[OP_STRB_I] = -3; - OpAdvTable[OP_LCTRL] = -3; - OpAdvTable[OP_SCTRL] = -3; - OpAdvTable[OP_ALIGN_PRI] = -3; - OpAdvTable[OP_ALIGN_ALT] = -3; - OpAdvTable[OP_JREL] = -3; - OpAdvTable[OP_CMPS] = -3; - OpAdvTable[OP_UMUL] = -3; - OpAdvTable[OP_UDIV] = -3; - OpAdvTable[OP_UDIV_ALT] = -3; - OpAdvTable[OP_LESS] = -3; - OpAdvTable[OP_LEQ] = -3; - OpAdvTable[OP_GRTR] = -3; - OpAdvTable[OP_GEQ] = -3; - OpAdvTable[OP_JLESS] = -3; - OpAdvTable[OP_JLEQ] = -3; - OpAdvTable[OP_JGRTR] = -3; - OpAdvTable[OP_JGEQ] = -3; -} diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index b1c600ac..9859bd4a 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -18,8 +18,10 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit); /** * Generates code to set an error state in the VM and return. * This is used for generating the error set points in the VM. + * GetError writes the error from the context. SetError hardcodes. */ -void Write_SetError(JitWriter *jit, bool always_inline, int error); +void Write_GetError(JitWriter *jit); +void Write_SetError(JitWriter *jit, int error); /** * Checks the stacks for min and low errors. @@ -210,7 +212,7 @@ typedef enum OP_SWAP_ALT, //~VERIFIED (swap.alt) OP_PUSH_ADR, //VERIFIED OP_NOP, //VERIFIED (lol) - OP_SYSREQ_N, + OP_SYSREQ_N, //VERIFIED OP_SYMTAG, // !GEN DEPRECATED OP_BREAK, //DONE OP_PUSH2_C, //~VERIFIED (push3.c) @@ -244,6 +246,4 @@ typedef enum OP_NUM_OPCODES } OPCODE; -extern int OpAdvTable[]; - #endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index fde04a9d..759fbe1b 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -643,10 +643,22 @@ WriteOp_Call(jit); break; } + case OP_SYSREQ_N: + { + if (data->inline_level & JIT_INLINE_NATIVES) + { + WriteOp_Sysreq_N(jit); + } else { + WriteOp_Sysreq_N_NoInline(jit); + } + break; + } #if defined USE_UNGEN_OPCODES #include "ungen_opcode_switch.inc" #endif default: { - assert(0); - } \ No newline at end of file + data->error_set = SP_ERR_INVALID_INSTRUCTION; + break; + } + \ No newline at end of file diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 1a8d957d..a742cceb 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -899,6 +899,22 @@ inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) jit->outptr = oldptr; } +/** + * Corrects a jump using an absolute offset, not a relative one. + */ +inline void IA32_Write_Jump32_Abs(JitWriter *jit, jitoffs_t jmp, void *target) +{ + //save old ptr + jitcode_t oldptr = jit->outptr; + //get relative difference + long diff = ((long)target - ((long)jit->outbase + jmp + 4)); + //overwrite old value + jit->outptr = jit->outbase + jmp; + jit->write_int32(diff); + //restore old ptr + jit->outptr = oldptr; +} + /* For writing and auto-calculating an absolute target */ inline void IA32_Jump_Imm32_Abs(JitWriter *jit, jitoffs_t target) { diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index ef932a3d..718f230b 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -12,6 +12,7 @@ using namespace SourcePawn; BaseContext::BaseContext(sp_context_t *_ctx) { ctx = _ctx; + ctx->context = this; } IVirtualMachine *BaseContext::GetVirtualMachine() From 6adba4b7317d7504ce03ac4c2227281c060fe4d0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Oct 2006 00:27:18 +0000 Subject: [PATCH 0088/1664] changed error defines to have "ERROR" instead of "ERR" added and verified sysreq.c which is generated on -O0 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40118 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 101 +++++++++++++++++---- sourcepawn/vm/jit/x86/jit_x86.h | 28 +++--- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 82 ++++++++++++++++-- sourcepawn/vm/jit/x86/opcode_helpers.h | 5 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 7 +- sourcepawn/vm/sp_vm_basecontext.cpp | 106 +++++++++++------------ sourcepawn/vm/sp_vm_engine.cpp | 14 +-- sourcepawn/vm/test_main.cpp | 44 +++++++++- 8 files changed, 285 insertions(+), 102 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 5ef91c9d..e969e293 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1407,6 +1407,26 @@ inline void WriteOp_Casetbl(JitWriter *jit) jit->inptr += num_cases; } +inline void WriteOp_Sysreq_C(JitWriter *jit) +{ + /* store the number of parameters on the stack, + * and store the native index as well. + */ + cell_t native_index = jit->read_cell(); + + if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num) + { + ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM; + return; + } + + //mov ecx, + IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG); + + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c); +} + inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) { /* store the number of parameters on the stack, @@ -1417,7 +1437,7 @@ inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num) { - ((CompData *)jit->data)->error_set = SP_ERR_INSTRUCTION_PARAM; + ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM; return; } @@ -1439,7 +1459,7 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) if ((uint32_t)native_index >= data->plugin->info.natives_num) { - data->error_set = SP_ERR_INSTRUCTION_PARAM; + data->error_set = SP_ERROR_INSTRUCTION_PARAM; return; } @@ -1481,8 +1501,13 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //call NativeCallback IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, NativeCallback); - + if (!data->debug) + { + IA32_Write_Jump32_Abs(jit, call, NativeCallback); + } else { + IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + } + /* check for errors */ //mov ecx, [esi+context] //cmp [ecx+err], 0 @@ -1528,13 +1553,55 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) /* Technically both aren't needed, I guess */ if (native->status == SP_NATIVE_NONE) { - ctx->err = SP_ERR_NATIVE_PENDING; + ctx->err = SP_ERROR_NATIVE_PENDING; return 0; } return native->pfn(ctx, params); } +cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params) +{ + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + + if (ctx->hp < ctx->heapbase) + { + ctx->err = SP_ERROR_HEAPMIN; + return 0; + } + + if (ctx->hp + STACK_MARGIN > ctx->sp) + { + ctx->err = SP_ERROR_STACKLOW; + return 0; + } + + if ((uint32_t)ctx->sp >= ctx->memory) + { + ctx->err = SP_ERROR_STACKMIN; + return 0; + } + + cell_t result = NativeCallback(ctx, native_idx, params); + + if (ctx->err != SP_ERROR_NONE) + { + return result; + } + + if (save_sp != ctx->sp) + { + ctx->err = SP_ERROR_STACKLEAK; + return result; + } else if (save_hp != ctx->hp) { + ctx->err = SP_ERROR_HEAPLEAK; + return result; + } + + return result; +} + jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) { if (jit->outptr) @@ -1559,25 +1626,25 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) void WriteErrorRoutines(CompData *data, JitWriter *jit) { data->jit_error_divzero = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_DIVIDE_BY_ZERO); + Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO); data->jit_error_stacklow = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_STACKLOW); + Write_SetError(jit, SP_ERROR_STACKLOW); data->jit_error_stackmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_STACKMIN); + Write_SetError(jit, SP_ERROR_STACKMIN); data->jit_error_bounds = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_ARRAY_BOUNDS); + Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS); data->jit_error_memaccess = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_MEMACCESS); + Write_SetError(jit, SP_ERROR_MEMACCESS); data->jit_error_heaplow = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_HEAPLOW); + Write_SetError(jit, SP_ERROR_HEAPLOW); data->jit_error_heapmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERR_HEAPMIN); + Write_SetError(jit, SP_ERROR_HEAPMIN); data->jit_extern_error = jit->get_outputpos(); Write_GetError(jit); @@ -1629,6 +1696,10 @@ jit_rewind: WriteOp_Sysreq_N_Function(jit); } + /* Plugins compiled with -O0 will need this! */ + data->jit_sysreq_c = jit->get_outputpos(); + WriteOp_Sysreq_C_Function(jit); + /* Write error checking routines that are called to */ if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { @@ -1663,7 +1734,7 @@ jit_rewind: #include "opcode_switch.inc" } /* Check for errors. This should only happen in the first pass. */ - if (data->error_set != SP_ERR_NONE) + if (data->error_set != SP_ERROR_NONE) { *err = data->error_set; AbortCompilation(co); @@ -1812,7 +1883,7 @@ jit_rewind: /* clean up relocation+compilation memory */ AbortCompilation(co); - *err = SP_ERR_NONE; + *err = SP_ERROR_NONE; return ctx; } @@ -1848,7 +1919,7 @@ ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) data->plugin = plugin; data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES; - data->error_set = SP_ERR_NONE; + data->error_set = SP_ERROR_NONE; return data; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 49198999..ee54e78e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -15,17 +15,18 @@ class CompData : public ICompilation { public: CompData() : plugin(NULL), - debug(false), inline_level(0), rebase(NULL) + debug(false), inline_level(0), rebase(NULL), + error_set(SP_ERROR_NONE) { }; public: - sp_plugin_t *plugin; - jitcode_t rebase; - jitoffs_t jit_return; + sp_plugin_t *plugin; /* plugin handle */ + jitcode_t rebase; /* relocation map */ + jitoffs_t jit_return; /* point in main call to return to */ jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; - jitoffs_t jit_break; - jitoffs_t jit_sysreq_n; + jitoffs_t jit_break; /* call to op.break */ + jitoffs_t jit_sysreq_n; /* call version of op.sysreq.n */ jitoffs_t jit_error_bounds; jitoffs_t jit_error_divzero; jitoffs_t jit_error_stacklow; @@ -33,11 +34,12 @@ public: jitoffs_t jit_error_memaccess; jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; - jitoffs_t jit_extern_error; - uint32_t codesize; - int inline_level; - int error_set; - bool debug; + jitoffs_t jit_extern_error; /* returning generic error */ + jitoffs_t jit_sysreq_c; /* old version! */ + uint32_t codesize; /* total codesize */ + int inline_level; /* inline optimization level */ + int error_set; /* error code to halt process */ + bool debug; /* whether to compile debug mode */ }; class JITX86 : public IVirtualMachine @@ -53,6 +55,7 @@ public: }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); +cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params); jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_REG_PRI REG_EAX @@ -69,8 +72,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_INFO_RETVAL 8 //physical #define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_STACKTOP 16 //relocated -#define AMX_INFO_HEAPLOW 20 //not relocated. currently unused -#define AMX_INFO_STACKTOP_U 24 //not relocated +#define AMX_INFO_STACKTOP_U 20 //not relocated extern ISourcePawnEngine *engine; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 92cea6e1..55b45e71 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -4,7 +4,7 @@ #include "opcode_helpers.h" #include "x86_macros.h" -#define NUM_INFO_PARAMS 7 +#define NUM_INFO_PARAMS 6 jitoffs_t Write_Execute_Function(JitWriter *jit) { @@ -66,14 +66,10 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) //mov [esi+x], ecx - store unrelocated //add ecx, ebp - relocate //mov [esi+x], ecx - store relocated - //mov ecx, [eax+] - get heap low - //mov [esi+20], ecx - store heap low into info pointer IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U); IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase)); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW); /* Remaining needed vars */ //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack) @@ -88,10 +84,10 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) /* if the code flow gets to here, there was a normal return */ //mov ecx, [esi+8] - get retval pointer //mov [ecx], eax - store retval from PRI - //mov eax, SP_ERR_NONE - set no error + //mov eax, SP_ERROR_NONE - set no error IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL); IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG); - IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE); + IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE); /* save where error checking/halting functions should go to */ jitoffs_t offs_return = jit->get_outputpos(); @@ -390,6 +386,71 @@ void Macro_PushN(JitWriter *jit, int i) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); } +void WriteOp_Sysreq_C_Function(JitWriter *jit) +{ + /* The small daddy of the big daddy of opcodes. + * ecx - native index + */ + CompData *data = (CompData *)jit->data; + + /* save registers we will need */ + //push edx + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* push some callback stuff */ + //push edi ; stack + //push ecx ; native index + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Push_Reg(jit, REG_ECX); + + /* Relocate stack, heap, frm information, then store back */ + //sub edi, ebp + //mov ecx, [esi+hea] + //mov eax, [esi+context] + //mov [eax+hp], ecx + //mov [eax+sp], edi + //mov ecx, [esi+frm] + //mov [eax+frm], ecx + IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); + + /* finally, push the last parameter and make the call */ + //push eax ; context + //call NativeCallback + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + if (!data->debug) + { + IA32_Write_Jump32_Abs(jit, call, NativeCallback); + } else { + IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + } + + /* Test for error */ + //mov ecx, [esi+context] + //cmp [ecx+err], 0 + //jnz :error + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); + + /* restore what we damaged */ + //add esp, 4*3 + //add edi, ebp + //pop edx + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_ALT); + + //ret + IA32_Return(jit); +} + void WriteOp_Sysreq_N_Function(JitWriter *jit) { /* The big daddy of opcodes. @@ -437,7 +498,12 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) //call NativeCallback IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)&NativeCallback); + if (!data->debug) + { + IA32_Write_Jump32_Abs(jit, call, NativeCallback); + } else { + IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + } /* Test for error */ //mov ecx, [esi+context] diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 9859bd4a..5e303efc 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -11,9 +11,10 @@ jitoffs_t Write_Execute_Function(JitWriter *jit); /** - * Writes the Sysreq.n opcode as a function call. + * Writes the Sysreq.* opcodes as a function call. */ void WriteOp_Sysreq_N_Function(JitWriter *jit); +void WriteOp_Sysreq_C_Function(JitWriter *jit); /** * Generates code to set an error state in the VM and return. @@ -200,7 +201,7 @@ typedef enum OP_HALT, //DONE OP_BOUNDS, //VERIFIED OP_SYSREQ_PRI, // !GEN - OP_SYSREQ_C, // !GEN DEPRECATED + OP_SYSREQ_C, //VERIFIED OP_FILE, // !GEN DEPRECATED OP_LINE, // !GEN DEPRECATED OP_SYMBOL, // !GEN DEPRECATED diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index 759fbe1b..4f389db7 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -643,6 +643,11 @@ WriteOp_Call(jit); break; } + case OP_SYSREQ_C: + { + WriteOp_Sysreq_C(jit); + break; + } case OP_SYSREQ_N: { if (data->inline_level & JIT_INLINE_NATIVES) @@ -658,7 +663,7 @@ #endif default: { - data->error_set = SP_ERR_INVALID_INSTRUCTION; + data->error_set = SP_ERROR_INVALID_INSTRUCTION; break; } \ No newline at end of file diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index 718f230b..34c38b23 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -34,13 +34,13 @@ int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) { if (!IsDebugging()) { - return SP_ERR_NOTDEBUGGING; + return SP_ERROR_NOTDEBUGGING; } *oldpfn = ctx->dbreak; ctx->dbreak = newpfn; - return SP_ERR_NONE; + return SP_ERROR_NONE; } IPluginDebugInfo *BaseContext::GetDebugInfo() @@ -56,7 +56,7 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) int err; sp_public_t *pubfunc; - if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERR_NONE) + if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERROR_NONE) { return err; } @@ -74,13 +74,13 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) */ #if defined _DEBUG - if (err == SP_ERR_NONE) + if (err == SP_ERROR_NONE) { assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); assert(ctx->hp == save_hp); } #endif - if (err != SP_ERR_NONE) + if (err != SP_ERROR_NONE) { ctx->sp = save_sp; ctx->hp = save_hp; @@ -97,7 +97,7 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys #if 0 if (cells > CELLBOUNDMAX) { - return SP_ERR_PARAM; + return SP_ERROR_ARAM; } #else assert(cells < CELLBOUNDMAX); @@ -110,7 +110,7 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys */ if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) { - return SP_ERR_HEAPLOW; + return SP_ERROR_HEAPLOW; } addr = (cell_t *)(ctx->data + ctx->hp); @@ -128,7 +128,7 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys ctx->hp += realmem; - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::HeapPop(cell_t local_addr) @@ -140,7 +140,7 @@ int BaseContext::HeapPop(cell_t local_addr) local_addr -= sizeof(cell_t); if (local_addr < ctx->heapbase || local_addr >= ctx->sp) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } addr = (cell_t *)(ctx->data + local_addr); @@ -148,12 +148,12 @@ int BaseContext::HeapPop(cell_t local_addr) /* check if this memory count looks valid */ if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } ctx->hp = local_addr; - return SP_ERR_NONE; + return SP_ERROR_NONE; } @@ -161,12 +161,12 @@ int BaseContext::HeapRelease(cell_t local_addr) { if (local_addr < ctx->heapbase) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } ctx->hp = local_addr - sizeof(cell_t); - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::FindNativeByName(const char *name, uint32_t *index) @@ -187,7 +187,7 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) { *index = mid; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } else if (diff < 0) { low = mid + 1; } else { @@ -195,14 +195,14 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) } } - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) { if (index >= ctx->plugin->info.natives_num) { - return SP_ERR_INDEX; + return SP_ERROR_INDEX; } if (native) @@ -210,7 +210,7 @@ int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) *native = &(ctx->natives[index]); } - return SP_ERR_NONE; + return SP_ERROR_NONE; } @@ -237,7 +237,7 @@ int BaseContext::FindPublicByName(const char *name, uint32_t *index) { *index = mid; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } else if (diff < 0) { low = mid + 1; } else { @@ -245,14 +245,14 @@ int BaseContext::FindPublicByName(const char *name, uint32_t *index) } } - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) { if (index >= ctx->plugin->info.publics_num) { - return SP_ERR_INDEX; + return SP_ERROR_INDEX; } if (pblic) @@ -260,7 +260,7 @@ int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) *pblic = &(ctx->publics[index]); } - return SP_ERR_NONE; + return SP_ERROR_NONE; } uint32_t BaseContext::GetPublicsNum() @@ -272,7 +272,7 @@ int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) { if (index >= ctx->plugin->info.pubvars_num) { - return SP_ERR_INDEX; + return SP_ERROR_INDEX; } if (pubvar) @@ -280,7 +280,7 @@ int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) *pubvar = &(ctx->pubvars[index]); } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::FindPubvarByName(const char *name, uint32_t *index) @@ -301,7 +301,7 @@ int BaseContext::FindPubvarByName(const char *name, uint32_t *index) { *index = mid; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } else if (diff < 0) { low = mid + 1; } else { @@ -309,20 +309,20 @@ int BaseContext::FindPubvarByName(const char *name, uint32_t *index) } } - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) { if (index >= ctx->plugin->info.pubvars_num) { - return SP_ERR_INDEX; + return SP_ERROR_INDEX; } *local_addr = ctx->plugin->info.pubvars[index].address; *phys_addr = ctx->pubvars[index].offs; - return SP_ERR_NONE; + return SP_ERROR_NONE; } uint32_t BaseContext::GetPubVarsNum() @@ -353,7 +353,7 @@ int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int ove } } - return SP_ERR_NONE; + return SP_ERROR_NONE; } @@ -363,7 +363,7 @@ int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) uint32_t index; int err; - if ((err = FindNativeByName(native->name, &index)) != SP_ERR_NONE) + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) { return err; } @@ -371,7 +371,7 @@ int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) ctx->natives[index].pfn = native->func; ctx->natives[index].status = status; - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) @@ -389,14 +389,14 @@ int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) } } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) { if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } if (phys_addr) @@ -404,21 +404,21 @@ int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) *phys_addr = (cell_t *)(ctx->data + local_addr); } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::PushCell(cell_t value) { if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) { - return SP_ERR_STACKLOW; + return SP_ERROR_STACKLOW; } ctx->sp -= sizeof(cell_t); *(cell_t *)(ctx->data + ctx->sp) = value; ctx->pushcount++; - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) @@ -428,7 +428,7 @@ int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) for (i=0; isp += (cell_t)(i * sizeof(cell_t)); ctx->pushcount -= i; @@ -436,7 +436,7 @@ int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) } } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) @@ -444,14 +444,14 @@ int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t ar cell_t *ph_addr; int err; - if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERR_NONE) + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) { return err; } memcpy(ph_addr, array, numcells * sizeof(cell_t)); - if ((err = PushCell(*local_addr)) != SP_ERR_NONE) + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) { HeapRelease(*local_addr); return err; @@ -462,7 +462,7 @@ int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t ar *phys_addr = ph_addr; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) @@ -472,7 +472,7 @@ int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } src = (cell_t *)(ctx->data + local_addr); @@ -495,7 +495,7 @@ int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength *chars = len; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) @@ -504,7 +504,7 @@ int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char * int err; unsigned int i, numcells = strlen(string); - if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE) + if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE) { return err; } @@ -515,7 +515,7 @@ int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char * } ph_addr[numcells] = '\0'; - if ((err = PushCell(*local_addr)) != SP_ERR_NONE) + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) { HeapRelease(*local_addr); return err; @@ -526,7 +526,7 @@ int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char * *phys_addr = ph_addr; } - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *source) @@ -536,7 +536,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *sour if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) { - return SP_ERR_INVALID_ADDRESS; + return SP_ERROR_INVALID_ADDRESS; } len = strlen(source); @@ -553,7 +553,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *sour } dest[len] = '\0'; - return SP_ERR_NONE; + return SP_ERROR_NONE; } #define USHR(x) ((unsigned int)(x)>>1) @@ -578,12 +578,12 @@ int BaseContext::LookupFile(ucell_t addr, const char **filename) if (low == -1) { - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } *filename = ctx->files[low].name; - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::LookupFunction(ucell_t addr, const char **name) @@ -602,12 +602,12 @@ int BaseContext::LookupFunction(ucell_t addr, const char **name) if (iter >= max) { - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } *name = ctx->symbols[iter].name; - return SP_ERR_NONE; + return SP_ERROR_NONE; } int BaseContext::LookupLine(ucell_t addr, uint32_t *line) @@ -630,10 +630,10 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) if (low == -1) { - return SP_ERR_NOT_FOUND; + return SP_ERROR_NOT_FOUND; } *line = ctx->lines[low].line; - return SP_ERR_NONE; + return SP_ERROR_NONE; } diff --git a/sourcepawn/vm/sp_vm_engine.cpp b/sourcepawn/vm/sp_vm_engine.cpp index fa3d2a79..1e108263 100644 --- a/sourcepawn/vm/sp_vm_engine.cpp +++ b/sourcepawn/vm/sp_vm_engine.cpp @@ -151,7 +151,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, if (err) { - *err = SP_ERR_NONE; + *err = SP_ERROR_NONE; } return plugin; @@ -159,7 +159,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, return_error: if (err) { - *err = SP_ERR_FILE_FORMAT; + *err = SP_ERROR_FILE_FORMAT; } return NULL; @@ -175,7 +175,7 @@ sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) if (!fp) { - error = SP_ERR_NOT_FOUND; + error = SP_ERROR_NOT_FOUND; goto return_error; } @@ -185,7 +185,7 @@ sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) if (hdr.magic != SPFILE_MAGIC) { - error = SP_ERR_FILE_FORMAT; + error = SP_ERROR_FILE_FORMAT; goto return_error; } @@ -211,7 +211,7 @@ sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) { free(sectheader); free(uncompdata); - error = SP_ERR_DECOMPRESSOR; + error = SP_ERROR_DECOMPRESSOR; goto return_error; } @@ -232,7 +232,7 @@ sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) } default: { - error = SP_ERR_DECOMPRESSOR; + error = SP_ERROR_DECOMPRESSOR; goto return_error; } } @@ -300,5 +300,5 @@ int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) free(plugin); } - return SP_ERR_NONE; + return SP_ERROR_NONE; } diff --git a/sourcepawn/vm/test_main.cpp b/sourcepawn/vm/test_main.cpp index b6094321..c22c7dba 100644 --- a/sourcepawn/vm/test_main.cpp +++ b/sourcepawn/vm/test_main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "sp_vm_engine.h" #include "sp_vm_basecontext.h" #define WINDOWS_LEAN_AND_MEAN @@ -10,6 +11,29 @@ using namespace SourcePawn; typedef void (*GIVEENGINE)(ISourcePawnEngine *); typedef IVirtualMachine *(*GETEXPORT)(unsigned int); +cell_t TestNative(sp_context_t *ctx, cell_t *params) +{ + IPluginContext *pl = ctx->context; + cell_t *phys; + int err; + printf("params[0] = %d\n", params[0]); + printf("params[1] = %d\n", params[1]); + if ((err=pl->LocalToPhysAddr(params[2], &phys)) != SP_ERROR_NONE) + { + ctx->err = err; + return 0; + } + printf("params[2] %c%c%c%c%c\n", phys[0], phys[1], phys[2], phys[3], phys[4]); + if ((err=pl->LocalToPhysAddr(params[3], &phys)) != SP_ERROR_NONE) + { + ctx->err = err; + return 0; + } + printf("params[3] = %d\n", *phys); + *phys = 95; + return 5; +} + int main() { SourcePawnEngine engine; @@ -30,7 +54,7 @@ int main() return 0; } plugin = engine.LoadFromFilePointer(fp, &err); - if (err != SP_ERR_NONE) + if (err != SP_ERROR_NONE) { printf("Error loading: %d", err); return 0; @@ -56,12 +80,26 @@ int main() } co = vm->StartCompilation(plugin); - ctx = vm->CompileToContext(co, &err); + if ((ctx = vm->CompileToContext(co, &err)) == NULL) + { + printf("CompileToContext() failed: %d", err); + return 0; + } IPluginContext *base = engine.CreateBaseContext(ctx); + sp_nativeinfo_t mynative; + mynative.name = "gaben"; + mynative.func = TestNative; + + if ((err=base->BindNative(&mynative, SP_NATIVE_OKAY)) != SP_ERROR_NONE) + { + printf("BindNative() failed: %d", err); + return 0; + } + base->PushCell(1); - base->PushCell(5); + base->PushCell(4); err = base->Execute(0, &result); printf("Result: %d Error: %d\n", result, err); From 785173578b3c49b34c16c798660d0f7b6cc85919 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Oct 2006 00:27:47 +0000 Subject: [PATCH 0089/1664] committed new header --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40119 --- sourcepawn/include/sp_vm_context.h | 2 +- sourcepawn/include/sp_vm_types.h | 53 ++++++++++++++++-------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h index e10dfca8..12dcbd51 100644 --- a/sourcepawn/include/sp_vm_context.h +++ b/sourcepawn/include/sp_vm_context.h @@ -284,7 +284,7 @@ namespace SourcePawn /** * Binds a single native. Overwrites any existing bind. * If the context does not contain the native that will be binded the function will return - * with a SP_ERR_NOT_FOUND error. + * with a SP_ERROR_OT_FOUND error. * * @param native Pointer to native. * @param status Status value to set (should be SP_NATIVE_OKAY). diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index c0bfb5cb..9a41d4ab 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -9,23 +9,26 @@ typedef int32_t cell_t; /** * Error codes */ -#define SP_ERR_NONE 0 -#define SP_ERR_FILE_FORMAT 1 /* File format unrecognized */ -#define SP_ERR_DECOMPRESSOR 2 /* A decompressor was not found */ -#define SP_ERR_HEAPLOW 3 /* Not enough space left on the heap */ -#define SP_ERR_PARAM 4 /* Invalid parameter */ -#define SP_ERR_INVALID_ADDRESS 5 /* A memory address was not valid */ -#define SP_ERR_NOT_FOUND 6 /* The object in question was not found */ -#define SP_ERR_INDEX 7 /* Invalid index parameter */ -#define SP_ERR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ -#define SP_ERR_STACKLOW 9 /* Nnot enough space left on the stack */ -#define SP_ERR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ -#define SP_ERR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ -#define SP_ERR_MEMACCESS 12 /* Invalid memory access */ -#define SP_ERR_STACKMIN 13 /* Stack went beyond its minimum value */ -#define SP_ERR_HEAPMIN 14 /* Heap went beyond its minimum value */ -#define SP_ERR_DIVIDE_BY_ZERO 15 /* Division by zero */ -#define SP_ERR_ARRAY_BOUNDS 16 /* Array index is out of bounds */ +#define SP_ERROR_NONE 0 +#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /* Invalid parameter */ +#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ +#define SP_ERROR_INDEX 7 /* Invalid index parameter */ +#define SP_ERROR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ +#define SP_ERROR_STACKLOW 9 /* Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 12 /* Invalid memory access */ +#define SP_ERROR_STACKMIN 13 /* Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 14 /* Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 15 /* Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 16 /* Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 17 /* Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 18 /* A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 19 /* A native leaked an item on the heap */ /********************************************** *** The following structures are reference structures. @@ -86,7 +89,16 @@ typedef struct sp_plugin_s sp_plugin_debug_t debug; /* debug info table */ } sp_plugin_t; +/** Forward declarations */ + +namespace SourcePawn +{ + class IPluginContext; + class IVirtualMachine; +}; + struct sp_context_s; + typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); /********************************************** @@ -175,12 +187,6 @@ typedef struct sp_debug_symbol_s sp_fdbg_symbol_t *sym; /* pointer to original symbol */ } sp_debug_symbol_t; -namespace SourcePawn -{ - class IPluginContext; - class IVirtualMachine; -}; - /** * Breaks into a debugger * Params: @@ -190,7 +196,6 @@ namespace SourcePawn */ typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t); - #define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ /** From 6f2ebd8da7d47b2d19099da4e10e8ce349f70409 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 15 Oct 2006 20:26:51 +0000 Subject: [PATCH 0090/1664] separated this from the rest --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40120 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 8 ++ sourcepawn/compiler/sc3.c | 97 +------------------------ sourcepawn/compiler/sctracker.c | 86 ++++++++++++++++++++++ sourcepawn/compiler/sctracker.h | 26 +++++++ 4 files changed, 121 insertions(+), 96 deletions(-) create mode 100644 sourcepawn/compiler/sctracker.c create mode 100644 sourcepawn/compiler/sctracker.h diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index 08d373a6..e430f784 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -240,6 +240,10 @@ RelativePath="..\scstate.c" > + + @@ -278,6 +282,10 @@ RelativePath="..\sc.h" > + + diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index c9b2e467..e54d2c5e 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -28,6 +28,7 @@ #include #endif #include "sc.h" +#include "sctracker.h" static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval, int (*hier)(value*),value *lval); @@ -60,104 +61,8 @@ static int dbltest(void (*oper)(),value *lval1,value *lval2); static int commutative(void (*oper)()); static int constant(value *lval); -#define HEAPUSE_STATIC 0 -#define HEAPUSE_DYNAMIC 1 - -typedef struct heapuse_s { - int type; /* HEAPUSE_STATIC or HEAPUSE_DYNAMIC */ - int size; /* size of array for static (0 for dynamic) */ - struct heapuse_s *prev; /* previous array on the list */ -} heapuse_t; - -typedef struct heapuse_list_s { - struct heapuse_list_s *prev; /* last used list */ - heapuse_t *head; /* head of the current list */ -} heapuse_list_t; - static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */ static int bitwise_opercount; /* count of bitwise operators in an expression */ -//static int decl_heap=0; -static heapuse_list_t *heapusage = NULL; - -/** - * Creates a new heap allocation tracker entry - */ -void pushheaplist() -{ - heapuse_list_t *newlist=(heapuse_list_t *)malloc(sizeof(heapuse_list_t)); - newlist->prev=heapusage; - newlist->head=NULL; - heapusage=newlist; -} - -/** - * Generates code to free all heap allocations on a tracker - */ -void freeheapusage(heapuse_list_t *heap) -{ - heapuse_t *cur=heap->head; - heapuse_t *tmp; - while (cur) { - if (cur->type == HEAPUSE_STATIC) { - modheap((-1)*cur->size*sizeof(cell)); - } else { - modheap_i(); - } - tmp=cur->prev; - free(cur); - cur=tmp; - } - heap->head=NULL; -} - -/** - * Pops a heap list but does not free it. - */ -heapuse_list_t *popsaveheaplist() -{ - heapuse_list_t *oldlist=heapusage; - heapusage=heapusage->prev; - return oldlist; -} - -/** - * Pops a heap list and frees it. - */ -void popheaplist() -{ - heapuse_list_t *oldlist; - assert(heapusage!=NULL); - - freeheapusage(heapusage); - assert(heapusage->head==NULL); - - oldlist=heapusage->prev; - free(heapusage); - heapusage=oldlist; -} - -/* - * Returns the size passed in - */ -int markheap(int type, int size) -{ - heapuse_t *use; - if (type==HEAPUSE_STATIC && size==0) - return 0; - use=heapusage->head; - if (use && (type==HEAPUSE_STATIC) - && (use->type == type)) - { - use->size += size; - } else { - use=(heapuse_t *)malloc(sizeof(heapuse_t)); - use->type=type; - use->size=size; - use->prev=heapusage->head; - heapusage->head=use; - } - return size; -} /* Function addresses of binary operators for signed operations */ static void (*op1[17])(void) = { diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c new file mode 100644 index 00000000..2c5619f5 --- /dev/null +++ b/sourcepawn/compiler/sctracker.c @@ -0,0 +1,86 @@ +#include +#include +#include "sc.h" +#include "sctracker.h" + +heapuse_list_t *heapusage = NULL; + +/** +* Creates a new heap allocation tracker entry +*/ +void pushheaplist() +{ + heapuse_list_t *newlist=(heapuse_list_t *)malloc(sizeof(heapuse_list_t)); + newlist->prev=heapusage; + newlist->head=NULL; + heapusage=newlist; +} + +/** +* Generates code to free all heap allocations on a tracker +*/ +void freeheapusage(heapuse_list_t *heap) +{ + heapuse_t *cur=heap->head; + heapuse_t *tmp; + while (cur) { + if (cur->type == HEAPUSE_STATIC) { + modheap((-1)*cur->size*sizeof(cell)); + } else { + modheap_i(); + } + tmp=cur->prev; + free(cur); + cur=tmp; + } + heap->head=NULL; +} + +/** +* Pops a heap list but does not free it. +*/ +heapuse_list_t *popsaveheaplist() +{ + heapuse_list_t *oldlist=heapusage; + heapusage=heapusage->prev; + return oldlist; +} + +/** +* Pops a heap list and frees it. +*/ +void popheaplist() +{ + heapuse_list_t *oldlist; + assert(heapusage!=NULL); + + freeheapusage(heapusage); + assert(heapusage->head==NULL); + + oldlist=heapusage->prev; + free(heapusage); + heapusage=oldlist; +} + +/* +* Returns the size passed in +*/ +int markheap(int type, int size) +{ + heapuse_t *use; + if (type==HEAPUSE_STATIC && size==0) + return 0; + use=heapusage->head; + if (use && (type==HEAPUSE_STATIC) + && (use->type == type)) + { + use->size += size; + } else { + use=(heapuse_t *)malloc(sizeof(heapuse_t)); + use->type=type; + use->size=size; + use->prev=heapusage->head; + heapusage->head=use; + } + return size; +} \ No newline at end of file diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h new file mode 100644 index 00000000..c936d0e9 --- /dev/null +++ b/sourcepawn/compiler/sctracker.h @@ -0,0 +1,26 @@ +#ifndef _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ +#define _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ + +#define HEAPUSE_STATIC 0 +#define HEAPUSE_DYNAMIC 1 + +typedef struct heapuse_s { + int type; /* HEAPUSE_STATIC or HEAPUSE_DYNAMIC */ + int size; /* size of array for static (0 for dynamic) */ + struct heapuse_s *prev; /* previous array on the list */ +} heapuse_t; + +typedef struct heapuse_list_s { + struct heapuse_list_s *prev; /* last used list */ + heapuse_t *head; /* head of the current list */ +} heapuse_list_t; + +extern heapuse_list_t *heapusage; + +void pushheaplist(); +void freeheapusage(heapuse_list_t *heap); +heapuse_list_t *popsaveheaplist(); +void popheaplist(); +int markheap(int type, int size); + +#endif //_INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ From 2c65e423794a60d6ea1757ab239c702cb54a9f17 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 15 Oct 2006 20:57:14 +0000 Subject: [PATCH 0091/1664] reorganized the tracker to be a bit more modular --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40121 --- sourcepawn/compiler/sc1.c | 1 + sourcepawn/compiler/sc3.c | 26 ++--- sourcepawn/compiler/sctracker.c | 181 ++++++++++++++++++++------------ sourcepawn/compiler/sctracker.h | 40 ++++--- 4 files changed, 152 insertions(+), 96 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 73a5bc8a..cc656799 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -66,6 +66,7 @@ #include "lstring.h" #include "sc.h" #include "svnrev.h" +#include "sctracker.h" #define VERSION_STR "3.2." SVN_REVSTR #define VERSION_INT 0x0302 diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index e54d2c5e..fba92491 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1056,13 +1056,13 @@ static int hier14(value *lval1) * (a() ? return_array() : return_array()) ? return_array() : return_array() */ -void dynarray_from_heaplist(heapuse_list_t *heap) +void dynarray_from_heaplist(memuse_list_t *heap) { - heapuse_t *use=heap->head; - heapuse_t *tmp; + memuse_t *use=heap->head; + memuse_t *tmp; long total=0; while (use) { - assert(use->type==HEAPUSE_STATIC); + assert(use->type==MEMUSE_STATIC); total+=use->size; tmp=use->prev; free(use); @@ -1081,7 +1081,7 @@ static int hier13(value *lval) int flab2=getlabel(); value lval2={0}; int array1,array2; - heapuse_list_t *heap; + memuse_list_t *heap; pushheaplist(); if (lvalue) { @@ -1124,7 +1124,7 @@ static int hier13(value *lval) dynarray_from_heaplist(heap); setlabel(flab2); if (array1 && array2) { - markheap(HEAPUSE_DYNAMIC, 0); + markheap(MEMUSE_DYNAMIC, 0); } if (lval->ident==iARRAY) lval->ident=iREFARRAY; /* iARRAY becomes iREFARRAY */ @@ -1907,7 +1907,7 @@ static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int */ assert(array_sz>=size); modheap((int)array_sz*sizeof(cell)); - markheap(HEAPUSE_STATIC, array_sz); + markheap(MEMUSE_STATIC, array_sz); /* ??? should perhaps fill with zeros first */ memcopy(size*sizeof(cell)); moveto1(); @@ -1982,7 +1982,7 @@ static int nesting=0; assert(retsize>0); modheap(retsize*sizeof(cell));/* address is in ALT */ pushreg(sALT); /* pass ALT as the last (hidden) parameter */ - markheap(HEAPUSE_STATIC, retsize); + markheap(MEMUSE_STATIC, retsize); /* also mark the ident of the result as "array" */ lval_result->ident=iREFARRAY; lval_result->sym=symret; @@ -2090,14 +2090,14 @@ static int nesting=0; } else { rvalue(&lval); /* get value in PRI */ setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc+=markheap(HEAPUSE_STATIC, 1); + heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ } else if (lvalue) { address(lval.sym,sPRI); } else { setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc+=markheap(HEAPUSE_STATIC, 1); + heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION @@ -2109,7 +2109,7 @@ static int nesting=0; /* allocate a cell on the heap and store the * value (already in PRI) there */ setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc+=markheap(HEAPUSE_STATIC, 1); + heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ /* ??? handle const array passed by reference */ @@ -2147,7 +2147,7 @@ static int nesting=0; address(lval.sym,sPRI); } else { setheap_pri(); /* address of the value on the heap in PRI */ - heapalloc+=markheap(HEAPUSE_STATIC, 1); + heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ } /* if */ @@ -2294,7 +2294,7 @@ static int nesting=0; } else if (arg[argidx].ident==iREFERENCE) { setheap(arg[argidx].defvalue.val); /* address of the value on the heap in PRI */ - heapalloc+=markheap(HEAPUSE_STATIC, 1); + heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } else { int dummytag=arg[argidx].tags[0]; diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 2c5619f5..e2df4d92 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -3,84 +3,129 @@ #include "sc.h" #include "sctracker.h" -heapuse_list_t *heapusage = NULL; +memuse_list_t *heapusage = NULL; +memuse_list_t *stackusage = NULL; /** -* Creates a new heap allocation tracker entry -*/ + * Creates a new mem usage tracker entry + */ +void _push_memlist(memuse_list_t **head) +{ + memuse_list_t *newlist = (memuse_list_t *)malloc(sizeof(memuse_list_t)); + (*head)->prev = *head; + (*head)->head = NULL; + *head = newlist; +} + +/** + * Pops a heap list but does not free it. + */ +memuse_list_t *_pop_save_memlist(memuse_list_t **head) +{ + memuse_list_t *oldlist = *head; + *head = (*head)->prev; + return oldlist; +} + +/** + * Marks a memory usage on a memory list + */ +int _mark_memlist(memuse_list_t *head, int type, int size) +{ + memuse_t *use; + if (type==MEMUSE_STATIC && size==0) + { + return 0; + } + use=head->head; + if (use && (type==MEMUSE_STATIC) + && (use->type == type)) + { + use->size += size; + } else { + use=(memuse_t *)malloc(sizeof(memuse_t)); + use->type=type; + use->size=size; + use->prev=head->head; + head->head=use; + } + return size; +} + +/** + * Wrapper for pushing the heap list + */ void pushheaplist() { - heapuse_list_t *newlist=(heapuse_list_t *)malloc(sizeof(heapuse_list_t)); - newlist->prev=heapusage; - newlist->head=NULL; - heapusage=newlist; + _push_memlist(&heapusage); } /** -* Generates code to free all heap allocations on a tracker -*/ -void freeheapusage(heapuse_list_t *heap) + * Wrapper for popping and saving the heap list + */ +memuse_list_t *popsaveheaplist() { - heapuse_t *cur=heap->head; - heapuse_t *tmp; - while (cur) { - if (cur->type == HEAPUSE_STATIC) { - modheap((-1)*cur->size*sizeof(cell)); - } else { - modheap_i(); - } - tmp=cur->prev; - free(cur); - cur=tmp; - } - heap->head=NULL; + return _pop_save_memlist(&heapusage); } /** -* Pops a heap list but does not free it. -*/ -heapuse_list_t *popsaveheaplist() -{ - heapuse_list_t *oldlist=heapusage; - heapusage=heapusage->prev; - return oldlist; -} - -/** -* Pops a heap list and frees it. -*/ -void popheaplist() -{ - heapuse_list_t *oldlist; - assert(heapusage!=NULL); - - freeheapusage(heapusage); - assert(heapusage->head==NULL); - - oldlist=heapusage->prev; - free(heapusage); - heapusage=oldlist; -} - -/* -* Returns the size passed in -*/ + * Wrapper for marking the heap + */ int markheap(int type, int size) { - heapuse_t *use; - if (type==HEAPUSE_STATIC && size==0) - return 0; - use=heapusage->head; - if (use && (type==HEAPUSE_STATIC) - && (use->type == type)) - { - use->size += size; - } else { - use=(heapuse_t *)malloc(sizeof(heapuse_t)); - use->type=type; - use->size=size; - use->prev=heapusage->head; - heapusage->head=use; - } - return size; -} \ No newline at end of file + return _mark_memlist(heapusage, type, size); +} + +/** + * Wrapper for pushing the stack list + */ +void pushstacklist() +{ + _push_memlist(&stackusage); +} + +/** + * Wrapper for marking the stack + */ +int markstack(int type, int size) +{ + return _mark_memlist(stackusage, type, size); +} + +/** + * Generates code to free all heap allocations on a tracker + */ +void _heap_freeusage(memuse_list_t *heap) +{ + memuse_t *cur=heap->head; + memuse_t *tmp; + while (cur) { + if (cur->type == MEMUSE_STATIC) { + modheap((-1)*cur->size*sizeof(cell)); + } else { + modheap_i(); + } + tmp=cur->prev; + free(cur); + cur=tmp; + } + heap->head=NULL; +} + +/** + * Pops a heap list and frees it. + */ +void popheaplist() +{ + memuse_list_t *oldlist; + assert(heapusage!=NULL); + + _heap_freeusage(heapusage); + assert(heapusage->head==NULL); + + oldlist=heapusage->prev; + free(heapusage); + heapusage=oldlist; +} + + diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index c936d0e9..4f79d11d 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -1,26 +1,36 @@ #ifndef _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ #define _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ -#define HEAPUSE_STATIC 0 -#define HEAPUSE_DYNAMIC 1 +#define MEMUSE_STATIC 0 +#define MEMUSE_DYNAMIC 1 -typedef struct heapuse_s { - int type; /* HEAPUSE_STATIC or HEAPUSE_DYNAMIC */ - int size; /* size of array for static (0 for dynamic) */ - struct heapuse_s *prev; /* previous array on the list */ -} heapuse_t; +typedef struct memuse_s { + int type; /* MEMUSE_STATIC or MEMUSE_DYNAMIC */ + int size; /* size of array for static (0 for dynamic) */ + struct memuse_s *prev; /* previous block on the list */ +} memuse_t; -typedef struct heapuse_list_s { - struct heapuse_list_s *prev; /* last used list */ - heapuse_t *head; /* head of the current list */ -} heapuse_list_t; - -extern heapuse_list_t *heapusage; +typedef struct memuse_list_s { + struct memuse_list_s *prev; /* last used list */ + memuse_t *head; /* head of the current list */ +} memuse_list_t; +/** + * Heap functions + */ void pushheaplist(); -void freeheapusage(heapuse_list_t *heap); -heapuse_list_t *popsaveheaplist(); +memuse_list_t *popsaveheaplist(); void popheaplist(); int markheap(int type, int size); +/** + * Stack functions + */ +void pushstacklist(); +void popstacklist(); +int markstack(int type, int size); + +extern memuse_list_t *heapusage; +extern memuse_list_t *stackusage; + #endif //_INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ From ea6e82d79a051ff25a42e79b271c700b4816077b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 15 Oct 2006 23:31:09 +0000 Subject: [PATCH 0092/1664] committed new stack modification method --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40122 --- sourcepawn/compiler/sc1.c | 33 +++++++----- sourcepawn/compiler/sctracker.c | 90 +++++++++++++++++++++++++++++++-- sourcepawn/compiler/sctracker.h | 12 +++++ 3 files changed, 119 insertions(+), 16 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index cc656799..145b5e21 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1972,6 +1972,7 @@ static int declloc(int fstatic) } /* if */ markexpr(sLDECL,name,-declared*sizeof(cell)); /* mark for better optimization */ modstk(-(int)size*sizeof(cell)); + markstack(MEMUSE_STATIC, size); assert(curfunc!=NULL); assert((curfunc->usage & uNATIVE)==0); if (curfunc->x.stacksizeusage & uRETVALUE); /* set "return type" variable */ curfunc=sym; define_args(); /* add the symbolic info for the function arguments */ @@ -3361,7 +3363,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc * has only a single statement in its body (no compound block) and that * statement declares a new variable */ - modstk((int)declared*sizeof(cell)); /* remove all local variables */ + popstacklist(); declared=0; } /* if */ if ((lastst!=tRETURN) && (lastst!=tGOTO)){ @@ -4770,6 +4772,7 @@ static void compound(int stmt_sameline,int starttok) int block_start=fline; /* save line where the compound block started */ int endtok; + pushstacklist(); /* if there is more text on this line, we should adjust the statement indent */ if (stmt_sameline) { int i; @@ -4808,8 +4811,9 @@ static void compound(int stmt_sameline,int starttok) } /* while */ if (lastst!=tRETURN) destructsymbols(&loctab,nestlevel); - if (lastst!=tRETURN && lastst!=tGOTO) - modstk((int)(declared-save_decl)*sizeof(cell)); /* delete local variable space */ + if (lastst!=tRETURN && lastst!=tGOTO) { + popstacklist(); + } testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ declared=save_decl; delete_symbols(&loctab,nestlevel,FALSE,TRUE); /* erase local symbols, but @@ -5069,7 +5073,8 @@ static int dofor(void) save_decl=declared; save_nestlevel=nestlevel; save_endlessloop=endlessloop; - + pushstacklist(); + addwhile(wq); skiplab=getlabel(); endtok= matchtoken('(') ? ')' : tDO; @@ -5094,8 +5099,11 @@ static int dofor(void) */ ptr=readwhile(); assert(ptr!=NULL); - ptr[wqBRK]=(int)declared; - ptr[wqCONT]=(int)declared; + /*ptr[wqBRK]=(int)declared; + *ptr[wqCONT]=(int)declared; + */ + ptr[wqBRK] = stackusage->list_id; + ptr[wqCONT] = stackusage->list_id; jumplabel(skiplab); /* skip expression 3 1st time */ setlabel(wq[wqLOOP]); /* "continue" goes to this label: expr3 */ setline(TRUE); @@ -5135,7 +5143,7 @@ static int dofor(void) * variable in "expr1". */ destructsymbols(&loctab,nestlevel); - modstk((int)(declared-save_decl)*sizeof(cell)); + popstacklist(); testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ declared=save_decl; delete_symbols(&loctab,nestlevel,FALSE,TRUE); @@ -5152,7 +5160,7 @@ static int dofor(void) * 2. only one instruction may appear below each case, use a compound * instruction to execute multiple instructions * 3. the "case" keyword accepts a comma separated list of values to - * match, it also accepts a range using the syntax "1 .. 4" + * match * * SWITCH param * PRI = expression result @@ -5349,6 +5357,8 @@ static void dolabel(void) /* since one can jump around variable declarations or out of compound * blocks, the stack must be manually adjusted */ + //:TODO: This is actually generated, egads! + //We have to support this and LCTRL/SCTRL setstk(-declared*sizeof(cell)); sym->usage|=uDEFINE; /* label is now defined */ } @@ -5496,8 +5506,7 @@ static void doreturn(void) rettype|=uRETNONE; /* function does not return anything */ } /* if */ destructsymbols(&loctab,0); /* call destructor for *all* locals */ - modstk((int)declared*sizeof(cell)); /* end of function, remove *all* - * local variables */ + genstackfree(-1); /* free everything on the stack */ ffret(strcmp(curfunc->name,uENTRYFUNC)!=0); } @@ -5511,7 +5520,7 @@ static void dobreak(void) if (ptr==NULL) return; destructsymbols(&loctab,nestlevel); - modstk(((int)declared-ptr[wqBRK])*sizeof(cell)); + genstackfree(ptr[wqBRK]); jumplabel(ptr[wqEXIT]); } @@ -5524,7 +5533,7 @@ static void docont(void) if (ptr==NULL) return; destructsymbols(&loctab,nestlevel); - modstk(((int)declared-ptr[wqCONT])*sizeof(cell)); + genstackfree(ptr[wqCONT]); jumplabel(ptr[wqLOOP]); } diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index e2df4d92..a5aa3127 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -12,8 +12,14 @@ memuse_list_t *stackusage = NULL; void _push_memlist(memuse_list_t **head) { memuse_list_t *newlist = (memuse_list_t *)malloc(sizeof(memuse_list_t)); - (*head)->prev = *head; - (*head)->head = NULL; + if (*head != NULL) + { + newlist->list_id = (*head)->list_id + 1; + } else { + newlist->list_id = 0; + } + newlist->prev = *head; + newlist->head = NULL; *head = newlist; } @@ -52,6 +58,26 @@ int _mark_memlist(memuse_list_t *head, int type, int size) return size; } +void _reset_memlist(memuse_list_t **head) +{ + memuse_list_t *curlist = *head; + memuse_list_t *tmplist; + while (curlist) { + memuse_t *curuse = curlist->head; + memuse_t *tmpuse; + while (curuse) { + tmpuse = curuse->prev; + free(curuse); + curuse = tmpuse; + } + tmplist = curlist->prev; + free(curlist); + curlist = tmplist; + } + *head = NULL; +} + + /** * Wrapper for pushing the heap list */ @@ -99,8 +125,10 @@ void _heap_freeusage(memuse_list_t *heap) { memuse_t *cur=heap->head; memuse_t *tmp; - while (cur) { - if (cur->type == MEMUSE_STATIC) { + while (cur) + { + if (cur->type == MEMUSE_STATIC) + { modheap((-1)*cur->size*sizeof(cell)); } else { modheap_i(); @@ -112,6 +140,34 @@ void _heap_freeusage(memuse_list_t *heap) heap->head=NULL; } +void _stack_genusage(memuse_list_t *stack, int dofree) +{ + memuse_t *cur = stack->head; + memuse_t *tmp; + while (cur) + { + if (cur->type == MEMUSE_DYNAMIC) + { + /* no idea yet */ + assert(0); + } else { + modstk(cur->size * sizeof(cell)); + } + if (dofree) + { + tmp = cur->prev; + free(cur); + cur = tmp; + } else { + cur = cur->prev; + } + } + if (dofree) + { + stack->head = NULL; + } +} + /** * Pops a heap list and frees it. */ @@ -128,4 +184,30 @@ void popheaplist() heapusage=oldlist; } +void genstackfree(int stop_id) +{ + memuse_list_t *curlist = stackusage; + while (curlist && curlist->list_id > stop_id) + { + _stack_genusage(curlist, 0); + curlist = curlist->prev; + } +} +void popstacklist() +{ + memuse_list_t *oldlist; + assert(stackusage != NULL); + + _stack_genusage(stackusage, 1); + assert(stackusage->head==NULL); + + oldlist = stackusage->prev; + free(stackusage); + stackusage = oldlist; +} + +void resetstacklist() +{ + _reset_memlist(&stackusage); +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 4f79d11d..25be54ab 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -12,6 +12,7 @@ typedef struct memuse_s { typedef struct memuse_list_s { struct memuse_list_s *prev; /* last used list */ + int list_id; memuse_t *head; /* head of the current list */ } memuse_list_t; @@ -29,6 +30,17 @@ int markheap(int type, int size); void pushstacklist(); void popstacklist(); int markstack(int type, int size); +/** + * Generates code to free stack usage, but does not pop the list. + * This is used for code like dobreak()/docont()/doreturn(). + * stop_id is the list at which to stop generating. + */ +void genstackfree(int stop_id); + +/** + * Resets the stack list by freeing everything + */ +void resetstacklist(); extern memuse_list_t *heapusage; extern memuse_list_t *stackusage; From b7180795ecd6fc944dece34f159d78db4258a1f1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Oct 2006 02:05:26 +0000 Subject: [PATCH 0093/1664] initial import of.... DYNAMIC ARRAYS --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40123 --- sourcepawn/compiler/sc.h | 1 + sourcepawn/compiler/sc1.c | 73 +++++++++++++++++++++++++-------- sourcepawn/compiler/sc4.c | 19 +++++---- sourcepawn/compiler/sc6.c | 4 +- sourcepawn/compiler/sctracker.c | 35 +++++++++++++--- sourcepawn/compiler/sctracker.h | 6 ++- 6 files changed, 104 insertions(+), 34 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 05676716..92f613a5 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -590,6 +590,7 @@ SC_FUNC void moveto1(void); SC_FUNC void pushreg(regid reg); SC_FUNC void pushval(cell val); SC_FUNC void popreg(regid reg); +SC_FUNC void genarray(int dims); SC_FUNC void swap1(void); SC_FUNC void ffswitch(int label); SC_FUNC void ffcase(cell value,char *labelname,int newtable); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 145b5e21..b04da88c 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1667,7 +1667,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst ispublic=TRUE; /* implicitly public variable */ assert(!fstatic); } /* if */ - while (matchtoken('[')) { + while (matchtoken('[')) { ident=iARRAY; if (numdim == sDIMEN_MAX) { error(53); /* exceeding maximum number of dimensions */ @@ -1926,19 +1926,45 @@ static int declloc(int fstatic) */ if ((sym=findloc(name))!=NULL && sym->compound!=nestlevel || findglb(name,sGLOBAL)!=NULL) error(219,name); /* variable shadows another symbol */ - while (matchtoken('[')){ - ident=iARRAY; - if (numdim == sDIMEN_MAX) { - error(53); /* exceeding maximum number of dimensions */ - return ident; - } /* if */ - size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */ - #if INT_MAX < LONG_MAX - if (size > INT_MAX) - error(105); /* overflow, exceeding capacity */ - #endif - dim[numdim++]=(int)size; - } /* while */ + if (matchtoken('[')) { + do { + ident=iARRAY; + if (numdim == sDIMEN_MAX) { + error(53); /* exceeding maximum number of dimensions */ + return ident; + } /* if */ + size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */ + #if INT_MAX < LONG_MAX + if (size > INT_MAX) + error(105); /* overflow, exceeding capacity */ + #endif + dim[numdim++]=(int)size; + } while (matchtoken('[')); + } else if (matchtoken('(')) { + int dim_ident; + int dim_tag; + symbol *dim_sym; + do { + ident=iREFARRAY; + if (numdim == sDIMEN_MAX) { + error(53); + return iREFARRAY; + } /* if */ + dim_ident = doexpr(TRUE,FALSE,FALSE,FALSE,&dim_tag,&dim_sym,0); + dim[numdim++] = 1; + if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION) { + pushreg(sPRI); + } else if (dim_ident == iCONSTEXPR) { + pushreg(sPRI); + } else { + assert(0); //:TODO: make this an error + } + if (!matchtag(tag, dim_tag, FALSE)) + error(213); + needtoken(')'); + } while (matchtoken('(')); + genarray(numdim); + } if (getstates(name)) error(88,name); /* local variables may not have states */ if (ident==iARRAY || fstatic) { @@ -1952,7 +1978,7 @@ static int declloc(int fstatic) return ident; /* error message already given */ if (numdim==1) dim[0]=(int)size; - } /* if */ + } /* reserve memory (on the stack) for the variable */ if (fstatic) { /* write zeros for uninitialized fields */ @@ -1960,7 +1986,7 @@ static int declloc(int fstatic) litadd(0); sym=addvariable(name,(cur_lit+glb_declared)*sizeof(cell),ident,sSTATIC, tag,dim,numdim,idxtag); - } else { + } else if (ident!=iREFARRAY) { declared+=(int)size; /* variables are put on stack, adjust "declared" */ sym=addvariable(name,-declared*sizeof(cell),ident,sLOCAL,tag, dim,numdim,idxtag); @@ -1977,6 +2003,15 @@ static int declloc(int fstatic) assert((curfunc->usage & uNATIVE)==0); if (curfunc->x.stacksizex.stacksize=declared+1; /* +1 for PROC opcode */ + } else if (ident==iREFARRAY) { + declared+=1; /* one cell for address */ + sym=addvariable(name,-declared*sizeof(cell),ident,sLOCAL,tag,dim,numdim,idxtag); + //markexpr(sLDECL,name,-declared*sizeof(cell)); /* mark for better optimization */ + /* genarray() pushes the address onto the stack, so we don't need to call modstk() here! */ + markheap(MEMUSE_DYNAMIC, 0); + assert(curfunc != NULL && ((curfunc->usage & uNATIVE) == 0)); + if (curfunc->x.stacksizex.stacksize=declared+1; /* +1 for PROC opcode */ } /* if */ /* now that we have reserved memory for the variable, we can proceed * to initialize it */ @@ -2017,7 +2052,7 @@ static int declloc(int fstatic) * "uWRITTEN" flag that store() set */ if (!explicit_init) sym->usage &= ~uWRITTEN; - } else { + } else if (ident!=iREFARRAY) { /* an array */ assert(cur_lit>=0 && cur_lit<=litidx && litidx<=litmax); assert(size>0 && size>=sym->dim.array.length); @@ -3336,6 +3371,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc } /* if */ declared=0; /* number of local cells */ resetstacklist(); + resetheaplist(); rettype=(sym->usage & uRETVALUE); /* set "return type" variable */ curfunc=sym; define_args(); /* add the symbolic info for the function arguments */ @@ -4773,6 +4809,7 @@ static void compound(int stmt_sameline,int starttok) int endtok; pushstacklist(); + pushheaplist(); /* if there is more text on this line, we should adjust the statement indent */ if (stmt_sameline) { int i; @@ -4812,6 +4849,7 @@ static void compound(int stmt_sameline,int starttok) if (lastst!=tRETURN) destructsymbols(&loctab,nestlevel); if (lastst!=tRETURN && lastst!=tGOTO) { + popheaplist(); popstacklist(); } testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ @@ -5506,6 +5544,7 @@ static void doreturn(void) rettype|=uRETNONE; /* function does not return anything */ } /* if */ destructsymbols(&loctab,0); /* call destructor for *all* locals */ + genheapfree(-1); genstackfree(-1); /* free everything on the stack */ ffret(strcmp(curfunc->name,uENTRYFUNC)!=0); } diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index f4d969af..834aeac5 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -672,6 +672,16 @@ SC_FUNC void popreg(regid reg) code_idx+=opcodes(1); } +/* + * Generate an array + */ +SC_FUNC void genarray(int dims) +{ + stgwrite("\tgenarray "); + outval(dims, TRUE); + code_idx+=opcodes(1)+opargs(1); +} + /* * swap the top-of-stack with the value in primary register */ @@ -846,13 +856,8 @@ SC_FUNC void modheap(int delta) SC_FUNC void modheap_i() { - pushreg(sPRI); - pushreg(sALT); - stgwrite("\tpop.h.pri\n"); - stgwrite("\theap.pri\n"); - code_idx+=opcodes(2); - popreg(sALT); - popreg(sPRI); + stgwrite("\theap.i\n"); + code_idx+=opcodes(1); } SC_FUNC void setheap_save(cell value) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 7539a09b..7dd4a295 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -489,11 +489,12 @@ static OPCODEC opcodelist[] = { {105, "eq.c.pri", sIN_CSEG, parm1 }, /*{124, "file", sIN_CSEG, do_file }, */ {119, "fill", sIN_CSEG, parm1 }, + {162, "genarray", sIN_CSEG, parm1 }, {100, "geq", sIN_CSEG, parm0 }, { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, { 45, "heap", sIN_CSEG, parm1 }, - {160, "heap.pri", sIN_CSEG, parm0 }, + {160, "heap.i", sIN_CSEG, parm0 }, { 27, "idxaddr", sIN_CSEG, parm0 }, { 28, "idxaddr.b", sIN_CSEG, parm1 }, {109, "inc", sIN_CSEG, parm1 }, @@ -544,7 +545,6 @@ static OPCODEC opcodelist[] = { { 84, "not", sIN_CSEG, parm0 }, { 82, "or", sIN_CSEG, parm0 }, { 43, "pop.alt", sIN_CSEG, parm0 }, - {162, "pop.h.pri", sIN_CSEG, parm0 }, { 42, "pop.pri", sIN_CSEG, parm0 }, { 46, "proc", sIN_CSEG, parm0 }, { 40, "push", sIN_CSEG, parm1 }, diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index a5aa3127..b1d312e3 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -121,7 +121,7 @@ int markstack(int type, int size) /** * Generates code to free all heap allocations on a tracker */ -void _heap_freeusage(memuse_list_t *heap) +void _heap_freeusage(memuse_list_t *heap, int dofree) { memuse_t *cur=heap->head; memuse_t *tmp; @@ -133,11 +133,19 @@ void _heap_freeusage(memuse_list_t *heap) } else { modheap_i(); } - tmp=cur->prev; - free(cur); - cur=tmp; + if (dofree) + { + tmp=cur->prev; + free(cur); + cur=tmp; + } else { + cur=cur->prev; + } + } + if (dofree) + { + heap->head=NULL; } - heap->head=NULL; } void _stack_genusage(memuse_list_t *stack, int dofree) @@ -176,7 +184,7 @@ void popheaplist() memuse_list_t *oldlist; assert(heapusage!=NULL); - _heap_freeusage(heapusage); + _heap_freeusage(heapusage, 1); assert(heapusage->head==NULL); oldlist=heapusage->prev; @@ -194,6 +202,16 @@ void genstackfree(int stop_id) } } +void genheapfree(int stop_id) +{ + memuse_list_t *curlist = heapusage; + while (curlist && curlist->list_id > stop_id) + { + _heap_freeusage(curlist, 0); + curlist = curlist->prev; + } +} + void popstacklist() { memuse_list_t *oldlist; @@ -211,3 +229,8 @@ void resetstacklist() { _reset_memlist(&stackusage); } + +void resetheaplist() +{ + _reset_memlist(&heapusage); +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 25be54ab..8cb02b72 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -31,16 +31,18 @@ void pushstacklist(); void popstacklist(); int markstack(int type, int size); /** - * Generates code to free stack usage, but does not pop the list. + * Generates code to free mem usage, but does not pop the list. * This is used for code like dobreak()/docont()/doreturn(). * stop_id is the list at which to stop generating. */ void genstackfree(int stop_id); +void genheapfree(int stop_id); /** - * Resets the stack list by freeing everything + * Resets a mem list by freeing everything */ void resetstacklist(); +void resetheaplist(); extern memuse_list_t *heapusage; extern memuse_list_t *stackusage; From a19823e4c6c5052b1111e8b348c09ffa3cdc516a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Oct 2006 04:08:18 +0000 Subject: [PATCH 0094/1664] fixed dynamic arrays not generating stack correctly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40124 --- sourcepawn/compiler/amx.h | 2 ++ sourcepawn/compiler/sc1.c | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 7c6b3c7e..057b4067 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -620,6 +620,8 @@ typedef enum { OP_SYSREQ_ND, /* ----- */ OP_HEAP_I, + OP_PUSH_H_C, + OP_GENARRAY, OP_NUM_OPCODES } OPCODE; diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index b04da88c..6d4082c0 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1942,7 +1942,6 @@ static int declloc(int fstatic) } while (matchtoken('[')); } else if (matchtoken('(')) { int dim_ident; - int dim_tag; symbol *dim_sym; do { ident=iREFARRAY; @@ -1950,8 +1949,8 @@ static int declloc(int fstatic) error(53); return iREFARRAY; } /* if */ - dim_ident = doexpr(TRUE,FALSE,FALSE,FALSE,&dim_tag,&dim_sym,0); - dim[numdim++] = 1; + dim_ident = doexpr(TRUE,FALSE,FALSE,FALSE,&idxtag[numdim],&dim_sym,0); + dim[numdim] = 0; if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION) { pushreg(sPRI); } else if (dim_ident == iCONSTEXPR) { @@ -1959,9 +1958,8 @@ static int declloc(int fstatic) } else { assert(0); //:TODO: make this an error } - if (!matchtag(tag, dim_tag, FALSE)) - error(213); needtoken(')'); + numdim++; } while (matchtoken('(')); genarray(numdim); } @@ -2009,6 +2007,7 @@ static int declloc(int fstatic) //markexpr(sLDECL,name,-declared*sizeof(cell)); /* mark for better optimization */ /* genarray() pushes the address onto the stack, so we don't need to call modstk() here! */ markheap(MEMUSE_DYNAMIC, 0); + markstack(MEMUSE_STATIC, 1); assert(curfunc != NULL && ((curfunc->usage & uNATIVE) == 0)); if (curfunc->x.stacksizex.stacksize=declared+1; /* +1 for PROC opcode */ From 209dd31751c4a532aab02c60287f64057700dd3d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Oct 2006 04:10:01 +0000 Subject: [PATCH 0095/1664] Added new op.genarray for dynamic arrays Fixed up opcode table for new opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40125 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 64 +++++++++++++++++------- sourcepawn/vm/jit/x86/jit_x86.h | 1 + sourcepawn/vm/jit/x86/opcode_helpers.cpp | 4 ++ sourcepawn/vm/jit/x86/opcode_helpers.h | 9 +++- sourcepawn/vm/jit/x86/opcode_switch.inc | 30 +++++------ sourcepawn/vm/jit/x86/x86_macros.h | 4 +- 6 files changed, 75 insertions(+), 37 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e969e293..9a0f540c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -960,15 +960,55 @@ inline void WriteOp_Fill(JitWriter *jit) IA32_Pop_Reg(jit, REG_EDI); } -inline void WriteOp_Heap_Pri(JitWriter *jit) +inline void WriteOp_Heap_I(JitWriter *jit) { - //mov edx, [esi+hea] - //add [esi+hea], eax - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); + //sub [esi+hea], 4 + //mov ecx, [esi+hea] + //mov ecx, [ebp+ecx] + //sub [esi+hea], ecx + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); + IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); - /* :TODO: should we do a full bounds check here? */ Write_CheckHeap_Min(jit); + Write_CheckHeap_Low(jit); +} + +inline void WriteOp_GenArray(JitWriter *jit) +{ + cell_t val = jit->read_cell(); + if (val == 1) + { + /* flat array. we can generate this without indirection tables. */ + /* Note that we can overwrite ALT because technically STACK should be destroying ALT */ + //mov edx, [esi+info.heap] + //mov ecx, [edi] + //mov [edi], edx ;store base of array into stack + //lea edx, [edx+ecx*4+4] ;get the final new heap pointer + //mov [esi+info.heap], edx ;store heap pointer back + //add edx, ebp ;relocate + //cmp edx, edi ;compare against stack pointer + //jae :error ;error out if not enough space + //shl ecx, 2 + //mov [edx-4], ecx ;store # of cells allocated + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4, 4); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP); + IA32_Add_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); + IA32_Cmp_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); + IA32_Shl_Rm_Imm8(jit, AMX_REG_TMP, 4, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_ALT, AMX_REG_TMP, -4); + } else { + //mov ecx, num_dims + //call [genarray] + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_genarray); + } } inline void WriteOp_Push_Heap_C(JitWriter *jit) @@ -984,18 +1024,6 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) Write_CheckHeap_Low(jit); } -inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) -{ - //sub [esi+hea], 4 - //mov ecx, [esi+hea] - //mov eax, [ebp+ecx] - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); - - Write_CheckHeap_Min(jit); -} - inline void WriteOp_Load_Both(JitWriter *jit) { WriteOp_Load_Pri(jit); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index ee54e78e..88fc895c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -27,6 +27,7 @@ public: jitoffs_t jit_verify_addr_edx; jitoffs_t jit_break; /* call to op.break */ jitoffs_t jit_sysreq_n; /* call version of op.sysreq.n */ + jitoffs_t jit_genarray; /* call to genarray intrinsic */ jitoffs_t jit_error_bounds; jitoffs_t jit_error_divzero; jitoffs_t jit_error_stacklow; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 55b45e71..5263ed52 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -451,6 +451,10 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) IA32_Return(jit); } +void WriteIntrinsic_GenArray(JitWriter *jit) +{ +} + void WriteOp_Sysreq_N_Function(JitWriter *jit) { /* The big daddy of opcodes. diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 5e303efc..3cf1942a 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -16,6 +16,11 @@ jitoffs_t Write_Execute_Function(JitWriter *jit); void WriteOp_Sysreq_N_Function(JitWriter *jit); void WriteOp_Sysreq_C_Function(JitWriter *jit); +/** + * Write the GENARRAY intrinsic function. + */ +void WriteIntrinsic_GenArray(JitWriter *jit); + /** * Generates code to set an error state in the VM and return. * This is used for generating the error set points in the VM. @@ -240,9 +245,9 @@ typedef enum OP_SYSREQ_D, // !GEN UNSUPPORT OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ - OP_HEAP_PRI, //DONE + OP_HEAP_I, // OP_PUSH_HEAP_C, //DONE - OP_POP_HEAP_PRI, //DONE + OP_GENARRAY, // /* ----- */ OP_NUM_OPCODES } OPCODE; diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index 4f389db7..6b2e3946 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -458,21 +458,6 @@ WriteOp_Fill(jit); break; } - case OP_HEAP_PRI: - { - WriteOp_Heap_Pri(jit); - break; - } - case OP_PUSH_HEAP_C: - { - WriteOp_Push_Heap_C(jit); - break; - } - case OP_POP_HEAP_PRI: - { - WriteOp_Pop_Heap_Pri(jit); - break; - } case OP_PUSH_C: { WriteOp_Push_C(jit); @@ -658,6 +643,21 @@ } break; } + case OP_PUSH_HEAP_C: + { + WriteOp_Push_Heap_C(jit); + break; + } + case OP_HEAP_I: + { + WriteOp_Heap_I(jit); + break; + } + case OP_GENARRAY: + { + WriteOp_GenArray(jit); + break; + } #if defined USE_UNGEN_OPCODES #include "ungen_opcode_switch.inc" #endif diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index a742cceb..85c4a1f1 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -82,6 +82,8 @@ #define IA32_CMP_RM_IMM8 0x83 // encoding is /7 #define IA32_CMP_AL_IMM32 0x3C // no extra encoding #define IA32_CMP_EAX_IMM32 0x3D // no extra encoding +#define IA32_CMP_RM_REG 0x39 // encoding is /r +#define IA32_CMP_REG_RM 0x3B // encoding is /r #define IA32_CMPSB 0xA6 // no extra encoding #define IA32_TEST_RM_REG 0x85 // encoding is /r #define IA32_JCC_IMM 0x70 // encoding is +cc @@ -110,8 +112,6 @@ #define IA32_SHR_RM_CL 0xD3 // encoding is /5 #define IA32_SHL_RM_CL 0xD3 // encoding is /4 #define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 -#define IA32_CMP_RM_REG 0x39 // encoding is /r -#define IA32_CMP_REG_RM 0x3B // encoding is /r #define IA32_SETCC_RM8_1 0x0F // opcode part 1 #define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits) #define IA32_XCHG_EAX_REG 0x90 // encoding is +r From eb341f9a1d012a9135433b5e483b5f60de71cb83 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Oct 2006 22:25:18 +0000 Subject: [PATCH 0096/1664] finished dynamic array generation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40126 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 13 +-- sourcepawn/vm/jit/x86/jit_x86.h | 1 + sourcepawn/vm/jit/x86/opcode_helpers.cpp | 133 +++++++++++++++++++++++ sourcepawn/vm/jit/x86/x86_macros.h | 39 ++++++- 4 files changed, 178 insertions(+), 8 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 9a0f540c..7eea2026 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1087,21 +1087,14 @@ inline void WriteOp_Lidx(JitWriter *jit) inline void WriteOp_Stack(JitWriter *jit) { - /* :TODO: Find an instance in the compiler where - * the ALT value from STACK is actually used! - */ - //mov edx, edi //add edi, - //sub edx, ebp cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) { IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); } else { IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); } - IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); if (val > 0) { @@ -1674,6 +1667,9 @@ void WriteErrorRoutines(CompData *data, JitWriter *jit) data->jit_error_heapmin = jit->get_outputpos(); Write_SetError(jit, SP_ERROR_HEAPMIN); + data->jit_error_array_too_big = jit->get_outputpos(); + Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG); + data->jit_extern_error = jit->get_outputpos(); Write_GetError(jit); } @@ -1728,6 +1724,9 @@ jit_rewind: data->jit_sysreq_c = jit->get_outputpos(); WriteOp_Sysreq_C_Function(jit); + data->jit_genarray = jit->get_outputpos(); + WriteIntrinsic_GenArray(jit); + /* Write error checking routines that are called to */ if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 88fc895c..223d68ca 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -35,6 +35,7 @@ public: jitoffs_t jit_error_memaccess; jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; + jitoffs_t jit_error_array_too_big; jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 5263ed52..8e1e3c7f 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -451,8 +451,141 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) IA32_Return(jit); } +void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t dimcount) +{ + cell_t vectors = 1; /* we need one vector to start off with */ + cell_t cur_offs = 0; + cell_t cur_write = 0; + + /* Initialize rotation */ + cur_write = dims[dimcount-1]; + + while (--dimcount >= 1) + { + cell_t cur_dim = dims[dimcount]; + cell_t sub_dim = dims[dimcount-1]; + for (cell_t i=0; iget_outputpos(); + IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX); + jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); + IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4); + IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); + IA32_Add_Rm_Reg(jit, REG_EDX, REG_ECX, MOD_REG); + IA32_Inc_Reg(jit, REG_EAX); + IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1); + IA32_Send_Jump8_Here(jit, done1); + + /* Test if we have heap space for this */ + //mov eax, [esi+info.heap] ;get heap pointer + //lea eax, [eax+edx*4+4] ;new heap pointer + //cmp eax, ;compare to heap low + //jbe :error ;die if we hit this (it should always be >) + //add eax, ebp ;relocate to stack + //cmp eax, edi ;die if above the stack pointer + //jae :error + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4, 4); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size); + IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big); + IA32_Add_Rm_Reg(jit, REG_EAX, AMX_REG_DAT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big); + + /* Prepare for indirection iteration */ + //mov eax, [esi+info.heap] ;get heap pointer + //lea ebx, [eax+edx*4+4] ;new heap pointer + //mov [esi+info.heap], ebx ;store back + //lea ebx, [ebp+ebx-4] ;relocate + //mov [ebx], edx ;store back total size + //push eax ;save heap pointer - we need it + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4, 4); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, REG_EBX, AMX_REG_DAT, REG_EBX, NOSCALE, -4); + IA32_Mov_Rm_Reg(jit, REG_EBX, REG_EDX, MOD_MEM_REG); + IA32_Push_Reg(jit, REG_EAX); + + /* This part is too messy to do in straight assembly. + * I'm letting the compiler handle it and thus it's in C. + */ + //lea ebx, [ebp+eax] ;get base pointer + //push dword [esp-4] ;push dimension count + //push edi ;push dim array + //push ebx + //call GenerateArrayIndirectionVectors + //add esp, 4*3 + IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE); + IA32_Push_Rm_Disp8_ESP(jit, 4); + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_EBX); + IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + + /* Store the heap pointer back into the stack */ + //pop eax ;restore heap pointer + //pop ecx ;restore param count + //lea edi, [edi+ecx*4-4] ;pop params-4 off the stack + //mov [edi], eax ;store back the heap pointer + IA32_Pop_Reg(jit, REG_EAX); + IA32_Pop_Reg(jit, REG_ECX); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4); + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG); + + /* Return to caller */ + //pop eax + //pop ebx + //ret + IA32_Pop_Reg(jit, REG_EAX); + IA32_Pop_Reg(jit, REG_EBX); + IA32_Return(jit); } void WriteOp_Sysreq_N_Function(JitWriter *jit) diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 85c4a1f1..18596535 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -102,10 +102,12 @@ #define IA32_NOT_RM 0xF7 // encoding is /2 #define IA32_DIV_RM 0xF7 // encoding is /6 #define IA32_MUL_RM 0xF7 // encoding is /4 -#define IA32_IMUL_RM 0xF7 // encoding is /5 #define IA32_IDIV_RM 0xF7 // encoding is /7 +#define IA32_IMUL_RM 0xF7 // encoding is /5 #define IA32_IMUL_REG_IMM32 0x69 // encoding is /r #define IA32_IMUL_REG_IMM8 0x6B // encoding is /r +#define IA32_IMUL_REG_RM_1 0x0F // encoding is _2 +#define IA32_IMUL_REG_RM_2 0xAF // encoding is /r #define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 #define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 #define IA32_SAR_RM_CL 0xD3 // encoding is /7 @@ -445,6 +447,13 @@ inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mod jit->write_int32(value); } +inline void IA32_IMul_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_IMUL_REG_RM_1); + jit->write_ubyte(IA32_IMUL_REG_RM_2); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_ADD_RM_REG); @@ -634,6 +643,14 @@ inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8 jit->write_byte(disp8); } +inline void IA32_Push_Rm_Disp8_ESP(JitWriter *jit, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_PUSH_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); + jit->write_byte(disp8); +} + /** * Moving from REGISTER/MEMORY to REGISTER */ @@ -677,6 +694,19 @@ inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); } +inline void IA32_Mov_Reg_Rm_Disp_Reg_Disp8(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t src_scale, + jit_int8_t disp8) +{ + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); + jit->write_byte(disp8); +} + inline void IA32_Mov_Reg_RmEBP_Disp_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, @@ -968,6 +998,13 @@ inline void IA32_Cmp_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } +inline void IA32_Cmp_Reg_Rm_ESP(JitWriter *jit, jit_uint8_t cmpreg) +{ + jit->write_ubyte(IA32_CMP_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, cmpreg, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); +} + inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8) { jit->write_ubyte(IA32_CMP_REG_RM); From e3dccb8ae480ca7011ffcb4c556bb9d4279df17d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Oct 2006 22:25:45 +0000 Subject: [PATCH 0097/1664] new error code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40127 --- sourcepawn/include/sp_vm_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 9a41d4ab..d6dd8989 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -29,6 +29,7 @@ typedef int32_t cell_t; #define SP_ERROR_INSTRUCTION_PARAM 17 /* Instruction had an invalid parameter */ #define SP_ERROR_STACKLEAK 18 /* A native leaked an item on the stack */ #define SP_ERROR_HEAPLEAK 19 /* A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 20 /* A dynamic array is too big */ /********************************************** *** The following structures are reference structures. From 53be062c6b4fe137f96dc3985ea4a0ac3fa0022e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 17 Oct 2006 03:44:37 +0000 Subject: [PATCH 0098/1664] added new op.genarray.z for zeroing arrays --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40128 --- sourcepawn/compiler/sc.h | 2 +- sourcepawn/compiler/sc1.c | 2 +- sourcepawn/compiler/sc4.c | 8 ++++++-- sourcepawn/compiler/sc6.c | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 92f613a5..c6e0e8de 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -590,7 +590,7 @@ SC_FUNC void moveto1(void); SC_FUNC void pushreg(regid reg); SC_FUNC void pushval(cell val); SC_FUNC void popreg(regid reg); -SC_FUNC void genarray(int dims); +SC_FUNC void genarray(int dims, int _autozero); SC_FUNC void swap1(void); SC_FUNC void ffswitch(int label); SC_FUNC void ffcase(cell value,char *labelname,int newtable); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 6d4082c0..50b7c320 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1961,7 +1961,7 @@ static int declloc(int fstatic) needtoken(')'); numdim++; } while (matchtoken('(')); - genarray(numdim); + genarray(numdim, autozero); } if (getstates(name)) error(88,name); /* local variables may not have states */ diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index 834aeac5..a9971783 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -675,9 +675,13 @@ SC_FUNC void popreg(regid reg) /* * Generate an array */ -SC_FUNC void genarray(int dims) +SC_FUNC void genarray(int dims, int _autozero) { - stgwrite("\tgenarray "); + if (_autozero) { + stgwrite("\tgenarray.z "); + } else { + stgwrite("\tgenarray "); + } outval(dims, TRUE); code_idx+=opcodes(1)+opargs(1); } diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 7dd4a295..97ead13e 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -490,6 +490,7 @@ static OPCODEC opcodelist[] = { /*{124, "file", sIN_CSEG, do_file }, */ {119, "fill", sIN_CSEG, parm1 }, {162, "genarray", sIN_CSEG, parm1 }, + {163, "genarray.z", sIN_CSEG, parm1 }, {100, "geq", sIN_CSEG, parm0 }, { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, From 0c67ad1e7d3a8078d96c995077583c2dcee8f4df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 17 Oct 2006 05:50:59 +0000 Subject: [PATCH 0099/1664] added support for op.genarray.z opcode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40129 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 32 +++++++++++++++++++++++- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 26 ++++++++++++++++--- sourcepawn/vm/jit/x86/opcode_helpers.h | 7 +++--- sourcepawn/vm/jit/x86/opcode_switch.inc | 7 +++++- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 7eea2026..450362d9 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -975,7 +975,7 @@ inline void WriteOp_Heap_I(JitWriter *jit) Write_CheckHeap_Low(jit); } -inline void WriteOp_GenArray(JitWriter *jit) +inline void WriteOp_GenArray(JitWriter *jit, bool autozero) { cell_t val = jit->read_cell(); if (val == 1) @@ -1002,10 +1002,40 @@ inline void WriteOp_GenArray(JitWriter *jit) IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); IA32_Shl_Rm_Imm8(jit, AMX_REG_TMP, 4, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_ALT, AMX_REG_TMP, -4); + if (autozero) + { + /* Zero out the array - inline a quick fill */ + //push eax ;save pri + //push edi ;save stk + //xor eax, eax ;zero source + //mov edi, [edi] ;get heap ptr out of the stack + //add edi, ebp ;relocate + //cld ;clear direction flag + //rep stosd ;copy (note: ECX is sane from above) + //pop edi ;pop stk + //pop eax ;pop pri + IA32_Push_Reg(jit, REG_EAX); + IA32_Push_Reg(jit, REG_EDI); + IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_REG); + IA32_Add_Rm_Reg(jit, REG_EDI, REG_EBP, MOD_REG); + IA32_Cld(jit); + IA32_Rep(jit); + IA32_Stosd(jit); + IA32_Pop_Reg(jit, REG_EDI); + IA32_Pop_Reg(jit, REG_EAX); + } } else { //mov ecx, num_dims + //mov edx, 0/1 //call [genarray] IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); + if (autozero) + { + IA32_Mov_Reg_Imm32(jit, REG_EDX, 1); + } else { + IA32_Mov_Reg_Imm32(jit, REG_EDX, 0); + } jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_genarray); } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 8e1e3c7f..d6b6b54e 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -451,11 +451,12 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) IA32_Return(jit); } -void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t dimcount) +void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero) { cell_t vectors = 1; /* we need one vector to start off with */ cell_t cur_offs = 0; cell_t cur_write = 0; + cell_t dimcount = _dimcount; /* Initialize rotation */ cur_write = dims[dimcount-1]; @@ -476,6 +477,17 @@ void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t d vectors = cur_dim; } + /* everything after cur_offs can be zeroed */ + if (autozero) + { + size_t size = 1; + for (ucell_t i=0; i<_dimcount; i++) + { + size *= dims[i]; + } + memset(&arraybase[cur_offs], 0, size*sizeof(cell_t)); + } + return; } @@ -492,9 +504,11 @@ void WriteIntrinsic_GenArray(JitWriter *jit) */ //push ebx //push eax + //push edx //push ecx ;value is referenced on stack IA32_Push_Reg(jit, REG_EBX); IA32_Push_Reg(jit, REG_EAX); + IA32_Push_Reg(jit, REG_EDX); IA32_Push_Reg(jit, REG_ECX); /** @@ -557,17 +571,19 @@ void WriteIntrinsic_GenArray(JitWriter *jit) * I'm letting the compiler handle it and thus it's in C. */ //lea ebx, [ebp+eax] ;get base pointer - //push dword [esp-4] ;push dimension count + //push dword [esp-8] ;push autozero + //push dword [esp-8] ;push dimension count //push edi ;push dim array //push ebx //call GenerateArrayIndirectionVectors //add esp, 4*3 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE); - IA32_Push_Rm_Disp8_ESP(jit, 4); + IA32_Push_Rm_Disp8_ESP(jit, 8); + IA32_Push_Rm_Disp8_ESP(jit, 8); IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); /* Store the heap pointer back into the stack */ //pop eax ;restore heap pointer @@ -580,9 +596,11 @@ void WriteIntrinsic_GenArray(JitWriter *jit) IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG); /* Return to caller */ + //pop edx //pop eax //pop ebx //ret + IA32_Pop_Reg(jit, REG_ECX); IA32_Pop_Reg(jit, REG_EAX); IA32_Pop_Reg(jit, REG_EBX); IA32_Return(jit); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 3cf1942a..0afe8498 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -245,9 +245,10 @@ typedef enum OP_SYSREQ_D, // !GEN UNSUPPORT OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ - OP_HEAP_I, // - OP_PUSH_HEAP_C, //DONE - OP_GENARRAY, // + OP_HEAP_I, //VERIFIED + OP_PUSH_HEAP_C, //VERIFIED + OP_GENARRAY, //VERIFIED + OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays) /* ----- */ OP_NUM_OPCODES } OPCODE; diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index 6b2e3946..d5786fec 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -655,7 +655,12 @@ } case OP_GENARRAY: { - WriteOp_GenArray(jit); + WriteOp_GenArray(jit, false); + break; + } + case OP_GENARRAY_Z: + { + WriteOp_GenArray(jit, true); break; } #if defined USE_UNGEN_OPCODES From 2f9a5a224e82a8a91177c37dafa35ff9603c4106 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 20 Oct 2006 23:03:16 +0000 Subject: [PATCH 0100/1664] Pairing and other asm optimizations made ungen_opcodes.h Compile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40130 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 68 ++++++++++++++---------- sourcepawn/vm/jit/x86/jit_x86.h | 1 - sourcepawn/vm/jit/x86/opcode_helpers.cpp | 40 +++++++------- sourcepawn/vm/jit/x86/opcode_helpers.h | 18 +++++++ sourcepawn/vm/jit/x86/ungen_opcodes.h | 10 ++-- sourcepawn/vm/jit/x86/x86_macros.h | 40 ++++++++++---- 6 files changed, 112 insertions(+), 65 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 450362d9..3dc39273 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -253,13 +253,14 @@ inline void WriteOp_Proc(JitWriter *jit) IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); //save frame: - //:TODO: move to a temp reg, subtract and then move to mem, faster?? - //mov [esi+frm], edi - get new frame + //mov ecx, edi - get new frame //mov ebx, edi - store frame back - //sub [esi+frm], ebp - relocate local frame - IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_STK, MOD_MEM_REG); + //sub ecx, ebp - relocate local frame + //mov [esi+frm], ecx + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); - IA32_Sub_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_DAT, MOD_MEM_REG); + IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG); } inline void WriteOp_Lidx_B(JitWriter *jit) @@ -888,17 +889,19 @@ inline void WriteOp_Swap_Alt(JitWriter *jit) inline void WriteOp_PushAddr(JitWriter *jit) { //mov ecx, [esi+frm] ;get address (offset from frame) - //add ecx, - //mov [edi-4], ecx //sub edi, 4 + //add ecx, + //mov [edi], ecx cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); - else - IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + if (val < SCHAR_MAX && val > SCHAR_MIN) + { + IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); + } else { + IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG); + } + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } inline void WriteOp_Movs(JitWriter *jit) @@ -1217,7 +1220,12 @@ inline void WriteOp_Bounds(JitWriter *jit) //cmp eax, //ja :error - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, val); + if (val < SCHAR_MAX && val > SCHAR_MIN) + { + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); + } else { + IA32_Cmp_Eax_Imm32(jit, val); + } IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds); } @@ -1405,9 +1413,9 @@ inline void WriteOp_Switch(JitWriter *jit) * ECX still has the correctly bound offset in it, luckily! * thus, we simply need to relocate ECX and store the cases. */ - //shl ecx, 2 + //lea ecx, [ecx*4] //add ecx, - IA32_Shl_Rm_Imm8(jit, AMX_REG_TMP, 2, MOD_REG); + IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0); jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); /* The case table starts here. Go back and write the output pointer. */ @@ -1472,7 +1480,7 @@ inline void WriteOp_Sysreq_C(JitWriter *jit) } //mov ecx, - IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG); + IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index); jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c); @@ -1494,8 +1502,8 @@ inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) //mov eax, //mov ecx, - IA32_Mov_Rm_Imm32(jit, REG_EAX, num_params, MOD_REG); - IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG); + IA32_Mov_Reg_Imm32(jit, REG_EAX, num_params); + IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index); jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n); @@ -1528,27 +1536,31 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //push edi ; stack //push ; native index IA32_Push_Reg(jit, AMX_REG_STK); - IA32_Push_Imm32(jit, native_index); + if (native_index < SCHAR_MAX && native_index > SCHAR_MIN) + { + IA32_Push_Imm8(jit, (jit_int8_t)native_index); + } else { + IA32_Push_Imm32(jit, native_index); + } /* Relocate stack, heap, frm information, then store back */ - //sub edi, ebp - //mov ecx, [esi+hea] //mov eax, [esi+context] + //mov ecx, [esi+hea] + //sub edi, ebp //mov [eax+hp], ecx + //mov ecx, [esi] //mov [eax+sp], edi - //mov ecx, [esi+frm] //mov [eax+frm], ecx - IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); /* finally, push the last parameter and make the call */ //push eax ; context - //mov eax, [eax+context] //call NativeCallback IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); @@ -1564,7 +1576,7 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -1572,7 +1584,7 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //add edi, ebp //pop edx IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_ALT); /* pop the stack. do not check the margins. diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 223d68ca..28673ecd 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -74,7 +74,6 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_INFO_RETVAL 8 //physical #define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_STACKTOP 16 //relocated -#define AMX_INFO_STACKTOP_U 20 //not relocated extern ISourcePawnEngine *engine; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index d6b6b54e..993f30e7 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -4,7 +4,7 @@ #include "opcode_helpers.h" #include "x86_macros.h" -#define NUM_INFO_PARAMS 6 +#define NUM_INFO_PARAMS 5 jitoffs_t Write_Execute_Function(JitWriter *jit) { @@ -63,11 +63,9 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) /* Info memory setup */ //mov ecx, [eax+] - copy memsize to temp var - //mov [esi+x], ecx - store unrelocated //add ecx, ebp - relocate //mov [esi+x], ecx - store relocated IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U); IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); @@ -277,9 +275,9 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg) */ /* Part 1: Check if we're in the memory bounds */ - //cmp , [esi+info.stpu] + //cmp , //jae :error - IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP_U); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory); IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess); /* Part 2: Check if we're in the invalid region between HP and SP */ @@ -404,19 +402,19 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) IA32_Push_Reg(jit, REG_ECX); /* Relocate stack, heap, frm information, then store back */ - //sub edi, ebp - //mov ecx, [esi+hea] //mov eax, [esi+context] + //mov ecx, [esi+hea] + //sub edi, ebp //mov [eax+hp], ecx + //mov ecx, [esi] //mov [eax+sp], edi - //mov ecx, [esi+frm] //mov [eax+frm], ecx - IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); /* finally, push the last parameter and make the call */ @@ -436,7 +434,7 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -444,7 +442,7 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) //add edi, ebp //pop edx IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_ALT); //ret @@ -633,19 +631,19 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Push_Reg(jit, REG_ECX); /* Relocate stack, heap, frm information, then store back */ - //sub edi, ebp - //mov ecx, [esi+hea] //mov eax, [esi+context] + //mov ecx, [esi+hea] + //sub edi, ebp //mov [eax+hp], ecx + //mov ecx, [esi] //mov [eax+sp], edi - //mov ecx, [esi+frm] //mov [eax+frm], ecx - IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); /* finally, push the last parameter and make the call */ @@ -665,7 +663,7 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -674,7 +672,7 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) //pop edx //pop ecx ; num_params IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_ALT); IA32_Pop_Reg(jit, REG_ECX); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 0afe8498..669b9215 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -253,4 +253,22 @@ typedef enum OP_NUM_OPCODES } OPCODE; +/* +* :TODO: List of ASM Opts +* from jit_x86.cpp +* TODO: all new array opcodes (4 ATM) +* DONE: Rest of opcodes including the SYSREQ.N inlined version (rev2) +* DONE: ALL ungen opcodes (rev1) +* from opcode_helpers.cpp +* DONE: SYSREQ.N .C (rev2) +* MACRO OPCODES (rev2) +* ERROR CHECKS\{VERIFY ADDR} (rev2) +* TODO: BrkDebug +* ARRAY STUFF +* EXEC FUNCTION +* VERIFY ADDR +* +* Oh and ALIGN all stuff that is called via CALL like what's done with PROC. +*/ + #endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h index 94836acf..f720946d 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcodes.h +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -113,7 +113,7 @@ inline void WriteOp_Cmps(JitWriter *jit) inline void WriteOp_Lodb_I(JitWriter *jit) { - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); //mov eax, [ebp+eax] IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); @@ -137,7 +137,7 @@ inline void WriteOp_Lodb_I(JitWriter *jit) inline void WriteOp_Strb_I(JitWriter *jit) { - Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + Write_Check_VerifyAddr(jit, AMX_REG_ALT); //mov [ebp+edx], eax cell_t val = jit->read_cell(); switch (val) @@ -211,10 +211,10 @@ inline void WriteOp_Lctrl(JitWriter *jit) { //mov eax, [cip] jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - jitoffs_t save = jit->jit_curpos(); - jit->setpos(imm32); + jitoffs_t save = jit->get_outputpos(); + jit->set_outputpos(imm32); jit->write_int32((uint32_t)(jit->outbase + save)); - jit->setpos(save); + jit->set_outputpos(save); break; } } diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 18596535..68e13426 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -16,16 +16,17 @@ #define SCALE8 3 //Register codes -#define REG_EAX 0 -#define REG_ECX 1 -#define REG_EDX 2 -#define REG_EBX 3 -#define REG_ESP 4 -#define REG_SIB 4 -#define REG_NOIDX 4 -#define REG_EBP 5 -#define REG_ESI 6 -#define REG_EDI 7 +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_SIB 4 +#define REG_NOIDX 4 +#define REG_IMM_BASE 5 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 #define IA32_16BIT_PREFIX 0x66 @@ -122,6 +123,7 @@ #define IA32_PUSH_REG 0x50 // encoding is +r #define IA32_PUSH_RM 0xFF // encoding is /6 #define IA32_PUSH_IMM32 0x68 // encoding is +#define IA32_PUSH_IMM8 0x6A // encoding is #define IA32_REP 0xF3 // no extra encoding #define IA32_MOVSD 0xA5 // no extra encoding #define IA32_MOVSB 0xA4 // no extra encoding @@ -592,6 +594,18 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit->write_byte(val); } +inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_index, + jit_uint8_t scale, + jit_int32_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, REG_IMM_BASE)); + jit->write_int32(val); +} + inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) { jit->write_ubyte(IA32_LEA_REG_MEM); @@ -620,6 +634,12 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(IA32_PUSH_REG+reg); } +inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val) +{ + jit->write_ubyte(IA32_PUSH_IMM8); + jit->write_byte(val); +} + inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val) { jit->write_ubyte(IA32_PUSH_IMM32); From 0196df3cc96573ffdb2f774aeb8bf6ce265ff1d8 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 26 Oct 2006 17:06:30 +0000 Subject: [PATCH 0101/1664] oh didn't notice these shift instructions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40131 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 28 ++++++++++++++++++++++++---- sourcepawn/vm/jit/x86/x86_macros.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 3dc39273..a55fb07e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -312,28 +312,48 @@ inline void WriteOp_Shl_C_Pri(JitWriter *jit) { //shl eax, jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + if (val == 1) + { + IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG); + } else { + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + } } inline void WriteOp_Shl_C_Alt(JitWriter *jit) { //shl edx, jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); + if (val == 1) + { + IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG); + } else { + IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); + } } inline void WriteOp_Shr_C_Pri(JitWriter *jit) { //shr eax, jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + if (val == 1) + { + IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG); + } else { + IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); + } } inline void WriteOp_Shr_C_Alt(JitWriter *jit) { //shr edx, jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); + if (val == 1) + { + IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG); + } else { + IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); + } } inline void WriteOp_SMul(JitWriter *jit) diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 68e13426..a99904e1 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -110,7 +110,9 @@ #define IA32_IMUL_REG_RM_1 0x0F // encoding is _2 #define IA32_IMUL_REG_RM_2 0xAF // encoding is /r #define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 +#define IA32_SHR_RM_1 0xD1 // encoding is /5 #define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 +#define IA32_SHL_RM_1 0xD1 // encoding is /4 #define IA32_SAR_RM_CL 0xD3 // encoding is /7 #define IA32_SHR_RM_CL 0xD3 // encoding is /5 #define IA32_SHL_RM_CL 0xD3 // encoding is /4 @@ -292,6 +294,12 @@ inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value jit->write_ubyte(value); } +inline void IA32_Shr_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_SHR_RM_1); + jit->write_ubyte(ia32_modrm(mode, 5, dest)); +} + inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { jit->write_ubyte(IA32_SHL_RM_IMM8); @@ -299,6 +307,12 @@ inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value jit->write_ubyte(value); } +inline void IA32_Shl_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_SHL_RM_1); + jit->write_ubyte(ia32_modrm(mode, 4, dest)); +} + inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) { jit->write_ubyte(IA32_SAR_RM_IMM8); From 4f5f8dced9ca6a158c428a93a010b937a6cc3b87 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 31 Oct 2006 07:17:23 +0000 Subject: [PATCH 0102/1664] arrays can now be public variables --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40132 --- sourcepawn/compiler/sc1.c | 4 +++- sourcepawn/compiler/sc6.c | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 50b7c320..5944a520 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1678,8 +1678,10 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst if (size > INT_MAX) error(105); /* overflow, exceeding capacity */ #endif +#if 0 /* We don't actually care */ if (ispublic) error(56,name); /* arrays cannot be public */ +#endif dim[numdim++]=(int)size; } /* while */ assert(sc_curstates==0); @@ -1857,7 +1859,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst assert(sym!=NULL); sc_curstates=0; if (ispublic) - sym->usage|=uPUBLIC; + sym->usage|=uPUBLIC|uREAD; if (fconst) sym->usage|=uCONST; if (fstock) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 97ead13e..1c397fd5 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -713,7 +713,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) assert(sym->vclass==sGLOBAL); mainaddr=sym->addr; } /* if */ - } else if (sym->ident==iVARIABLE) { + } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) { if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) match=++numpubvars; } /* if */ @@ -891,7 +891,8 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) /* write the public variables table */ count=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { + if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY) + && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { assert((sym->usage & uDEFINE)!=0); assert(sym->vclass==sGLOBAL); func.address=sym->addr; From 4d44a1df4fd60db66e7f4b793ad29ef17a9fec1a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 31 Oct 2006 08:31:14 +0000 Subject: [PATCH 0103/1664] Fixed a bug where dynamic arrays might not be freed in loops --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40133 --- sourcepawn/compiler/sc1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 5944a520..189b9238 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -5574,6 +5574,7 @@ static void docont(void) return; destructsymbols(&loctab,nestlevel); genstackfree(ptr[wqCONT]); + genheapfree(ptr[wqCONT]); jumplabel(ptr[wqLOOP]); } From a10aabaedafa264579797e1845e57a9af57c3c09 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 2 Nov 2006 18:36:38 +0000 Subject: [PATCH 0104/1664] swapped usage to new tracker opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40134 --- sourcepawn/compiler/sc4.c | 4 ++-- sourcepawn/compiler/sc6.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index a9971783..ff8045c3 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -860,14 +860,14 @@ SC_FUNC void modheap(int delta) SC_FUNC void modheap_i() { - stgwrite("\theap.i\n"); + stgwrite("\ttracker.pop.setheap\n"); code_idx+=opcodes(1); } SC_FUNC void setheap_save(cell value) { assert(value); - stgwrite("\tpush.h.c "); + stgwrite("\ttracker.push.c "); outval(value, TRUE); code_idx+=opcodes(1)+opargs(1); } diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 1c397fd5..970583aa 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -495,7 +495,6 @@ static OPCODEC opcodelist[] = { { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, { 45, "heap", sIN_CSEG, parm1 }, - {160, "heap.i", sIN_CSEG, parm0 }, { 27, "idxaddr", sIN_CSEG, parm0 }, { 28, "idxaddr.b", sIN_CSEG, parm1 }, {109, "inc", sIN_CSEG, parm1 }, @@ -552,7 +551,6 @@ static OPCODEC opcodelist[] = { {133, "push.adr", sIN_CSEG, parm1 }, /* version 4 */ { 37, "push.alt", sIN_CSEG, parm0 }, { 39, "push.c", sIN_CSEG, parm1 }, - {161, "push.h.c", sIN_CSEG, parm1 }, { 36, "push.pri", sIN_CSEG, parm0 }, { 38, "push.r", sIN_CSEG, parm1 }, /* obsolete (never generated) */ { 41, "push.s", sIN_CSEG, parm1 }, @@ -615,6 +613,8 @@ static OPCODEC opcodelist[] = { {123, "sysreq.c", sIN_CSEG, parm1 }, {135, "sysreq.n", sIN_CSEG, parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */ {122, "sysreq.pri", sIN_CSEG, parm0 }, + {161, "tracker.pop.setheap", sIN_CSEG, parm0 }, + {160, "tracker.push.c", sIN_CSEG, parm1 }, { 76, "udiv", sIN_CSEG, parm0 }, { 77, "udiv.alt", sIN_CSEG, parm0 }, { 75, "umul", sIN_CSEG, parm0 }, From 5b9ba35f0f000d2541541808546a16808c41c30e Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 2 Nov 2006 20:23:14 +0000 Subject: [PATCH 0105/1664] added new tracker opcodes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40135 --- sourcepawn/include/sp_vm_types.h | 1 + sourcepawn/vm/jit/x86/jit_x86.cpp | 130 ++++++++++++++++++----- sourcepawn/vm/jit/x86/jit_x86.h | 10 ++ sourcepawn/vm/jit/x86/opcode_helpers.cpp | 36 +++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 10 +- sourcepawn/vm/jit/x86/opcode_switch.inc | 8 +- sourcepawn/vm/jit/x86/x86_macros.h | 7 ++ 7 files changed, 168 insertions(+), 34 deletions(-) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index d6dd8989..e6973b74 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -30,6 +30,7 @@ typedef int32_t cell_t; #define SP_ERROR_STACKLEAK 18 /* A native leaked an item on the stack */ #define SP_ERROR_HEAPLEAK 19 /* A native leaked an item on the heap */ #define SP_ERROR_ARRAY_TOO_BIG 20 /* A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 21 /* Tracker stack is out of bounds */ /********************************************** *** The following structures are reference structures. diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index a55fb07e..6a48bbd2 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -983,21 +983,6 @@ inline void WriteOp_Fill(JitWriter *jit) IA32_Pop_Reg(jit, REG_EDI); } -inline void WriteOp_Heap_I(JitWriter *jit) -{ - //sub [esi+hea], 4 - //mov ecx, [esi+hea] - //mov ecx, [ebp+ecx] - //sub [esi+hea], ecx - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); - IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); - - Write_CheckHeap_Min(jit); - Write_CheckHeap_Low(jit); -} - inline void WriteOp_GenArray(JitWriter *jit, bool autozero) { cell_t val = jit->read_cell(); @@ -1064,19 +1049,6 @@ inline void WriteOp_GenArray(JitWriter *jit, bool autozero) } } -inline void WriteOp_Push_Heap_C(JitWriter *jit) -{ - //mov ecx, [esi+hea] - //mov [ebp+ecx], - //add [esi+hea], 4 - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_RmEBP_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - - Write_CheckHeap_Low(jit); -} - inline void WriteOp_Load_Both(JitWriter *jit) { WriteOp_Load_Pri(jit); @@ -1622,6 +1594,97 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) } } +inline void WriteOp_Tracker_Push_C(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + cell_t val = jit->read_cell(); + + /* Save registers that may be damaged by the call */ + //push eax + //push edx + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* Get the context ptr, push it and call the check */ + //mov eax, [esi+context] + //push eax + //call JIT_VerifyOrAllocateTracker + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); + + /* Check for errors */ + //pop eax + //cmp [eax+err], 0 + //jnz :error + IA32_Pop_Reg(jit, REG_EAX); + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + + /* Push the value into the stack and increment pCur */ + //mov edx, [eax+vm[]] + //mov ecx, [edx+pcur] + //mov [ecx], + //add [edx+pcur], 4 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); + IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_MEM_REG); + IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + + /* Restore PRI & ALT */ + //pop edx + //pop eax + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + +inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + + /* Save registers that may be damaged by the call */ + //push eax + //push edx + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* Get the context ptr, push it and call the check */ + //mov eax, [esi+context] + //push eax + //call JIT_VerifyLowBoundTracker + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker); + + /* Check for errors */ + //pop eax + //cmp [eax+err], 0 + //jnz :error + IA32_Pop_Reg(jit, REG_EAX); + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + + /* Pop the value from the stack and decrease the heap by it*/ + //mov edx, [eax+vm[]] + //sub [edx+pcur], 4 + //mov ecx, [edx+pcur] + //mov ecx, [ecx] + //sub [esi+hea], ecx + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); + IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG); + IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); + + /* Restore PRI & ALT */ + //pop edx + //pop eax + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1732,6 +1795,9 @@ void WriteErrorRoutines(CompData *data, JitWriter *jit) data->jit_error_array_too_big = jit->get_outputpos(); Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG); + data->jit_error_tracker_bounds = jit->get_outputpos(); + Write_SetError(jit, SP_ERROR_TRACKER_BOUNDS); + data->jit_extern_error = jit->get_outputpos(); Write_GetError(jit); } @@ -1969,6 +2035,12 @@ jit_rewind: } } + tracker_t *trk = new tracker_t; + ctx->vm[JITVARS_TRACKER] = trk; + trk->pBase = (ucell_t *)malloc(1024); + trk->pCur = trk->pBase; + trk->size = 1024; + /* clean up relocation+compilation memory */ AbortCompilation(co); @@ -1999,6 +2071,8 @@ void JITX86::FreeContext(sp_context_t *ctx) delete [] ctx->publics; delete [] ctx->pubvars; delete [] ctx->symbols; + free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); + delete ctx->vm[JITVARS_TRACKER]; delete ctx; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 28673ecd..f4f40f4c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -11,6 +11,15 @@ using namespace SourcePawn; #define JIT_INLINE_NATIVES (1<<1) #define STACK_MARGIN 64 //8 parameters of safety, I guess +#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble + +typedef struct tracker_s +{ + size_t size; + ucell_t *pBase; + ucell_t *pCur; +} tracker_t; + class CompData : public ICompilation { public: @@ -36,6 +45,7 @@ public: jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; jitoffs_t jit_error_array_too_big; + jitoffs_t jit_error_tracker_bounds; jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 993f30e7..a00dffda 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "jit_x86.h" #include "opcode_helpers.h" #include "x86_macros.h" @@ -687,3 +688,38 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Return(jit); } +void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) +{ + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); + + if ((size_t)(trk->pCur - trk->pBase) >= trk->size) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + return; + } + + if (trk->pCur+1 - (trk->pBase + trk->size) == 0) + { + size_t disp = trk->size - 1; + trk->size *= 2; + trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size); + + if (!trk->pBase) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + return; + } + + trk->pCur = trk->pBase + disp; + } +} + +void JIT_VerifyLowBoundTracker(sp_context_t *ctx) +{ + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); + + if (trk->pCur <= trk->pBase) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + } +} \ No newline at end of file diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 669b9215..f47e85bc 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -66,6 +66,12 @@ void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); void Macro_PushN(JitWriter *jit, int i); +/** +* Bound checking for the tracker stack, +*/ +void JIT_VerifyLowBoundTracker(sp_context_t *ctx); +void JIT_VerifyOrAllocateTracker(sp_context_t *ctx); + /** * Legend for Statuses: * ****** *** ******** @@ -245,8 +251,8 @@ typedef enum OP_SYSREQ_D, // !GEN UNSUPPORT OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ - OP_HEAP_I, //VERIFIED - OP_PUSH_HEAP_C, //VERIFIED + OP_TRACKER_PUSH_C, //DONE + OP_TRACKER_POP_SETHEAP, //DONE OP_GENARRAY, //VERIFIED OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays) /* ----- */ diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index d5786fec..febe45e6 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -643,14 +643,14 @@ } break; } - case OP_PUSH_HEAP_C: + case OP_TRACKER_PUSH_C: { - WriteOp_Push_Heap_C(jit); + WriteOp_Tracker_Push_C(jit); break; } - case OP_HEAP_I: + case OP_TRACKER_POP_SETHEAP: { - WriteOp_Heap_I(jit); + WriteOp_Tracker_Pop_SetHeap(jit); break; } case OP_GENARRAY: diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index a99904e1..e623c6c8 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -398,6 +398,13 @@ inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp8); } +inline void IA32_Sub_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_SUB_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(disp8); +} + inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_RM_IMM8); From fca7456f4d4e1b71b5eb0b355c55c97acb96c81b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 2 Nov 2006 20:48:15 +0000 Subject: [PATCH 0106/1664] removed the old heap setting code for arrays --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40136 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 11 +++++------ sourcepawn/vm/jit/x86/opcode_helpers.cpp | 14 ++++++-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 6a48bbd2..2991e402 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -993,23 +993,22 @@ inline void WriteOp_GenArray(JitWriter *jit, bool autozero) //mov edx, [esi+info.heap] //mov ecx, [edi] //mov [edi], edx ;store base of array into stack - //lea edx, [edx+ecx*4+4] ;get the final new heap pointer + //lea edx, [edx+ecx*4] ;get the final new heap pointer //mov [esi+info.heap], edx ;store heap pointer back //add edx, ebp ;relocate //cmp edx, edi ;compare against stack pointer //jae :error ;error out if not enough space - //shl ecx, 2 - //mov [edx-4], ecx ;store # of cells allocated IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4, 4); + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP); IA32_Add_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); IA32_Cmp_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); - IA32_Shl_Rm_Imm8(jit, AMX_REG_TMP, 4, MOD_REG); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_ALT, AMX_REG_TMP, -4); + + /* :TODO: PUSH ECX ONTO TRACKER */ + if (autozero) { /* Zero out the array - inline a quick fill */ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index a00dffda..35203f2a 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -538,14 +538,14 @@ void WriteIntrinsic_GenArray(JitWriter *jit) /* Test if we have heap space for this */ //mov eax, [esi+info.heap] ;get heap pointer - //lea eax, [eax+edx*4+4] ;new heap pointer + //lea eax, [eax+edx*4] ;new heap pointer //cmp eax, ;compare to heap low //jbe :error ;die if we hit this (it should always be >) //add eax, ebp ;relocate to stack //cmp eax, edi ;die if above the stack pointer //jae :error IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Lea_Reg_DispRegMultImm8(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4, 4); + IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4); IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size); IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big); IA32_Add_Rm_Reg(jit, REG_EAX, AMX_REG_DAT, MOD_REG); @@ -554,17 +554,15 @@ void WriteIntrinsic_GenArray(JitWriter *jit) /* Prepare for indirection iteration */ //mov eax, [esi+info.heap] ;get heap pointer - //lea ebx, [eax+edx*4+4] ;new heap pointer + //lea ebx, [eax+edx*4] ;new heap pointer //mov [esi+info.heap], ebx ;store back - //lea ebx, [ebp+ebx-4] ;relocate - //mov [ebx], edx ;store back total size //push eax ;save heap pointer - we need it IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Lea_Reg_DispRegMultImm8(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4, 4); + IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP); - IA32_Lea_Reg_DispRegMultImm8(jit, REG_EBX, AMX_REG_DAT, REG_EBX, NOSCALE, -4); - IA32_Mov_Rm_Reg(jit, REG_EBX, REG_EDX, MOD_MEM_REG); IA32_Push_Reg(jit, REG_EAX); + + /* :TODO: Push EDX into tracker */ /* This part is too messy to do in straight assembly. * I'm letting the compiler handle it and thus it's in C. From bc16901bd6941c5c775bdfca5d20b5e59f59302f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 3 Nov 2006 06:14:43 +0000 Subject: [PATCH 0107/1664] Expanded weak function pointers with type checking Added function typing enumeration --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40137 --- sourcepawn/compiler/pawncc.c | 2 +- sourcepawn/compiler/sc.h | 100 ++++++++------ sourcepawn/compiler/sc1.c | 228 +++++++++++++++++++++++++++++++- sourcepawn/compiler/sc2.c | 2 +- sourcepawn/compiler/sc3.c | 195 ++++++++++++++++++++++++++- sourcepawn/compiler/sctracker.c | 84 ++++++++++++ sourcepawn/compiler/sctracker.h | 38 ++++++ 7 files changed, 596 insertions(+), 53 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index ff78485c..dc919128 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) int err; uint32_t i; sp_file_t *spf; - memfile_t *dbgtab = NULL; + memfile_t *dbgtab = NULL; //dbgcrab unsigned char *dbgptr = NULL; uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0}; FILE *fp; diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index c6e0e8de..ecd01dd0 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -57,6 +57,8 @@ #define sDEF_AMXSTACK 4096 /* default stack size for AMX files */ #define PREPROC_TERM '\x7f'/* termination character for preprocessor expressions (the "DEL" code) */ #define sDEF_PREFIX "sourcemod.inc" /* default prefix filename */ +#define sARGS_MAX 32 /* number of arguments a function can have, max */ +#define sTAGS_MAX 16 /* maximum number of tags on an argument */ typedef union { void *pv; /* e.g. a name */ @@ -283,7 +285,7 @@ typedef struct s_stringpair { */ #define tFIRST 256 /* value of first multi-character operator */ #define tMIDDLE 280 /* value of last multi-character operator */ -#define tLAST 329 /* value of last multi-character match-able token */ +#define tLAST 330 /* value of last multi-character match-able token */ /* multi-character operators */ #define taMULT 256 /* *= */ #define taDIV 257 /* /= */ @@ -327,51 +329,52 @@ typedef struct s_stringpair { #define tEXIT 294 #define tFOR 295 #define tFORWARD 296 -#define tGOTO 297 -#define tIF 298 -#define tNATIVE 299 -#define tNEW 300 -#define tDECL 301 -#define tOPERATOR 302 -#define tPUBLIC 303 -#define tRETURN 304 -#define tSIZEOF 305 -#define tSLEEP 306 -#define tSTATE 307 -#define tSTATIC 308 -#define tSTOCK 309 -#define tSWITCH 310 -#define tTAGOF 311 -#define tTHEN 312 -#define tWHILE 313 +#define tFUNCENUM 297 +#define tGOTO 298 +#define tIF 299 +#define tNATIVE 300 +#define tNEW 301 +#define tDECL 302 +#define tOPERATOR 303 +#define tPUBLIC 304 +#define tRETURN 305 +#define tSIZEOF 306 +#define tSLEEP 307 +#define tSTATE 308 +#define tSTATIC 309 +#define tSTOCK 310 +#define tSWITCH 311 +#define tTAGOF 312 +#define tTHEN 313 +#define tWHILE 314 /* compiler directives */ -#define tpASSERT 314 /* #assert */ -#define tpDEFINE 315 -#define tpELSE 316 /* #else */ -#define tpELSEIF 317 /* #elseif */ -#define tpEMIT 318 -#define tpENDIF 319 -#define tpENDINPUT 320 -#define tpENDSCRPT 321 -#define tpERROR 322 -#define tpFILE 323 -#define tpIF 324 /* #if */ -#define tINCLUDE 325 -#define tpLINE 326 -#define tpPRAGMA 327 -#define tpTRYINCLUDE 328 -#define tpUNDEF 329 +#define tpASSERT 315 /* #assert */ +#define tpDEFINE 316 +#define tpELSE 317 /* #else */ +#define tpELSEIF 318 /* #elseif */ +#define tpEMIT 319 +#define tpENDIF 320 +#define tpENDINPUT 321 +#define tpENDSCRPT 322 +#define tpERROR 323 +#define tpFILE 324 +#define tpIF 325 /* #if */ +#define tINCLUDE 326 +#define tpLINE 327 +#define tpPRAGMA 328 +#define tpTRYINCLUDE 329 +#define tpUNDEF 330 /* semicolon is a special case, because it can be optional */ -#define tTERM 330 /* semicolon or newline */ -#define tENDEXPR 331 /* forced end of expression */ +#define tTERM 331 /* semicolon or newline */ +#define tENDEXPR 332 /* forced end of expression */ /* other recognized tokens */ -#define tNUMBER 332 /* integer number */ -#define tRATIONAL 333 /* rational number */ -#define tSYMBOL 334 -#define tLABEL 335 -#define tSTRING 336 -#define tEXPR 337 /* for assigment to "lastst" only (see SC1.C) */ -#define tENDLESS 338 /* endless loop, for assigment to "lastst" only */ +#define tNUMBER 333 /* integer number */ +#define tRATIONAL 334 /* rational number */ +#define tSYMBOL 335 +#define tLABEL 336 +#define tSTRING 337 +#define tEXPR 338 /* for assigment to "lastst" only (see SC1.C) */ +#define tENDLESS 339 /* endless loop, for assigment to "lastst" only */ /* (reversed) evaluation of staging buffer */ #define sSTARTREORDER 0x01 @@ -432,9 +435,11 @@ typedef enum s_optmark { #if INT_MAX<0x8000u #define PUBLICTAG 0x8000u #define FIXEDTAG 0x4000u + #define FUNCTAG 0x2000u #else #define PUBLICTAG 0x80000000Lu #define FIXEDTAG 0x40000000Lu + #define FUNCTAG 0x20000000Lu #endif #define TAGMASK (~PUBLICTAG) #define CELL_MAX (((ucell)1 << (sizeof(cell)*8-1)) - 1) @@ -451,6 +456,7 @@ typedef enum s_optmark { int pc_compile(int argc, char **argv); int pc_addconstant(char *name,cell value,int tag); int pc_addtag(char *name); +int pc_addfunctag(char *name); int pc_enablewarning(int number,int enable); /* @@ -517,6 +523,7 @@ SC_FUNC void delete_consttable(constvalue *table); SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag); SC_FUNC void exporttag(int tag); SC_FUNC void sc_attachdocumentation(symbol *sym); +SC_FUNC constvalue *find_tag_byval(int tag); /* function prototypes in SC2.C */ #define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); } @@ -801,6 +808,7 @@ SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecate SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ +SC_VDECL int pc_functag; /* global function tag */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ SC_VDECL constvalue sc_state_tab; /* state table */ @@ -815,6 +823,12 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */ SC_VDECL int sc_makereport; /* generate a cross-reference report */ #endif +#if defined WIN32 +#if !defined snprintf +#define snprintf _snprintf +#endif +#endif + #endif /* SC_SKIP_VDECL */ #endif /* SC_H_INCLUDED */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 189b9238..656d9297 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -70,6 +70,8 @@ #define VERSION_STR "3.2." SVN_REVSTR #define VERSION_INT 0x0302 +int pc_functag = 0; + static void resetglobals(void); static void initglobals(void); static char *get_extension(char *filename); @@ -126,6 +128,7 @@ static void doswitch(void); static void dogoto(void); static void dolabel(void); static void doreturn(void); +static void dofuncenum(void); static void dobreak(void); static void docont(void); static void dosleep(void); @@ -320,6 +323,7 @@ int pc_compile(int argc, char *argv[]) inst_datetime_defines(); #endif resetglobals(); + funcenums_free(); sc_ctrlchar=sc_ctrlchar_org; sc_packstr=lcl_packstr; sc_needsemicolon=lcl_needsemicolon; @@ -380,6 +384,7 @@ int pc_compile(int argc, char *argv[]) /* reset "defined" flag of all functions and global variables */ reduce_referrers(&glbtab); delete_symbols(&glbtab,0,TRUE,FALSE); + funcenums_free(); #if !defined NO_DEFINE delete_substtable(); inst_datetime_defines(); @@ -577,6 +582,7 @@ int pc_addtag(char *name) if (strcmp(name,ptr->name)==0) return tag; /* tagname is known, return its sequence number */ tag &= (int)~FIXEDTAG; + tag &= (int)~FUNCTAG; if (tag>last) last=tag; ptr=ptr->next; @@ -590,6 +596,43 @@ int pc_addtag(char *name) return tag; } +int pc_addfunctag(char *name) +{ + cell val; + constvalue *ptr; + int last,tag; + + if (name==NULL) { + /* no tagname was given, check for one */ + if (lex(&val,&name)!=tLABEL) { + lexpush(); + return 0; /* untagged */ + } /* if */ + } /* if */ + + assert(strchr(name,':')==NULL); /* colon should already have been stripped */ + last=0; + ptr=tagname_tab.next; + while (ptr!=NULL) { + tag=(int)(ptr->value & TAGMASK); + if (strcmp(name,ptr->name)==0) + return tag; /* tagname is known, return its sequence number */ + tag &= (int)~FIXEDTAG; + tag &= (int)~FUNCTAG; + if (tag>last) + last=tag; + ptr=ptr->next; + } /* while */ + + /* tagname currently unknown, add it */ + tag=last+1; /* guaranteed not to exist already */ + if (isupper(*name)) + tag |= (int)FIXEDTAG; + tag |= (int)FUNCTAG; + append_constval(&tagname_tab,name,(cell)tag,0); + return tag; +} + static void resetglobals(void) { /* reset the subset of global variables that is modified by the first pass */ @@ -1204,6 +1247,7 @@ static void setconstants(void) assert(sc_status==statIDLE); append_constval(&tagname_tab,"_",0,0);/* "untagged" */ append_constval(&tagname_tab,"bool",1,0); + pc_functag = pc_addfunctag("Function"); add_constant("true",1,sGLOBAL,1); /* boolean flags */ add_constant("false",0,sGLOBAL,1); @@ -1363,6 +1407,9 @@ static void parse(void) case tENUM: decl_enum(sGLOBAL); break; + case tFUNCENUM: + dofuncenum(); + break; case tPUBLIC: /* This can be a public function or a public variable; see the comment * above (for static functions/variables) for details. @@ -2536,6 +2583,185 @@ static void decl_const(int vclass) needtoken(tTERM); } +/* dofuncenum - declare function enumerations + * + */ +static void dofuncenum(void) +{ + cell val; + char *str,*ptr; + char tagname[sNAMEMAX+1]; + constvalue *cur; + funcenum_t *fenum = NULL; + int i; + + /* get the explicit tag (required!) */ + int l = lex(&val,&str); + if (l != tSYMBOL) + { + /* Incomprehensible but it works for now! */ + error(57); + } + + /* This tag can't already exist! */ + cur=tagname_tab.next; + while (cur) + { + if (strcmp(cur->name, str) == 0) + { + /* Another bad one... */ + if (!(cur->value & FUNCTAG)) + { + error(213); + } + break; + } + cur = cur->next; + } + strcpy(tagname, str); + + fenum = funcenums_add(tagname); + + needtoken('{'); + do + { + functag_t func; + if (matchtoken('}')) + { + /* Quick exit */ + lexpush(); + break; + } + memset(&func, 0, sizeof(func)); + func.ret_tag = pc_addtag(NULL); /* Get the return tag */ + l = lex(&val, &str); + if (l == tFORWARD) + { + func.type = uFORWARD; + } else if (l == tPUBLIC) { + func.type = uPUBLIC; + } else { + error(1, "[forward,public]", str); + } + needtoken('('); + do + { + funcarg_t *arg = &(func.args[func.argcount]); + + /* Quick exit */ + if (matchtoken(')')) + { + lexpush(); + break; + } + l = lex(&val, &str); + if (l == '&') + { + if ((arg->ident != iVARIABLE && arg->ident != 0) || arg->tagcount > 0) + { + error(1, "-identifier-", "&"); + } + arg->ident = iREFERENCE; + } else if (l == tCONST) { + if ((arg->ident != iVARIABLE && arg->ident != 0) || arg->tagcount > 0) + { + error(1, "-identifier-", "const"); + } + arg->fconst=TRUE; + } else if (l == tLABEL) { + if (arg->tagcount > 0) + { + error(1, "-identifier-", "-tagname-"); + } + arg->tags[arg->tagcount++] = pc_addtag(str); +#if 0 + while (arg->tagcount < sTAGS_MAX) + { + if (!matchtoken('_') && !needtoken(tSYMBOL)) + { + break; + } + tokeninfo(&val, &ptr); + arg->tags[arg->tagcount++] = pc_addtag(ptr); + if (matchtoken('}')) + { + break; + } + needtoken(','); + } + needtoken(':'); +#endif + l=tLABEL; + } else if (l == tSYMBOL) { + if (func.argcount >= sARGS_MAX) + { + error(45); + } + if (str[0] == PUBLIC_CHAR) + { + error(56, str); + } + if (matchtoken('[')) + { + if (arg->ident == iREFERENCE) + { + error(67, str); + } + do + { + constvalue *enumroot; + cell size; + int ignore_tag; + if (arg->dimcount == sDIMEN_MAX) + { + error(53); + break; + } + size = needsub(&ignore_tag, &enumroot); + arg->dims[arg->dimcount] = size; + arg->dimcount += 1; + } while (matchtoken('[')); + arg->ident=iREFARRAY; + } else if (arg->ident == 0) { + arg->ident = iVARIABLE; + } + + if (matchtoken('=')) + { + needtoken('0'); + arg->ommittable = TRUE; + func.ommittable = TRUE; + } else if (func.ommittable) { + /* :TODO: ERROR HERE! */ + } + func.argcount++; + } else if (l == tELLIPS) { + if (arg->ident == iVARIABLE) + { + error(10); + } + arg->ident = iVARARGS; + func.argcount++; + } else { + error(10); + } + } while (l == '&' || l == tLABEL || l == tCONST || l != tELLIPS && matchtoken(',')); + needtoken(')'); + for (i=0; i=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", "assert", "*begin", "break", "case", "char", "const", "continue", "default", - "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "goto", + "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", "sleep", "state", "static", "stock", "switch", "tagof", "*then", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index fba92491..4e7e47a6 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -288,8 +288,178 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) /* if the formal tag is zero and the actual tag is not "fixed", the actual * tag is "coerced" to zero */ - if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) - return FALSE; + if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) { + if (formaltag & FUNCTAG) + { + if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG)) + { + return TRUE; + } else if (actualtag & FUNCTAG) { + constvalue *v = find_tag_byval(actualtag); + int index; + short usage = uPUBLIC; + symbol *sym, *found = NULL; + funcenum_t *e; + functag_t *t; + + if (strncmp(v->name, "$Func", 5) != 0) + { + return FALSE; + } + + /* Now we have to go about looking up each function in this enum. WHICH IS IT. */ + e = funcenums_find_byval(formaltag); + if (!e) + { + return FALSE; + } + + assert(v->name[5] == '@' || v->name[5] == '!'); + + /* Deduce which function type this is */ + if (v->name[5] == '@') + { + usage = uPUBLIC; + } else if (v->name[5] = '!') { + usage = uFORWARD; + } + + index = atoi(&v->name[6]); + + assert(index >= 0); + + /* Find the function, either by public idx or code addr */ + if (usage == uPUBLIC) + { + for (sym=glbtab.next; sym!=NULL; sym=sym->next) { + if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->vclass == sGLOBAL)) + { + if (index-- == 0) + { + found = sym; + break; + } + } + } + } else if (usage == uFORWARD) { + for (sym=glbtab.next; sym!=NULL; sym=sym->next) { + if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) + { + if (sym->codeaddr == index) + { + found = sym; + break; + } + } + } + } + + if (!found) + { + assert(found); + return FALSE; + } + + /* Wow, we now have: + * 1) The functional enum deduced from formaltag + * 2) The function trying to be shoved in deduced from actualtag + * Now we have to check if it matches any one of the functags inside the enum. + */ + t = e->first; + while (t) + { + int curarg,skip=0,i; + arginfo *func_arg; + funcarg_t *enum_arg; + /* Check return type first. */ + if (t->ret_tag != sym->tag) + { + t = t->next; + continue; + } + /* Check usage */ + if (t->type != usage) + { + t = t->next; + continue; + } + /* Begin iterating arguments */ + for (curarg=0; curargargcount; curarg++) + { + enum_arg = &t->args[curarg]; + /* Check whether we've exhausted our arguments */ + if (sym->dim.arglist[curarg].ident == 0) + { + /* Can we bail out early? */ + if (!enum_arg->ommittable) + { + /* No! */ + skip = 1; + } + break; + } + func_arg = &sym->dim.arglist[curarg]; + /* First check the ident type */ + if (enum_arg->ident != func_arg->ident) + { + skip = 1; + break; + } + /* Next check arrayness */ + if (enum_arg->dimcount != func_arg->numdim) + { + skip = 1; + break; + } + if (enum_arg->dimcount > 0) + { + for (i=0; idimcount; i++) + { + if (enum_arg->dims[i] != func_arg->dim[i]) + { + skip = 1; + break; + } + } + if (skip) + { + break; + } + } + /* Lastly, check the tags */ + if (enum_arg->tagcount != func_arg->numtags) + { + skip = 1; + break; + } + /* They should all be in the same order just for clarity... */ + for (i=0; itagcount; i++) + { + if (enum_arg->tags[i] != func_arg->tags[i]) + { + skip = 1; + break; + } + } + if (skip) + { + break; + } + } + if (!skip) + { + /* Make sure there are no trailing arguments */ + if (sym->dim.arglist[curarg].ident == 0) + { + return TRUE; + } + } + t = t->next; + } + } + } + return FALSE; + } } /* if */ return TRUE; } @@ -1723,24 +1893,35 @@ restart: if (sc_allowproccall) { callfunction(sym,lval1,FALSE); } else { + symbol *oldsym=sym; int n=-1,iter=0; + int usage = ((sym->usage & uPUBLIC) == uPUBLIC) ? uPUBLIC : 0; + cell code_addr=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN - && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) + if (sym->ident==iFUNCTN && sym->vclass == sGLOBAL && (!usage || (sym->usage & usage))) { - assert(sym->vclass==sGLOBAL); if (strcmp(sym->name, lval1->sym->name)==0) { n = iter; + code_addr = sym->codeaddr; break; } iter++; } } if (n!=-1) { + char faketag[sNAMEMAX+1]; lval1->sym=NULL; lval1->ident=iCONSTEXPR; - lval1->constval=n; - lval1->tag=pc_addtag("Function"); + /* Generate a quick pseudo-tag! */ + if (usage == uPUBLIC) { + lval1->constval=(n>>1)|(1<<1); + snprintf(faketag, sizeof(faketag)-1, "$Func@%d", n); + } else { + lval1->constval=(code_addr>>1)|(1<<0); + snprintf(faketag, sizeof(faketag)-1, "$Func!%d", code_addr); + } + lval1->tag=pc_addfunctag(faketag); + oldsym->usage |= uREAD; } else { error(76); /* invalid function call, or syntax error */ } /* if */ diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index b1d312e3..308bd751 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -1,10 +1,94 @@ #include +#include #include #include "sc.h" #include "sctracker.h" memuse_list_t *heapusage = NULL; memuse_list_t *stackusage = NULL; +funcenum_t *firstenum = NULL; +funcenum_t *lastenum = NULL; + +void funcenums_free() +{ + funcenum_t *e, *next; + + e = firstenum; + while (e) + { + functag_t *tag, *nexttag; + tag = e->first; + while (tag) + { + nexttag = tag->next; + free(tag); + tag = nexttag; + } + next = e->next; + free(e); + e = next; + } + + firstenum = NULL; + lastenum = NULL; +} + +funcenum_t *funcenums_find_byval(int value) +{ + funcenum_t *e = firstenum; + + while (e) + { + if (e->value == value) + { + return e; + } + e = e->next; + } + + return NULL; +} + +funcenum_t *funcenums_add(const char *name) +{ + funcenum_t *e = (funcenum_t *)malloc(sizeof(funcenum_t)); + + memset(e, 0, sizeof(funcenum_t)); + + if (firstenum == NULL) + { + firstenum = e; + lastenum = e; + } else { + lastenum->next = e; + lastenum = e; + } + + strcpy(e->name, name); + e->value = pc_addfunctag((char *)name); + + return e; +} + +functag_t *functags_add(funcenum_t *en, functag_t *src) +{ + functag_t *t = (functag_t *)malloc(sizeof(functag_t)); + + memcpy(t, src, sizeof(functag_t)); + + t->next = NULL; + + if (en->first == NULL) + { + en->first = t; + en->last = t; + } else { + en->last->next = t; + en->last = t; + } + + return t; +} /** * Creates a new mem usage tracker entry diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 8cb02b72..1e05a2c7 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -16,6 +16,44 @@ typedef struct memuse_list_s { memuse_t *head; /* head of the current list */ } memuse_list_t; +typedef struct funcarg_s +{ + int tagcount; + int tags[sTAGS_MAX]; + int dimcount; + cell dims[sDIMEN_MAX]; + int ident; + int fconst; + int ommittable; +} funcarg_t; + +typedef struct functag_s +{ + int ret_tag; + int type; + int argcount; + int ommittable; + funcarg_t args[sARGS_MAX]; + struct functag_s *next; +} functag_t; + +typedef struct funcenum_s +{ + int value; + char name[sNAMEMAX+1]; + functag_t *first; + functag_t *last; + struct funcenum_s *next; +} funcenum_t; + +/** + * Function enumeration tags + */ +void funcenums_free(); +funcenum_t *funcenums_add(const char *name); +funcenum_t *funcenums_find_byval(int value); +functag_t *functags_add(funcenum_t *en, functag_t *src); + /** * Heap functions */ From f95dd901ca17e04798d1bf9f9e619517875e8850 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 4 Nov 2006 18:00:27 +0000 Subject: [PATCH 0108/1664] added this to encode strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40138 --- sourcepawn/compiler/scpack.c | 450 +++++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 sourcepawn/compiler/scpack.c diff --git a/sourcepawn/compiler/scpack.c b/sourcepawn/compiler/scpack.c new file mode 100644 index 00000000..37d553c8 --- /dev/null +++ b/sourcepawn/compiler/scpack.c @@ -0,0 +1,450 @@ +/* compress.c -- Byte Pair Encoding compression */ +/* Copyright 1996 Philip Gage */ + +/* This program appeared in the September 1997 issue of + * C/C++ Users Journal. The original source code may still + * be found at the web site of the magazine (www.cuj.com). + * + * It has been modified by me (Thiadmer Riemersma) to + * compress only a section of the input file and to store + * the compressed output along with the input as "C" strings. + * + * Compiling instructions: + * Borland C++ 16-bit (large memory model is required): + * bcc -ml scpack.c + * + * Watcom C/C++ 32-bit: + * wcl386 scpack.c + * + * GNU C (Linux), 32-bit: + * gcc scpack.c -o scpack + */ + +#include +#include +#include +#include +#include + +#if UINT_MAX > 0xFFFFU + #define MAXSIZE 1024*1024L +#else + #define MAXSIZE UINT_MAX /* Input file buffer size */ +#endif +#define HASHSIZE 8192 /* Hash table size, power of 2 */ +#define THRESHOLD 3 /* Increase for speed, min 3 */ + +#define START_TOKEN "#ifdef SCPACK" /* start reading the buffer here */ +#define NAME_TOKEN "#define SCPACK_TABLE" +#define SEP_TOKEN "#define SCPACK_SEPARATOR" +#define TERM_TOKEN "#define SCPACK_TERMINATOR" +#define TEMPFILE "~SCPACK.TMP" +static char tablename[32+1] = "scpack_table"; +static char separator[16]=","; +static char terminator[16]=""; + +int compress(unsigned char *buffer, unsigned buffersize, unsigned char pairtable[128][2]) +{ + unsigned char *left, *right, *count; + unsigned char a, b, bestcount; + unsigned i, j, index, bestindex, code=128; + + /* Dynamically allocate buffers and check for errors */ + left = (unsigned char *)malloc(HASHSIZE); + right = (unsigned char *)malloc(HASHSIZE); + count = (unsigned char *)malloc(HASHSIZE); + if (left==NULL || right==NULL || count==NULL) { + printf("Error allocating memory\n"); + exit(1); + } + + /* Check for errors */ + for (i=0; i 127) { + printf("This program works only on text files (7-bit ASCII)\n"); + exit(1); + } + + memset(pairtable, 0, 128*2*sizeof(char)); + + do { /* Replace frequent pairs with bytes 128..255 */ + + /* Enter counts of all byte pairs into hash table */ + memset(count,0,HASHSIZE); + for (i=0; i bestcount) { + bestcount = count[i]; + bestindex = i; + } + } + + /* Compress if enough occurrences of pair */ + if (bestcount >= THRESHOLD) { + + /* Add pair to table using code as index */ + a = pairtable[code-128][0] = left[bestindex]; + b = pairtable[code-128][1] = right[bestindex]; + + /* Replace all pair occurrences with unused byte */ + for (i=0, j=0; i= 128 || *bufptr == '"' || *bufptr == '\\') + fprintf(output, "\\%03o", *bufptr); + else + fprintf(output, "%c", *bufptr); + bufptr++; + } /* while */ + fprintf(output, "\""); + needseparator = 1; + bufptr++; /* skip '\0' */ + } /* while */ + fprintf(output, "%s\n",terminator); + bufptr++; + + /* skip the input file until the #endif section */ + while (fgets(str,sizeof str,input)!=NULL) { + if (strmatch(str,"#endif",NULL)) { + fprintf(output,"%s",str); + break; /* done */ + } /* if */ + } /* while */ + } /* while - !feof(input) */ +} + +static void usage(void) +{ + printf("Usage: scpack [output file]\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *in, *out; + unsigned char *buffer; + unsigned buffersize, orgbuffersize; + unsigned char pairtable[128][2]; + + if (argc < 2 || argc > 3) + usage(); + if ((in=fopen(argv[1],"rt"))==NULL) { + printf("SCPACK: error opening input %s\n",argv[1]); + usage(); + } /* if */ + if (argc == 2) { + if ((out=fopen(TEMPFILE,"wt"))==NULL) { + printf("SCPACK: error opening temporary file %s\n",TEMPFILE); + usage(); + } /* if */ + } else { + if ((out=fopen(argv[2],"wt"))==NULL) { + printf("SCPACK: error opening output file %s\n",argv[2]); + usage(); + } /* if */ + } /* if */ + + buffer = (unsigned char *)malloc(MAXSIZE); + if (buffer == NULL) { + printf("SCPACK: error allocating memory\n"); + return 1; + } /* if */ + /* 1. read the buffer + * 2. compress the buffer + * 3. copy the file, insert the compressed buffer + */ + buffersize = readbuffer(in, buffer); + orgbuffersize = buffersize; + if (buffersize > 0) { + buffersize = compress(buffer, buffersize, pairtable); + writefile(in, out, buffer, buffersize, pairtable); + printf("SCPACK: compression ratio: %ld%% (%d -> %d)\n", + 100L-(100L*buffersize)/orgbuffersize, orgbuffersize, buffersize); + } else { + printf("SCPACK: no SCPACK section found, nothing to do\n"); + } /* if */ + fclose(out); + fclose(in); + /* let the new file replace the old file */ + if (buffersize == 0) { + if (argc == 2) + remove(TEMPFILE); + else + remove(argv[2]); + } else if (argc == 2) { + remove(argv[1]); + rename(TEMPFILE,argv[1]); + } /* if */ + return 0; +} From 0ece7914b77c9171788b845b33613c8eb3c656d8 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 4 Nov 2006 18:30:20 +0000 Subject: [PATCH 0109/1664] added tracker push helper dyn arrays are working now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40139 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 18 +++--- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 78 +++++++++++++++++++++--- sourcepawn/vm/jit/x86/opcode_helpers.h | 9 ++- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 2991e402..ca066953 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1003,11 +1003,11 @@ inline void WriteOp_GenArray(JitWriter *jit, bool autozero) IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP); - IA32_Add_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); - IA32_Cmp_Rm_Reg(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); + IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); + IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); - /* :TODO: PUSH ECX ONTO TRACKER */ + WriteOp_Tracker_Push_Reg(jit, REG_ECX); if (autozero) { @@ -1024,8 +1024,8 @@ inline void WriteOp_GenArray(JitWriter *jit, bool autozero) IA32_Push_Reg(jit, REG_EAX); IA32_Push_Reg(jit, REG_EDI); IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_REG); - IA32_Add_Rm_Reg(jit, REG_EDI, REG_EBP, MOD_REG); + IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG); + IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); IA32_Cld(jit); IA32_Rep(jit); IA32_Stosd(jit); @@ -1624,11 +1624,11 @@ inline void WriteOp_Tracker_Push_C(JitWriter *jit) /* Push the value into the stack and increment pCur */ //mov edx, [eax+vm[]] //mov ecx, [edx+pcur] - //mov [ecx], + //mov [ecx], *4 ; we want the count in bytes not in cells //add [edx+pcur], 4 IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_MEM_REG); + IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG); IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); /* Restore PRI & ALT */ @@ -1677,6 +1677,8 @@ inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG); IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); + Write_CheckHeap_Min(jit); + /* Restore PRI & ALT */ //pop edx //pop eax @@ -2038,7 +2040,7 @@ jit_rewind: ctx->vm[JITVARS_TRACKER] = trk; trk->pBase = (ucell_t *)malloc(1024); trk->pCur = trk->pBase; - trk->size = 1024; + trk->size = 1024 / sizeof(cell_t); /* clean up relocation+compilation memory */ AbortCompilation(co); diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 35203f2a..555b3605 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -107,7 +107,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP); IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp)); - IA32_Mov_Rm_Reg(jit, REG_ECX, REG_EDX, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp)); //add esp, 4*NUM_INFO_PARAMS //pop ebx @@ -521,7 +521,7 @@ void WriteIntrinsic_GenArray(JitWriter *jit) //mov ecx, [edi+eax*4] ;get dimension size //imul edx, ecx ;multiply by size //add edx, ecx ;add size (indirection vector) - //inc eax ;increment + //add eax, 1 ;increment //jmp :loop ;jump back //:done IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG); @@ -531,8 +531,8 @@ void WriteIntrinsic_GenArray(JitWriter *jit) jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4); IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); - IA32_Add_Rm_Reg(jit, REG_EDX, REG_ECX, MOD_REG); - IA32_Inc_Reg(jit, REG_EAX); + IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG); IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1); IA32_Send_Jump8_Here(jit, done1); @@ -548,7 +548,7 @@ void WriteIntrinsic_GenArray(JitWriter *jit) IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4); IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size); IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big); - IA32_Add_Rm_Reg(jit, REG_EAX, AMX_REG_DAT, MOD_REG); + IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG); IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG); IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big); @@ -562,7 +562,7 @@ void WriteIntrinsic_GenArray(JitWriter *jit) IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP); IA32_Push_Reg(jit, REG_EAX); - /* :TODO: Push EDX into tracker */ + WriteOp_Tracker_Push_Reg(jit, REG_EDX); /* This part is too messy to do in straight assembly. * I'm letting the compiler handle it and thus it's in C. @@ -686,6 +686,70 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Return(jit); } +void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) +{ + CompData *data = (CompData *)jit->data; + + //:TODO: optimize reg usage, i dont like it. + + /* Save registers that may be damaged by the call */ + //push eax + //push edx + //push ecx + //push + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Push_Reg(jit, AMX_REG_ALT); + IA32_Push_Reg(jit, AMX_REG_TMP); + if (reg != REG_ECX) + { + IA32_Push_Reg(jit, reg); + } + + /* Get the context ptr, push it and call the check */ + //mov eax, [esi+context] + //push eax + //call JIT_VerifyOrAllocateTracker + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); + + /* Check for errors */ + //pop eax + //cmp [eax+err], 0 + //jnz :error + IA32_Pop_Reg(jit, REG_EAX); + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + + /* Push the register into the stack and increment pCur */ + //pop ecx + //mov edx, [eax+vm[]] + //mov eax, [edx+pcur] + //lea ecx, [ecx*4] ; we want the count in bytes not in cells + //mov [eax], ecx + //add [edx+pcur], 4 + IA32_Pop_Reg(jit, REG_ECX); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur)); + IA32_Lea_Reg_RegMultImm32(jit, REG_ECX, REG_ECX, SCALE4, 0); + IA32_Mov_Rm_Reg(jit, REG_EAX, REG_ECX, MOD_MEM_REG); + IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + + /* Restore PRI, ALT and STK */ + //pop ecx + //pop edx + //pop eax + if (reg != REG_ECX) + { + IA32_Pop_Reg(jit, AMX_REG_ALT); + } else { + IA32_Shr_Rm_Imm8(jit, REG_ECX, 2, MOD_REG); + } + IA32_Pop_Reg(jit, AMX_REG_TMP); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) { tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); @@ -700,7 +764,7 @@ void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) { size_t disp = trk->size - 1; trk->size *= 2; - trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size); + trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t)); if (!trk->pBase) { diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index f47e85bc..5cddf40f 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -72,6 +72,11 @@ void Macro_PushN(JitWriter *jit, int i); void JIT_VerifyLowBoundTracker(sp_context_t *ctx); void JIT_VerifyOrAllocateTracker(sp_context_t *ctx); +/** +* Writes the push into tracker function. +*/ +void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg); + /** * Legend for Statuses: * ****** *** ******** @@ -252,7 +257,7 @@ typedef enum OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ OP_TRACKER_PUSH_C, //DONE - OP_TRACKER_POP_SETHEAP, //DONE + OP_TRACKER_POP_SETHEAP, //VERIFIED OP_GENARRAY, //VERIFIED OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays) /* ----- */ @@ -262,8 +267,8 @@ typedef enum /* * :TODO: List of ASM Opts * from jit_x86.cpp -* TODO: all new array opcodes (4 ATM) * DONE: Rest of opcodes including the SYSREQ.N inlined version (rev2) +* Including genarray and the 2 tracker ones * DONE: ALL ungen opcodes (rev1) * from opcode_helpers.cpp * DONE: SYSREQ.N .C (rev2) From 8099cb09bd993c89dd47e5b9e85b391ca520b93e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 4 Nov 2006 18:54:03 +0000 Subject: [PATCH 0110/1664] made these names a little nicer --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40140 --- sourcepawn/include/sp_vm_types.h | 7 +- sourcepawn/vm/jit/x86/jit_x86.cpp | 20 ++--- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 2 +- sourcepawn/vm/sp_vm_basecontext.cpp | 22 ++--- sourcepawn/vm/test_main.cpp | 110 ----------------------- 5 files changed, 26 insertions(+), 135 deletions(-) delete mode 100644 sourcepawn/vm/test_main.cpp diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index e6973b74..5dff68ca 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -218,9 +218,10 @@ typedef struct sp_context_s uint32_t flags; /* compilation flags */ SPVM_DEBUGBREAK dbreak; /* debug break function */ /* context runtime information */ - ucell_t memory; /* total memory size; */ - uint8_t *data; /* data chunk */ - cell_t heapbase; /* heap base */ + uint8_t *memory; /* data chunk */ + ucell_t mem_size; /* total memory size; */ + cell_t data_size; /* data chunk size, always starts at 0 */ + cell_t heap_base; /* where the heap starts */ /* execution specific data */ cell_t hp; /* heap pointer */ cell_t sp; /* stack pointer */ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index ca066953..8898563d 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1712,7 +1712,7 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; - if (ctx->hp < ctx->heapbase) + if (ctx->hp < ctx->heap_base) { ctx->err = SP_ERROR_HEAPMIN; return 0; @@ -1724,7 +1724,7 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param return 0; } - if ((uint32_t)ctx->sp >= ctx->memory) + if ((uint32_t)ctx->sp >= ctx->mem_size) { ctx->err = SP_ERROR_STACKMIN; return 0; @@ -1936,12 +1936,12 @@ jit_rewind: ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); /* setup memory */ - ctx->data = new uint8_t[plugin->memory]; - memcpy(ctx->data, plugin->data, plugin->data_size); - ctx->memory = plugin->memory; - ctx->heapbase = plugin->data_size; - ctx->hp = ctx->heapbase; - ctx->sp = ctx->memory - sizeof(cell_t); + ctx->memory = new uint8_t[plugin->memory]; + memcpy(ctx->memory, plugin->data, plugin->data_size); + ctx->mem_size = plugin->memory; + ctx->heap_base = plugin->data_size; + ctx->hp = ctx->heap_base; + ctx->sp = ctx->mem_size - sizeof(cell_t); const char *strbase = plugin->info.stringbase; uint32_t max, iter; @@ -1960,7 +1960,7 @@ jit_rewind: /* relocate pubvar info */ if ((max = plugin->info.pubvars_num)) { - uint8_t *dat = ctx->data; + uint8_t *dat = ctx->memory; ctx->pubvars = new sp_pubvar_t[max]; for (iter=0; iterExecFree(ctx->codebase); - delete [] ctx->data; + delete [] ctx->memory; delete [] ctx->files; delete [] ctx->lines; delete [] ctx->natives; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 555b3605..1aa0d670 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -52,7 +52,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory)); /* Frame setup */ //mov edi, [eax+] - get stack pointer diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index 34c38b23..f147aa1b 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -113,7 +113,7 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys return SP_ERROR_HEAPLOW; } - addr = (cell_t *)(ctx->data + ctx->hp); + addr = (cell_t *)(ctx->memory + ctx->hp); /* store size of allocation in cells */ *addr = (cell_t)cells; addr++; @@ -138,12 +138,12 @@ int BaseContext::HeapPop(cell_t local_addr) /* check the bounds of this address */ local_addr -= sizeof(cell_t); - if (local_addr < ctx->heapbase || local_addr >= ctx->sp) + if (local_addr < ctx->heap_base || local_addr >= ctx->sp) { return SP_ERROR_INVALID_ADDRESS; } - addr = (cell_t *)(ctx->data + local_addr); + addr = (cell_t *)(ctx->memory + local_addr); cellcount = (*addr) * sizeof(cell_t); /* check if this memory count looks valid */ if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) @@ -159,7 +159,7 @@ int BaseContext::HeapPop(cell_t local_addr) int BaseContext::HeapRelease(cell_t local_addr) { - if (local_addr < ctx->heapbase) + if (local_addr < ctx->heap_base) { return SP_ERROR_INVALID_ADDRESS; } @@ -394,14 +394,14 @@ int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) { - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; } if (phys_addr) { - *phys_addr = (cell_t *)(ctx->data + local_addr); + *phys_addr = (cell_t *)(ctx->memory + local_addr); } return SP_ERROR_NONE; @@ -415,7 +415,7 @@ int BaseContext::PushCell(cell_t value) } ctx->sp -= sizeof(cell_t); - *(cell_t *)(ctx->data + ctx->sp) = value; + *(cell_t *)(ctx->memory + ctx->sp) = value; ctx->pushcount++; return SP_ERROR_NONE; @@ -470,12 +470,12 @@ int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength int len = 0; cell_t *src; - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; } - src = (cell_t *)(ctx->data + local_addr); + src = (cell_t *)(ctx->memory + local_addr); while ((*src != '\0') && ((size_t)len < maxlength)) { buffer[len++] = (char)*src++; @@ -534,13 +534,13 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *sour cell_t *dest; int i, len; - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory)) + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; } len = strlen(source); - dest = (cell_t *)(ctx->data + local_addr); + dest = (cell_t *)(ctx->memory + local_addr); if ((size_t)len >= chars) { diff --git a/sourcepawn/vm/test_main.cpp b/sourcepawn/vm/test_main.cpp deleted file mode 100644 index c22c7dba..00000000 --- a/sourcepawn/vm/test_main.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include -#include "sp_vm_engine.h" -#include "sp_vm_basecontext.h" -#define WINDOWS_LEAN_AND_MEAN -#include - -using namespace SourcePawn; - -typedef void (*GIVEENGINE)(ISourcePawnEngine *); -typedef IVirtualMachine *(*GETEXPORT)(unsigned int); - -cell_t TestNative(sp_context_t *ctx, cell_t *params) -{ - IPluginContext *pl = ctx->context; - cell_t *phys; - int err; - printf("params[0] = %d\n", params[0]); - printf("params[1] = %d\n", params[1]); - if ((err=pl->LocalToPhysAddr(params[2], &phys)) != SP_ERROR_NONE) - { - ctx->err = err; - return 0; - } - printf("params[2] %c%c%c%c%c\n", phys[0], phys[1], phys[2], phys[3], phys[4]); - if ((err=pl->LocalToPhysAddr(params[3], &phys)) != SP_ERROR_NONE) - { - ctx->err = err; - return 0; - } - printf("params[3] = %d\n", *phys); - *phys = 95; - return 5; -} - -int main() -{ - SourcePawnEngine engine; - IVirtualMachine *vm; - ICompilation *co; - sp_plugin_t *plugin = NULL; - sp_context_t *ctx = NULL; - cell_t result; - int err; - - /* Note: for now this is hardcoded for testing purposes! - * The ..\ should be one above msvc8. - */ - - FILE *fp = fopen("..\\test.smx", "rb"); - if (!fp) - { - return 0; - } - plugin = engine.LoadFromFilePointer(fp, &err); - if (err != SP_ERROR_NONE) - { - printf("Error loading: %d", err); - return 0; - } - HMODULE dll = LoadLibrary("..\\jit\\x86\\msvc8\\Debug\\jit-x86.dll"); - if (dll == NULL) - { - printf("Error loading DLL: %d\n", GetLastError()); - return 0; - } - GIVEENGINE give_eng = (GIVEENGINE)GetProcAddress(dll, "GiveEnginePointer"); - if (!give_eng) - { - printf("Error getting \"GiveEnginePointer!\"!\n"); - return 0; - } - give_eng(&engine); - GETEXPORT getex = (GETEXPORT)GetProcAddress(dll, "GetExport"); - if ((vm=getex(0)) == NULL) - { - printf("GetExport() returned no VM!\n"); - return 0; - } - - co = vm->StartCompilation(plugin); - if ((ctx = vm->CompileToContext(co, &err)) == NULL) - { - printf("CompileToContext() failed: %d", err); - return 0; - } - - IPluginContext *base = engine.CreateBaseContext(ctx); - - sp_nativeinfo_t mynative; - mynative.name = "gaben"; - mynative.func = TestNative; - - if ((err=base->BindNative(&mynative, SP_NATIVE_OKAY)) != SP_ERROR_NONE) - { - printf("BindNative() failed: %d", err); - return 0; - } - - base->PushCell(1); - base->PushCell(4); - err = base->Execute(0, &result); - printf("Result: %d Error: %d\n", result, err); - - engine.FreeBaseContext(base); - - fclose(fp); - FreeLibrary(dll); -} From 4d61a07d583e2a79d84fcf16bb5df83c3dce446e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 4 Nov 2006 18:58:27 +0000 Subject: [PATCH 0111/1664] --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40141 --- sourcepawn/compiler/sc1.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 656d9297..3f6d6cea 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2599,7 +2599,7 @@ static void dofuncenum(void) int l = lex(&val,&str); if (l != tSYMBOL) { - /* Incomprehensible but it works for now! */ + /* Error should be: "expected tag name identifier" */ error(57); } @@ -2612,6 +2612,7 @@ static void dofuncenum(void) /* Another bad one... */ if (!(cur->value & FUNCTAG)) { + /* Error should be: "function enumeration requires unique tag" */ error(213); } break; @@ -2641,7 +2642,7 @@ static void dofuncenum(void) } else if (l == tPUBLIC) { func.type = uPUBLIC; } else { - error(1, "[forward,public]", str); + error(1, "-forward,public-", str); } needtoken('('); do @@ -2732,7 +2733,8 @@ static void dofuncenum(void) arg->ommittable = TRUE; func.ommittable = TRUE; } else if (func.ommittable) { - /* :TODO: ERROR HERE! */ + /* Error should be: "cannot have required parameters after optional parameters" */ + error(1); } func.argcount++; } else if (l == tELLIPS) { From 8402d7976007edde4a0fad6aec0f68b01b03e43f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 4 Nov 2006 19:27:20 +0000 Subject: [PATCH 0112/1664] initial import of project file and a few files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40142 --- core/mm_api.cpp | 73 ++++++++++++ core/mm_api.h | 29 +++++ core/msvc8/sourcemod_mm.sln | 20 ++++ core/msvc8/sourcemod_mm.vcproj | 211 +++++++++++++++++++++++++++++++++ core/sm_version.h | 10 ++ 5 files changed, 343 insertions(+) create mode 100644 core/mm_api.cpp create mode 100644 core/mm_api.h create mode 100644 core/msvc8/sourcemod_mm.sln create mode 100644 core/msvc8/sourcemod_mm.vcproj create mode 100644 core/sm_version.h diff --git a/core/mm_api.cpp b/core/mm_api.cpp new file mode 100644 index 00000000..296e5c41 --- /dev/null +++ b/core/mm_api.cpp @@ -0,0 +1,73 @@ +#include +#include "mm_api.h" +#include "sm_version.h" + +SourceMod g_SourceMod; + +PLUGIN_EXPOSE(SourceMod, g_SourceMod); + +bool SourceMod::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + return true; +} + +bool SourceMod::Unload(char *error, size_t maxlen) +{ + return true; +} + +bool SourceMod::Pause(char *error, size_t maxlen) +{ + return true; +} + +bool SourceMod::Unpause(char *error, size_t maxlen) +{ + return true; +} + +void SourceMod::AllPluginsLoaded() +{ +} + +const char *SourceMod::GetAuthor() +{ + return "AlliedModders, LLC"; +} + +const char *SourceMod::GetName() +{ + return "SourceMod"; +} + +const char *SourceMod::GetDescription() +{ + return "Extensible administration and scripting system"; +} + +const char *SourceMod::GetURL() +{ + return "http://www.sourcemod.net/"; +} + +const char *SourceMod::GetLicense() +{ + return "See LICENSE.txt"; +} + +const char *SourceMod::GetVersion() +{ + return SOURCEMOD_VERSION; +} + +const char *SourceMod::GetDate() +{ + return __DATE__; +} + +const char *SourceMod::GetLogTag() +{ + return "SRCMOD"; +} diff --git a/core/mm_api.h b/core/mm_api.h new file mode 100644 index 00000000..af3a829c --- /dev/null +++ b/core/mm_api.h @@ -0,0 +1,29 @@ +#ifndef _INCLUDE_SOURCEMOD_MM_API_H_ +#define _INCLUDE_SOURCEMOD_MM_API_H_ + +#include + +class SourceMod : public ISmmPlugin +{ +public: + bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); + bool Unload(char *error, size_t maxlen); + bool Pause(char *error, size_t maxlen); + bool Unpause(char *error, size_t maxlen); + void AllPluginsLoaded(); +public: + const char *GetAuthor(); + const char *GetName(); + const char *GetDescription(); + const char *GetURL(); + const char *GetLicense(); + const char *GetVersion(); + const char *GetDate(); + const char *GetLogTag(); +}; + +extern SourceMod g_SourceMod; + +PLUGIN_GLOBALVARS(); + +#endif //_INCLUDE_SOURCEMOD_MM_API_H_ diff --git a/core/msvc8/sourcemod_mm.sln b/core/msvc8/sourcemod_mm.sln new file mode 100644 index 00000000..6a65d2ef --- /dev/null +++ b/core/msvc8/sourcemod_mm.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemod_mm", "sourcemod_mm.vcproj", "{E39527CD-7CAB-4420-97CC-DA1B93B260BC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug|Win32.Build.0 = Debug|Win32 + {E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release|Win32.ActiveCfg = Release|Win32 + {E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj new file mode 100644 index 00000000..d55bb6c0 --- /dev/null +++ b/core/msvc8/sourcemod_mm.vcproj @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/sm_version.h b/core/sm_version.h new file mode 100644 index 00000000..6986a5bd --- /dev/null +++ b/core/sm_version.h @@ -0,0 +1,10 @@ +#ifndef _INCLUDE_SOURCEMOD_VERSION_H_ +#define _INCLUDE_SOURCEMOD_VERSION_H_ + +#define SOURCEMOD_VERSION "1.0.0.0" +#define SOURCEMOD_V_MAJOR 1 +#define SOURCEMOD_V_MINOR 0 +#define SOURCEMOD_V_REV 0 +#define SOURCEMOD_V_BUILD 0 + +#endif //_INCLUDE_SOURCEMOD_VERSION_H_ From b5e203a67d8596a0f6383bd3d59efd6bb5789075 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 4 Nov 2006 19:35:21 +0000 Subject: [PATCH 0113/1664] added 3 errors for dofuncenum --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40143 --- sourcepawn/compiler/sc1.c | 9 +- sourcepawn/compiler/sc5.scp | 306 ++++++++++++++++++------------------ 2 files changed, 159 insertions(+), 156 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 3f6d6cea..0188be0f 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2599,8 +2599,7 @@ static void dofuncenum(void) int l = lex(&val,&str); if (l != tSYMBOL) { - /* Error should be: "expected tag name identifier" */ - error(57); + error(93); } /* This tag can't already exist! */ @@ -2612,8 +2611,7 @@ static void dofuncenum(void) /* Another bad one... */ if (!(cur->value & FUNCTAG)) { - /* Error should be: "function enumeration requires unique tag" */ - error(213); + error(94); } break; } @@ -2733,8 +2731,7 @@ static void dofuncenum(void) arg->ommittable = TRUE; func.ommittable = TRUE; } else if (func.ommittable) { - /* Error should be: "cannot have required parameters after optional parameters" */ - error(1); + error(95); } func.argcount++; } else if (l == tELLIPS) { diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index 1bf02541..ec3cc398 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -26,14 +26,14 @@ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned ch #define SCPACK_TABLE errstr_table /*-*SCPACK start of pair table, do not change or remove this line */ unsigned char errstr_table[][2] = { - {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {116,105}, {100,32}, {115,32}, {101,114}, {97,108}, {101,110}, {37,115}, {133,129}, {34,139}, {141,34}, {117,110}, - {114,101}, {110,111}, {115,105}, {121,32}, {97,116}, {111,114}, {97,110}, {32,142}, {109,98}, {115,116}, {41,10}, {100,101}, {109,138}, {101,134}, {98,108}, {140,32}, - {111,108}, {114,97}, {145,130}, {118,137}, {143,99}, {102,164}, {115,121}, {166,152}, {167,160}, {117,115}, {97,32}, {115,146}, {97,158}, {149,32}, {132,161}, {105,134}, - {103,32}, {163,175}, {103,117}, {178,156}, {136,32}, {132,179}, {131,177}, {111,102}, {116,104}, {101,120}, {105,135}, {165,159}, {101,100}, {99,104}, {118,132}, {168,151}, - {105,172}, {190,192}, {155,102}, {174,147}, {183,32}, {109,97}, {116,111}, {99,129}, {101,135}, {112,144}, {181,130}, {98,128}, {115,10}, {153,148}, {44,32}, {40,191}, - {169,130}, {151,10}, {101,10}, {207,154}, {109,208}, {116,97}, {194,131}, {193,128}, {34,32}, {129,32}, {105,99}, {132,97}, {100,105}, {146,122}, {110,32}, {137,32}, - {104,97}, {101,108}, {117,108}, {99,111}, {108,111}, {109,148}, {199,153}, {58,209}, {111,112}, {97,115}, {108,128}, {232,136}, {230,150}, {150,32}, {201,171}, {131,176}, - {212,203}, {102,105}, {119,105}, {185,238}, {109,112}, {116,136}, {165,140}, {197,147}, {102,149}, {111,32}, {131,32}, {213,176}, {110,117}, {115,117}, {118,128} + {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {116,105}, {100,32}, {115,32}, {101,114}, {101,110}, {133,129}, {97,108}, {37,115}, {34,140}, {141,34}, {117,110}, + {114,101}, {110,111}, {115,105}, {97,116}, {121,32}, {97,110}, {111,114}, {109,98}, {32,142}, {100,101}, {115,116}, {109,137}, {41,10}, {101,134}, {138,32}, {98,108}, + {145,130}, {111,108}, {114,97}, {143,99}, {118,139}, {102,163}, {115,121}, {166,151}, {167,161}, {117,115}, {97,32}, {115,146}, {97,159}, {132,162}, {103,32}, {136,32}, + {150,32}, {103,117}, {105,134}, {177,155}, {164,178}, {132,179}, {111,102}, {101,120}, {165,158}, {131,180}, {99,104}, {116,104}, {105,135}, {153,102}, {101,100}, {118,132}, + {168,152}, {182,32}, {105,172}, {191,194}, {101,135}, {173,148}, {109,97}, {116,111}, {99,129}, {115,10}, {112,144}, {116,97}, {181,130}, {98,128}, {154,147}, {44,32}, + {40,192}, {132,97}, {169,130}, {189,131}, {152,10}, {101,10}, {208,156}, {109,210}, {195,128}, {34,32}, {129,32}, {139,32}, {104,97}, {105,99}, {100,105}, {146,122}, + {109,147}, {110,32}, {101,108}, {117,108}, {99,111}, {108,111}, {111,112}, {116,136}, {200,154}, {58,212}, {102,105}, {97,115}, {108,128}, {230,136}, {232,149}, {149,32}, + {202,171}, {131,174}, {203,174}, {215,205}, {119,105}, {109,112}, {183,240}, {110,117}, {118,128}, {165,138}, {247,151}, {198,148}, {102,150}, {111,32}, {131,32} }; /*-*SCPACK end of pair table, do not change or remove this line */ @@ -130,100 +130,106 @@ static char *errmsg[] = { /*089*/ "state variables may not be initialized (symbol \"%s\")\n", /*090*/ "public functions may not return arrays (symbol \"%s\")\n", /*091*/ "ambiguous constant; tag override is required (symbol \"%s\")\n", -/*092*/ "number of arguments does not match definition\n" +/*092*/ "number of arguments does not match definition\n", +/*093*/ "expected tag name identifier\n", +/*094*/ "function enumeration requires unique tag\n", +/*095*/ "cannot have required parameters after optional parameters\n" #else - "\271pect\235\306k\212:\227\316bu\202fo\217\206\216\012", - "\201l\223\252s\203g\352\315e\234\202(\255\363\201) c\355f\240\344w ea\275 \042c\351e\042\012", - "\233cl\333\237\304\252\344c\337\327\324appe\204 \372\252\343\364o\217\206\236ock\012", - "\366\227 \272\242i\364le\234t\274\012", - "\273\367\242\340\376\265t\314", - "\360a\253gn\235\306 \355\256y\012", - "\353\224\255c\226\242\313\220\326\274\012", - "\360\252\354\202\363\201; \351\375m\235z\210o\012", - "\266\303\335\200(nega\205ve\316z\210\371\255ou\202\304bo\217ds\232", - "\266\273\255\233cl\333\214\012", - "\266out\222d\200\366\314", - "\266\273c\211l\316\242\252\261add\220s\314", - "\221 \212tr\223po\203\202(\221 pu\236\332 \366s\232", - "\266\315e\234t; \242\372s\362t\275\012", - "\042\302a\342t\330c\351\200\360\270\200l\351\202c\351\200\372s\362t\275 \315e\234t\012", - "m\342\205p\352\302a\342t\207\372\042s\362t\275\042\012", - "\217\326\235\277\012", - "\203i\205\211iza\237d\224\252\271ce\274\207\233cl\204\235\335\322", - "\242\252lab\341\347", - "\266\250 nam\200\216\012", - "\250 \211\220ad\223\326\274\347", - "\360l\243u\200(n\201-\354t\232", - "\303a\253gn\234\202\360\222\364\352a\253gn\234t\012", - "\042b\220ak\330\255\042\307t\203ue\330\272ou\202\304\307t\271t\012", - "\273head\357\334ff\210\207from pro\306typ\322", - "\221 \345\275\357\042#if...\042\012", - "\266\275\333ct\264\354t\012", - "\266\375bscrip\202(\242\355\303\255\306\371m\226\223\375bscripts)\347", - "\266\363\201\316\351\375m\235z\210o\012", - "\343\364o\217\206\315e\234\202\242c\344s\235a\202\270\200\212\206\304\361\352(\231\204t\235a\202l\203\200%d\232", - "\217k\221w\336\334\220c\205v\322", - "\303\203\233x ou\202\304bo\217d\207(\327\216\232", - "\303\360\203\233x\235(\327\216\232", - "\312do\310\242\340\376\252\302a\342\202\243u\200(\312%d\232", - "\312typ\200mis\345\275 (\312%d\232", - "e\364t\223\315e\234t\012", - "\266\231r\357(po\253\236\223n\201-\365m\203\224\235\231r\203g\232", - "\271t\241 \275\333c\365\207\331l\203\322", - "\354\202\250 \340\207\221 \335\322", - "dupl\332\224\200\042c\351e\330lab\341 (\243u\200%d\232", - "\266\341lip\222s\316\303\335\200\272\242k\221wn\012", - "\266\343\230\203a\237\304cl\351\207speci\361\210\314", - "\275\333ct\264\354\202\271ce\274\207r\226g\200f\255pack\235\231r\203g\012", - "po\222\214\337p\333me\365\207\324\311c\274\200\211l nam\235p\333me\365\314", - "\306\371m\226\223\273\265t\314", - "\217k\221w\336\303\335\200(\327\216\232", - "\303\335\310d\371\242\345\275\316\255\233\231\203a\237\303\272\306\371sm\211l\012", - "\303\334\234\222\201\207d\371\242\345\275\012", - "\266l\203\200\307t\203ua\214\012", - "\266r\226g\322", - "\266\375bscript\316\251\200\042[ ]\330\353\224\225\207\331\305j\255\334\234\222\201\314", - "m\342\205-\334\234\222\201\337\256y\207\360f\342l\223\203i\205\211iz\274\012", - "\271ce\274\357\305ximum \374\230\264\304\334\234\222\201\314", - "\217\345\275\235c\344s\357b\241c\200(\042}\042\232", - "\231\204\202\304\273bod\223\362\270ou\202\273head\210\012", - "\256ys\316\344c\337\301\310\226\206\273\265t\207c\226\242\313pu\236\332 (\327\216\232", - "\217f\203ish\235\363\331be\370\200\343\364il\264\334\220c\205v\322", - "dupl\332\224\200\265t; sam\200\312\272p\351s\235tw\332\322", - "\273\312\367\242\340\376\252\302a\342\202\243u\200(\327\216\232", - "m\342\205p\352\042#\341se\330\334\220c\205v\310betwe\212 \042#if ... #\212\334f\042\012", - "\042#\341seif\330\334\220c\205\376f\240\344w\207\355\042#\341se\330\334\220c\205v\322", - "\374\230\264\304\353\226d\207do\310\242\361\202\270\200\353\224\225\012", - "\273\220s\342\202\373\304\353\224\225\227 \360\216\012", - "c\226\242\275\226g\200\311\326\235\353\224\225\314", - "\273\312\367\201l\223\340\376\252s\203g\352\373(\312%d\232", - "\273\312\367\242\313\252\220f\210\212c\200\312\255\355\303(\312\216\232", - "\327c\226\242\313bo\270 \252\220f\210\212c\200\226\206\355\303(\327\216\232", - "\266\241\214\337\374\230\264\311ci\222\331\372#p\241g\305\012", - "\241\214\337\374\230\264\370\305\202\211\220ad\223\326\274\012", - "\241\214\337\374\230\264\375pp\225\202wa\207\242\212\254\274\012", - "\251\210-\326\235\353\224\255\360\233cl\204\235be\370\200\251\200(\366\227\232", - "\042\335e\267\330\353\224\255\272\266\331\042\366\330\250\314", - "\273\312\360\355\303(\312\216\232", - "#\326\200p\224\365\336\324\231\204\202\362\270 \355\211p\340be\205c \275\333c\365\012", - "\203pu\202l\203\200\306\371l\201\260(aft\264\375bs\205tu\214s\232", - "\246n\325x \210r\255\372\270\200\363\201\316\255\266\273c\211l\012", - "m\211\370m\235UTF-8 \212\343d\203g\316\255c\225rupt\235\361le: \213\012", - "\273\251\310bo\270 \042\220turn\330\226\206\042\220tur\336<\243ue>\042\012", - "\203\307\222\231\212\202\220tur\336typ\310(\303& n\201-\256y\232", - "\217k\221w\336\250\316\255\242\252\354\202\250 \323", - "c\226\242\325k\200\252\373a\207\252\302a\342\202\243u\200f\255\355\203\233x\235\303p\333met\264\323", - "\251\210-\326\235\353\224\225\207\226\206na\205\376\366\207\367\242\340\376\315e\314", - "\252\273\255\327\367\201l\223b\341\201\260\306 \252s\203g\352au\306\345\331\323", - "\315\200\307fl\332t: \201\200\304\270\200\315\310\272\211\220ad\223a\253gn\235\306 a\221\270\264i\364le\234\325\237\323", - "\221 \315\310\204\200\326\235f\255\277\012", - "\217k\221w\336au\306\345\201\321", - "\217k\221w\336\315\200\216 f\255au\306\345\201\321", - "pu\236\332 \301\310\226\206\344c\337\301\310\367\242\340\376\315\310\323", - "\315\200\301\310\367\242\313\203i\205\211iz\235\323", - "pu\236\332 \366\207\367\242\220tur\336\256y\207\323", - "a\230i\262ou\207\354t; \373ov\210rid\200\272\220qui\220\206\323", - "\374\230\264\304\265t\207do\310\242\345\275 \326i\214\012" + "\267pect\235\307k\211:\230\317bu\202fo\217\206\216\012", + "\201l\224\252s\203g\354\316e\233\202(\260\366\201) c\357f\241\345w ea\272 \042c\353e\042\012", + "\231cl\321\236\301\252\345c\333\330\327appe\204 \376\252\344\365o\217\206\237ock\012", + "\371\230 \274\240i\365le\233t\276\012", + "\270\373\240\334\370\265t\311", + "\363a\253gn\235\307 \357\255y\012", + "\355\223\260c\225\240\315\220\323\276\012", + "\363\252\356\202\366\201; \353sum\235z\210o\012", + "\271\305\337\200(nega\205ve\317z\210\375\260ou\202\301bo\217ds\234", + "\271\270\260\231cl\321\212\012", + "\271out\222d\200\371\311", + "\271\270c\213l\317\240\252\264add\220s\311", + "\221 \211tr\224po\203\202(\221 pu\237\335 \371s\234", + "\271\316e\233t; \240\376s\364t\272\012", + "\042\275a\343t\331c\353\200\363\273\200l\353\202c\353\200\376s\364t\272 \316e\233t\012", + "m\343\205p\354\275a\343t\207\376\042s\364t\272\042\012", + "\217\323\235\300\012", + "\203i\205\213iza\236d\223\252\267ce\276\207\231cl\204\235\337\325", + "\240\252lab\342\351", + "\271\250 nam\200\216\012", + "\250 \213\220ad\224\323\276\351", + "\363l\244u\200(n\201-\356t\234", + "\305a\253gn\233\202\363\222\365\354a\253gn\233t\012", + "\042b\220ak\331\260\042\310t\203ue\331\274ou\202\301\310t\267t\012", + "\270head\361\336ff\210\207from pro\307typ\325", + "\221 \340\272\361\042#if...\042\012", + "\271\272\321ct\257\356t\012", + "\271subscrip\202(\240\357\305\260\307\375m\225\224subscripts)\351", + "\271\366\201\317\353sum\235z\210o\012", + "\344\365o\217\206\316e\233\202\240c\345s\235a\202\273\200\211\206\301\352\354(\232\204t\235a\202l\203\200%d\234", + "\217k\221w\341\336\220c\205v\325", + "\305\203\231x ou\202\301bo\217d\207(\330\216\234", + "\305\363\203\231x\235(\330\216\234", + "\314do\304\240\334\370\252\275a\343\202\244u\200(\314%d\234", + "\314typ\200mis\340\272 (\314%d\234", + "e\365t\224\316e\233t\012", + "\271\232r\361(po\253\237\224n\201-\347m\203\223\235\232r\203g\234", + "\267t\242 \272\321c\347\207\332l\203\325", + "\356\202\250 \334\207\221 \337\325", + "dupl\335\223\200\042c\353e\331lab\342 (\244u\200%d\234", + "\271\342lip\222s\317\305\337\200\274\240k\221wn\012", + "\271\344\227\203a\236\301cl\353\207speci\352\210\311", + "\272\321ct\257\356\202\267ce\276\207r\225g\200f\260pack\235\232r\203g\012", + "po\222\212\333p\321me\347\207\327\312c\276\200\213l nam\235p\321me\347\311", + "\307\375m\225\224\270\265t\311", + "\217k\221w\341\305\337\200(\330\216\234", + "\305\337\304d\375\240\340\272\317\260\231\232\203a\236\305\274\307\375sm\213l\012", + "\305\336\233\222\201\207d\375\240\340\272\012", + "\271l\203\200\310t\203ua\212\012", + "\271r\225g\325", + "\271subscript\317\251\200\042[ ]\331\355\223\226\207\332\306j\260\336\233\222\201\311", + "m\343\205-\336\233\222\201\333\255y\207\363f\343l\224\203i\205\213iz\276\012", + "\267ce\276\361\306ximum \372\257\301\336\233\222\201\311", + "\217\340\272\235c\345s\361b\242c\200(\042}\042\234", + "\232\204\202\301\270bod\224\364\273ou\202\270head\210\012", + "\255ys\317\345c\333\303\304\225\206\270\265t\207c\225\240\315pu\237\335 (\330\216\234", + "\217f\203ish\235\366\332be\374\200\344\365il\257\336\220c\205v\325", + "dupl\335\223\200\265t; sam\200\314\274p\353s\235tw\335\325", + "\270\314\373\240\334\370\252\275a\343\202\244u\200(\330\216\234", + "m\343\205p\354\042#\342se\331\336\220c\205v\304betwe\211 \042#if ... #\211\336f\042\012", + "\042#\342seif\331\336\220c\205\370f\241\345w\207\357\042#\342se\331\336\220c\205v\325", + "\372\257\301\355\225d\207do\304\240\352\202\273\200\355\223\226\012", + "\270\220s\343\202\362\301\355\223\226\230 \363\216\012", + "c\225\240\272\225g\200\312\323\235\355\223\226\311", + "\270\314\373\201l\224\334\370\252s\203g\354\362(\314%d\234", + "\270\314\373\240\315\252\220f\210\211c\200\314\260\357\305(\314\216\234", + "\330c\225\240\315bo\273 \252\220f\210\211c\200\225\206\357\305(\330\216\234", + "\271\242\212\333\372\257\312ci\222\332\376#p\242g\306\012", + "\242\212\333\372\257\374\306\202\213\220ad\224\323\276\012", + "\242\212\333\372\257supp\226\202wa\207\240\211\254\276\012", + "\251\210-\323\235\355\223\260\363\231cl\204\235be\374\200\251\200(\371\230\234", + "\042\337e\266\331\355\223\260\274\271\332\042\371\331\250\311", + "\270\314\363\357\305(\314\216\234", + "#\323\200p\223\347\341\327\232\204\202\364\273 \357\213p\334be\205c \272\321c\347\012", + "\203pu\202l\203\200\307\375l\201\256(aft\257subs\205tu\212s\234", + "\246n\313x \210r\260\376\273\200\366\201\317\260\271\270c\213l\012", + "m\213\374m\235UTF-8 \211\344d\203g\317\260c\226rupt\235\352le: \214\012", + "\270\251\304bo\273 \042\220turn\331\225\206\042\220tur\341<\244ue>\042\012", + "\203\310\222\232\211\202\220tur\341typ\304(\305& n\201-\255y\234", + "\217k\221w\341\250\317\260\240\252\356\202\250 \326", + "c\225\240\313k\200\252\362a\207\252\275a\343\202\244u\200f\260\357\203\231x\235\305p\321met\257\326", + "\251\210-\323\235\355\223\226\207\225\206na\205\370\371\207\373\240\334\370\316e\311", + "\252\270\260\330\373\201l\224b\342\201\256\307 \252s\203g\354au\307\340\332\326", + "\316\200\310fl\335t: \201\200\301\273\200\316\304\274\213\220ad\224a\253gn\235\307 a\221\273\257i\365le\233\313\236\326", + "\221 \316\304\204\200\323\235f\260\300\012", + "\217k\221w\341au\307\340\201\324", + "\217k\221w\341\316\200\216 f\260au\307\340\201\324", + "pu\237\335 \303\304\225\206\345c\333\303\304\373\240\334\370\316\304\326", + "\316\200\303\304\373\240\315\203i\205\213iz\235\326", + "pu\237\335 \371\207\373\240\220tur\341\255y\207\326", + "a\227i\261ou\207\356t; \362ov\210rid\200\274\220qui\220\206\326", + "\372\257\301\265t\207do\304\240\340\272 \323i\212\012", + "\267pect\235\362nam\200id\211\205\352\210\012", + "\270\211um\210a\236\220qui\220\207\217iqu\200\313g\012", + "c\225\240\334\370\220qui\220\206p\321me\347\207aft\257\346\212\333p\321me\347\311" #endif }; @@ -248,18 +254,18 @@ static char *fatalmsg[] = { /*110*/ "assertion failed: %s\n", /*111*/ "user error: %s\n", #else - "c\226\242\220a\206from \361le\347", - "c\226\242writ\200\306 \361le\347", - "t\254\200ov\210f\344w\347", - "\203\375ff\332i\212\202mem\225y\012", - "\266\351se\230l\264\203\231ruc\214\321", - "\374m\210\332 ov\210f\344w\316\271ce\274\357capacity\012", - "\343\364il\235scrip\202\271ce\274\207\270\200\305ximum mem\225\223\335\200(%l\206bytes\232", - "\306\371m\226\223\210r\255messag\310\331\201\200l\203\322", - "\343\233pag\200\305pp\357\361\352\242fo\217d\012", - "\266p\224h\347", - "\351s\210\237fail\274: \213\012", - "\251\264\210r\225: \213\012" + "c\225\240\220a\206from \352le\351", + "c\225\240writ\200\307 \352le\351", + "t\254\200ov\210f\345w\351", + "\203suff\335i\211\202mem\226y\012", + "\271\353se\227l\257\203\232ruc\212\324", + "\367m\210\335 ov\210f\345w\317\267ce\276\361capacity\012", + "\344\365il\235scrip\202\267ce\276\207\273\200\306ximum mem\226\224\337\200(%l\206bytes\234", + "\307\375m\225\224\210r\260messag\304\332\201\200l\203\325", + "\344\231pag\200\306pp\361\352\354\240fo\217d\012", + "\271p\223h\351", + "\353s\210\236fail\276: \214\012", + "\251\257\210r\226: \214\012" #endif }; @@ -303,42 +309,42 @@ static char *warnmsg[] = { /*235*/ "public function lacks forward declaration (symbol \"%s\")\n", /*236*/ "unknown parameter in substitution (incorrect #define pattern)\n" #else - "\277 \272tr\244\224\235\306 %\206\275\333c\365\314", - "\220\326i\237\304\354t/\305cr\371\323", - "\374\230\264\304\265t\207do\310\242\345\275 \326i\214\012", - "\250 \272nev\264\251\274\347", - "\250 \272a\253gn\235\252\243u\200\270a\202\272nev\264\251\274\347", - "\220d\217d\226\202\343\233: \354\202\363\331\272z\210o\012", - "\220d\217d\226\202te\231: \354\202\363\331\272n\201-z\210o\012", - "\217k\221w\336#p\241g\305\012", - "\273\362\270 \373\220s\342\202\251\235be\370\200\326i\214\316\370c\357\220p\204s\322", - "\366\227 sho\342\206\220tur\336\252\243u\322", - "po\253\236\200\251\200\304\250 be\370\200\203i\205\211iza\214\347", - "po\253\236\223\217\203t\212\233\206a\253gn\234t\012", - "po\253\236\223\217\203t\212\233\206bit\362s\200\353a\214\012", - "\373mis\345\275\012", - "po\253\236\223\252\042\346\330\303\312wa\207\203t\212\233d\347", - "\363\331\340\207\221 effect\012", - "ne\231\235\343m\234t\012", - "\344os\200\203d\212\325\214\012", - "\240\206\231y\352pro\306typ\310\251\235\362\270 \350\214\337sem\332\240umn\314", - "\344c\337\327\216 s\340dow\207\252\327a\202\252\311c\274\357lev\341\012", - "\363\331\362\270 \373ov\210rid\200\324appe\204 betwe\212 p\204\212\270ese\314", - "lab\341 nam\200\216 s\340dow\207\373nam\322", - "\374\230\264\304\334git\207\271ce\274\207\241\214\337\374\230\264\311ci\222\201\012", - "\220d\217d\226\202\042\335e\267\042: \312\335\200\272\211way\2071 \323", - "\203\233\365m\203\224\200\303\335\200\372\042\335e\267\330\363\331\323", - "\217\220a\275\254\200\343\233\012", - "\252\327\272a\253gn\235\306 its\341f \323", - "m\225\200\203i\205\211l\210\207\270\355\212um \361\341d\314", - "l\212g\270 \304\203i\205\211l\264\271ce\274\207\335\200\304\270\200\212um \361\341d\012", - "\203\233x \373mis\345\275 \323", - "\221 i\364le\234\325\237f\255\315\200\216 \372\366\227\316\221 f\211l-back\012", - "\315\200specif\332a\237\331\370w\204\206\233cl\333\237\272ig\221\220d\012", - "outpu\202\361\352\272writt\212\316bu\202\362\270 \343\364ac\202\212\343d\357\334s\254\274\012", - "\315\200\327\216 s\340dow\207\252g\344b\337\301\322", - "\273\272\233\311c\224\235\317) \213\012", - "pu\236\332 \273lack\207\370w\204\206\233cl\333\237\323", - "\217k\221w\336p\333met\264\372\375bs\205tu\237(\203c\225\220c\202#\326\200p\224\365n\232" + "\300 \274tr\243\223\235\307 %\206\272\321c\347\311", + "\220\323i\236\301\356t/\306cr\375\326", + "\372\257\301\265t\207do\304\240\340\272 \323i\212\012", + "\250 \274nev\257\251\276\351", + "\250 \274a\253gn\235\252\244u\200\273a\202\274nev\257\251\276\351", + "\220d\217d\225\202\344\231: \356\202\366\332\274z\210o\012", + "\220d\217d\225\202te\232: \356\202\366\332\274n\201-z\210o\012", + "\217k\221w\341#p\242g\306\012", + "\270\364\273 \362\220s\343\202\251\235be\374\200\323i\212\317\374c\361\220p\204s\325", + "\371\230 sho\343\206\220tur\341\252\244u\325", + "po\253\237\200\251\200\301\250 be\374\200\203i\205\213iza\212\351", + "po\253\237\224\217\203t\211\231\206a\253gn\233t\012", + "po\253\237\224\217\203t\211\231\206bit\364s\200\355a\212\012", + "\362mis\340\272\012", + "po\253\237\224\252\042\350\331\305\314wa\207\203t\211\231d\351", + "\366\332\334\207\221 effect\012", + "ne\232\235\344m\233t\012", + "\345os\200\203d\211\313\212\012", + "\241\206\232y\354pro\307typ\304\251\235\364\273 \346\212\333sem\335\241umn\311", + "\345c\333\330\216 s\334dow\207\252\330a\202\252\312c\276\361lev\342\012", + "\366\332\364\273 \362ov\210rid\200\327appe\204 betwe\211 p\204\211\273ese\311", + "lab\342 nam\200\216 s\334dow\207\362nam\325", + "\372\257\301\336git\207\267ce\276\207\242\212\333\372\257\312ci\222\201\012", + "\220d\217d\225\202\042\337e\266\042: \314\337\200\274\213way\2071 \326", + "\203\231\347m\203\223\200\305\337\200\376\042\337e\266\331\366\332\326", + "\217\220a\272\254\200\344\231\012", + "\252\330\274a\253gn\235\307 its\342f \326", + "m\226\200\203i\205\213l\210\207\273\357\211um \352\342d\311", + "l\211g\273 \301\203i\205\213l\257\267ce\276\207\337\200\301\273\200\211um \352\342d\012", + "\203\231x \362mis\340\272 \326", + "\221 i\365le\233\313\236f\260\316\200\216 \376\371\230\317\221 f\213l-back\012", + "\316\200specif\335a\236\332\374w\204\206\231cl\321\236\274ig\221\220d\012", + "outpu\202\352\354\274writt\211\317bu\202\364\273 \344\365ac\202\211\344d\361\336s\254\276\012", + "\316\200\330\216 s\334dow\207\252g\345b\333\303\325", + "\270\274\231\312c\223\235\320) \214\012", + "pu\237\335 \270lack\207\374w\204\206\231cl\321\236\326", + "\217k\221w\341p\321met\257\376subs\205tu\236(\203c\226\220c\202#\323\200p\223\347n\234" #endif }; From c63d26e1c52ab602bca80b8f5f7cf796e8dd86b3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 5 Nov 2006 00:29:44 +0000 Subject: [PATCH 0115/1664] initial import of the first four core interfaces --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40145 --- core/interfaces/ILibrarySys.h | 114 ++++++++++++++++++++++++++++ core/interfaces/IModuleSys.h | 92 ++++++++++++++++++++++ core/interfaces/IPluginSys.h | 59 ++++++++++++++ core/interfaces/IShareSys.h | 135 +++++++++++++++++++++++++++++++++ core/mm_api.cpp | 28 +++---- core/mm_api.h | 4 +- core/msvc8/sourcemod_mm.vcproj | 18 +++++ core/sm_version.h | 4 +- 8 files changed, 436 insertions(+), 18 deletions(-) create mode 100644 core/interfaces/ILibrarySys.h create mode 100644 core/interfaces/IModuleSys.h create mode 100644 core/interfaces/IPluginSys.h create mode 100644 core/interfaces/IShareSys.h diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h new file mode 100644 index 00000000..18a32d81 --- /dev/null +++ b/core/interfaces/ILibrarySys.h @@ -0,0 +1,114 @@ +#ifndef _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ +#define _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ + +#include + +namespace SourceMod +{ + #define SMINTERFACE_LIBRARYSYS_NAME "ILibrarySys" + #define SMINTERFACE_LIBRARYSYS_VERSION 1 + + class ILibrary + { + public: + /** + * @brief Closes dynamic library and invalidates pointer. + */ + virtual void CloseLibrary() =0; + + /** + * @brief Retrieves a symbol pointer from the dynamic library. + * + * @param symname Symbol name. + * @return Symbol pointer, NULL if not found. + */ + virtual void *GetSymbolAddress(const char *symname) =0; + }; + + /** + * @brief Directory browsing abstraction. + */ + class IDirectory + { + public: + /** + * @brief Returns true if there are more files to read, false otherwise. + */ + virtual bool MoreFiles() =0; + + /** + * @brief Advances to the next entry in the stream. + */ + virtual void NextEntry() =0; + + /** + * @brief Returns the name of the current entry. + */ + virtual const char *GetEntryName() =0; + + /** + * @brief Returns whether the current entry is a directory. + */ + virtual bool IsEntryDirectory() =0; + + /** + * @brief Returns whether the current entry is a file. + */ + virtual bool IsEntryFile() =0; + }; + + /** + * @brief Contains various operating system specific code. + */ + class ILibrarySys : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_LIBRARYSYS_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_LIBRARYSYS_VERSION; + } + public: + /** + * @brief Opens a dynamic library file. + * + * @param path Path to library file (.dll/.so). + * @param error Buffer for any error message (may be NULL). + * @param err_max Maximum length of error buffer. + * @return Pointer to an ILibrary, NULL if failed. + */ + virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max) =0; + + /** + * @brief Opens a directory for reading. + * + * @param path Path to directory. + * @param error Buffer for any error message (may be NULL). + * @param err_max Maximum length of error buffer. + * @return Pointer to an IDirectory, NULL if failed. + */ + virtual IDirectory *OpenDirectory(const char *path, char *error, size_t err_max) =0; + + /** + * @brief Closes a directory and frees its handle. + * + * @param dir Pointer to IDirectory. + */ + virtual void CloseDirectory(IDirectory *dir) =0; + + /** + * @brief Returns true if the path is a normal file. + */ + virtual bool IsPathFile(const char *path) =0; + + /** + * @brief Returns true if the path is a normal directory. + */ + virtual bool IsPathDirectory(const char *path) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ diff --git a/core/interfaces/IModuleSys.h b/core/interfaces/IModuleSys.h new file mode 100644 index 00000000..6b4eabe4 --- /dev/null +++ b/core/interfaces/IModuleSys.h @@ -0,0 +1,92 @@ +#ifndef _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ + +#include +#include + +namespace SourceMod +{ + class IModuleInterface; + + class IModule : public IUnloadableParent + { + public: + virtual UnloadableParentType GetParentType() + { + return ParentType_Module; + } + public: + virtual IModuleInterface *GetModuleInfo() =0; + virtual const char *GetFilename() =0; + }; + + class IModuleInterface + { + public: + /** + * @brief Called when the module is loaded. + * + * @param me Pointer back to module. + * @param sys Pointer to interface sharing system of SourceMod. + * @param error Error buffer to print back to, if any. + * @param err_max Maximum size of error buffer. + * @param late If this module was loaded "late" (i.e. manually). + * @return True if load should continue, false otherwise. + */ + virtual bool OnModuleLoad(IModule *me, IShareSys *sys, char *error, size_t err_max, bool late) =0; + + /** + * @brief Called when the module is unloaded. + * + * @param force True if this unload will be forced. + * @param error Error message buffer. + * @param err_max Maximum siez of error buffer. + * @return True on success, false to request no unload. + */ + virtual bool OnModuleUnload(bool force, char *error, size_t err_max) =0; + + /** + * @brief Called when your pause state is about to change. + * + * @param pause True if pausing, false if unpausing. + */ + virtual void OnPauseChange(bool pause) =0; + + public: + virtual const char *GetModuleName() =0; + virtual const char *GetModuleVersion() =0; + virtual const char *GetModuleURL() =0; + virtual const char *GetModuleTags() =0; + virtual const char *GetModuleAuthor() =0; + }; + + #define SMINTERFACE_MODULEMANAGER_NAME "IModuleManager" + #define SMINTERFACE_MODULEMANAGER_VERSION 1 + + enum ModuleLifetime + { + ModuleLifetime_Forever, //Module will never be unloaded automatically + ModuleLifetime_Map, //Module will be unloaded at the end of the map + ModuleLifetime_Dependent, //Module will be unloaded once its dependencies are gone + }; + + class IModuleManager : public SMInterface + { + public: + /** + * @brief Loads a module into the module system. + * + * @param path Path to module file, relative to the modules folder. + * @param lifetime Lifetime of the module. + * @param error Error buffer. + * @param err_max Maximum error buffer length. + * @return New IModule on success, NULL on failure. + */ + virtual IModule *LoadModule(const char *path, + ModuleLifetime lifetime, + char *error, + size_t err_max); + }; +}; + +#endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h new file mode 100644 index 00000000..446a7975 --- /dev/null +++ b/core/interfaces/IPluginSys.h @@ -0,0 +1,59 @@ +#ifndef _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ + +#include + +#define SMINTERFACE_PLUGINMANAGER_NAME "IPluginManager" +#define SMINTERFACE_PLUGINMANAGER_VERSION 1 + +namespace SourceMod +{ + class IPlugin : public IUnloadableParent + { + public: + UnloadableParentType GetParentType() + { + return ParentType_Module; + } + }; + + enum PluginLifetime + { + PluginLifetime_Forever, + PluginLifetime_Map + }; + + class IPluginManager : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_PLUGINMANAGER_NAME; + } + + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_PLUGINMANAGER_VERSION; + } + public: + /** + * @brief Attempts to load a plugin. + * + * @param path Path and filename of plugin, relative to plugins folder. + * @param extended Whether or not the plugin is a static plugin or optional plugin. + * @param debug Whether or not to default the plugin into debug mode. + * @param lifetime Lifetime of the plugin. + * @param error Buffer to hold any error message. + * @param err_max Maximum length of error message buffer. + * @return A new plugin pointer on success, false otherwise. + */ + virtual IPlugin *LoadPlugin(const char *path, + bool extended, + bool debug, + PluginLifetime lifetime, + char error[], + size_t err_max) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h new file mode 100644 index 00000000..7e08f72c --- /dev/null +++ b/core/interfaces/IShareSys.h @@ -0,0 +1,135 @@ +#ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ +#define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ + +namespace SourceMod +{ + /** + * @brief Defines the base functionality required by a shared interface. + */ + class SMInterface + { + public: + /** + * @brief Must return an integer defining the interface's version. + */ + virtual unsigned int GetInterfaceVersion() =0; + + /** + * @brief Must return a string defining the interface's unique name. + */ + virtual const char *GetInterfaceName() =0; + + /** + * @brief Must return whether the requested version number is backwards comaptible. + * Note: This can be overridden for breaking changes or custom versioning. + * + * @param version Version number to compare against. + * @return True if compatible, false otherwise. + */ + virtual bool IsVersionCompatible(unsigned int version) + { + if (version > GetInterfaceVersion()) + { + return false; + } + + return true; + } + }; + + enum UnloadableParentType + { + ParentType_Module, + ParentType_Plugin + }; + + /** + * @brief Denotes a top-level unloadable object. + */ + class IUnloadableParent + { + public: + virtual UnloadableParentType GetParentType() =0; + + virtual void *GetParentToken() =0; + + /** + * @brief Called when an interface this object has requested is removed. + * + * @param pIface Interface being removed. + */ + virtual void OnInterfaceUnlink(SMInterface *pIface) =0; + protected: + void *m_parent_token; + }; + + /** + * @brief Listens for unlinked objects. + */ + class IUnlinkListener + { + public: + /** + * @brief Called when a parent object is unloaded. + * + * @param parent The parent object which is dying. + */ + virtual void OnParentUnlink(IUnloadableParent *parent) + { + } + }; + + /** + * @brief Tracks dependencies and fires dependency listeners. + */ + class IShareSys + { + public: + /** + * @brief Adds an interface to the global interface system + * + * @param iface Interface pointer (must be unique). + * @param parent Parent unloadable token given to the module/interface. + */ + virtual bool AddInterface(SMInterface *iface, IUnloadableParent *parent) =0; + + /** + * @brief Requests an interface from the global interface system. + * If found, the interface's internal reference count will be increased. + * + * @param iface_name Interface name. + * @param iface_vers Interface version to attempt to match. + * @param me Object requesting this interface, in order to track dependencies. + * @param pIface Pointer to store the return value in. + */ + virtual bool RequestInterface(const char *iface_name, + unsigned int iface_vers, + IUnloadableParent *me, + void **pIface) =0; + + /** + * @brief Unloads an interface. + * + * @param iface Interface pointer. + * @param parent Security token, trivial measure to prevent accidental unloads. + * This token must match the one used with AddInterface(). + */ + virtual void RemoveInterface(SMInterface *iface, IUnloadableParent *parent) =0; + + /** + * @brief Adds an unlink listener. + * + * @param pListener Listener pointer. + */ + virtual void AddUnlinkListener(IUnlinkListener *pListener) =0; + + /** + * @brief Removes an unlink listener. + * + * @param pListener Listener pointer. + */ + virtual void RemoveUnlinkListener(IUnlinkListener *pListener) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ diff --git a/core/mm_api.cpp b/core/mm_api.cpp index 296e5c41..82db205b 100644 --- a/core/mm_api.cpp +++ b/core/mm_api.cpp @@ -2,72 +2,72 @@ #include "mm_api.h" #include "sm_version.h" -SourceMod g_SourceMod; +SourceMod_Core g_SourceMod; PLUGIN_EXPOSE(SourceMod, g_SourceMod); -bool SourceMod::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); return true; } -bool SourceMod::Unload(char *error, size_t maxlen) +bool SourceMod_Core::Unload(char *error, size_t maxlen) { return true; } -bool SourceMod::Pause(char *error, size_t maxlen) +bool SourceMod_Core::Pause(char *error, size_t maxlen) { return true; } -bool SourceMod::Unpause(char *error, size_t maxlen) +bool SourceMod_Core::Unpause(char *error, size_t maxlen) { return true; } -void SourceMod::AllPluginsLoaded() +void SourceMod_Core::AllPluginsLoaded() { } -const char *SourceMod::GetAuthor() +const char *SourceMod_Core::GetAuthor() { return "AlliedModders, LLC"; } -const char *SourceMod::GetName() +const char *SourceMod_Core::GetName() { return "SourceMod"; } -const char *SourceMod::GetDescription() +const char *SourceMod_Core::GetDescription() { return "Extensible administration and scripting system"; } -const char *SourceMod::GetURL() +const char *SourceMod_Core::GetURL() { return "http://www.sourcemod.net/"; } -const char *SourceMod::GetLicense() +const char *SourceMod_Core::GetLicense() { return "See LICENSE.txt"; } -const char *SourceMod::GetVersion() +const char *SourceMod_Core::GetVersion() { return SOURCEMOD_VERSION; } -const char *SourceMod::GetDate() +const char *SourceMod_Core::GetDate() { return __DATE__; } -const char *SourceMod::GetLogTag() +const char *SourceMod_Core::GetLogTag() { return "SRCMOD"; } diff --git a/core/mm_api.h b/core/mm_api.h index af3a829c..5b230f39 100644 --- a/core/mm_api.h +++ b/core/mm_api.h @@ -3,7 +3,7 @@ #include -class SourceMod : public ISmmPlugin +class SourceMod_Core : public ISmmPlugin { public: bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); @@ -22,7 +22,7 @@ public: const char *GetLogTag(); }; -extern SourceMod g_SourceMod; +extern SourceMod_Core g_SourceMod; PLUGIN_GLOBALVARS(); diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d55bb6c0..ace96064 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -40,6 +40,7 @@ + + + + + + + + diff --git a/core/sm_version.h b/core/sm_version.h index 6986a5bd..91b35912 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -1,8 +1,8 @@ #ifndef _INCLUDE_SOURCEMOD_VERSION_H_ #define _INCLUDE_SOURCEMOD_VERSION_H_ -#define SOURCEMOD_VERSION "1.0.0.0" -#define SOURCEMOD_V_MAJOR 1 +#define SOURCEMOD_VERSION "0.0.0.0" +#define SOURCEMOD_V_MAJOR 0 #define SOURCEMOD_V_MINOR 0 #define SOURCEMOD_V_REV 0 #define SOURCEMOD_V_BUILD 0 From f83a597e49b576086881a0063c832db72ad42ca7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 5 Nov 2006 02:47:13 +0000 Subject: [PATCH 0116/1664] began platform support initial import of platform library code tested on win32 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40146 --- core/interfaces/ILibrarySys.h | 27 +++- core/mm_api.cpp | 1 + core/msvc8/sourcemod_mm.vcproj | 34 +++- core/sm_platform.h | 23 +++ core/systems/LibrarySys.cpp | 278 +++++++++++++++++++++++++++++++++ core/systems/LibrarySys.h | 65 ++++++++ 6 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 core/sm_platform.h create mode 100644 core/systems/LibrarySys.cpp create mode 100644 core/systems/LibrarySys.h diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h index 18a32d81..80858072 100644 --- a/core/interfaces/ILibrarySys.h +++ b/core/interfaces/ILibrarySys.h @@ -10,6 +10,11 @@ namespace SourceMod class ILibrary { + public: + virtual ~ILibrary() + { + /* Calling delete will call CloseLibrary! */ + }; public: /** * @brief Closes dynamic library and invalidates pointer. @@ -30,6 +35,10 @@ namespace SourceMod */ class IDirectory { + public: + virtual ~IDirectory() + { + } public: /** * @brief Returns true if there are more files to read, false otherwise. @@ -90,7 +99,7 @@ namespace SourceMod * @param err_max Maximum length of error buffer. * @return Pointer to an IDirectory, NULL if failed. */ - virtual IDirectory *OpenDirectory(const char *path, char *error, size_t err_max) =0; + virtual IDirectory *OpenDirectory(const char *path) =0; /** * @brief Closes a directory and frees its handle. @@ -99,6 +108,11 @@ namespace SourceMod */ virtual void CloseDirectory(IDirectory *dir) =0; + /** + * @brief Returns true if a path exists. + */ + virtual bool PathExists(const char *path) =0; + /** * @brief Returns true if the path is a normal file. */ @@ -108,6 +122,17 @@ namespace SourceMod * @brief Returns true if the path is a normal directory. */ virtual bool IsPathDirectory(const char *path) =0; + + /** + * @brief Gets a platform-specific error message. + * This should only be called when an ILibrary function fails. + * Win32 equivalent: GetLastError() + FormatMessage() + * POSIX equivalent: errno + strerror() + * + * @param error Error message buffer. + * @param err_max Maximum length of error buffer. + */ + virtual void GetPlatformError(char *error, size_t err_max) =0; }; }; diff --git a/core/mm_api.cpp b/core/mm_api.cpp index 82db205b..77691245 100644 --- a/core/mm_api.cpp +++ b/core/mm_api.cpp @@ -1,6 +1,7 @@ #include #include "mm_api.h" #include "sm_version.h" +#include "systems/LibrarySys.h" SourceMod_Core g_SourceMod; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index ace96064..07ab0db1 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -40,8 +40,8 @@ + + @@ -215,7 +219,7 @@ > + + + + + + + + + + diff --git a/core/sm_platform.h b/core/sm_platform.h new file mode 100644 index 00000000..eca8070c --- /dev/null +++ b/core/sm_platform.h @@ -0,0 +1,23 @@ +#ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ +#define _INCLUDE_SOURCEMOD_PLATFORM_H_ + +#if defined WIN32 || defined WIN64 +#define PLATFORM_WINDOWS +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#if !defined snprintf +#define snprintf _snprintf +#endif +#include +#include +#define PLATFORM_MAX_PATH MAX_PATH +#else if defined __linux__ +#define PLATFORM_LINUX +#define PLATFORM_POSIX +#include +#include +#define PLATFORM_MAX_PATH PATH_MAX +#endif + +#endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp new file mode 100644 index 00000000..9bce6c88 --- /dev/null +++ b/core/systems/LibrarySys.cpp @@ -0,0 +1,278 @@ +#include +#include "LibrarySys.h" + +LibrarySystem g_LibSys; + +CLibrary::~CLibrary() +{ + if (m_lib) + { +#if defined PLATFORM_WINDOWS + FreeLibrary(m_lib); +#else if defined PLATFORM_POSIX + dlclose(m_lib); +#endif + m_lib = NULL; + } +} + +CLibrary::CLibrary(LibraryHandle me) +{ + m_lib = me; +} + +void CLibrary::CloseLibrary() +{ + delete this; +} + +void *CLibrary::GetSymbolAddress(const char *symname) +{ +#if defined PLATFORM_WINDOWS + return GetProcAddress(m_lib, symname); +#else if defined PLATFORM_POSIX + return dlsym(m_lib, symname); +#endif +} + + +/******************** + ** Directory Code ** + ********************/ + + +CDirectory::CDirectory(const char *path) +{ +#if defined PLATFORM_WINDOWS + char newpath[PLATFORM_MAX_PATH]; + snprintf(newpath, sizeof(newpath), "%s\\*.*", path); + m_dir = FindFirstFileA(newpath, &m_fd); + if (!IsValid()) + { + m_fd.cFileName[0] = '\0'; + } +#else if defined PLATFORM_POSIX + m_dir = opendir(path); + if (IsValid()) + { + /* :TODO: we need to read past "." and ".."! */ + ep = readdir(dp); + snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path); + } else { + ep = NULL; + } +#endif +} + +CDirectory::~CDirectory() +{ + if (IsValid()) + { +#if defined PLATFORM_WINDOWS + FindClose(m_dir); +#else if defined PLATFORM_POSIX + closedir(m_dir); +#endif + } +} + +void CDirectory::NextEntry() +{ +#if defined PLATFORM_WINDOWS + if (FindNextFile(m_dir, &m_fd) == 0) + { + FindClose(m_dir); + m_dir = INVALID_HANDLE_VALUE; + } +#else if defined PLATFORM_POSIX + if ((ep=readdir(m_dir) == NULL) + { + closedir(m_dir); + m_dir = NULL; + } +#endif +} + +bool CDirectory::IsEntryDirectory() +{ +#if defined PLATFORM_WINDOWS + return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); +#else if defined PLATFORM_LINUX + char temppath[PLATFORM_MAX_PATH]; + snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); + return g_LibrarySys.IsPathDirectory(temppath); +#endif +} + +bool CDirectory::IsEntryFile() +{ +#if defined PLATFORM_WINDOWS + return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)); +#else if defined PLATFORM_POSIX + char temppath[PLATFORM_MAX_PATH]; + snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); + return g_LibrarySys.IsPathFile(temppath); +#endif +} + +const char *CDirectory::GetEntryName() +{ +#if defined PLATFORM_WINDOWS + return m_fd.cFileName; +#else if defined PLATFORM_LINUX + return ep ? ep->d_name : ""; +#endif +} + +bool CDirectory::MoreFiles() +{ + return IsValid(); +} + +bool CDirectory::IsValid() +{ +#if defined PLATFORM_WINDOWS + return (m_dir != INVALID_HANDLE_VALUE); +#else if defined PLATFORM_LINUX + return (m_dir != NULL); +#endif +} + + +/************************* + ** Library System Code ** + *************************/ + + +bool LibrarySystem::PathExists(const char *path) +{ +#if defined PLATFORM_WINDOWS + DWORD attr = GetFileAttributesA(path); + + return (attr != INVALID_FILE_ATTRIBUTES); +#else if defined PLATFORM_POSIX + struct stat s; + + return (stat(path, &s) == 0); +#endif +} + +bool LibrarySystem::IsPathFile(const char *path) +{ +#if defined PLATFORM_WINDOWS + DWORD attr = GetFileAttributes(path); + + if (attr == INVALID_FILE_ATTRIBUTES) + { + return false; + } + + if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) + { + return false; + } + + return true; +#else if defined PLATFORM_LINUX + struct stat s; + + if (stat(path, &s) != 0) + { + return false; + } + + return S_ISREG(s.st_mode) ? true : false; +#endif +} + +bool LibrarySystem::IsPathDirectory(const char *path) +{ +#if defined PLATFORM_WINDOWS + DWORD attr = GetFileAttributes(path); + + if (attr == INVALID_FILE_ATTRIBUTES) + { + return false; + } + + if (attr & FILE_ATTRIBUTE_DIRECTORY) + { + return true; + } + +#else if defined PLATFORM_LINUX + struct stat s; + + if (stat(path, &s) != 0) + { + return false; + } + + if (S_ISDIR(s.st_mode)) + { + return true; + } +#endif + + return false; +} + +IDirectory *LibrarySystem::OpenDirectory(const char *path) +{ + CDirectory *dir = new CDirectory(path); + + if (!dir->IsValid()) + { + delete dir; + return NULL; + } + + return dir; +} + +void LibrarySystem::GetPlatformError(char *error, size_t err_max) +{ + if (error && err_max) + { +#if defined PLATFORM_WINDOWS + DWORD dw = GetLastError(); + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)error, + err_max, + NULL); +#else if defined PLATFORM_POSIX + snprintf(error, err_max, "%s", strerror(errno)); +#endif + } +} + +void LibrarySystem::CloseDirectory(IDirectory *dir) +{ + delete dir; +} + +ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_max) +{ + LibraryHandle lib; +#if defined PLATFORM_WINDOWS + lib = LoadLibraryA(path); + if (!lib) + { + GetPlatformError(error, err_max); + return false; + } +#else if defined PLATFORM_POSIX + lib = dlopen(path, RTLD_NOW); + if (!lib) + { + GetPlatformError(error, err_max); + return false; + } +#endif + + return new CLibrary(lib); +} diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h new file mode 100644 index 00000000..f471745d --- /dev/null +++ b/core/systems/LibrarySys.h @@ -0,0 +1,65 @@ +#ifndef _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_ +#define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_ + +#include +#include "sm_platform.h" + +using namespace SourceMod; + +#if defined PLATFORM_WINDOWS +typedef HMODULE LibraryHandle; +#else if defined PLATFORM_POSIX +typedef void * LibraryHandle; +#endif + +class CDirectory : public IDirectory +{ +public: + CDirectory(const char *path); + ~CDirectory(); +public: + virtual bool MoreFiles(); + virtual void NextEntry(); + virtual const char *GetEntryName(); + virtual bool IsEntryDirectory(); + virtual bool IsEntryFile(); +public: + bool IsValid(); +private: +#if defined PLATFORM_WINDOWS + HANDLE m_dir; + WIN32_FIND_DATAA m_fd; +#else if defined PLATFORM_LINUX + DIR *m_dir; + struct dirent *ep; + char m_origpath[PLATFORM_MAX_PATH]; +#endif +}; + +class CLibrary : public ILibrary +{ +public: + CLibrary(LibraryHandle me); + ~CLibrary(); +public: + virtual void CloseLibrary(); + virtual void *GetSymbolAddress(const char *symname); +private: + LibraryHandle m_lib; +}; + +class LibrarySystem +{ +public: + virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max); + virtual IDirectory *OpenDirectory(const char *path); + virtual void CloseDirectory(IDirectory *dir); + virtual bool PathExists(const char *path); + virtual bool IsPathFile(const char *path); + virtual bool IsPathDirectory(const char *path); + virtual void GetPlatformError(char *error, size_t err_max); +}; + +extern LibrarySystem g_LibSys; + +#endif //_INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_ From 1682417afaa0893569c4b6bccb3a6887edffa3d4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 5 Nov 2006 07:19:23 +0000 Subject: [PATCH 0117/1664] Added ITextParsers interfaces Initial import of admin configuration (proposed) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40147 --- configs/admins_simple.cfg | 45 ++++++++++++ configs/permissions.cfg | 124 +++++++++++++++++++++++++++++++++ core/interfaces/ITextParsers.h | 96 +++++++++++++++++++++++++ core/msvc8/sourcemod_mm.vcproj | 4 ++ 4 files changed, 269 insertions(+) create mode 100644 configs/admins_simple.cfg create mode 100644 configs/permissions.cfg create mode 100644 core/interfaces/ITextParsers.h diff --git a/configs/admins_simple.cfg b/configs/admins_simple.cfg new file mode 100644 index 00000000..11b9a1d8 --- /dev/null +++ b/configs/admins_simple.cfg @@ -0,0 +1,45 @@ +/*************************************** + * READ THIS CAREFULLY! SEE BOTTOM FOR EXAMPLES + * + * For each admin, you need two settings: + * "identity" "permissions" + * + * For the Identity, you can use a SteamID, IP address, or Name (the type will be auto-detected). + * For the Permissions, you can use a flag string or group (read below), and an optional password. + * + * There are 26 flags (a-z), and each flag has a specific meaning/role. + * For example, the "b" flag means "kick permissions." + * + * You can combine flags into a string like this: + * "abcdefgh" + * + * The default flags are: + * + * "reservation" "a" //Slot reservation + "kick" "b" //Kick other players + "ban" "c" //Ban other players + "unban" "d" //Unban other players + "slay" "e" //Slay other players + "changemap" "f" //Change the map or gameplay type + "cvars" "g" //Change cvars + "configs" "h" //Run config files + "chat" "i" //See dead/team chat and chat with other admins + "votes" "j" //Display votes + "password" "h" //Change server password + "rcon" "i" //Use RCON + "root" "z" //All permissions + * + * NOTE: If you specify a - in a flag string, each subsequent flag will be subtracted instead of added. + * You can specify a + to "undo" this in the same string. + * + * Examples: + * "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID + * "127.0.0.1" "z" //all permissions for this ip + * "BAILOPAN" "mypassword:abc" //name BAILOPAN, password "mypassword" gets reservation, kick, ban + * + ***************************************/ + +FastAdmins: +{ + "127.0.0.1" "z" +} diff --git a/configs/permissions.cfg b/configs/permissions.cfg new file mode 100644 index 00000000..971f4926 --- /dev/null +++ b/configs/permissions.cfg @@ -0,0 +1,124 @@ + +/** + * USE THIS SECTION TO DECLARE DETAILED ADMIN PROPERTIES. + * + * Each admin should have its own "Admin" section, followed by a name. + * The name does not have to be unique. + * + * Available properties: (Anything else is filtered as custom) + * "auth" - REQUIRED - Auth method to use. Built-in methods are: + * "steam" - Steam based authentication + * "name" - Name based authentication + * "ip" - IP based authentication + * Anything else is treated as custom. + * + * "identity" - REQUIRED - Identification string, for example, a steamid or name. + * "password" - Optional password to use. + * "group" - Inherits a set of group permissions. + * "flags" - Inherits a set of flags. + * "immunity" - Sets an immunity to a group (* for all, empty string for default users) + * CommandGroups - See the Permissions section. + * Commands - See the Permissions section. + * + * Example: + Admin: "BAILOPAN" + { + "auth" "steam" + "identity" "STEAM_0:1:16" + "flags" "abcdef" + } + * + */ +Admins: +{ +} + + +/** + * Use this section to tweak admin permission levels and groupings. + * You can also define admin roles in this section. + */ +Levels: +{ + /** + * These are the default role flag mappings. + * You can assign new letters for custom purposes, however you should + * not change the default names, as SourceMod hardcodes these. + */ + Flags: + { + "reservation" "a" + "kick" "b" + "ban" "c" + "unban" "d" + "slay" "e" + "changemap" "f" + "cvars" "g" + "configs" "h" + "chat" "i" + "votes" "j" + "password" "h" + "rcon" "i" + + //Custom flags START + //Custom flags END + + //Note - root is a magic access flag that grants all permissions. + "root" "z" + } + + /** + * By default, commands are registered with three pieces of information: + * 1)Command Name (for example, "csdm_enable") + * 2)Command Group Name (for example, "CSDM") + * 3)Command Level (for example, "changemap") + * You can override the default flags assigned to individual commands or command groups in this way. + * You can specify either a one-character, lower-case flag, or a named flag from "Levels." + * Examples: + * "CSDM" "i" + * "csdm_enable" "j" + */ + Overrides: + { + CommandGroups: + { + } + Commands: + { + } + } +} + +Permissions: +{ + + //Lastly, you can define groups for admins. This helps organize large admin lists. + Groups: + { + /** + * Allowed properties for a group: + * + * "flags" - Flag string (you can use -/+ as allowed earlier). + * "inherit" - Inherits permissions from another group. + * "immunity" - Specifies a group to be immune to. Use "*" for all or "" for users with no group. + * Note: You can use - to strip immunity from a group, in the case of inheritance. + */ + Group: "Sample" + { + /** + * You can override commands and command groups here. + * Specify a command name or group and either "allow" or "deny" + * You can have multiple entries for both sections in order to override/tweak them. + * Examples: + * "CSDM" "allow" + * "csdm_enable" "deny" + */ + CommandGroups: + { + } + Commands: + { + } + } + } +} diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h new file mode 100644 index 00000000..d626e414 --- /dev/null +++ b/core/interfaces/ITextParsers.h @@ -0,0 +1,96 @@ +#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ +#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ + +#include + +namespace SourceMod +{ + class ITextListener_INI + { + public: + /** + * @brief Called when a new section is encountered in an INI file. + * + * @param section Name of section in between the [ and ] characters. + * @return True to keep parsing, false otherwise. + */ + virtual bool ReadINI_NewSection(const char *section) + { + return true; + } + + /** + * @brief Called when encountering a key/value pair in an INI file. + * + * @param key Name of key. + * @param value Name of value. + * @return True to keep parsing, false otherwise. + */ + virtual bool ReadINI_KeyValue(const char *key, const char *value) + { + return true; + } + }; + + class ITextListener_SMC + { + public: + enum SMCParseResult + { + SMCParse_Continue, + SMCParse_SkipSection, + SMCParse_Halt, + SMCParse_HaltFail + }; + + /** + * @brief Called when entering a new section + * + * @param name Name of section, with the colon omitted. + * @param option Optional text after the colon, quotes removed. NULL if none. + * @param colon Whether or not the required ':' was encountered. + * @return SMCParseResult directive. + */ + virtual SMCParseResult ReadSMC_NewSection(const char *name, const char *option, bool colon) + { + return SMCParse_Continue; + } + + /** + * @brief Called when encountering a key/value pair in a section. + * + * @param key Key string. + * @param value Value string. If no quotes were specified, this will be NULL, + and key will contain the entire string. + * @param key_quotes Whether or not the key was in quotation marks. + * @param value_quotes Whether or not the value was in quotation marks. + * @return SMCParseResult directive. + */ + virtual SMCParseResult ReadSMC_KeyValue(const char *key, + const char *value, + bool key_quotes, + bool value_quotes) + { + return SMCParse_Continue; + } + + /** + * @brief Called when leaving the current section. + * + * @return SMCParseResult directive. + */ + virtual SMCParseResult ReadSMC_LeavingSection() + { + return SMCParse_Continue; + } + }; + + class ITextParsers : public SMInterface + { + public: + virtual bool ParseFile_INI(const char *file, ITextListener_INI *ini_listener) =0; + virtual bool ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 07ab0db1..601f50e8 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -226,6 +226,10 @@ RelativePath="..\interfaces\IShareSys.h" > + + Date: Sun, 5 Nov 2006 08:36:59 +0000 Subject: [PATCH 0118/1664] clarified text parsing a bit, improved interface. i am eating a dumpling, it is very tasty! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40148 --- core/interfaces/ITextParsers.h | 116 +++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 5 deletions(-) diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h index d626e414..6654e6be 100644 --- a/core/interfaces/ITextParsers.h +++ b/core/interfaces/ITextParsers.h @@ -5,6 +5,44 @@ namespace SourceMod { + /** + * The INI file format is defined as: + * WHITESPACE: 0x20, \n, \t, \r + * IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? / + * STRING: Any set of symbols + * + * Basic syntax is comprised of SECTIONs. + * A SECTION is defined as: + * [SECTIONNAME] + * OPTION + * OPTION + * OPTION... + * + * SECTIONNAME is an IDENTIFIER. + * OPTION can be repeated any number of times, once per line. + * OPTION is defined as one of: + * KEY = "VALUE" + * KEY = VALUE + * KEY + * Where KEY is an IDENTIFIER and VALUE is a STRING. + * + * WHITESPACE should always be omitted. + * COMMENTS should be stripped, and are defined as text occuring in: + * ; + * + * Example file below. Note that + * The second line is technically invalid. The event handler + * must decide whether this should be allowed. + * --FILE BELOW-- + * [gaben] + * hi = clams + * bye = "NO CLAMS" + * + * [valve] + * cannot + * maintain + * products + */ class ITextListener_INI { public: @@ -24,14 +62,49 @@ namespace SourceMod * * @param key Name of key. * @param value Name of value. + * @param quotes Whether value was enclosed in quotes. * @return True to keep parsing, false otherwise. */ - virtual bool ReadINI_KeyValue(const char *key, const char *value) + virtual bool ReadINI_KeyValue(const char *key, const char *value, bool quotes) { return true; } }; + /** + * :TODO: write this in CFG format so it makes sense + * + * The SMC file format is defined as: + * WHITESPACE: 0x20, \n, \t, \r + * IDENTIFIER: Any ASCII character EXCLUDING ", ', :, WHITESPACE + * STRING: Any set of symbols + * + * Basic syntax is comprised of SECTIONBLOCKs. + * A SECTIONBLOCK defined as: + * + * SECTION: "SECTIONNAME" + * { + * OPTION + * } + * + * OPTION can be repeated any number of times inside a SECTIONBLOCK. + * A new line will terminate an OPTION, but there can be more than one OPTION per line. + * OPTION is defined any of: + * "KEY" "VALUE" + * "SINGLEKEY" + * SECTIONBLOCK + * + * SECTION is an IDENTIFIER + * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings + * + * For an example, see configs/permissions.cfg + * + * WHITESPACE should be ignored. + * Comments are text occuring inside the following tokens, and should be stripped + * unless they are inside literal strings: + * ; + * // + * /* */ class ITextListener_SMC { public: @@ -49,9 +122,13 @@ namespace SourceMod * @param name Name of section, with the colon omitted. * @param option Optional text after the colon, quotes removed. NULL if none. * @param colon Whether or not the required ':' was encountered. + * @param start_token Whether a start token was detected. * @return SMCParseResult directive. */ - virtual SMCParseResult ReadSMC_NewSection(const char *name, const char *option, bool colon) + virtual SMCParseResult ReadSMC_NewSection(const char *name, + const char *option, + bool colon, + bool start_token) { return SMCParse_Continue; } @@ -77,9 +154,10 @@ namespace SourceMod /** * @brief Called when leaving the current section. * + * @param end_token Whether an end token was detected. * @return SMCParseResult directive. */ - virtual SMCParseResult ReadSMC_LeavingSection() + virtual SMCParseResult ReadSMC_LeavingSection(bool end_token) { return SMCParse_Continue; } @@ -88,8 +166,36 @@ namespace SourceMod class ITextParsers : public SMInterface { public: - virtual bool ParseFile_INI(const char *file, ITextListener_INI *ini_listener) =0; - virtual bool ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener) =0; + /** + * @brief Parses an INI-format file. + * + * @param file Path to file. + * @param ini_listener Event handler for reading file. + * @param line If non-NULL, will contain last line parsed (0 if file could not be opened). + * @param col If non-NULL, will contain last column parsed (undefined if file could not be opened). + * @return True if parsing succeded, false if file couldn't be opened or there was a syntax error. + */ + virtual bool ParseFile_INI(const char *file, + ITextListener_INI *ini_listener, + unsigned int *line, + unsigned int *col) =0; + + /** + * @brief Parses an SMC-format text file. + * Note that the parser makes every effort to obey broken syntax. + * For example, if an open brace is missing, but the section name has a colon, + * it will let you know. It is up to the event handlers to decide whether to be strict or not. + * + * @param file Path to file. + * @param smc_listener Event handler for reading file. + * @param line If non-NULL, will contain last line parsed (0 if file could not be opened). + * @param col If non-NULL, will contain last column parsed (undefined if file could not be opened). + * @return True if parsing succeded, false if file couldn't be opened or there was a syntax error. + */ + virtual bool ParseFile_SMC(const char *file, + ITextListener_SMC *smc_listener, + unsigned int *line, + unsigned int *col) =0; }; }; From 13775b11b622e8bb927b7401a6e91bf717fadf50 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 5 Nov 2006 13:24:29 +0000 Subject: [PATCH 0119/1664] added a library table for module autoloading updated VM plugin loader to read in this new section --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40149 --- sourcepawn/compiler/pawncc.c | 33 +++++++++++++++++- sourcepawn/compiler/sc2.c | 51 +++++++++++++++++++++++++--- sourcepawn/include/sp_file_headers.h | 6 ++++ sourcepawn/include/sp_vm_types.h | 2 ++ sourcepawn/vm/sp_vm_engine.cpp | 5 +++ 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index dc919128..a31f1e4a 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -16,6 +16,7 @@ enum FileSections FS_Publics, FS_Pubvars, FS_Natives, + FS_Libraries, FS_Nametable, /* required */ FS_DbgFile, FS_DbgSymbol, @@ -47,7 +48,7 @@ int main(int argc, char *argv[]) sp_file_t *spf; memfile_t *dbgtab = NULL; //dbgcrab unsigned char *dbgptr = NULL; - uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0}; + uint32_t sections[FS_Number] = {1,1,0,0,0,0,1,0,0,0,0,0,0}; FILE *fp; if (bin_file == NULL) @@ -87,6 +88,11 @@ int main(int argc, char *argv[]) { spfw_add_section(spf, ".natives"); } + sections[FS_Libraries] = (hdr->pubvars - hdr->libraries) / hdr->defsize; + if (sections[FS_Libraries]) + { + spfw_add_section(spf, ".libraries"); + } spfw_add_section(spf, ".names"); @@ -251,6 +257,31 @@ int main(int argc, char *argv[]) spfw_next_section(spf); } + if (sections[FS_Libraries]) + { + sp_file_libraries_t *libtbl; + AMX_FUNCSTUBNT *stub; + unsigned char *stubptr; + uint32_t libraries = sections[FS_Libraries]; + + libtbl = (sp_file_libraries_t *)malloc(sizeof(sp_file_libraries_t) * libraries); + stubptr = (unsigned char *)hdr + hdr->libraries; + + for (i=0; inameofs - (hdr->nametable + sizeof(uint16_t)); + + stubptr += hdr->defsize; + } + if (libraries) + { + sfwrite(libtbl, sizeof(sp_file_libraries_t), libraries, spf); + } + free(libtbl); + spfw_next_section(spf); + } + if (sections[FS_Nametable]) { unsigned char *base; diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 6a1c627d..93576701 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1071,8 +1071,28 @@ static int command(void) lptr=(unsigned char*)strchr((char*)lptr,'\0'); /* skip to end (ignore "extra characters on line") */ } else if (strcmp(str,"dynamic")==0) { preproc_expr(&pc_stksize,NULL); - } else if (strcmp(str,"library")==0) { - char name[sNAMEMAX+1]; + } else if (!strcmp(str,"library") + ||!strcmp(str,"reqclass") + ||!strcmp(str,"loadlib") + ||!strcmp(str,"explib") + ||!strcmp(str,"expclass") + ||!strcmp(str,"defclasslib")) { + char name[sNAMEMAX+1],sname[sNAMEMAX+1]; + const char *prefix=""; + sname[0]='\0'; + sname[1]='\0'; + if (!strcmp(str,"library")) + prefix="??li_"; + else if (!strcmp(str,"reqclass")) + prefix="??rc_"; + else if (!strcmp(str,"loadlib")) + prefix="??f_"; + else if (!strcmp(str,"explib")) + prefix="??el_"; + else if (!strcmp(str,"expclass")) + prefix="??ec_"; + else if (!strcmp(str,"defclasslib")) + prefix="??d_"; while (*lptr<=' ' && *lptr!='\0') lptr++; if (*lptr=='"') { @@ -1082,6 +1102,18 @@ static int command(void) for (i=0; iinfo.natives_num = secptr->size / sizeof(sp_file_natives_t); plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs); } + else if (!(plugin->info.lib) && !strcmp(nameptr, ".libraries")) + { + plugin->info.libraries_num = secptr->size / sizeof(sp_file_libraries_t); + plugin->info.lib = (sp_file_libraries_t *)(base + secptr->dataoffs); + } else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) { plugin->info.stringbase = (const char *)(base + secptr->dataoffs); From f19fbac013e4ef84fe56e16598b5025bb3055a14 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 6 Nov 2006 10:57:37 +0000 Subject: [PATCH 0120/1664] renamed mm_api, I don't like short names! finished and tested the INI parser and its API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40150 --- core/CTextParsers.cpp | 286 ++++++++++++++++++++++++++ core/CTextParsers.h | 27 +++ core/interfaces/ITextParsers.h | 54 ++++- core/msvc8/sourcemod_mm.vcproj | 12 +- core/{mm_api.cpp => sourcemm_api.cpp} | 12 +- core/{mm_api.h => sourcemm_api.h} | 0 core/systems/LibrarySys.h | 2 +- 7 files changed, 382 insertions(+), 11 deletions(-) create mode 100644 core/CTextParsers.cpp create mode 100644 core/CTextParsers.h rename core/{mm_api.cpp => sourcemm_api.cpp} (80%) rename core/{mm_api.h => sourcemm_api.h} (100%) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp new file mode 100644 index 00000000..063d1f3b --- /dev/null +++ b/core/CTextParsers.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include "CTextParsers.h" + +CTextParsers g_TextParse; + +static int g_ini_chartable1[255] = {0}; + +CTextParsers::CTextParsers() +{ + g_ini_chartable1['_'] = 1; + g_ini_chartable1['-'] = 1; + g_ini_chartable1[','] = 1; + g_ini_chartable1['+'] = 1; + g_ini_chartable1['.'] = 1; + g_ini_chartable1['$'] = 1; + g_ini_chartable1['?'] = 1; + g_ini_chartable1['/'] = 1; +} + +bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col) +{ + /* :TODO: Implement this */ + if (line) + { + *line = 0; + } + + return false; +} + +bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col) +{ + FILE *fp = fopen(file, "rt"); + unsigned int curline = 0; + unsigned int curtok; + size_t len; + + if (!fp) + { + if (line) + { + *line = 0; + } + + return false; + } + + char buffer[2048]; + char *ptr, *save_ptr; + bool in_quote; + while (!feof(fp)) + { + curline++; + curtok = 0; + buffer[0] = '\0'; + if (fgets(buffer, sizeof(buffer), fp) == NULL) + { + break; + } + + /* Preprocess the string before anything */ + ptr = buffer; + + /* First strip beginning whitespace */ + while ((*ptr != '\0') && isspace(*ptr)) + { + ptr++; + } + + len = strlen(ptr); + + if (!len) + { + continue; + } + + /* Now search for comment characters */ + in_quote = false; + save_ptr = ptr; + for (size_t i=0; i=0 && iReadINI_RawLine(ptr, &curtok)) + { + goto event_failed; + } + + if (*ptr == '[') + { + bool invalid_tokens = false; + bool got_bracket = false; + bool extra_tokens = false; + char c; + + for (size_t i=1; iReadINI_NewSection(&ptr[1], invalid_tokens, got_bracket, extra_tokens, &curtok)) + { + goto event_failed; + } + } else { + char *key_ptr = ptr; + char *val_ptr = NULL; + char c; + size_t first_space = 0; + bool invalid_tokens = false; + bool equal_token = false; + bool quotes = false; + + for (size_t i=0; iReadINI_KeyValue(key_ptr, val_ptr, invalid_tokens, equal_token, quotes, &curtok)) + { + curtok = 0; + goto event_failed; + } + } + } + + if (line) + { + *line = curline; + } + + fclose(fp); + + return true; + +event_failed: + if (line) + { + *line = curline; + } + + if (col) + { + *col = curtok; + } + + fclose(fp); + + return false; +} diff --git a/core/CTextParsers.h b/core/CTextParsers.h new file mode 100644 index 00000000..d6c255ae --- /dev/null +++ b/core/CTextParsers.h @@ -0,0 +1,27 @@ +#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ +#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ + +#include "interfaces/ITextParsers.h" + +using namespace SourceMod; + +class CTextParsers : public ITextParsers +{ + +public: + CTextParsers(); +public: + virtual bool ParseFile_INI(const char *file, + ITextListener_INI *ini_listener, + unsigned int *line, + unsigned int *col); + + virtual bool ParseFile_SMC(const char *file, + ITextListener_SMC *smc_listener, + unsigned int *line, + unsigned int *col); +}; + +extern CTextParsers g_TextParse; + +#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h index 6654e6be..11ac1ae3 100644 --- a/core/interfaces/ITextParsers.h +++ b/core/interfaces/ITextParsers.h @@ -1,5 +1,5 @@ -#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ -#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ +#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ #include @@ -50,9 +50,18 @@ namespace SourceMod * @brief Called when a new section is encountered in an INI file. * * @param section Name of section in between the [ and ] characters. + * @param invalid_tokens True if invalid tokens were detected in the name. + * @param close_bracket True if a closing bracket was detected, false otherwise. + * @param extra_tokens True if extra tokens were detected on the line. + * @param curtok Contains current token in the line where the section name starts. + * You can add to this offset when failing to point to a token. * @return True to keep parsing, false otherwise. */ - virtual bool ReadINI_NewSection(const char *section) + virtual bool ReadINI_NewSection(const char *section, + bool invalid_tokens, + bool close_bracket, + bool extra_tokens, + unsigned int *curtok) { return true; } @@ -61,11 +70,32 @@ namespace SourceMod * @brief Called when encountering a key/value pair in an INI file. * * @param key Name of key. - * @param value Name of value. + * @param value String containing value (with quotes stripped, if any). + * @param invalid_tokens Whether or not the key contained invalid tokens. + * @param equal_token There was an '=' sign present (in case the value is missing). * @param quotes Whether value was enclosed in quotes. + * @param curtoken Contains the token index of the start of the value string. + * This can be changed when returning false. * @return True to keep parsing, false otherwise. */ - virtual bool ReadINI_KeyValue(const char *key, const char *value, bool quotes) + virtual bool ReadINI_KeyValue(const char *key, + const char *value, + bool invalid_tokens, + bool equal_token, + bool quotes, + unsigned int *curtok) + { + return true; + } + + /** + * @brief Called after a line has been preprocessed, if it has text. + * + * @param line Contents of line. + * @param curtok Pointer to optionally store failed position in string. + * @return True to keep parsing, false otherwise. + */ + virtual bool ReadINI_RawLine(const char *line, unsigned int *cutok) { return true; } @@ -163,8 +193,20 @@ namespace SourceMod } }; + #define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers" + #define SMINTERFACE_TEXTPARSERS_VERSION 1 + class ITextParsers : public SMInterface { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_TEXTPARSERS_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_TEXTPARSERS_VERSION; + } public: /** * @brief Parses an INI-format file. @@ -199,4 +241,4 @@ namespace SourceMod }; }; -#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ +#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 601f50e8..99938f78 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -179,7 +179,11 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -189,7 +193,7 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + -#include "mm_api.h" +#include "sourcemm_api.h" #include "sm_version.h" -#include "systems/LibrarySys.h" +#include "CTextParsers.h" SourceMod_Core g_SourceMod; PLUGIN_EXPOSE(SourceMod, g_SourceMod); +class Test : public ITextListener_INI +{ +public: +}; + bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); + Test test; + bool result = g_TextParse.ParseFile_INI("c:\\gaben.ini", &test, NULL, NULL); + return true; } diff --git a/core/mm_api.h b/core/sourcemm_api.h similarity index 100% rename from core/mm_api.h rename to core/sourcemm_api.h diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index f471745d..1937523c 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -48,7 +48,7 @@ private: LibraryHandle m_lib; }; -class LibrarySystem +class LibrarySystem : public ILibrarySys { public: virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max); From 739bad19124da5096689d1940f62f1d1b7caaf88 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 6 Nov 2006 11:04:20 +0000 Subject: [PATCH 0121/1664] OH MY GOD REMOVED THIS TEST CRAP IT IS LATE AND I AM TIRED WHY AM I YELLING OH WELL --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40151 --- core/sourcemm_api.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 4c4f0bfd..dd327190 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -1,24 +1,15 @@ #include #include "sourcemm_api.h" #include "sm_version.h" -#include "CTextParsers.h" SourceMod_Core g_SourceMod; PLUGIN_EXPOSE(SourceMod, g_SourceMod); -class Test : public ITextListener_INI -{ -public: -}; - bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); - Test test; - bool result = g_TextParse.ParseFile_INI("c:\\gaben.ini", &test, NULL, NULL); - return true; } From 445959182533a65ebc7219087388ee9078785009 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 6 Nov 2006 22:23:13 +0000 Subject: [PATCH 0122/1664] small opt in push tracker --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40152 --- sourcepawn/vm/jit/x86/jit_x86.cpp | 4 +-- sourcepawn/vm/jit/x86/opcode_helpers.cpp | 38 ++++++++++-------------- sourcepawn/vm/jit/x86/opcode_helpers.h | 2 +- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 8898563d..3bb0da3e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1624,12 +1624,12 @@ inline void WriteOp_Tracker_Push_C(JitWriter *jit) /* Push the value into the stack and increment pCur */ //mov edx, [eax+vm[]] //mov ecx, [edx+pcur] - //mov [ecx], *4 ; we want the count in bytes not in cells //add [edx+pcur], 4 + //mov [ecx], *4 ; we want the count in bytes not in cells IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG); IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG); /* Restore PRI & ALT */ //pop edx diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 1aa0d670..6b366ade 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -520,8 +520,8 @@ void WriteIntrinsic_GenArray(JitWriter *jit) //jae :done ;end loop if done //mov ecx, [edi+eax*4] ;get dimension size //imul edx, ecx ;multiply by size - //add edx, ecx ;add size (indirection vector) //add eax, 1 ;increment + //add edx, ecx ;add size (indirection vector) //jmp :loop ;jump back //:done IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG); @@ -531,8 +531,8 @@ void WriteIntrinsic_GenArray(JitWriter *jit) jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4); IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); - IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG); + IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1); IA32_Send_Jump8_Here(jit, done1); @@ -573,7 +573,7 @@ void WriteIntrinsic_GenArray(JitWriter *jit) //push edi ;push dim array //push ebx //call GenerateArrayIndirectionVectors - //add esp, 4*3 + //add esp, 4*4 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE); IA32_Push_Rm_Disp8_ESP(jit, 8); IA32_Push_Rm_Disp8_ESP(jit, 8); @@ -690,20 +690,18 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) { CompData *data = (CompData *)jit->data; - //:TODO: optimize reg usage, i dont like it. - /* Save registers that may be damaged by the call */ //push eax - //push edx //push ecx - //push + //push edi + //lea edi, [*4] ; we want the count in bytes not in cells IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Push_Reg(jit, AMX_REG_ALT); - IA32_Push_Reg(jit, AMX_REG_TMP); - if (reg != REG_ECX) + if (reg == REG_ECX) { - IA32_Push_Reg(jit, reg); + IA32_Push_Reg(jit, AMX_REG_TMP); } + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0); /* Get the context ptr, push it and call the check */ //mov eax, [esi+context] @@ -723,30 +721,24 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); /* Push the register into the stack and increment pCur */ - //pop ecx //mov edx, [eax+vm[]] //mov eax, [edx+pcur] - //lea ecx, [ecx*4] ; we want the count in bytes not in cells - //mov [eax], ecx //add [edx+pcur], 4 - IA32_Pop_Reg(jit, REG_ECX); + //mov [eax], edi IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Lea_Reg_RegMultImm32(jit, REG_ECX, REG_ECX, SCALE4, 0); - IA32_Mov_Rm_Reg(jit, REG_EAX, REG_ECX, MOD_MEM_REG); IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG); /* Restore PRI, ALT and STK */ + //pop edi //pop ecx - //pop edx //pop eax - if (reg != REG_ECX) + IA32_Pop_Reg(jit, AMX_REG_STK); + if (reg == REG_ECX) { - IA32_Pop_Reg(jit, AMX_REG_ALT); - } else { - IA32_Shr_Rm_Imm8(jit, REG_ECX, 2, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_TMP); } - IA32_Pop_Reg(jit, AMX_REG_TMP); IA32_Pop_Reg(jit, AMX_REG_PRI); } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 5cddf40f..11b7748c 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -274,8 +274,8 @@ typedef enum * DONE: SYSREQ.N .C (rev2) * MACRO OPCODES (rev2) * ERROR CHECKS\{VERIFY ADDR} (rev2) +* ARRAY STUFF * TODO: BrkDebug -* ARRAY STUFF * EXEC FUNCTION * VERIFY ADDR * From ba9b4f4211da4efb95648ab27b83e4d1c367b511 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 6 Nov 2006 22:30:59 +0000 Subject: [PATCH 0123/1664] what --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40153 --- core/interfaces/ILibrarySys.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h index 80858072..aed3379a 100644 --- a/core/interfaces/ILibrarySys.h +++ b/core/interfaces/ILibrarySys.h @@ -95,8 +95,6 @@ namespace SourceMod * @brief Opens a directory for reading. * * @param path Path to directory. - * @param error Buffer for any error message (may be NULL). - * @param err_max Maximum length of error buffer. * @return Pointer to an IDirectory, NULL if failed. */ virtual IDirectory *OpenDirectory(const char *path) =0; From a5f4929c60328091853c07a24f82981843d8f19d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 6 Nov 2006 22:49:12 +0000 Subject: [PATCH 0124/1664] reaching comment perfection --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40154 --- sourcepawn/include/sp_vm_api.h | 6 +++--- sourcepawn/include/sp_vm_context.h | 8 +++----- sourcepawn/vm/sp_vm_engine.h | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index c07248d8..8f707fe9 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -19,7 +19,7 @@ namespace SourcePawn * Loads a named file from a file pointer. * Using this means base memory will be allocated by the VM. * - * @param fp File pointer. May be at any offset. Not closed on return. + * @param fp File pointer. May be at any offset. Not closed on return. * @param err Optional error code pointer. * @return A new plugin structure. */ @@ -69,7 +69,7 @@ namespace SourcePawn /** * Frees memory allocated with BaseAlloc. * - * @param mem Memory address to free. + * @param memory Memory address to free. */ virtual void BaseFree(void *memory) =0; @@ -84,7 +84,7 @@ namespace SourcePawn /** * Frees executable memory. * - * @param mem Address to free. + * @param address Address to free. */ virtual void ExecFree(void *address) =0; }; diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h index 12dcbd51..523a6410 100644 --- a/sourcepawn/include/sp_vm_context.h +++ b/sourcepawn/include/sp_vm_context.h @@ -154,7 +154,7 @@ namespace SourcePawn * Gets public function info by index. * * @param index Public function index number. - * @param pblic Optionally filled with pointer to public structure. + * @param public Optionally filled with pointer to public structure. */ virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; @@ -177,8 +177,6 @@ namespace SourcePawn * * @param name Name of pubvar * @param index Optionally filled with pubvar index number. - * @param local_addr Optionally filled with local address offset. - * @param phys_addr Optionally filled with relocated physical address. */ virtual int FindPubvarByName(const char *name, uint32_t *index) =0; @@ -255,8 +253,7 @@ namespace SourcePawn * * @param local_addr Filled with local address to release. * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. + * @param string Source string to push. */ virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; @@ -278,6 +275,7 @@ namespace SourcePawn * * @param natives Array of natives. * @param num Number of natives in array. + * @param overwrite Toggles overwrite. */ virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h index 9a181c26..fb13f405 100644 --- a/sourcepawn/vm/sp_vm_engine.h +++ b/sourcepawn/vm/sp_vm_engine.h @@ -14,7 +14,7 @@ namespace SourcePawn * Note: The file handle position may be undefined on entry, and is * always undefined on conclusion. * - * @param fp File pointer. May be at any offset. Not closed on return. + * @param fp File pointer. May be at any offset. Not closed on return. * @param err Optional error code pointer. * @return A new plugin structure. */ @@ -64,11 +64,10 @@ namespace SourcePawn /** * Frees memory allocated with BaseAlloc. * - * @param mem Memory address to free. + * @param memory Memory address to free. */ void BaseFree(void *memory); - /** * Allocates executable memory. * @@ -80,7 +79,7 @@ namespace SourcePawn /** * Frees executable memory. * - * @param mem Address to free. + * @param address Address to free. */ void ExecFree(void *address); }; From 89b125f6c15626bbf99bad06cb3b21a710861e7f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 00:53:06 +0000 Subject: [PATCH 0125/1664] added and tested UTF-8 support for ini files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40155 --- core/CTextParsers.cpp | 79 +++++++++++++++++++++++++++++----- core/CTextParsers.h | 21 ++++++++- core/interfaces/ITextParsers.h | 9 ++++ core/sourcemm_api.cpp | 1 + 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 063d1f3b..eae4f764 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -1,11 +1,14 @@ #include #include +#include #include +#include #include "CTextParsers.h" CTextParsers g_TextParse; static int g_ini_chartable1[255] = {0}; +static int g_ws_chartable[255] = {0}; CTextParsers::CTextParsers() { @@ -17,6 +20,17 @@ CTextParsers::CTextParsers() g_ini_chartable1['$'] = 1; g_ini_chartable1['?'] = 1; g_ini_chartable1['/'] = 1; + g_ws_chartable['\n'] = 1; + g_ws_chartable['\v'] = 1; + g_ws_chartable['\r'] = 1; + g_ws_chartable['\t'] = 1; + g_ws_chartable['\f'] = 1; + g_ws_chartable[' '] = 1; +} + +unsigned int CTextParsers::GetUTF8CharBytes(const char *stream) +{ + return _GetUTF8CharBytes(stream); } bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col) @@ -50,6 +64,7 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen char buffer[2048]; char *ptr, *save_ptr; bool in_quote; + while (!feof(fp)) { curline++; @@ -59,12 +74,26 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen { break; } - - /* Preprocess the string before anything */ - ptr = buffer; - + + //:TODO: this will only run once, so find a nice way to move it out of the while loop + /* If this is the first line, check the first three bytes for BOM */ + if (curline == 1 && + buffer[0] == (char)0xEF && + buffer[1] == (char)0xBB && + buffer[2] == (char)0xBF) + { + /* We have a UTF-8 marked file... skip these bytes */ + ptr = &buffer[3]; + } else { + ptr = buffer; + } + + /*************************************************** + * We preprocess the string before parsing tokens! * + ***************************************************/ + /* First strip beginning whitespace */ - while ((*ptr != '\0') && isspace(*ptr)) + while (*ptr != '\0' && g_ws_chartable[*ptr] != 0) { ptr++; } @@ -117,7 +146,7 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen /* Lastly, strip ending whitespace off */ for (size_t i=len-1; i>=0 && i #include "sourcemm_api.h" #include "sm_version.h" +#include "CTextParsers.h" SourceMod_Core g_SourceMod; From e18699c7027ee28c61266ff6f30c01a831bfbb84 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 09:50:09 +0000 Subject: [PATCH 0126/1664] added experimental new String tag. this tag will revert array usage to "char" sizing and packed strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40156 --- sourcepawn/compiler/sc.h | 5 +++ sourcepawn/compiler/sc1.c | 31 ++++++++++++--- sourcepawn/compiler/sc2.c | 15 +++++--- sourcepawn/compiler/sc3.c | 80 ++++++++++++++++++++++++++++++--------- sourcepawn/compiler/sc4.c | 4 ++ 5 files changed, 106 insertions(+), 29 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index ecd01dd0..ffac5b94 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -567,9 +567,13 @@ SC_FUNC char *itoh(ucell val); SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam, value *lval,int *resulttag); SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce); +SC_FUNC int checktag(int tags[],int numtags,int exprtag); SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult); SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state); SC_FUNC cell array_totalsize(symbol *sym); +SC_FUNC int matchtag_string(int ident, int tag); +SC_FUNC int checktag_string(value *sym1, value *sym2); +SC_FUNC int checktags_string(int tags[], int numtags, value *sym1); /* function prototypes in SC4.C */ SC_FUNC void writeleader(symbol *root); @@ -809,6 +813,7 @@ SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ SC_VDECL int pc_functag; /* global function tag */ +SC_VDECL int pc_tag_string; /* global string tag */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ SC_VDECL constvalue sc_state_tab; /* state table */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 0188be0f..58d657b1 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -71,6 +71,7 @@ #define VERSION_INT 0x0302 int pc_functag = 0; +int pc_tag_string = 0; static void resetglobals(void); static void initglobals(void); @@ -683,7 +684,7 @@ static void initglobals(void) verbosity=1; /* verbosity level, no copyright banner */ sc_debug=sCHKBOUNDS|sSYMBOLIC; /* sourcemod: full debug stuff */ pc_optimize=sOPTIMIZE_DEFAULT; /* sourcemod: full optimization */ - sc_packstr=FALSE; /* strings are unpacked by default */ + sc_packstr=TRUE; /* strings are packed by default */ sc_compress=FALSE; /* always disable compact encoding! */ sc_needsemicolon=FALSE;/* semicolon required to terminate expressions? */ sc_dataalign=sizeof(cell); @@ -1248,6 +1249,7 @@ static void setconstants(void) append_constval(&tagname_tab,"_",0,0);/* "untagged" */ append_constval(&tagname_tab,"bool",1,0); pc_functag = pc_addfunctag("Function"); + pc_tag_string = pc_addtag("String"); add_constant("true",1,sGLOBAL,1); /* boolean flags */ add_constant("false",0,sGLOBAL,1); @@ -1731,6 +1733,8 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst #endif dim[numdim++]=(int)size; } /* while */ + if (ident == iARRAY && tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); assert(sc_curstates==0); sc_curstates=getstates(name); if (sc_curstates<0) { @@ -1989,6 +1993,9 @@ static int declloc(int fstatic) #endif dim[numdim++]=(int)size; } while (matchtoken('[')); + /* Change the last dimension to be based on chars instead if we have a string */ + if (tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); } else if (matchtoken('(')) { int dim_ident; symbol *dim_sym; @@ -2072,10 +2079,11 @@ static int declloc(int fstatic) /* simple variable, also supports initialization */ int ctag = tag; /* set to "tag" by default */ int explicit_init=FALSE;/* is the variable explicitly initialized? */ + int cident=ident; if (matchtoken('=')) { if (!autozero) error(10); - doexpr(FALSE,FALSE,FALSE,FALSE,&ctag,NULL,TRUE); + cident=doexpr(FALSE,FALSE,FALSE,FALSE,&ctag,NULL,TRUE); explicit_init=TRUE; } else { if (autozero) @@ -2094,7 +2102,7 @@ static int declloc(int fstatic) assert(staging); /* end staging phase (optimize expression) */ stgout(staging_start); stgset(FALSE); - if (!matchtag(tag,ctag,TRUE)) + if (!matchtag_string(cident, ctag) && !matchtag(tag,ctag,TRUE)) error(213); /* tag mismatch */ /* if the variable was not explicitly initialized, reset the * "uWRITTEN" flag that store() set */ @@ -2501,7 +2509,7 @@ static cell init(int ident,int *tag,int *errorfound) error(6); /* must be assigned to an array */ litidx=1; /* reset literal queue */ } /* if */ - *tag=0; + *tag=pc_tag_string; } else if (constexpr(&i,tag,NULL)){ litadd(i); /* store expression result in literal table */ } else { @@ -2702,6 +2710,7 @@ static void dofuncenum(void) } if (matchtoken('[')) { + cell size; if (arg->ident == iREFERENCE) { error(67, str); @@ -2709,7 +2718,6 @@ static void dofuncenum(void) do { constvalue *enumroot; - cell size; int ignore_tag; if (arg->dimcount == sDIMEN_MAX) { @@ -2720,6 +2728,11 @@ static void dofuncenum(void) arg->dims[arg->dimcount] = size; arg->dimcount += 1; } while (matchtoken('[')); + /* Handle strings */ + if (arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + { + arg->dims[arg->dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); + } arg->ident=iREFARRAY; } else if (arg->ident == 0) { arg->ident = iVARIABLE; @@ -2850,6 +2863,7 @@ static void decl_enum(int vclass) constexpr(&size,&fieldtag,NULL); /* get size */ needtoken(']'); } /* if */ + /* :TODO: do we need a size modifier here for pc_tag_string? */ if (matchtoken('=')) constexpr(&value,NULL,NULL); /* get value */ /* add_constant() checks whether a variable (global or local) or @@ -3355,6 +3369,9 @@ static void funcstub(int fnative) dim[numdim++]=(int)size; } /* while */ + if (tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); + tok=lex(&val,&str); fpublic=(tok==tPUBLIC) || (tok==tSYMBOL && str[0]==PUBLIC_CHAR); if (fnative) { @@ -3933,6 +3950,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, arg->numdim+=1; } while (matchtoken('[')); ident=iREFARRAY; /* "reference to array" (is a pointer) */ + if (checktag(tags, numtags, pc_tag_string)) + arg->dim[arg->numdim - 1] = (size + sizeof(cell) - 1) / sizeof(cell); if (matchtoken('=')) { lexpush(); /* initials() needs the "=" token again */ assert(litidx==0); /* at the start of a function, this is reset */ @@ -5682,7 +5701,7 @@ static void doreturn(void) rettype|=uRETVALUE; /* function returns a value */ /* check tagname with function tagname */ assert(curfunc!=NULL); - if (!matchtag(curfunc->tag,tag,TRUE)) + if (!matchtag_string(ident, tag) && !matchtag(curfunc->tag,tag,TRUE)) error(213); /* tagname mismatch */ if (ident==iARRAY || ident==iREFARRAY) { int dim[sDIMEN_MAX],numdim; diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 93576701..a65e684f 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1795,7 +1795,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) int i; ucell val,c; - i=sizeof(ucell)-(sCHARBITS/8); /* start at most significant byte */ + i=0; /* start at least significant byte */ val=0; while (*lptr!='\"' && *lptr!='\0') { if (*lptr=='\a') { /* ignore '\a' (which was inserted at a line concatenation) */ @@ -1806,14 +1806,16 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) if (c>=(ucell)(1 << sCHARBITS)) error(43); /* character constant exceeds range */ val |= (c << 8*i); - if (i==0) { + if (i==sizeof(ucell)-(sCHARBITS/8)) { litadd(val); val=0; - } /* if */ - i=(i+sizeof(ucell)-(sCHARBITS/8)) % sizeof(ucell); + i=0; + } else { + i=i+1; + } } /* if */ /* save last code; make sure there is at least one terminating zero character */ - if (i!=(int)(sizeof(ucell)-(sCHARBITS/8))) + if (i!=0) litadd(val); /* at least one zero character in "val" */ else litadd(0); /* add full cell of zeros */ @@ -1875,7 +1877,7 @@ char *sc_tokens[] = { "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=", "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", - "assert", "*begin", "break", "case", "char", "const", "continue", "default", + "assert", "*begin", "break", "case", "chars", "const", "continue", "default", "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", "sleep", "state", "static", "stock", "switch", "tagof", "*then", "while", @@ -2008,6 +2010,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym) lptr+=1; /* skip double quote */ if ((stringflags & RAWMODE)!=0) lptr+=1; /* skip "escape" character too */ + /* Note that this should always be packedstring() for SourcePawn */ lptr=sc_packstr ? packedstring(lptr,stringflags) : unpackedstring(lptr,stringflags); if (*lptr=='\"') lptr+=1; /* skip final quote */ diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 4e7e47a6..a0a37657 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -282,6 +282,44 @@ static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec }; return TRUE; } +SC_FUNC int checktags_string(int tags[], int numtags, value *sym1) +{ + int i; + if (sym1->ident == iARRAY || sym1->ident == iREFARRAY) + { + return FALSE; + } + for (i=0; itag == pc_tag_string && tags[i] == 0) || + (sym1->tag == 0 && tags[i] == pc_tag_string)) + return TRUE; + } + return FALSE; +} + +SC_FUNC int checktag_string(value *sym1, value *sym2) +{ + if (sym1->ident == iARRAY || sym2->ident == iARRAY + || sym1->ident == iREFARRAY || sym2->ident == iREFARRAY) + { + return FALSE; + } + if ((sym1->tag == pc_tag_string && sym2->tag == 0) + || (sym1->tag == 0 && sym2->tag == pc_tag_string)) + { + return TRUE; + } + + return FALSE; +} + +SC_FUNC int matchtag_string(int ident, int tag) +{ + if (ident == iARRAY || ident == iREFARRAY) + return FALSE; + return (tag == pc_tag_string) ? TRUE : FALSE; +} + SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) { if (formaltag!=actualtag) { @@ -781,7 +819,7 @@ static void plnge2(void (*oper)(void), error(213); /* tagname mismatch */ lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult); } else { - if (!matchtag(lval1->tag,lval2->tag,FALSE)) + if (!checktag_string(lval1, lval2) && !matchtag(lval1->tag,lval2->tag,FALSE)) error(213); /* tagname mismatch */ (*oper)(); /* do the (signed) operation */ lval1->ident=iEXPRESSION; @@ -1205,7 +1243,7 @@ static int hier14(value *lval1) check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag); store(&lval3); /* now, store the expression result */ } /* if */ - if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE)) + if (!oper && !checktag_string(&lval3, &lval2) && !matchtag(lval3.tag,lval2.tag,TRUE)) error(213); /* tagname mismatch (if "oper", warning already given in plunge2()) */ if (lval3.sym) markusage(lval3.sym,uWRITTEN); @@ -1658,6 +1696,10 @@ static int hier2(value *lval) popreg(sPRI); /* restore PRI (result of rvalue()) */ sideeffect=TRUE; return FALSE; +/* This is temporarily disabled because we detect it automatically. + * Thus, it could be weird if both were used at once + */ +#if 0 case tCHAR: /* char (compute required # of cells */ if (lval->ident==iCONSTEXPR) { lval->constval *= sCHARBITS/8; /* from char to bytes */ @@ -1670,6 +1712,7 @@ static int hier2(value *lval) addr2cell(); /* truncate to number of cells */ } /* if */ return FALSE; +#endif default: lexpush(); return lvalue; @@ -1745,7 +1788,7 @@ restart: assert(sym->dim.array.level>=0 && sym->dim.array.levelarrayidx[sym->dim.array.level]=lval2.constval; } /* if */ - if (close==']') { + if (close==']' && !(sym->tag == pc_tag_string && sym->dim.array.level == 0)) { /* normal array index */ if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval) error(32,sym->name); /* array index out of bounds */ @@ -1826,7 +1869,11 @@ restart: } /* if */ assert(sym->dim.array.level==0); /* set type to fetch... INDIRECTLY */ - lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR); + if (sym->tag == pc_tag_string) { + lval1->ident = iARRAYCHAR; + } else { + lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR); + } /* if the array index is a field from an enumeration, get the tag name * from the field and save the size of the field too. Otherwise, the * tag is the one from the array symbol. @@ -2105,7 +2152,7 @@ static int findnamedarg(arginfo *arg,char *name) return -1; } -static int checktag(int tags[],int numtags,int exprtag) +int checktag(int tags[],int numtags,int exprtag) { int i; @@ -2281,12 +2328,8 @@ static int nesting=0; heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ - } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION - || lval.ident==iARRAYCHAR) + } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION) { - /* fetch value if needed */ - if (lval.ident==iARRAYCHAR) - rvalue(&lval); /* allocate a cell on the heap and store the * value (already in PRI) there */ setheap_pri(); /* address of the value on the heap in PRI */ @@ -2297,7 +2340,8 @@ static int nesting=0; /* otherwise, the address is already in PRI */ if (lval.sym!=NULL) markusage(lval.sym,uWRITTEN); - if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) + if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) + && !checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) error(213); if (lval.tag!=0) append_constval(&taglst,arg[argidx].name,lval.tag,0); @@ -2311,14 +2355,15 @@ static int nesting=0; /* otherwise, the expression result is already in PRI */ assert(arg[argidx].numtags>0); check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag); - if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) + if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) + && !checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) error(213); if (lval.tag!=0) append_constval(&taglst,arg[argidx].name,lval.tag,0); argidx++; /* argument done */ break; case iREFERENCE: - if (!lvalue || lval.ident==iARRAYCHAR) + if (!lvalue) error(35,argidx+1); /* argument type mismatch */ if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) error(35,argidx+1); /* argument type mismatch */ @@ -2343,7 +2388,7 @@ static int nesting=0; break; case iREFARRAY: if (lval.ident!=iARRAY && lval.ident!=iREFARRAY - && lval.ident!=iARRAYCELL) + && lval.ident!=iARRAYCELL && lval.ident!=iARRAYCHAR) { error(35,argidx+1); /* argument type mismatch */ break; @@ -2354,7 +2399,7 @@ static int nesting=0; * A literal array always has a single dimension. * An iARRAYCELL parameter is also assumed to have a single dimension. */ - if (lval.sym==NULL || lval.ident==iARRAYCELL) { + if (lval.sym==NULL || lval.ident==iARRAYCELL || lval.ident==iARRAYCHAR) { if (arg[argidx].numdim!=1) { error(48); /* array dimensions must match */ } else if (arg[argidx].dim[0]!=0) { @@ -2372,14 +2417,14 @@ static int nesting=0; error(47); /* array sizes must match */ } /* if */ } /* if */ - if (lval.ident!=iARRAYCELL) { + if (lval.ident!=iARRAYCELL && lval.ident!=iARRAYCHAR) { /* save array size, for default values with uSIZEOF flag */ cell array_sz=lval.constval; assert(array_sz!=0);/* literal array must have a size */ if (array_sz<0) array_sz= -array_sz; append_constval(&arrayszlst,arg[argidx].name,array_sz,0); - } /* if */ + }/* if */ } else { symbol *sym=lval.sym; short level=0; @@ -2669,6 +2714,7 @@ static int constant(value *lval) * value distinguishes between literal arrays * and literal strings (this was done for * array assignment). */ + lval->tag=pc_tag_string; } else if (tok=='{') { int tag,lasttag=-1; val=litidx; diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index ff8045c3..509b4e06 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -961,12 +961,16 @@ SC_FUNC void char2addr(void) * The ALIGN.pri/alt instructions must solve this machine dependence; * that is, on Big Endian computers, ALIGN.pri/alt shuold do nothing * and on Little Endian computers they should toggle the address. + * + * NOTE: For Source Pawn, this is fliped. It will do nothing on Little-Endian. */ SC_FUNC void charalign(void) { +#if 0 /* TEMPORARILY DISABLED BECAUSE WE DON'T USE BIG ENDIAN */ stgwrite("\talign.pri "); outval(sCHARBITS/8,TRUE); code_idx+=opcodes(1)+opargs(1); +#endif } /* From 0bdf321d67c2c5928c671270c85779444b7de360 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 10:49:16 +0000 Subject: [PATCH 0127/1664] dynamic arrays no longer use a different token --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40157 --- sourcepawn/compiler/sc.h | 2 +- sourcepawn/compiler/sc1.c | 99 +++++++++++++++++++++++++-------------- sourcepawn/compiler/sc3.c | 6 ++- 3 files changed, 70 insertions(+), 37 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index ffac5b94..2af0db35 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -568,7 +568,7 @@ SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam, value *lval,int *resulttag); SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce); SC_FUNC int checktag(int tags[],int numtags,int exprtag); -SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult); +SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval); SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state); SC_FUNC cell array_totalsize(symbol *sym); SC_FUNC int matchtag_string(int ident, int tag); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 58d657b1..607e7083 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -119,6 +119,8 @@ static void compound(int stmt_sameline,int starttok); static int test(int label,int parens,int invert); static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr, int *tag,symbol **symptr,int chkfuncresult); +static int doexpr2(int comma,int chkeffect,int allowarray,int mark_endexpr, + int *tag,symbol **symptr,int chkfuncresult,value *lval); static void doassert(void); static void doexit(void); static int doif(void); @@ -1733,7 +1735,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst #endif dim[numdim++]=(int)size; } /* while */ - if (ident == iARRAY && tag == pc_tag_string) + if (ident == iARRAY && tag == pc_tag_string && dim[numdim-1]) dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); assert(sc_curstates==0); sc_curstates=getstates(name); @@ -1944,7 +1946,7 @@ static int declloc(int fstatic) int idxtag[sDIMEN_MAX]; char name[sNAMEMAX+1]; symbol *sym; - constvalue *enumroot; + constvalue *enumroot=NULL; cell val,size; char *str; value lval = {0}; @@ -1980,44 +1982,63 @@ static int declloc(int fstatic) if ((sym=findloc(name))!=NULL && sym->compound!=nestlevel || findglb(name,sGLOBAL)!=NULL) error(219,name); /* variable shadows another symbol */ if (matchtoken('[')) { - do { - ident=iARRAY; - if (numdim == sDIMEN_MAX) { - error(53); /* exceeding maximum number of dimensions */ - return ident; - } /* if */ - size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */ - #if INT_MAX < LONG_MAX - if (size > INT_MAX) - error(105); /* overflow, exceeding capacity */ - #endif - dim[numdim++]=(int)size; - } while (matchtoken('[')); - /* Change the last dimension to be based on chars instead if we have a string */ - if (tag == pc_tag_string) - dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); - } else if (matchtoken('(')) { + int _index; + cell _code; int dim_ident; symbol *dim_sym; + value dim_val; + int all_constant = 1; + int _staging = staging; + + if (!_staging) + stgset(TRUE); + stgget(&_index, &_code); + do { - ident=iREFARRAY; if (numdim == sDIMEN_MAX) { - error(53); - return iREFARRAY; + error(53); /* exceeding maximum number of dimensions */ + return (all_constant ? iARRAY : iREFARRAY); } /* if */ - dim_ident = doexpr(TRUE,FALSE,FALSE,FALSE,&idxtag[numdim],&dim_sym,0); - dim[numdim] = 0; - if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION) { + if (matchtoken(']')) { + dim[numdim++] = 0; + continue; + } + dim_ident = doexpr2(TRUE,FALSE,FALSE,FALSE,&idxtag[numdim],&dim_sym,0,&dim_val); + if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION || dim_ident == iARRAYCELL) { + all_constant = 0; pushreg(sPRI); } else if (dim_ident == iCONSTEXPR) { pushreg(sPRI); + dim[numdim] = dim_val.constval; + /* :TODO: :URGENT: Make sure this still works */ + if (dim_sym && dim_sym->usage & uENUMROOT) + enumroot = dim_sym->dim.enumlist; + idxtag[numdim] = dim_sym ? dim_sym->tag : 0; + #if INT_MAX < LONG_MAX + if (dim[numdim] > INT_MAX) + error(105); /* overflow, exceeding capacity */ + #endif } else { - assert(0); //:TODO: make this an error + error(29); /* invalid expression, assumed 0 */ } - needtoken(')'); numdim++; - } while (matchtoken('(')); - genarray(numdim, autozero); + needtoken(']'); + } while (matchtoken('[')); + if (all_constant) { + /* Change the last dimension to be based on chars instead if we have a string */ + if (tag == pc_tag_string && dim[numdim-1]) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); + /* Scrap the code generated */ + ident = iARRAY; + stgdel(_index, _code); + } else { + memset(dim, 0, sizeof(int)*sDIMEN_MAX); + ident = iREFARRAY; + genarray(numdim, autozero); + } + stgout(_index); + if (!_staging) + stgset(FALSE); } if (getstates(name)) error(88,name); /* local variables may not have states */ @@ -3369,7 +3390,7 @@ static void funcstub(int fnative) dim[numdim++]=(int)size; } /* while */ - if (tag == pc_tag_string) + if (tag == pc_tag_string && dim[numdim-1]) dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); tok=lex(&val,&str); @@ -5111,6 +5132,16 @@ static void compound(int stmt_sameline,int starttok) */ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr, int *tag,symbol **symptr,int chkfuncresult) +{ + return doexpr2(comma,chkeffect,allowarray,mark_endexpr,tag,symptr,chkfuncresult,NULL); +} + +/* doexpr2 + * + * Global references: stgidx (referred to only) + */ +static int doexpr2(int comma,int chkeffect,int allowarray,int mark_endexpr, + int *tag,symbol **symptr,int chkfuncresult,value *lval) { int index,ident; int localstaging=FALSE; @@ -5128,7 +5159,7 @@ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr, if (index!=stgidx) markexpr(sEXPR,NULL,0); sideeffect=FALSE; - ident=expression(&val,tag,symptr,chkfuncresult); + ident=expression(&val,tag,symptr,chkfuncresult,lval); if (!allowarray && (ident==iARRAY || ident==iREFARRAY)) error(33,"-unknown-"); /* array must be indexed */ if (chkeffect && !sideeffect) @@ -5155,7 +5186,7 @@ SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr) stgset(TRUE); /* start stage-buffering */ stgget(&index,&cidx); /* mark position in code generator */ errorset(sEXPRMARK,0); - ident=expression(val,tag,symptr,FALSE); + ident=expression(val,tag,symptr,FALSE,NULL); stgdel(index,cidx); /* scratch generated code */ stgset(FALSE); /* stop stage-buffering */ if (ident!=iCONSTEXPR) { @@ -5214,7 +5245,7 @@ static int test(int label,int parens,int invert) do { stgget(&index,&cidx); /* mark position (of last expression) in * code generator */ - ident=expression(&constval,&tag,&sym,TRUE); + ident=expression(&constval,&tag,&sym,TRUE,NULL); tok=matchtoken(','); if (tok) markexpr(sEXPR,NULL,0); @@ -5596,7 +5627,7 @@ static void doassert(void) stgset(TRUE); /* start staging */ stgget(&index,&cidx); /* mark position in code generator */ do { - expression(NULL,NULL,NULL,FALSE); + expression(NULL,NULL,NULL,FALSE,NULL); stgdel(index,cidx); /* just scrap the code */ } while (matchtoken(',')); stgset(FALSE); /* stop staging */ diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index a0a37657..fe8e85ca 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -890,7 +890,7 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult) return 0; } -SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult) +SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval) { value lval={0}; pushheaplist(); @@ -908,6 +908,8 @@ SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult) *symptr=lval.sym; if (chkfuncresult) checkfunction(&lval); + if (_lval) + *_lval=lval; return lval.ident; } @@ -2723,7 +2725,7 @@ static int constant(value *lval) * on at this point */ assert(staging); stgget(&index,&cidx); /* mark position in code generator */ - ident=expression(&item,&tag,NULL,FALSE); + ident=expression(&item,&tag,NULL,FALSE,NULL); stgdel(index,cidx); /* scratch generated code */ if (ident!=iCONSTEXPR) error(8); /* must be constant expression */ From 1dc2662a62892a3bf8be3ba2fa6b7ca641ac08e3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 11:50:30 +0000 Subject: [PATCH 0128/1664] fixed constant dimension size bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40158 --- sourcepawn/compiler/sc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 607e7083..d6101068 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2027,7 +2027,7 @@ static int declloc(int fstatic) if (all_constant) { /* Change the last dimension to be based on chars instead if we have a string */ if (tag == pc_tag_string && dim[numdim-1]) - dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); + dim[numdim-1] = (dim[numdim-1] + sizeof(cell)-1) / sizeof(cell); /* Scrap the code generated */ ident = iARRAY; stgdel(_index, _code); From 2348f9106a5a5cfad04822cb8aadbfdf68866395 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 12:34:27 +0000 Subject: [PATCH 0129/1664] fixed a potential bug in tag matching (should this one go to thiadmer) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40159 --- sourcepawn/compiler/sc3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index fe8e85ca..8bdeb43a 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1782,7 +1782,7 @@ restart: if (lval2.ident==iARRAY || lval2.ident==iREFARRAY) error(33,lval2.sym->name); /* array must be indexed */ needtoken(close); - if (!matchtag(sym->x.tags.index,lval2.tag,TRUE)) + if ((sym->usage & uENUMROOT) && !matchtag(sym->x.tags.index,lval2.tag,TRUE)) error(213); if (lval2.ident==iCONSTEXPR) { /* constant expression */ stgdel(index,cidx); /* scratch generated code */ From 453f0db4761dda57fdc15080643edc85f93df2a6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 7 Nov 2006 13:06:04 +0000 Subject: [PATCH 0130/1664] Changed StringToLocal to work with real strings moved out two .b opcodes out of the ungenerated group since now are needed for strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40160 --- sourcepawn/include/sp_vm_context.h | 8 ++- sourcepawn/vm/jit/x86/jit_x86.cpp | 49 +++++++++++++++++++ sourcepawn/vm/jit/x86/opcode_helpers.h | 10 ++-- sourcepawn/vm/jit/x86/opcode_switch.inc | 10 ++++ sourcepawn/vm/jit/x86/ungen_opcode_switch.inc | 10 ---- sourcepawn/vm/jit/x86/ungen_opcodes.h | 49 ------------------- sourcepawn/vm/sp_vm_basecontext.cpp | 23 +-------- sourcepawn/vm/sp_vm_basecontext.h | 2 +- 8 files changed, 70 insertions(+), 91 deletions(-) diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h index 523a6410..23feef4f 100644 --- a/sourcepawn/include/sp_vm_context.h +++ b/sourcepawn/include/sp_vm_context.h @@ -204,17 +204,15 @@ namespace SourcePawn */ virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; - /** + /**:TODO: FIX ALL PACKED STUFF COMMENTS! * Converts a local address to a physical string. * Note that SourcePawn does not support packed strings, as such this function is * 'cell to char' only. * * @param local_addr Local address in plugin. - * @param buffer Destination output buffer. - * @param maxlength Maximum length of output buffer, including null terminator. - * @param chars Optionally filled with the number of characters written. + * @param addr Destination output pointer. */ - virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) =0; + virtual int LocalToString(cell_t local_addr, char **addr) =0; /** * Converts a physical string to a local address. diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 3bb0da3e..07787592 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -1093,6 +1093,30 @@ inline void WriteOp_Load_I(JitWriter *jit) IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } +inline void WriteOp_Lodb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_PRI); + + //mov eax, [ebp+eax] + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); + + //and eax, + cell_t val = jit->read_cell(); + switch(val) + { + case 1: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF); + break; + } + case 2: + { + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF); + break; + } + } +} + inline void WriteOp_Stor_I(JitWriter *jit) { //mov [ebp+edx], eax @@ -1100,6 +1124,31 @@ inline void WriteOp_Stor_I(JitWriter *jit) IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } +inline void WriteOp_Strb_I(JitWriter *jit) +{ + Write_Check_VerifyAddr(jit, AMX_REG_ALT); + //mov [ebp+edx], eax + cell_t val = jit->read_cell(); + switch (val) + { + case 1: + { + IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 2: + { + IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + case 4: + { + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); + break; + } + } +} + inline void WriteOp_Lidx(JitWriter *jit) { //lea eax, [edx+4*eax] diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 11b7748c..2036ead4 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -104,7 +104,7 @@ typedef enum OP_LREF_S_PRI, //VERIFIED OP_LREF_S_ALT, //~VERIFIED (lref.s.pri) OP_LOAD_I, //VERIFIED - OP_LODB_I, // !GEN :TODO: - only used for pack access - drop support in compiler first + OP_LODB_I, //VERIFIED OP_CONST_PRI, //VERIFIED OP_CONST_ALT, //~VERIFIED (const.pri) OP_ADDR_PRI, //VERIFIED @@ -118,7 +118,7 @@ typedef enum OP_SREF_S_PRI, //VERIFIED OP_SREF_S_ALT, //~VERIFIED (stor.s.alt) OP_STOR_I, //VERIFIED - OP_STRB_I, // !GEN :TODO: - only used for pack access, drop support in compiler first + OP_STRB_I, //VERIFIED OP_LIDX, //VERIFIED OP_LIDX_B, //DONE OP_IDXADDR, //VERIFIED @@ -127,7 +127,7 @@ typedef enum OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_LCTRL, // !GEN OP_SCTRL, // !GEN - OP_MOVE_PRI, //DONE + OP_MOVE_PRI, //~VERIFIED (move.alt) OP_MOVE_ALT, //VERIFIED OP_XCHG, //DONE OP_PUSH_PRI, //DONE @@ -139,7 +139,7 @@ typedef enum OP_POP_PRI, //VERIFIED OP_POP_ALT, //VERIFIED OP_STACK, //VERIFIED - OP_HEAP, //DONE + OP_HEAP, //VERIFIED OP_PROC, //VERIFIED OP_RET, // !GEN OP_RETN, //VERIFIED @@ -211,7 +211,7 @@ typedef enum OP_DEC, //VERIFIED OP_DEC_S, //VERIFIED OP_DEC_I, //VERIFIED - OP_MOVS, //DONE + OP_MOVS, //VERIFIED OP_CMPS, // !GEN OP_FILL, //VERIFIED OP_HALT, //DONE diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index febe45e6..7e1ebc0b 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -508,11 +508,21 @@ WriteOp_Load_I(jit); break; } + case OP_LODB_I: + { + WriteOp_Lodb_I(jit); + break; + } case OP_STOR_I: { WriteOp_Stor_I(jit); break; } + case OP_STRB_I: + { + WriteOp_Strb_I(jit); + break; + } case OP_LIDX: { WriteOp_Lidx(jit); diff --git a/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc b/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc index 0f9ba552..84549267 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc @@ -33,16 +33,6 @@ WriteOp_Align_Alt(jit); break; } - case OP_LODB_I: - { - WriteOp_Lodb_I(jit); - break; - } - case OP_STRB_I: - { - WriteOp_Strb_I(jit); - break; - } case OP_LCTRL: { WriteOp_Lctrl(jit); diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/vm/jit/x86/ungen_opcodes.h index f720946d..abae1dba 100644 --- a/sourcepawn/vm/jit/x86/ungen_opcodes.h +++ b/sourcepawn/vm/jit/x86/ungen_opcodes.h @@ -111,55 +111,6 @@ inline void WriteOp_Cmps(JitWriter *jit) IA32_Pop_Reg(jit, REG_EDI); } -inline void WriteOp_Lodb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - - //mov eax, [ebp+eax] - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - - //and eax, - cell_t val = jit->read_cell(); - switch(val) - { - case 1: - { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF); - break; - } - case 2: - { - IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF); - break; - } - } -} - -inline void WriteOp_Strb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_ALT); - //mov [ebp+edx], eax - cell_t val = jit->read_cell(); - switch (val) - { - case 1: - { - IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 2: - { - IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 4: - { - IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - } -} - inline void WriteOp_Lctrl(JitWriter *jit) { cell_t val = jit->read_cell(); diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index f147aa1b..002f85f4 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -465,7 +465,7 @@ int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t ar return SP_ERROR_NONE; } -int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) +int BaseContext::LocalToString(cell_t local_addr, char **addr) { int len = 0; cell_t *src; @@ -474,26 +474,7 @@ int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength { return SP_ERROR_INVALID_ADDRESS; } - - src = (cell_t *)(ctx->memory + local_addr); - while ((*src != '\0') && ((size_t)len < maxlength)) - { - buffer[len++] = (char)*src++; - } - - if ((size_t)len >= maxlength) - { - len = maxlength - 1; - } - if (len >= 0) - { - buffer[len] = '\0'; - } - - if (chars) - { - *chars = len; - } + *addr = (char *)(ctx->memory + local_addr); return SP_ERROR_NONE; } diff --git a/sourcepawn/vm/sp_vm_basecontext.h b/sourcepawn/vm/sp_vm_basecontext.h index e49972e4..049acdec 100644 --- a/sourcepawn/vm/sp_vm_basecontext.h +++ b/sourcepawn/vm/sp_vm_basecontext.h @@ -31,7 +31,7 @@ namespace SourcePawn virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); virtual uint32_t GetPubVarsNum(); virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); - virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars); + virtual int LocalToString(cell_t local_addr, char **addr); virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); virtual int PushCell(cell_t value); virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); From edeb131e94697a4dc6551a8f27ba7a1940167783 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 23:26:40 +0000 Subject: [PATCH 0131/1664] fixed an index bug on non-constant values --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40161 --- sourcepawn/compiler/sc3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 8bdeb43a..1c7986f8 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1741,6 +1741,7 @@ static int hier1(value *lval1) char *st; char close; symbol *sym; + int magic_string=0; symbol dummysymbol,*cursym; /* for changing the index tags in case of enumerated pseudo-arrays */ lvalue=primary(lval1); @@ -1750,6 +1751,7 @@ restart: sym=cursym; if (matchtoken('[') || matchtoken('{') || matchtoken('(')) { tok=tokeninfo(&val,&st); /* get token read by matchtoken() */ + magic_string = (sym->tag == pc_tag_string && sym->dim.array.level == 0); if (sym==NULL && symtok!=tSYMBOL) { /* we do not have a valid symbol and we appear not to have read a valid * symbol name (so it is unlikely that we would have read a name of an @@ -1834,7 +1836,7 @@ restart: } else { /* array index is not constant */ lval1->arrayidx=NULL; /* reset, so won't be checked */ - if (close==']') { + if (close==']' && !magic_string) { if (sym->dim.array.length!=0) ffbounds(sym->dim.array.length-1); /* run time check for array bounds */ cell2addr(); /* normal array index */ @@ -1845,7 +1847,7 @@ restart: } /* if */ popreg(sALT); ob_add(); /* base address was popped into secondary register */ - if (close!=']') + if (close!=']' || magic_string) charalign(); /* align character index into array */ } /* if */ /* the indexed item may be another array (multi-dimensional arrays) */ From aa033ee5775ab3072f71b8151f30de84a079e5c5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 06:24:28 +0000 Subject: [PATCH 0132/1664] some reorganization --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40162 --- sourcepawn/include/sp_vm_api.h | 288 ++- sourcepawn/include/sp_vm_context.h | 305 --- sourcepawn/{vm => }/jit/jit_helpers.h | 0 sourcepawn/{vm => }/jit/x86/dll_exports.cpp | 0 sourcepawn/{vm => }/jit/x86/dll_exports.h | 0 sourcepawn/{vm => }/jit/x86/jit_x86.cpp | 0 sourcepawn/{vm => }/jit/x86/jit_x86.h | 0 .../{vm => }/jit/x86/opcode_helpers.cpp | 0 sourcepawn/{vm => }/jit/x86/opcode_helpers.h | 0 sourcepawn/{vm => }/jit/x86/opcode_switch.inc | 0 .../{vm => }/jit/x86/ungen_opcode_switch.inc | 0 sourcepawn/{vm => }/jit/x86/ungen_opcodes.h | 0 sourcepawn/{vm => }/jit/x86/x86_macros.h | 0 sourcepawn/vm/jit/x86/msvc8/jit-x86.sln | 20 - sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj | 270 --- sourcepawn/vm/msvc8/vm.sln | 20 - sourcepawn/vm/msvc8/vm.vcproj | 338 ---- sourcepawn/vm/sp_vm_basecontext.cpp | 620 ------ sourcepawn/vm/sp_vm_basecontext.h | 53 - sourcepawn/vm/sp_vm_engine.cpp | 309 --- sourcepawn/vm/sp_vm_engine.h | 88 - sourcepawn/vm/zlib/adler32.c | 149 -- sourcepawn/vm/zlib/compress.c | 79 - sourcepawn/vm/zlib/crc32.c | 423 ---- sourcepawn/vm/zlib/crc32.h | 441 ----- sourcepawn/vm/zlib/deflate.c | 1736 ----------------- sourcepawn/vm/zlib/deflate.h | 331 ---- sourcepawn/vm/zlib/gzio.c | 1026 ---------- sourcepawn/vm/zlib/infback.c | 623 ------ sourcepawn/vm/zlib/inffast.c | 318 --- sourcepawn/vm/zlib/inffast.h | 11 - sourcepawn/vm/zlib/inffixed.h | 94 - sourcepawn/vm/zlib/inflate.c | 1368 ------------- sourcepawn/vm/zlib/inflate.h | 115 -- sourcepawn/vm/zlib/inftrees.c | 329 ---- sourcepawn/vm/zlib/inftrees.h | 55 - sourcepawn/vm/zlib/trees.c | 1219 ------------ sourcepawn/vm/zlib/trees.h | 128 -- sourcepawn/vm/zlib/uncompr.c | 61 - sourcepawn/vm/zlib/zconf.h | 281 --- sourcepawn/vm/zlib/zlib.h | 1357 ------------- sourcepawn/vm/zlib/zutil.c | 318 --- sourcepawn/vm/zlib/zutil.h | 269 --- 43 files changed, 286 insertions(+), 12756 deletions(-) delete mode 100644 sourcepawn/include/sp_vm_context.h rename sourcepawn/{vm => }/jit/jit_helpers.h (100%) rename sourcepawn/{vm => }/jit/x86/dll_exports.cpp (100%) rename sourcepawn/{vm => }/jit/x86/dll_exports.h (100%) rename sourcepawn/{vm => }/jit/x86/jit_x86.cpp (100%) rename sourcepawn/{vm => }/jit/x86/jit_x86.h (100%) rename sourcepawn/{vm => }/jit/x86/opcode_helpers.cpp (100%) rename sourcepawn/{vm => }/jit/x86/opcode_helpers.h (100%) rename sourcepawn/{vm => }/jit/x86/opcode_switch.inc (100%) rename sourcepawn/{vm => }/jit/x86/ungen_opcode_switch.inc (100%) rename sourcepawn/{vm => }/jit/x86/ungen_opcodes.h (100%) rename sourcepawn/{vm => }/jit/x86/x86_macros.h (100%) delete mode 100644 sourcepawn/vm/jit/x86/msvc8/jit-x86.sln delete mode 100644 sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj delete mode 100644 sourcepawn/vm/msvc8/vm.sln delete mode 100644 sourcepawn/vm/msvc8/vm.vcproj delete mode 100644 sourcepawn/vm/sp_vm_basecontext.cpp delete mode 100644 sourcepawn/vm/sp_vm_basecontext.h delete mode 100644 sourcepawn/vm/sp_vm_engine.cpp delete mode 100644 sourcepawn/vm/sp_vm_engine.h delete mode 100644 sourcepawn/vm/zlib/adler32.c delete mode 100644 sourcepawn/vm/zlib/compress.c delete mode 100644 sourcepawn/vm/zlib/crc32.c delete mode 100644 sourcepawn/vm/zlib/crc32.h delete mode 100644 sourcepawn/vm/zlib/deflate.c delete mode 100644 sourcepawn/vm/zlib/deflate.h delete mode 100644 sourcepawn/vm/zlib/gzio.c delete mode 100644 sourcepawn/vm/zlib/infback.c delete mode 100644 sourcepawn/vm/zlib/inffast.c delete mode 100644 sourcepawn/vm/zlib/inffast.h delete mode 100644 sourcepawn/vm/zlib/inffixed.h delete mode 100644 sourcepawn/vm/zlib/inflate.c delete mode 100644 sourcepawn/vm/zlib/inflate.h delete mode 100644 sourcepawn/vm/zlib/inftrees.c delete mode 100644 sourcepawn/vm/zlib/inftrees.h delete mode 100644 sourcepawn/vm/zlib/trees.c delete mode 100644 sourcepawn/vm/zlib/trees.h delete mode 100644 sourcepawn/vm/zlib/uncompr.c delete mode 100644 sourcepawn/vm/zlib/zconf.h delete mode 100644 sourcepawn/vm/zlib/zlib.h delete mode 100644 sourcepawn/vm/zlib/zutil.c delete mode 100644 sourcepawn/vm/zlib/zutil.h diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 8f707fe9..56e354de 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -3,11 +3,295 @@ #include #include "sp_vm_types.h" -#include "sp_vm_context.h" namespace SourcePawn { - class IPluginContext; + class IVirtualMachine; + + class IPluginDebugInfo + { + public: + /** + * Given a code pointer, finds the file it is associated with. + * + * @param addr Code address offset. + * @param filename Pointer to store filename pointer in. + */ + virtual int LookupFile(ucell_t addr, const char **filename) =0; + + /** + * Given a code pointer, finds the function it is associated with. + * + * @param addr Code address offset. + * @param name Pointer to store function name pointer in. + */ + virtual int LookupFunction(ucell_t addr, const char **name) =0; + + /** + * Given a code pointer, finds the line it is associated with. + * + * @param addr Code address offset. + * @param line Pointer to store line number in. + */ + virtual int LookupLine(ucell_t addr, uint32_t *line) =0; + }; + + class IPluginContext + { + public: + virtual ~IPluginContext() { }; + public: + /** + * Returns the parent IVirtualMachine. + * + * @return Parent virtual machine pointer. + */ + virtual IVirtualMachine *GetVirtualMachine() =0; + + /** + * Returns the child sp_context_t structure. + * + * @return Child sp_context_t structure. + */ + virtual sp_context_t *GetContext() =0; + + /** + * Returns true if the plugin is in debug mode. + * + * @return True if in debug mode, false otherwise. + */ + virtual bool IsDebugging() =0; + + /** + * Installs a debug break and returns the old one, if any. + * This will fail if the plugin is not debugging. + * + * @param newpfn New function pointer. + * @param oldpfn Pointer to retrieve old function pointer. + */ + virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; + + /** + * Returns debug info. + * + * @return IPluginDebugInfo, or NULL if no debug info found. + */ + virtual IPluginDebugInfo *GetDebugInfo() =0; + + /** + * Allocs memory on the secondary stack of a plugin. + * Note that although called a heap, it is in fact a stack. + * + * @param cells Number of cells to allocate. + * @param local_adddr Will be filled with data offset to heap. + * @param phys_addr Physical address to heap memory. + */ + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * Pops a heap address off the heap stack. Use this to free memory allocated with + * SP_HeapAlloc(). + * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations + * with this native should be performed in precisely the REVERSE order. + * + * @param local_addr Local address to free. + */ + virtual int HeapPop(cell_t local_addr) =0; + + /** + * Releases a heap address using a different method than SP_HeapPop(). + * This allows you to release in any order. However, if you allocate N + * objects, release only some of them, then begin allocating again, + * you cannot go back and starting freeing the originals. + * In other words, for each chain of allocations, if you start deallocating, + * then allocating more in a chain, you must only deallocate from the current + * allocation chain. This is basically HeapPop() except on a larger scale. + * + * @param local_addr Local address to free. + */ + virtual int HeapRelease(cell_t local_addr) =0; + + /** + * Finds a native by name. + * + * @param name Name of native. + * @param index Optionally filled with native index number. + */ + virtual int FindNativeByName(const char *name, uint32_t *index) =0; + + /** + * Gets native info by index. + * + * @param index Index number of native. + * @param native Optionally filled with pointer to native structure. + */ + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; + + /** + * Gets the number of natives. + * + * @return Filled with the number of natives. + */ + virtual uint32_t GetNativesNum() =0; + + /** + * Finds a public function by name. + * + * @param name Name of public + * @param index Optionally filled with public index number. + */ + virtual int FindPublicByName(const char *name, uint32_t *index) =0; + + /** + * Gets public function info by index. + * + * @param index Public function index number. + * @param public Optionally filled with pointer to public structure. + */ + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; + + /** + * Gets the number of public functions. + * + * @return Filled with the number of public functions. + */ + virtual uint32_t GetPublicsNum() =0; + + /** + * Gets public variable info by index. + * @param index Public variable index number. + * @param pubvar Optionally filled with pointer to pubvar structure. + */ + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; + + /** + * Finds a public variable by name. + * + * @param name Name of pubvar + * @param index Optionally filled with pubvar index number. + */ + virtual int FindPubvarByName(const char *name, uint32_t *index) =0; + + /** + * Gets the addresses of a public variable. + * + * @param index Index of public variable. + * @param local_addr Address to store local address in. + * @param phys_addr Address to store physically relocated in. + */ + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * Returns the number of public variables. + * + * @return Number of public variables. + */ + virtual uint32_t GetPubVarsNum() =0; + + /** + * Round-about method of converting a plugin reference to a physical address + * + * @param local_addr Local address in plugin. + * @param phys_addr Optionally filled with relocated physical address. + */ + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; + + /**:TODO: FIX ALL PACKED STUFF COMMENTS! + * Converts a local address to a physical string. + * Note that SourcePawn does not support packed strings, as such this function is + * 'cell to char' only. + * + * @param local_addr Local address in plugin. + * @param addr Destination output pointer. + */ + virtual int LocalToString(cell_t local_addr, char **addr) =0; + + /** + * Converts a physical string to a local address. + * Note that SourcePawn does not support packed strings. + * + * @param local_addr Local address in plugin. + * @param chars Number of chars to write, including NULL terminator. + * @param source Source string to copy. + */ + virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + + /** + * Pushes a cell onto the stack. Increases the parameter count by one. + * + * @param value Cell value. + */ + virtual int PushCell(cell_t value) =0; + + /** + * Pushes an array of cells onto the stack. Increases the parameter count by one. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; + + /** + * Pushes a string onto the stack (by reference) and increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param string Source string to push. + */ + virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; + + /** + * Individually pushes each cell of an array of cells onto the stack. Increases the + * parameter count by the number of cells pushed. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * + * @param array Array of cells to read from. + * @param numcells Number of cells to read. + */ + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; + + /** + * Binds a list of native names and their function pointers to a context. + * If num is 0, the list is read until an entry with a NULL name is reached. + * All natives are assigned a status of SP_NATIVE_OKAY by default. + * If overwrite is non-zero, already registered natives will be overwritten. + * + * @param natives Array of natives. + * @param num Number of natives in array. + * @param overwrite Toggles overwrite. + */ + virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; + + /** + * Binds a single native. Overwrites any existing bind. + * If the context does not contain the native that will be binded the function will return + * with a SP_ERROR_OT_FOUND error. + * + * @param native Pointer to native. + * @param status Status value to set (should be SP_NATIVE_OKAY). + */ + virtual int BindNative(sp_nativeinfo_t *native, uint32_t status) =0; + + /** + * Binds a single native to any non-registered or pending native. + * Status is automatically set to pending. + * + * @param native Native to bind. + */ + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; + + /** + * Executes a public function. + */ + virtual int Execute(uint32_t public_func, cell_t *result) =0; + }; /** * Contains helper functions used by VMs and the host app diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h deleted file mode 100644 index 23feef4f..00000000 --- a/sourcepawn/include/sp_vm_context.h +++ /dev/null @@ -1,305 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ -#define _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ - -#include "sp_vm_types.h" - -/***************** - ** Note that all functions return a non-zero error code on failure - * unless otherwise noted. - * All input pointers must be valid unless otherwise noted as optional. - * All output pointers on failure are undefined. - * All local address are guaranteed to be positive. However, they are stored - * as signed integers, because they must logically fit inside a cell. - */ - -namespace SourcePawn -{ - class IVirtualMachine; - - class IPluginDebugInfo - { - public: - /** - * Given a code pointer, finds the file it is associated with. - * - * @param addr Code address offset. - * @param filename Pointer to store filename pointer in. - */ - virtual int LookupFile(ucell_t addr, const char **filename) =0; - - /** - * Given a code pointer, finds the function it is associated with. - * - * @param addr Code address offset. - * @param name Pointer to store function name pointer in. - */ - virtual int LookupFunction(ucell_t addr, const char **name) =0; - - /** - * Given a code pointer, finds the line it is associated with. - * - * @param addr Code address offset. - * @param line Pointer to store line number in. - */ - virtual int LookupLine(ucell_t addr, uint32_t *line) =0; - }; - - class IPluginContext - { - public: - virtual ~IPluginContext() { }; - public: - /** - * Returns the parent IVirtualMachine. - * - * @return Parent virtual machine pointer. - */ - virtual IVirtualMachine *GetVirtualMachine() =0; - - /** - * Returns the child sp_context_t structure. - * - * @return Child sp_context_t structure. - */ - virtual sp_context_t *GetContext() =0; - - /** - * Returns true if the plugin is in debug mode. - * - * @return True if in debug mode, false otherwise. - */ - virtual bool IsDebugging() =0; - - /** - * Installs a debug break and returns the old one, if any. - * This will fail if the plugin is not debugging. - * - * @param newpfn New function pointer. - * @param oldpfn Pointer to retrieve old function pointer. - */ - virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; - - /** - * Returns debug info. - * - * @return IPluginDebugInfo, or NULL if no debug info found. - */ - virtual IPluginDebugInfo *GetDebugInfo() =0; - - /** - * Allocs memory on the secondary stack of a plugin. - * Note that although called a heap, it is in fact a stack. - * - * @param cells Number of cells to allocate. - * @param local_adddr Will be filled with data offset to heap. - * @param phys_addr Physical address to heap memory. - */ - virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; - - /** - * Pops a heap address off the heap stack. Use this to free memory allocated with - * SP_HeapAlloc(). - * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations - * with this native should be performed in precisely the REVERSE order. - * - * @param local_addr Local address to free. - */ - virtual int HeapPop(cell_t local_addr) =0; - - /** - * Releases a heap address using a different method than SP_HeapPop(). - * This allows you to release in any order. However, if you allocate N - * objects, release only some of them, then begin allocating again, - * you cannot go back and starting freeing the originals. - * In other words, for each chain of allocations, if you start deallocating, - * then allocating more in a chain, you must only deallocate from the current - * allocation chain. This is basically HeapPop() except on a larger scale. - * - * @param local_addr Local address to free. - */ - virtual int HeapRelease(cell_t local_addr) =0; - - /** - * Finds a native by name. - * - * @param name Name of native. - * @param index Optionally filled with native index number. - */ - virtual int FindNativeByName(const char *name, uint32_t *index) =0; - - /** - * Gets native info by index. - * - * @param index Index number of native. - * @param native Optionally filled with pointer to native structure. - */ - virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; - - /** - * Gets the number of natives. - * - * @return Filled with the number of natives. - */ - virtual uint32_t GetNativesNum() =0; - - /** - * Finds a public function by name. - * - * @param name Name of public - * @param index Optionally filled with public index number. - */ - virtual int FindPublicByName(const char *name, uint32_t *index) =0; - - /** - * Gets public function info by index. - * - * @param index Public function index number. - * @param public Optionally filled with pointer to public structure. - */ - virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; - - /** - * Gets the number of public functions. - * - * @return Filled with the number of public functions. - */ - virtual uint32_t GetPublicsNum() =0; - - /** - * Gets public variable info by index. - * @param index Public variable index number. - * @param pubvar Optionally filled with pointer to pubvar structure. - */ - virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; - - /** - * Finds a public variable by name. - * - * @param name Name of pubvar - * @param index Optionally filled with pubvar index number. - */ - virtual int FindPubvarByName(const char *name, uint32_t *index) =0; - - /** - * Gets the addresses of a public variable. - * - * @param index Index of public variable. - * @param local_addr Address to store local address in. - * @param phys_addr Address to store physically relocated in. - */ - virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; - - /** - * Returns the number of public variables. - * - * @return Number of public variables. - */ - virtual uint32_t GetPubVarsNum() =0; - - /** - * Round-about method of converting a plugin reference to a physical address - * - * @param local_addr Local address in plugin. - * @param phys_addr Optionally filled with relocated physical address. - */ - virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; - - /**:TODO: FIX ALL PACKED STUFF COMMENTS! - * Converts a local address to a physical string. - * Note that SourcePawn does not support packed strings, as such this function is - * 'cell to char' only. - * - * @param local_addr Local address in plugin. - * @param addr Destination output pointer. - */ - virtual int LocalToString(cell_t local_addr, char **addr) =0; - - /** - * Converts a physical string to a local address. - * Note that SourcePawn does not support packed strings. - * - * @param local_addr Local address in plugin. - * @param chars Number of chars to write, including NULL terminator. - * @param source Source string to copy. - */ - virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; - - /** - * Pushes a cell onto the stack. Increases the parameter count by one. - * - * @param value Cell value. - */ - virtual int PushCell(cell_t value) =0; - - /** - * Pushes an array of cells onto the stack. Increases the parameter count by one. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * Note that this does not release the heap, so you should release it after - * calling Execute(). - * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. - */ - virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; - - /** - * Pushes a string onto the stack (by reference) and increases the parameter count by one. - * Note that this does not release the heap, so you should release it after - * calling Execute(). - * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param string Source string to push. - */ - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; - - /** - * Individually pushes each cell of an array of cells onto the stack. Increases the - * parameter count by the number of cells pushed. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * - * @param array Array of cells to read from. - * @param numcells Number of cells to read. - */ - virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; - - /** - * Binds a list of native names and their function pointers to a context. - * If num is 0, the list is read until an entry with a NULL name is reached. - * All natives are assigned a status of SP_NATIVE_OKAY by default. - * If overwrite is non-zero, already registered natives will be overwritten. - * - * @param natives Array of natives. - * @param num Number of natives in array. - * @param overwrite Toggles overwrite. - */ - virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; - - /** - * Binds a single native. Overwrites any existing bind. - * If the context does not contain the native that will be binded the function will return - * with a SP_ERROR_OT_FOUND error. - * - * @param native Pointer to native. - * @param status Status value to set (should be SP_NATIVE_OKAY). - */ - virtual int BindNative(sp_nativeinfo_t *native, uint32_t status) =0; - - /** - * Binds a single native to any non-registered or pending native. - * Status is automatically set to pending. - * - * @param native Native to bind. - */ - virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; - - /** - * Executes a public function. - */ - virtual int Execute(uint32_t public_func, cell_t *result) =0; - }; -}; - -#endif //_INCLUDE_SOURCEPAWN_VM_CONTEXT_H_ diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/jit/jit_helpers.h similarity index 100% rename from sourcepawn/vm/jit/jit_helpers.h rename to sourcepawn/jit/jit_helpers.h diff --git a/sourcepawn/vm/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp similarity index 100% rename from sourcepawn/vm/jit/x86/dll_exports.cpp rename to sourcepawn/jit/x86/dll_exports.cpp diff --git a/sourcepawn/vm/jit/x86/dll_exports.h b/sourcepawn/jit/x86/dll_exports.h similarity index 100% rename from sourcepawn/vm/jit/x86/dll_exports.h rename to sourcepawn/jit/x86/dll_exports.h diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp similarity index 100% rename from sourcepawn/vm/jit/x86/jit_x86.cpp rename to sourcepawn/jit/x86/jit_x86.cpp diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h similarity index 100% rename from sourcepawn/vm/jit/x86/jit_x86.h rename to sourcepawn/jit/x86/jit_x86.h diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp similarity index 100% rename from sourcepawn/vm/jit/x86/opcode_helpers.cpp rename to sourcepawn/jit/x86/opcode_helpers.cpp diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h similarity index 100% rename from sourcepawn/vm/jit/x86/opcode_helpers.h rename to sourcepawn/jit/x86/opcode_helpers.h diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/jit/x86/opcode_switch.inc similarity index 100% rename from sourcepawn/vm/jit/x86/opcode_switch.inc rename to sourcepawn/jit/x86/opcode_switch.inc diff --git a/sourcepawn/vm/jit/x86/ungen_opcode_switch.inc b/sourcepawn/jit/x86/ungen_opcode_switch.inc similarity index 100% rename from sourcepawn/vm/jit/x86/ungen_opcode_switch.inc rename to sourcepawn/jit/x86/ungen_opcode_switch.inc diff --git a/sourcepawn/vm/jit/x86/ungen_opcodes.h b/sourcepawn/jit/x86/ungen_opcodes.h similarity index 100% rename from sourcepawn/vm/jit/x86/ungen_opcodes.h rename to sourcepawn/jit/x86/ungen_opcodes.h diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/jit/x86/x86_macros.h similarity index 100% rename from sourcepawn/vm/jit/x86/x86_macros.h rename to sourcepawn/jit/x86/x86_macros.h diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln b/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln deleted file mode 100644 index 149b2fc1..00000000 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jit-x86", "jit-x86.vcproj", "{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.ActiveCfg = Debug|Win32 - {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.Build.0 = Debug|Win32 - {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.ActiveCfg = Release|Win32 - {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj deleted file mode 100644 index f7e0b79c..00000000 --- a/sourcepawn/vm/jit/x86/msvc8/jit-x86.vcproj +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sourcepawn/vm/msvc8/vm.sln b/sourcepawn/vm/msvc8/vm.sln deleted file mode 100644 index d9b51a02..00000000 --- a/sourcepawn/vm/msvc8/vm.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vm", "vm.vcproj", "{1B84D3AE-5938-401E-AD85-84D22A823BDA}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Debug|Win32.ActiveCfg = Debug|Win32 - {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Debug|Win32.Build.0 = Debug|Win32 - {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Release|Win32.ActiveCfg = Release|Win32 - {1B84D3AE-5938-401E-AD85-84D22A823BDA}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj deleted file mode 100644 index c57a6b54..00000000 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ /dev/null @@ -1,338 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp deleted file mode 100644 index 002f85f4..00000000 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ /dev/null @@ -1,620 +0,0 @@ -#include -#include -#include -#include "sp_vm_api.h" -#include "sp_vm_basecontext.h" - -using namespace SourcePawn; - -#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) -#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) - -BaseContext::BaseContext(sp_context_t *_ctx) -{ - ctx = _ctx; - ctx->context = this; -} - -IVirtualMachine *BaseContext::GetVirtualMachine() -{ - return (IVirtualMachine *)ctx->vmbase; -} - -sp_context_t *BaseContext::GetContext() -{ - return ctx; -} - -bool BaseContext::IsDebugging() -{ - return (ctx->flags & SPFLAG_PLUGIN_DEBUG); -} - -int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) -{ - if (!IsDebugging()) - { - return SP_ERROR_NOTDEBUGGING; - } - - *oldpfn = ctx->dbreak; - ctx->dbreak = newpfn; - - return SP_ERROR_NONE; -} - -IPluginDebugInfo *BaseContext::GetDebugInfo() -{ - return this; -} - -int BaseContext::Execute(uint32_t public_func, cell_t *result) -{ - IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; - - uint32_t pushcount = ctx->pushcount; - - int err; - sp_public_t *pubfunc; - if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERROR_NONE) - { - return err; - } - - PushCell(pushcount++); - ctx->pushcount = 0; - - cell_t save_sp = ctx->sp; - cell_t save_hp = ctx->hp; - - err = vm->ContextExecute(ctx, pubfunc->offs, result); - - /** - * :TODO: turn this into an error check - */ - -#if defined _DEBUG - if (err == SP_ERROR_NONE) - { - assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); - assert(ctx->hp == save_hp); - } -#endif - if (err != SP_ERROR_NONE) - { - ctx->sp = save_sp; - ctx->hp = save_hp; - } - - return err; -} - -int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) -{ - cell_t *addr; - ucell_t realmem; - -#if 0 - if (cells > CELLBOUNDMAX) - { - return SP_ERROR_ARAM; - } -#else - assert(cells < CELLBOUNDMAX); -#endif - - realmem = cells * sizeof(cell_t); - - /** - * Check if the space between the heap and stack is sufficient. - */ - if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) - { - return SP_ERROR_HEAPLOW; - } - - addr = (cell_t *)(ctx->memory + ctx->hp); - /* store size of allocation in cells */ - *addr = (cell_t)cells; - addr++; - ctx->hp += sizeof(cell_t); - - *local_addr = ctx->hp; - - if (phys_addr) - { - *phys_addr = addr; - } - - ctx->hp += realmem; - - return SP_ERROR_NONE; -} - -int BaseContext::HeapPop(cell_t local_addr) -{ - cell_t cellcount; - cell_t *addr; - - /* check the bounds of this address */ - local_addr -= sizeof(cell_t); - if (local_addr < ctx->heap_base || local_addr >= ctx->sp) - { - return SP_ERROR_INVALID_ADDRESS; - } - - addr = (cell_t *)(ctx->memory + local_addr); - cellcount = (*addr) * sizeof(cell_t); - /* check if this memory count looks valid */ - if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr; - - return SP_ERROR_NONE; -} - - -int BaseContext::HeapRelease(cell_t local_addr) -{ - if (local_addr < ctx->heap_base) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr - sizeof(cell_t); - - return SP_ERROR_NONE; -} - -int BaseContext::FindNativeByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.natives_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->natives[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) -{ - if (index >= ctx->plugin->info.natives_num) - { - return SP_ERROR_INDEX; - } - - if (native) - { - *native = &(ctx->natives[index]); - } - - return SP_ERROR_NONE; -} - - -uint32_t BaseContext::GetNativesNum() -{ - return ctx->plugin->info.natives_num; -} - -int BaseContext::FindPublicByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.publics_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->publics[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) -{ - if (index >= ctx->plugin->info.publics_num) - { - return SP_ERROR_INDEX; - } - - if (pblic) - { - *pblic = &(ctx->publics[index]); - } - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPublicsNum() -{ - return ctx->plugin->info.publics_num; -} - -int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - if (pubvar) - { - *pubvar = &(ctx->pubvars[index]); - } - - return SP_ERROR_NONE; -} - -int BaseContext::FindPubvarByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.pubvars_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->pubvars[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - *local_addr = ctx->plugin->info.pubvars[index].address; - *phys_addr = ctx->pubvars[index].offs; - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPubVarsNum() -{ - return ctx->plugin->info.pubvars_num; -} - -int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) -{ - uint32_t i, j, max; - - max = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) - { - continue; - } - - for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) - { - ctx->natives[i].pfn = natives[j].func; - ctx->natives[i].status = SP_NATIVE_OKAY; - } - } - } - - return SP_ERROR_NONE; -} - - - -int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) -{ - uint32_t index; - int err; - - if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) - { - return err; - } - - ctx->natives[index].pfn = native->func; - ctx->natives[index].status = status; - - return SP_ERROR_NONE; -} - -int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) -{ - uint32_t nativesnum, i; - - nativesnum = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status != SP_NATIVE_OKAY) - { - ctx->natives[i].pfn = native; - ctx->natives[i].status = SP_NATIVE_PENDING; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (phys_addr) - { - *phys_addr = (cell_t *)(ctx->memory + local_addr); - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCell(cell_t value) -{ - if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) - { - return SP_ERROR_STACKLOW; - } - - ctx->sp -= sizeof(cell_t); - *(cell_t *)(ctx->memory + ctx->sp) = value; - ctx->pushcount++; - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) -{ - unsigned int i; - int err; - - for (i=0; isp += (cell_t)(i * sizeof(cell_t)); - ctx->pushcount -= i; - return err; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) -{ - cell_t *ph_addr; - int err; - - if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - memcpy(ph_addr, array, numcells * sizeof(cell_t)); - - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) - { - HeapRelease(*local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToString(cell_t local_addr, char **addr) -{ - int len = 0; - cell_t *src; - - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - *addr = (char *)(ctx->memory + local_addr); - - return SP_ERROR_NONE; -} - -int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) -{ - cell_t *ph_addr; - int err; - unsigned int i, numcells = strlen(string); - - if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - len = strlen(source); - dest = (cell_t *)(ctx->memory + local_addr); - - if ((size_t)len >= chars) - { - len = chars - 1; - } - - for (i=0; i>1) - -int BaseContext::LookupFile(ucell_t addr, const char **filename) -{ - int high, low, mid; - - high = ctx->plugin->debug.files_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->files[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERROR_NOT_FOUND; - } - - *filename = ctx->files[low].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupFunction(ucell_t addr, const char **name) -{ - uint32_t iter, max = ctx->plugin->debug.syms_num; - - for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) - && (ctx->symbols[iter].codestart <= addr) - && (ctx->symbols[iter].codeend > addr)) - { - break; - } - } - - if (iter >= max) - { - return SP_ERROR_NOT_FOUND; - } - - *name = ctx->symbols[iter].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupLine(ucell_t addr, uint32_t *line) -{ - int high, low, mid; - - high = ctx->plugin->debug.lines_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->lines[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERROR_NOT_FOUND; - } - - *line = ctx->lines[low].line; - - return SP_ERROR_NONE; -} diff --git a/sourcepawn/vm/sp_vm_basecontext.h b/sourcepawn/vm/sp_vm_basecontext.h deleted file mode 100644 index 049acdec..00000000 --- a/sourcepawn/vm/sp_vm_basecontext.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ -#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ - -#include "sp_vm_context.h" - -namespace SourcePawn -{ - class BaseContext : - public IPluginContext, - public IPluginDebugInfo - { - public: - BaseContext(sp_context_t *ctx); - public: //IPluginContext - IVirtualMachine *GetVirtualMachine(); - sp_context_t *GetContext(); - bool IsDebugging(); - int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn); - IPluginDebugInfo *GetDebugInfo(); - virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); - virtual int HeapPop(cell_t local_addr); - virtual int HeapRelease(cell_t local_addr); - virtual int FindNativeByName(const char *name, uint32_t *index); - virtual int GetNativeByIndex(uint32_t index, sp_native_t **native); - virtual uint32_t GetNativesNum(); - virtual int FindPublicByName(const char *name, uint32_t *index); - virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); - virtual uint32_t GetPublicsNum(); - virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); - virtual int FindPubvarByName(const char *name, uint32_t *index); - virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); - virtual uint32_t GetPubVarsNum(); - virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); - virtual int LocalToString(cell_t local_addr, char **addr); - virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); - virtual int PushCell(cell_t value); - virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); - virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); - virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); - virtual int BindNative(sp_nativeinfo_t *native, uint32_t status); - virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); - virtual int Execute(uint32_t public_func, cell_t *result); - public: //IPluginDebugInfo - virtual int LookupFile(ucell_t addr, const char **filename); - virtual int LookupFunction(ucell_t addr, const char **name); - virtual int LookupLine(ucell_t addr, uint32_t *line); - private: - sp_context_t *ctx; - }; -}; - -#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_ diff --git a/sourcepawn/vm/sp_vm_engine.cpp b/sourcepawn/vm/sp_vm_engine.cpp deleted file mode 100644 index dc39f480..00000000 --- a/sourcepawn/vm/sp_vm_engine.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include -#include -#include "sp_file_headers.h" -#include "sp_vm_types.h" -#include "sp_vm_engine.h" -#include "zlib/zlib.h" -#include "sp_vm_basecontext.h" - -#if defined WIN32 - #define WIN32_LEAN_AND_MEAN - #include -#else if defined __GNUC__ - #include -#endif - -using namespace SourcePawn; - -void *SourcePawnEngine::ExecAlloc(size_t size) -{ -#if defined WIN32 - return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else if defined __GNUC__ - void *base = memalign(sysconf(_SC_PAGESIZE), size); - if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) - { - free(base); - return NULL; - } - return base; -#endif -} - -void SourcePawnEngine::ExecFree(void *address) -{ -#if defined WIN32 - VirtualFree(address, 0, MEM_RELEASE); -#else if defined __GNUC__ - free(address); -#endif -} - -void *SourcePawnEngine::BaseAlloc(size_t size) -{ - return malloc(size); -} - -void SourcePawnEngine::BaseFree(void *memory) -{ - free(memory); -} - -IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx) -{ - return new BaseContext(ctx); -} - -void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx) -{ - sp_context_t *_ctx = ctx->GetContext(); - IVirtualMachine *vm = ctx->GetVirtualMachine(); - - vm->FreeContext(_ctx); - - delete ctx; -} - -sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err) -{ - char *nameptr; - uint8_t sectnum = 0; - sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t)); - - memset(plugin, 0, sizeof(sp_plugin_t)); - - plugin->base = base; - - while (sectnum < hdr->sections) - { - nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs); - - if (!(plugin->pcode) && !strcmp(nameptr, ".code")) - { - sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs); - plugin->pcode = base + secptr->dataoffs + cod->code; - plugin->pcode_size = cod->codesize; - plugin->flags = cod->flags; - } - else if (!(plugin->data) && !strcmp(nameptr, ".data")) - { - sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs); - plugin->data = base + secptr->dataoffs + dat->data; - plugin->data_size = dat->datasize; - plugin->memory = dat->memsize; - } - else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics")) - { - plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t); - plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs); - } - else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars")) - { - plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t); - plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); - } - else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives")) - { - plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t); - plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs); - } - else if (!(plugin->info.lib) && !strcmp(nameptr, ".libraries")) - { - plugin->info.libraries_num = secptr->size / sizeof(sp_file_libraries_t); - plugin->info.lib = (sp_file_libraries_t *)(base + secptr->dataoffs); - } - else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) - { - plugin->info.stringbase = (const char *)(base + secptr->dataoffs); - } - else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files")) - { - plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs); - } - else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines")) - { - plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); - } - else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols")) - { - plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); - } - else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info")) - { - sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs); - plugin->debug.files_num = inf->num_files; - plugin->debug.lines_num = inf->num_lines; - plugin->debug.syms_num = inf->num_syms; - } - else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) - { - plugin->debug.stringbase = (const char *)(base + secptr->dataoffs); - } - - secptr++; - sectnum++; - } - - if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase)) - { - goto return_error; - } - - if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) - { - goto return_error; - } - - if (err) - { - *err = SP_ERROR_NONE; - } - - return plugin; - -return_error: - if (err) - { - *err = SP_ERROR_FILE_FORMAT; - } - - return NULL; -} - -sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) -{ - sp_file_hdr_t hdr; - sp_plugin_t *plugin; - uint8_t *base; - int z_result; - int error; - - if (!fp) - { - error = SP_ERROR_NOT_FOUND; - goto return_error; - } - - /* Rewind for safety */ - rewind(fp); - fread(&hdr, sizeof(sp_file_hdr_t), 1, fp); - - if (hdr.magic != SPFILE_MAGIC) - { - error = SP_ERROR_FILE_FORMAT; - goto return_error; - } - - switch (hdr.compression) - { - case SPFILE_COMPRESSION_GZ: - { - uint32_t uncompsize = hdr.imagesize - hdr.dataoffs; - uint32_t compsize = hdr.disksize - hdr.dataoffs; - uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t); - uLongf destlen = uncompsize; - - char *tempbuf = (char *)malloc(compsize); - void *uncompdata = malloc(uncompsize); - void *sectheader = malloc(sectsize); - - fread(sectheader, sectsize, 1, fp); - fread(tempbuf, compsize, 1, fp); - - z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize); - free(tempbuf); - if (z_result != Z_OK) - { - free(sectheader); - free(uncompdata); - error = SP_ERROR_DECOMPRESSOR; - goto return_error; - } - - base = (uint8_t *)malloc(hdr.imagesize); - memcpy(base, &hdr, sizeof(sp_file_hdr_t)); - memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize); - free(sectheader); - memcpy(base + hdr.dataoffs, uncompdata, uncompsize); - free(uncompdata); - break; - } - case SPFILE_COMPRESSION_NONE: - { - base = (uint8_t *)malloc(hdr.imagesize); - rewind(fp); - fread(base, hdr.imagesize, 1, fp); - break; - } - default: - { - error = SP_ERROR_DECOMPRESSOR; - goto return_error; - } - } - - plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); - if (!_ReadPlugin(&hdr, base, plugin, err)) - { - free(plugin); - free(base); - return NULL; - } - - plugin->allocflags = 0; - - return plugin; - -return_error: - if (err) - { - *err = error; - } - return NULL; -} - -sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) -{ - sp_file_hdr_t hdr; - uint8_t noptr = 0; - - memcpy(&hdr, base, sizeof(sp_file_hdr_t)); - - if (!plugin) - { - plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); - noptr = 1; - } - - if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err)) - { - if (noptr) - { - free(plugin); - } - return NULL; - } - - if (!noptr) - { - plugin->allocflags |= SP_FA_SELF_EXTERNAL; - } - plugin->allocflags |= SP_FA_BASE_EXTERNAL; - - return plugin; -} - -int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) -{ - if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL)) - { - free(plugin->base); - plugin->base = NULL; - } - if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL)) - { - free(plugin); - } - - return SP_ERROR_NONE; -} diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h deleted file mode 100644 index fb13f405..00000000 --- a/sourcepawn/vm/sp_vm_engine.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ -#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ - -#include "sp_vm_api.h" - -namespace SourcePawn -{ - class SourcePawnEngine : public ISourcePawnEngine - { - public: - /** - * Loads a named file from a file pointer. - * Using this means base memory will be allocated by the VM. - * Note: The file handle position may be undefined on entry, and is - * always undefined on conclusion. - * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. - */ - sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); - - /** - * Loads a file from a base memory address. - * - * @param base Base address of the plugin's memory region. - * @param plugin If NULL, a new plugin pointer is returned. - * Otherwise, the passed pointer is used. - * @param err Optional error code pointer. - * @return The resulting plugin pointer. - */ - sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); - - /** - * Frees all of the memory associated with a plugin file. - * If allocated using SP_LoadFromMemory, the base and plugin pointer - * itself are not freed (so this may end up doing nothing). - */ - int FreeFromMemory(sp_plugin_t *plugin); - - /** - * Creates a new IContext from a context handle. - * - * @param ctx Context to use as a basis for the IPluginContext. - * @return New IPluginContext handle. - */ - IPluginContext *CreateBaseContext(sp_context_t *ctx); - - /** - * Frees a context. - * - * @param ctx Context pointer to free. - */ - void FreeBaseContext(IPluginContext *ctx); - - /** - * Allocates memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ - void *BaseAlloc(size_t size); - - /** - * Frees memory allocated with BaseAlloc. - * - * @param memory Memory address to free. - */ - void BaseFree(void *memory); - - /** - * Allocates executable memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ - void *ExecAlloc(size_t size); - - /** - * Frees executable memory. - * - * @param address Address to free. - */ - void ExecFree(void *address); - }; -}; - -#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/sourcepawn/vm/zlib/adler32.c b/sourcepawn/vm/zlib/adler32.c deleted file mode 100644 index f201d670..00000000 --- a/sourcepawn/vm/zlib/adler32.c +++ /dev/null @@ -1,149 +0,0 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware */ -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD4(a) \ - do { \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD4(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD4(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* the derivation of this formula is left as an exercise for the reader */ - rem = (unsigned)(len2 % BASE); - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 > BASE) sum1 -= BASE; - if (sum1 > BASE) sum1 -= BASE; - if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); - if (sum2 > BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} diff --git a/sourcepawn/vm/zlib/compress.c b/sourcepawn/vm/zlib/compress.c deleted file mode 100644 index d37e84f5..00000000 --- a/sourcepawn/vm/zlib/compress.c +++ /dev/null @@ -1,79 +0,0 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} diff --git a/sourcepawn/vm/zlib/crc32.c b/sourcepawn/vm/zlib/crc32.c deleted file mode 100644 index 32814c20..00000000 --- a/sourcepawn/vm/zlib/crc32.c +++ /dev/null @@ -1,423 +0,0 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case */ - if (len2 == 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320L; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} diff --git a/sourcepawn/vm/zlib/crc32.h b/sourcepawn/vm/zlib/crc32.h deleted file mode 100644 index 5de49bc9..00000000 --- a/sourcepawn/vm/zlib/crc32.h +++ /dev/null @@ -1,441 +0,0 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; diff --git a/sourcepawn/vm/zlib/deflate.c b/sourcepawn/vm/zlib/deflate.c deleted file mode 100644 index 529f716b..00000000 --- a/sourcepawn/vm/zlib/deflate.c +++ /dev/null @@ -1,1736 +0,0 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); - dictionary += dictLength - length; /* use the tail of the dictionary */ - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; - s->nice_match = nice_length; - s->max_chain_length = max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy(dest, source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - /* %%% avoid this when Z_RLE */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ - -#if 0 -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt run; /* length of run */ - uInt max; /* maximum length of run */ - uInt prev; /* byte at distance one to match */ - Bytef *scan; /* scan for end of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest encodable run. - */ - if (s->lookahead < MAX_MATCH) { - fill_window(s); - if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - run = 0; - if (s->strstart > 0) { /* if there is a previous byte, that is */ - max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; - scan = s->window + s->strstart - 1; - prev = *scan++; - do { - if (*scan++ != prev) - break; - } while (++run < max); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (run >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, run); - _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); - s->lookahead -= run; - s->strstart += run; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif diff --git a/sourcepawn/vm/zlib/deflate.h b/sourcepawn/vm/zlib/deflate.h deleted file mode 100644 index 222c53e0..00000000 --- a/sourcepawn/vm/zlib/deflate.h +++ /dev/null @@ -1,331 +0,0 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2004 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ diff --git a/sourcepawn/vm/zlib/gzio.c b/sourcepawn/vm/zlib/gzio.c deleted file mode 100644 index 5e20a4aa..00000000 --- a/sourcepawn/vm/zlib/gzio.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id$ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_DEFAULT_COMPRESSION; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[46]; /* allow for up to 128-bit integers */ - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - start++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= - (uInt)fread(next_out, 1, s->stream.avail_out, s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - if (len == s->stream.avail_out && - (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) - return -1; - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Returns 1 if reading and doing so transparently, otherwise zero. -*/ -int ZEXPORT gzdirect (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return 0; - return s->transparent; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - if (do_flush (file, Z_FINISH) != Z_OK) - return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -#ifdef STDC -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -/* =========================================================================== - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} diff --git a/sourcepawn/vm/zlib/infback.c b/sourcepawn/vm/zlib/infback.c deleted file mode 100644 index 1e03e1ba..00000000 --- a/sourcepawn/vm/zlib/infback.c +++ /dev/null @@ -1,623 +0,0 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} diff --git a/sourcepawn/vm/zlib/inffast.c b/sourcepawn/vm/zlib/inffast.c deleted file mode 100644 index fa31cad9..00000000 --- a/sourcepawn/vm/zlib/inffast.c +++ /dev/null @@ -1,318 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ diff --git a/sourcepawn/vm/zlib/inffast.h b/sourcepawn/vm/zlib/inffast.h deleted file mode 100644 index 614fa787..00000000 --- a/sourcepawn/vm/zlib/inffast.h +++ /dev/null @@ -1,11 +0,0 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/sourcepawn/vm/zlib/inffixed.h b/sourcepawn/vm/zlib/inffixed.h deleted file mode 100644 index 423d5c5b..00000000 --- a/sourcepawn/vm/zlib/inffixed.h +++ /dev/null @@ -1,94 +0,0 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; diff --git a/sourcepawn/vm/zlib/inflate.c b/sourcepawn/vm/zlib/inflate.c deleted file mode 100644 index 33ea9029..00000000 --- a/sourcepawn/vm/zlib/inflate.c +++ /dev/null @@ -1,1368 +0,0 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->wsize = 0; - state->whave = 0; - state->write = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - if (state->mode == DICT) { - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy(dest, source, sizeof(z_stream)); - zmemcpy(copy, state, sizeof(struct inflate_state)); - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} diff --git a/sourcepawn/vm/zlib/inflate.h b/sourcepawn/vm/zlib/inflate.h deleted file mode 100644 index fbbc8714..00000000 --- a/sourcepawn/vm/zlib/inflate.h +++ /dev/null @@ -1,115 +0,0 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; diff --git a/sourcepawn/vm/zlib/inftrees.c b/sourcepawn/vm/zlib/inftrees.c deleted file mode 100644 index 38ded81c..00000000 --- a/sourcepawn/vm/zlib/inftrees.c +++ /dev/null @@ -1,329 +0,0 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)1; - this.val = (unsigned short)0; - *(*table)++ = this; /* make a table to force an error */ - *(*table)++ = this; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} diff --git a/sourcepawn/vm/zlib/inftrees.h b/sourcepawn/vm/zlib/inftrees.h deleted file mode 100644 index dc0fd567..00000000 --- a/sourcepawn/vm/zlib/inftrees.h +++ /dev/null @@ -1,55 +0,0 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); diff --git a/sourcepawn/vm/zlib/trees.c b/sourcepawn/vm/zlib/trees.c deleted file mode 100644 index 7a048028..00000000 --- a/sourcepawn/vm/zlib/trees.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2005 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) - set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to BINARY or TEXT, using a crude approximation: - * set it to Z_TEXT if all symbols are either printable characters (33 to 255) - * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local void set_data_type(s) - deflate_state *s; -{ - int n; - - for (n = 0; n < 9; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - if (n == 9) - for (n = 14; n < 32; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} diff --git a/sourcepawn/vm/zlib/trees.h b/sourcepawn/vm/zlib/trees.h deleted file mode 100644 index 1ca868b8..00000000 --- a/sourcepawn/vm/zlib/trees.h +++ /dev/null @@ -1,128 +0,0 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - diff --git a/sourcepawn/vm/zlib/uncompr.c b/sourcepawn/vm/zlib/uncompr.c deleted file mode 100644 index ad6db0a6..00000000 --- a/sourcepawn/vm/zlib/uncompr.c +++ /dev/null @@ -1,61 +0,0 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} diff --git a/sourcepawn/vm/zlib/zconf.h b/sourcepawn/vm/zlib/zconf.h deleted file mode 100644 index 59b5e7a6..00000000 --- a/sourcepawn/vm/zlib/zconf.h +++ /dev/null @@ -1,281 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ diff --git a/sourcepawn/vm/zlib/zlib.h b/sourcepawn/vm/zlib/zlib.h deleted file mode 100644 index 62d0e467..00000000 --- a/sourcepawn/vm/zlib/zlib.h +++ /dev/null @@ -1,1357 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ diff --git a/sourcepawn/vm/zlib/zutil.c b/sourcepawn/vm/zlib/zutil.c deleted file mode 100644 index 0f4bd787..00000000 --- a/sourcepawn/vm/zlib/zutil.c +++ /dev/null @@ -1,318 +0,0 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ diff --git a/sourcepawn/vm/zlib/zutil.h b/sourcepawn/vm/zlib/zutil.h deleted file mode 100644 index 0ba6e020..00000000 --- a/sourcepawn/vm/zlib/zutil.h +++ /dev/null @@ -1,269 +0,0 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# ifndef _WIN32_WCE -# include -# endif -# include -# include -#endif -#ifdef NO_ERRNO_H -# ifdef _WIN32_WCE - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. We rename it to - * avoid conflict with other libraries that use the same workaround. - */ -# define errno z_errno -# endif - extern int errno; -#else -# ifndef _WIN32_WCE -# include -# endif -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# ifdef M_I86 - #include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ From 4242e06465afd6833375844d348ffbe910de8b3e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 06:25:25 +0000 Subject: [PATCH 0133/1664] re-added project files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40163 --- sourcepawn/jit/x86/msvc8/jit-x86.sln | 20 ++ sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 270 ++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 sourcepawn/jit/x86/msvc8/jit-x86.sln create mode 100644 sourcepawn/jit/x86/msvc8/jit-x86.vcproj diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.sln b/sourcepawn/jit/x86/msvc8/jit-x86.sln new file mode 100644 index 00000000..149b2fc1 --- /dev/null +++ b/sourcepawn/jit/x86/msvc8/jit-x86.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jit-x86", "jit-x86.vcproj", "{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.Build.0 = Debug|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.ActiveCfg = Release|Win32 + {6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj new file mode 100644 index 00000000..f7e0b79c --- /dev/null +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 65026ef57e4ebc9dbdc08324957965e1b6569ebf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 06:30:20 +0000 Subject: [PATCH 0134/1664] finalized new structure and imported newly proposed plugin system API added zlib to source tree added VM API to source tree --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40164 --- core/CTextParsers.cpp | 10 +- core/CTextParsers.h | 3 +- core/interfaces/IPluginSys.h | 170 +++- core/interfaces/ITextParsers.h | 49 +- core/msvc8/sourcemod_mm.vcproj | 152 +++ core/sourcemod.h | 8 + core/vm/sp_vm_basecontext.cpp | 617 ++++++++++++ core/vm/sp_vm_basecontext.h | 53 + core/vm/sp_vm_engine.cpp | 309 ++++++ core/vm/sp_vm_engine.h | 88 ++ core/zlib/adler32.c | 149 +++ core/zlib/compress.c | 79 ++ core/zlib/crc32.c | 423 ++++++++ core/zlib/crc32.h | 441 ++++++++ core/zlib/deflate.c | 1736 ++++++++++++++++++++++++++++++++ core/zlib/deflate.h | 331 ++++++ core/zlib/gzio.c | 1026 +++++++++++++++++++ core/zlib/infback.c | 623 ++++++++++++ core/zlib/inffast.c | 318 ++++++ core/zlib/inffast.h | 11 + core/zlib/inffixed.h | 94 ++ core/zlib/inflate.c | 1368 +++++++++++++++++++++++++ core/zlib/inflate.h | 115 +++ core/zlib/inftrees.c | 329 ++++++ core/zlib/inftrees.h | 55 + core/zlib/trees.c | 1219 ++++++++++++++++++++++ core/zlib/trees.h | 128 +++ core/zlib/uncompr.c | 61 ++ core/zlib/zconf.h | 281 ++++++ core/zlib/zlib.h | 1357 +++++++++++++++++++++++++ core/zlib/zutil.c | 318 ++++++ core/zlib/zutil.h | 269 +++++ 32 files changed, 12167 insertions(+), 23 deletions(-) create mode 100644 core/sourcemod.h create mode 100644 core/vm/sp_vm_basecontext.cpp create mode 100644 core/vm/sp_vm_basecontext.h create mode 100644 core/vm/sp_vm_engine.cpp create mode 100644 core/vm/sp_vm_engine.h create mode 100644 core/zlib/adler32.c create mode 100644 core/zlib/compress.c create mode 100644 core/zlib/crc32.c create mode 100644 core/zlib/crc32.h create mode 100644 core/zlib/deflate.c create mode 100644 core/zlib/deflate.h create mode 100644 core/zlib/gzio.c create mode 100644 core/zlib/infback.c create mode 100644 core/zlib/inffast.c create mode 100644 core/zlib/inffast.h create mode 100644 core/zlib/inffixed.h create mode 100644 core/zlib/inflate.c create mode 100644 core/zlib/inflate.h create mode 100644 core/zlib/inftrees.c create mode 100644 core/zlib/inftrees.h create mode 100644 core/zlib/trees.c create mode 100644 core/zlib/trees.h create mode 100644 core/zlib/uncompr.c create mode 100644 core/zlib/zconf.h create mode 100644 core/zlib/zlib.h create mode 100644 core/zlib/zutil.c create mode 100644 core/zlib/zutil.h diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index eae4f764..9c76d5c1 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -33,13 +33,9 @@ unsigned int CTextParsers::GetUTF8CharBytes(const char *stream) return _GetUTF8CharBytes(stream); } -bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col) +bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col, bool strict) { - /* :TODO: Implement this */ - if (line) - { - *line = 0; - } + /* This beast is a lot more rigorous than our INI friend. */ return false; } @@ -247,7 +243,7 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen { if (g_ws_chartable[c]) { - /* if it's a space, keep track of the last space */ + /* if it's a space, keep track of the first occurring space */ if (!first_space) { first_space = i; diff --git a/core/CTextParsers.h b/core/CTextParsers.h index 20450b5b..111a5c52 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -36,7 +36,8 @@ public: virtual bool ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, - unsigned int *col); + unsigned int *col, + bool strict); virtual unsigned int GetUTF8CharBytes(const char *stream); }; diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 446a7975..8dce1d39 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -2,12 +2,50 @@ #define _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ #include +#include #define SMINTERFACE_PLUGINMANAGER_NAME "IPluginManager" #define SMINTERFACE_PLUGINMANAGER_VERSION 1 namespace SourceMod { + /** + * @brief Encapsulates plugin public information. + */ + typedef struct sm_plugininfo_s + { + const char *name; + const char *author; + const char *description; + const char *version; + const char *url; + } sm_plugininfo_t; + + /** + * @brief Describes the usability status of a plugin. + */ + enum PluginStatus + { + Plugin_Running=0, /* Plugin is running */ + Plugin_Paused, /* Plugin is paused */ + Plugin_Stopped, /* Plugin is paused for map changes, too */ + Plugin_Error, /* Plugin has a blocking error */ + Plugin_BadLoad, /* Plugin failed to load */ + }; + + /** + * @brief Describes the object lifetime of a plugin. + */ + enum PluginLifetime + { + PluginLifetime_Forever, /* Plugin will never be unloaded */ + PluginLifetime_Map /* Plugin will be unloaded at mapchange */ + }; + + + /** + * @brief Encapsulates a run-time plugin as maintained by SourceMod. + */ class IPlugin : public IUnloadableParent { public: @@ -15,14 +53,108 @@ namespace SourceMod { return ParentType_Module; } + public: + /** + * @brief Returns the lifetime of a plugin. + */ + virtual PluginLifetime GetLifetime() =0; + + /** + * @brief Returns the current API context being used in the plugin. + * + * @return Pointer to an IPluginContext, or NULL if not loaded. + */ + virtual SourcePawn::IPluginContext *GetBaseContext() =0; + + /** + * @brief Returns the context structure being used in the plugin. + * + * @brief Pointer to an sp_context_t, or NULL if not loaded. + */ + virtual sp_context_t *GetContext() =0; + + /** + * @brief Returns information about the plugin. + * + * @brief Pointer to an sm_plugininfo_t, or NULL if not loaded. + */ + virtual sm_plugininfo_t *GetPublicInfo() =0; + + /** + * @brief Returns the plugin filename (relative to plugins dir). + */ + virtual const char *GetFilename() =0; + + /** + * @brief Returns true if a plugin is in debug mode, false otherwise. + */ + virtual bool IsDebugging() =0; + + /** + * @brief Returns the plugin status. + */ + virtual PluginStatus GetStatus() =0; + + /** + * @brief Sets whether the plugin is paused or not. + * + * @return True on successful pause, false otherwise. + */ + virtual bool SetPauseState(bool paused) =0; + + /** + * @brief Locks or unlocks the plugin from being updated on mapchange. + */ + virtual void SetLockForUpdates(bool lock_status) =0; + + /** + * @brief Returns whether the plugin is locked from being updated on mapchange. + */ + virtual bool GetLockForUpdates() =0; + + /** + * @brief Returns the unique serial number of a plugin. + */ + virtual unsigned int GetSerial() =0; }; - enum PluginLifetime + + /** + * @brief Iterates over a list of plugins. + */ + class IPluginIterator { - PluginLifetime_Forever, - PluginLifetime_Map + public: + virtual void ~IPluginIterator() + { + }; + public: + /** + * @brief Returns true if there are more plugins in the iterator. + */ + virtual bool MorePlugins() =0; + + /** + * @brief Returns the plugin at the current iterator position. + */ + virtual IPlugin *GetPlugin() =0; + + /** + * @brief Advances to the next plugin in the iterator. + */ + virtual void NextPlugin() =0; + + /** + * @brief Destroys the iterator object. + * Note: You may use 'delete' in lieu of this function. + */ + virtual void Release() =0; }; + + /** + * @brief Manages the runtime loading and unloading of plugins. + */ class IPluginManager : public SMInterface { public: @@ -40,7 +172,6 @@ namespace SourceMod * @brief Attempts to load a plugin. * * @param path Path and filename of plugin, relative to plugins folder. - * @param extended Whether or not the plugin is a static plugin or optional plugin. * @param debug Whether or not to default the plugin into debug mode. * @param lifetime Lifetime of the plugin. * @param error Buffer to hold any error message. @@ -48,11 +179,40 @@ namespace SourceMod * @return A new plugin pointer on success, false otherwise. */ virtual IPlugin *LoadPlugin(const char *path, - bool extended, bool debug, PluginLifetime lifetime, char error[], size_t err_max) =0; + + /** + * @brief Attempts to unload a plugin. + * + * @param Pointer to the plugin handle. + * @return True on success, false otherwise. + */ + virtual bool UnloadPlugin(IPlugin *plugin) =0; + + /** + * @brief Finds a plugin by its context. + * Note: This function should be considered O(1). + * + * @param Pointer to an sp_context_t. + * @return Pointer to a matching IPlugin, or NULL if none found. + */ + virtual IPlugin *FindPluginByContext(const sp_context_t *ctx) =0; + + /** + * @brief Returns the number of plugins (both failed and loaded). + * + * @return The number of internally cached plugins. + */ + virtual unsigned int GetPluginCount() =0; + + /** + * @brief Returns a pointer that can be used to iterate through plugins. + * Note: This pointer must be freed using EITHER delete OR IPluginIterator::Release(). + */ + virtual IPluginIterator *GetPluginIterator() =0; }; }; diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h index 9448295f..c4be06e3 100644 --- a/core/interfaces/ITextParsers.h +++ b/core/interfaces/ITextParsers.h @@ -140,25 +140,40 @@ namespace SourceMod public: enum SMCParseResult { - SMCParse_Continue, - SMCParse_SkipSection, - SMCParse_Halt, - SMCParse_HaltFail + SMCParse_Continue, //continue parsing + SMCParse_SkipSection, //skip the rest of the current section + SMCParse_Halt, //stop parsing here + SMCParse_HaltFail //stop parsing and return failure }; + /** + * @brief Called when starting parsing. + */ + virtual void ReadSMC_ParseStart() + { + }; + + /** + * @brief Called when ending parsing. + * + * @param halted True if abnormally halted, false otherwise. + * @param failed True if parsing failed, false otherwise. + */ + virtual void ReadSMC_ParseEnd(bool halted, bool failed) + { + } + /** * @brief Called when entering a new section * * @param name Name of section, with the colon omitted. * @param option Optional text after the colon, quotes removed. NULL if none. * @param colon Whether or not the required ':' was encountered. - * @param start_token Whether a start token was detected. * @return SMCParseResult directive. */ virtual SMCParseResult ReadSMC_NewSection(const char *name, const char *option, - bool colon, - bool start_token) + bool colon) { return SMCParse_Continue; } @@ -183,11 +198,23 @@ namespace SourceMod /** * @brief Called when leaving the current section. + * Note: Skipping the section has no meaning here. * - * @param end_token Whether an end token was detected. * @return SMCParseResult directive. */ - virtual SMCParseResult ReadSMC_LeavingSection(bool end_token) + virtual SMCParseResult ReadSMC_LeavingSection() + { + return SMCParse_Continue; + } + + /** + * @brief Called after an input line has been preprocessed. + * + * @param line String containing line input. + * @param curline Number of line in file. + * @return SMCParseResult directive. + */ + virtual SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline) { return SMCParse_Continue; } @@ -232,12 +259,14 @@ namespace SourceMod * @param smc_listener Event handler for reading file. * @param line If non-NULL, will contain last line parsed (0 if file could not be opened). * @param col If non-NULL, will contain last column parsed (undefined if file could not be opened). + * @param strict If strict mode is enabled, the parsing rules are obeyed rigorously rather than loosely. * @return True if parsing succeded, false if file couldn't be opened or there was a syntax error. */ virtual bool ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, - unsigned int *col) =0; + unsigned int *col, + bool strict) =0; public: /** * @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream. diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 99938f78..1e9d4c52 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -208,6 +208,10 @@ RelativePath="..\sourcemm_api.h" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/sourcemod.h b/core/sourcemod.h new file mode 100644 index 00000000..deadb72f --- /dev/null +++ b/core/sourcemod.h @@ -0,0 +1,8 @@ +#ifndef _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ +#define _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ + +#include +#include + + +#endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp new file mode 100644 index 00000000..f9961a17 --- /dev/null +++ b/core/vm/sp_vm_basecontext.cpp @@ -0,0 +1,617 @@ +#include +#include +#include +#include "sp_vm_api.h" +#include "sp_vm_basecontext.h" + +using namespace SourcePawn; + +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) + +BaseContext::BaseContext(sp_context_t *_ctx) +{ + ctx = _ctx; + ctx->context = this; +} + +IVirtualMachine *BaseContext::GetVirtualMachine() +{ + return (IVirtualMachine *)ctx->vmbase; +} + +sp_context_t *BaseContext::GetContext() +{ + return ctx; +} + +bool BaseContext::IsDebugging() +{ + return (ctx->flags & SPFLAG_PLUGIN_DEBUG); +} + +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) +{ + if (!IsDebugging()) + { + return SP_ERROR_NOTDEBUGGING; + } + + *oldpfn = ctx->dbreak; + ctx->dbreak = newpfn; + + return SP_ERROR_NONE; +} + +IPluginDebugInfo *BaseContext::GetDebugInfo() +{ + return this; +} + +int BaseContext::Execute(uint32_t public_func, cell_t *result) +{ + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; + + uint32_t pushcount = ctx->pushcount; + + int err; + sp_public_t *pubfunc; + if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERROR_NONE) + { + return err; + } + + PushCell(pushcount++); + ctx->pushcount = 0; + + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + + err = vm->ContextExecute(ctx, pubfunc->offs, result); + + /** + * :TODO: turn this into an error check + */ + +#if defined _DEBUG + if (err == SP_ERROR_NONE) + { + assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); + assert(ctx->hp == save_hp); + } +#endif + if (err != SP_ERROR_NONE) + { + ctx->sp = save_sp; + ctx->hp = save_hp; + } + + return err; +} + +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) +{ + cell_t *addr; + ucell_t realmem; + +#if 0 + if (cells > CELLBOUNDMAX) + { + return SP_ERROR_ARAM; + } +#else + assert(cells < CELLBOUNDMAX); +#endif + + realmem = cells * sizeof(cell_t); + + /** + * Check if the space between the heap and stack is sufficient. + */ + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) + { + return SP_ERROR_HEAPLOW; + } + + addr = (cell_t *)(ctx->memory + ctx->hp); + /* store size of allocation in cells */ + *addr = (cell_t)cells; + addr++; + ctx->hp += sizeof(cell_t); + + *local_addr = ctx->hp; + + if (phys_addr) + { + *phys_addr = addr; + } + + ctx->hp += realmem; + + return SP_ERROR_NONE; +} + +int BaseContext::HeapPop(cell_t local_addr) +{ + cell_t cellcount; + cell_t *addr; + + /* check the bounds of this address */ + local_addr -= sizeof(cell_t); + if (local_addr < ctx->heap_base || local_addr >= ctx->sp) + { + return SP_ERROR_INVALID_ADDRESS; + } + + addr = (cell_t *)(ctx->memory + local_addr); + cellcount = (*addr) * sizeof(cell_t); + /* check if this memory count looks valid */ + if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) + { + return SP_ERROR_INVALID_ADDRESS; + } + + ctx->hp = local_addr; + + return SP_ERROR_NONE; +} + + +int BaseContext::HeapRelease(cell_t local_addr) +{ + if (local_addr < ctx->heap_base) + { + return SP_ERROR_INVALID_ADDRESS; + } + + ctx->hp = local_addr - sizeof(cell_t); + + return SP_ERROR_NONE; +} + +int BaseContext::FindNativeByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.natives_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->natives[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERROR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) +{ + if (index >= ctx->plugin->info.natives_num) + { + return SP_ERROR_INDEX; + } + + if (native) + { + *native = &(ctx->natives[index]); + } + + return SP_ERROR_NONE; +} + + +uint32_t BaseContext::GetNativesNum() +{ + return ctx->plugin->info.natives_num; +} + +int BaseContext::FindPublicByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.publics_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->publics[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERROR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) +{ + if (index >= ctx->plugin->info.publics_num) + { + return SP_ERROR_INDEX; + } + + if (pblic) + { + *pblic = &(ctx->publics[index]); + } + + return SP_ERROR_NONE; +} + +uint32_t BaseContext::GetPublicsNum() +{ + return ctx->plugin->info.publics_num; +} + +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERROR_INDEX; + } + + if (pubvar) + { + *pubvar = &(ctx->pubvars[index]); + } + + return SP_ERROR_NONE; +} + +int BaseContext::FindPubvarByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.pubvars_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->pubvars[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERROR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERROR_INDEX; + } + + *local_addr = ctx->plugin->info.pubvars[index].address; + *phys_addr = ctx->pubvars[index].offs; + + return SP_ERROR_NONE; +} + +uint32_t BaseContext::GetPubVarsNum() +{ + return ctx->plugin->info.pubvars_num; +} + +int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) +{ + uint32_t i, j, max; + + max = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) + { + continue; + } + + for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) + { + ctx->natives[i].pfn = natives[j].func; + ctx->natives[i].status = SP_NATIVE_OKAY; + } + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) +{ + uint32_t index; + int err; + + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) + { + return err; + } + + ctx->natives[index].pfn = native->func; + ctx->natives[index].status = status; + + return SP_ERROR_NONE; +} + +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) +{ + uint32_t nativesnum, i; + + nativesnum = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status != SP_NATIVE_OKAY) + { + ctx->natives[i].pfn = native; + ctx->natives[i].status = SP_NATIVE_PENDING; + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) +{ + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + if (phys_addr) + { + *phys_addr = (cell_t *)(ctx->memory + local_addr); + } + + return SP_ERROR_NONE; +} + +int BaseContext::PushCell(cell_t value) +{ + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) + { + return SP_ERROR_STACKLOW; + } + + ctx->sp -= sizeof(cell_t); + *(cell_t *)(ctx->memory + ctx->sp) = value; + ctx->pushcount++; + + return SP_ERROR_NONE; +} + +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) +{ + unsigned int i; + int err; + + for (i=0; isp += (cell_t)(i * sizeof(cell_t)); + ctx->pushcount -= i; + return err; + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) +{ + cell_t *ph_addr; + int err; + + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) + { + return err; + } + + memcpy(ph_addr, array, numcells * sizeof(cell_t)); + + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) + { + HeapRelease(*local_addr); + return err; + } + + if (phys_addr) + { + *phys_addr = ph_addr; + } + + return SP_ERROR_NONE; +} + +int BaseContext::LocalToString(cell_t local_addr, char **addr) +{ + int len = 0; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + *addr = (char *)(ctx->memory + local_addr); + + return SP_ERROR_NONE; +} + +int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) +{ + cell_t *ph_addr; + int err; + unsigned int i, numcells = strlen(string); + + if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE) + { + return err; + } + + for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + len = strlen(source); + dest = (cell_t *)(ctx->memory + local_addr); + + if ((size_t)len >= chars) + { + len = chars - 1; + } + + for (i=0; i>1) + +int BaseContext::LookupFile(ucell_t addr, const char **filename) +{ + int high, low, mid; + + high = ctx->plugin->debug.files_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->files[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERROR_NOT_FOUND; + } + + *filename = ctx->files[low].name; + + return SP_ERROR_NONE; +} + +int BaseContext::LookupFunction(ucell_t addr, const char **name) +{ + uint32_t iter, max = ctx->plugin->debug.syms_num; + + for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) + && (ctx->symbols[iter].codestart <= addr) + && (ctx->symbols[iter].codeend > addr)) + { + break; + } + } + + if (iter >= max) + { + return SP_ERROR_NOT_FOUND; + } + + *name = ctx->symbols[iter].name; + + return SP_ERROR_NONE; +} + +int BaseContext::LookupLine(ucell_t addr, uint32_t *line) +{ + int high, low, mid; + + high = ctx->plugin->debug.lines_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->lines[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERROR_NOT_FOUND; + } + + *line = ctx->lines[low].line; + + return SP_ERROR_NONE; +} diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h new file mode 100644 index 00000000..1faf1b81 --- /dev/null +++ b/core/vm/sp_vm_basecontext.h @@ -0,0 +1,53 @@ +#ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ +#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ + +#include "sp_vm_api.h" + +namespace SourcePawn +{ + class BaseContext : + public IPluginContext, + public IPluginDebugInfo + { + public: + BaseContext(sp_context_t *ctx); + public: //IPluginContext + IVirtualMachine *GetVirtualMachine(); + sp_context_t *GetContext(); + bool IsDebugging(); + int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn); + IPluginDebugInfo *GetDebugInfo(); + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); + virtual int HeapPop(cell_t local_addr); + virtual int HeapRelease(cell_t local_addr); + virtual int FindNativeByName(const char *name, uint32_t *index); + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native); + virtual uint32_t GetNativesNum(); + virtual int FindPublicByName(const char *name, uint32_t *index); + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); + virtual uint32_t GetPublicsNum(); + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); + virtual int FindPubvarByName(const char *name, uint32_t *index); + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); + virtual uint32_t GetPubVarsNum(); + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); + virtual int LocalToString(cell_t local_addr, char **addr); + virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); + virtual int PushCell(cell_t value); + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); + virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); + virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); + virtual int BindNative(sp_nativeinfo_t *native, uint32_t status); + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); + virtual int Execute(uint32_t public_func, cell_t *result); + public: //IPluginDebugInfo + virtual int LookupFile(ucell_t addr, const char **filename); + virtual int LookupFunction(ucell_t addr, const char **name); + virtual int LookupLine(ucell_t addr, uint32_t *line); + private: + sp_context_t *ctx; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_ diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp new file mode 100644 index 00000000..dc39f480 --- /dev/null +++ b/core/vm/sp_vm_engine.cpp @@ -0,0 +1,309 @@ +#include +#include +#include "sp_file_headers.h" +#include "sp_vm_types.h" +#include "sp_vm_engine.h" +#include "zlib/zlib.h" +#include "sp_vm_basecontext.h" + +#if defined WIN32 + #define WIN32_LEAN_AND_MEAN + #include +#else if defined __GNUC__ + #include +#endif + +using namespace SourcePawn; + +void *SourcePawnEngine::ExecAlloc(size_t size) +{ +#if defined WIN32 + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else if defined __GNUC__ + void *base = memalign(sysconf(_SC_PAGESIZE), size); + if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + { + free(base); + return NULL; + } + return base; +#endif +} + +void SourcePawnEngine::ExecFree(void *address) +{ +#if defined WIN32 + VirtualFree(address, 0, MEM_RELEASE); +#else if defined __GNUC__ + free(address); +#endif +} + +void *SourcePawnEngine::BaseAlloc(size_t size) +{ + return malloc(size); +} + +void SourcePawnEngine::BaseFree(void *memory) +{ + free(memory); +} + +IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx) +{ + return new BaseContext(ctx); +} + +void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx) +{ + sp_context_t *_ctx = ctx->GetContext(); + IVirtualMachine *vm = ctx->GetVirtualMachine(); + + vm->FreeContext(_ctx); + + delete ctx; +} + +sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err) +{ + char *nameptr; + uint8_t sectnum = 0; + sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t)); + + memset(plugin, 0, sizeof(sp_plugin_t)); + + plugin->base = base; + + while (sectnum < hdr->sections) + { + nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs); + + if (!(plugin->pcode) && !strcmp(nameptr, ".code")) + { + sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs); + plugin->pcode = base + secptr->dataoffs + cod->code; + plugin->pcode_size = cod->codesize; + plugin->flags = cod->flags; + } + else if (!(plugin->data) && !strcmp(nameptr, ".data")) + { + sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs); + plugin->data = base + secptr->dataoffs + dat->data; + plugin->data_size = dat->datasize; + plugin->memory = dat->memsize; + } + else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics")) + { + plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t); + plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars")) + { + plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t); + plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives")) + { + plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t); + plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info.lib) && !strcmp(nameptr, ".libraries")) + { + plugin->info.libraries_num = secptr->size / sizeof(sp_file_libraries_t); + plugin->info.lib = (sp_file_libraries_t *)(base + secptr->dataoffs); + } + else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) + { + plugin->info.stringbase = (const char *)(base + secptr->dataoffs); + } + else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files")) + { + plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines")) + { + plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols")) + { + plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); + } + else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info")) + { + sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs); + plugin->debug.files_num = inf->num_files; + plugin->debug.lines_num = inf->num_lines; + plugin->debug.syms_num = inf->num_syms; + } + else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) + { + plugin->debug.stringbase = (const char *)(base + secptr->dataoffs); + } + + secptr++; + sectnum++; + } + + if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase)) + { + goto return_error; + } + + if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) + { + goto return_error; + } + + if (err) + { + *err = SP_ERROR_NONE; + } + + return plugin; + +return_error: + if (err) + { + *err = SP_ERROR_FILE_FORMAT; + } + + return NULL; +} + +sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) +{ + sp_file_hdr_t hdr; + sp_plugin_t *plugin; + uint8_t *base; + int z_result; + int error; + + if (!fp) + { + error = SP_ERROR_NOT_FOUND; + goto return_error; + } + + /* Rewind for safety */ + rewind(fp); + fread(&hdr, sizeof(sp_file_hdr_t), 1, fp); + + if (hdr.magic != SPFILE_MAGIC) + { + error = SP_ERROR_FILE_FORMAT; + goto return_error; + } + + switch (hdr.compression) + { + case SPFILE_COMPRESSION_GZ: + { + uint32_t uncompsize = hdr.imagesize - hdr.dataoffs; + uint32_t compsize = hdr.disksize - hdr.dataoffs; + uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t); + uLongf destlen = uncompsize; + + char *tempbuf = (char *)malloc(compsize); + void *uncompdata = malloc(uncompsize); + void *sectheader = malloc(sectsize); + + fread(sectheader, sectsize, 1, fp); + fread(tempbuf, compsize, 1, fp); + + z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize); + free(tempbuf); + if (z_result != Z_OK) + { + free(sectheader); + free(uncompdata); + error = SP_ERROR_DECOMPRESSOR; + goto return_error; + } + + base = (uint8_t *)malloc(hdr.imagesize); + memcpy(base, &hdr, sizeof(sp_file_hdr_t)); + memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize); + free(sectheader); + memcpy(base + hdr.dataoffs, uncompdata, uncompsize); + free(uncompdata); + break; + } + case SPFILE_COMPRESSION_NONE: + { + base = (uint8_t *)malloc(hdr.imagesize); + rewind(fp); + fread(base, hdr.imagesize, 1, fp); + break; + } + default: + { + error = SP_ERROR_DECOMPRESSOR; + goto return_error; + } + } + + plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); + if (!_ReadPlugin(&hdr, base, plugin, err)) + { + free(plugin); + free(base); + return NULL; + } + + plugin->allocflags = 0; + + return plugin; + +return_error: + if (err) + { + *err = error; + } + return NULL; +} + +sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) +{ + sp_file_hdr_t hdr; + uint8_t noptr = 0; + + memcpy(&hdr, base, sizeof(sp_file_hdr_t)); + + if (!plugin) + { + plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); + noptr = 1; + } + + if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err)) + { + if (noptr) + { + free(plugin); + } + return NULL; + } + + if (!noptr) + { + plugin->allocflags |= SP_FA_SELF_EXTERNAL; + } + plugin->allocflags |= SP_FA_BASE_EXTERNAL; + + return plugin; +} + +int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) +{ + if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL)) + { + free(plugin->base); + plugin->base = NULL; + } + if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL)) + { + free(plugin); + } + + return SP_ERROR_NONE; +} diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h new file mode 100644 index 00000000..fb13f405 --- /dev/null +++ b/core/vm/sp_vm_engine.h @@ -0,0 +1,88 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ +#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ + +#include "sp_vm_api.h" + +namespace SourcePawn +{ + class SourcePawnEngine : public ISourcePawnEngine + { + public: + /** + * Loads a named file from a file pointer. + * Using this means base memory will be allocated by the VM. + * Note: The file handle position may be undefined on entry, and is + * always undefined on conclusion. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ + sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); + + /** + * Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ + sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); + + /** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ + int FreeFromMemory(sp_plugin_t *plugin); + + /** + * Creates a new IContext from a context handle. + * + * @param ctx Context to use as a basis for the IPluginContext. + * @return New IPluginContext handle. + */ + IPluginContext *CreateBaseContext(sp_context_t *ctx); + + /** + * Frees a context. + * + * @param ctx Context pointer to free. + */ + void FreeBaseContext(IPluginContext *ctx); + + /** + * Allocates memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + void *BaseAlloc(size_t size); + + /** + * Frees memory allocated with BaseAlloc. + * + * @param memory Memory address to free. + */ + void BaseFree(void *memory); + + /** + * Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + void *ExecAlloc(size_t size); + + /** + * Frees executable memory. + * + * @param address Address to free. + */ + void ExecFree(void *address); + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/core/zlib/adler32.c b/core/zlib/adler32.c new file mode 100644 index 00000000..f201d670 --- /dev/null +++ b/core/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/core/zlib/compress.c b/core/zlib/compress.c new file mode 100644 index 00000000..d37e84f5 --- /dev/null +++ b/core/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/core/zlib/crc32.c b/core/zlib/crc32.c new file mode 100644 index 00000000..32814c20 --- /dev/null +++ b/core/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/core/zlib/crc32.h b/core/zlib/crc32.h new file mode 100644 index 00000000..5de49bc9 --- /dev/null +++ b/core/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/core/zlib/deflate.c b/core/zlib/deflate.c new file mode 100644 index 00000000..529f716b --- /dev/null +++ b/core/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/core/zlib/deflate.h b/core/zlib/deflate.h new file mode 100644 index 00000000..222c53e0 --- /dev/null +++ b/core/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/core/zlib/gzio.c b/core/zlib/gzio.c new file mode 100644 index 00000000..5e20a4aa --- /dev/null +++ b/core/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/core/zlib/infback.c b/core/zlib/infback.c new file mode 100644 index 00000000..1e03e1ba --- /dev/null +++ b/core/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/core/zlib/inffast.c b/core/zlib/inffast.c new file mode 100644 index 00000000..fa31cad9 --- /dev/null +++ b/core/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/core/zlib/inffast.h b/core/zlib/inffast.h new file mode 100644 index 00000000..614fa787 --- /dev/null +++ b/core/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/core/zlib/inffixed.h b/core/zlib/inffixed.h new file mode 100644 index 00000000..423d5c5b --- /dev/null +++ b/core/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/core/zlib/inflate.c b/core/zlib/inflate.c new file mode 100644 index 00000000..33ea9029 --- /dev/null +++ b/core/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/core/zlib/inflate.h b/core/zlib/inflate.h new file mode 100644 index 00000000..fbbc8714 --- /dev/null +++ b/core/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/core/zlib/inftrees.c b/core/zlib/inftrees.c new file mode 100644 index 00000000..38ded81c --- /dev/null +++ b/core/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/core/zlib/inftrees.h b/core/zlib/inftrees.h new file mode 100644 index 00000000..dc0fd567 --- /dev/null +++ b/core/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/core/zlib/trees.c b/core/zlib/trees.c new file mode 100644 index 00000000..7a048028 --- /dev/null +++ b/core/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/core/zlib/trees.h b/core/zlib/trees.h new file mode 100644 index 00000000..1ca868b8 --- /dev/null +++ b/core/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/core/zlib/uncompr.c b/core/zlib/uncompr.c new file mode 100644 index 00000000..ad6db0a6 --- /dev/null +++ b/core/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/core/zlib/zconf.h b/core/zlib/zconf.h new file mode 100644 index 00000000..59b5e7a6 --- /dev/null +++ b/core/zlib/zconf.h @@ -0,0 +1,281 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/core/zlib/zlib.h b/core/zlib/zlib.h new file mode 100644 index 00000000..62d0e467 --- /dev/null +++ b/core/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/core/zlib/zutil.c b/core/zlib/zutil.c new file mode 100644 index 00000000..0f4bd787 --- /dev/null +++ b/core/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/core/zlib/zutil.h b/core/zlib/zutil.h new file mode 100644 index 00000000..0ba6e020 --- /dev/null +++ b/core/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ From 9141ae103e3a73ff818be1fb4355c65da729f885 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 07:32:44 +0000 Subject: [PATCH 0135/1664] began JIT integration --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40165 --- core/msvc8/sourcemod_mm.vcproj | 22 ++++--- core/sm_globals.h | 15 +++++ core/sm_platform.h | 2 + core/sourcemm_api.cpp | 8 +-- core/sourcemm_api.h | 2 +- core/sourcemod.cpp | 103 +++++++++++++++++++++++++++++++++ core/sourcemod.h | 13 ++++- 7 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 core/sm_globals.h create mode 100644 core/sourcemod.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 1e9d4c52..53913af5 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -40,7 +40,7 @@ + + + + @@ -213,12 +221,6 @@ > - - @@ -410,6 +412,12 @@ > + + diff --git a/core/sm_globals.h b/core/sm_globals.h new file mode 100644 index 00000000..b89637b7 --- /dev/null +++ b/core/sm_globals.h @@ -0,0 +1,15 @@ +#ifndef _INCLUDE_SOURCEMOD_GLOBALS_H_ +#define _INCLUDE_SOURCEMOD_GLOBALS_H_ + +#include +#include +#include "sm_platform.h" +#include "interfaces/IShareSys.h" + +using namespace SourcePawn; +using namespace SourceMod; + +extern ISourcePawnEngine *g_pSourcePawn; +extern IVirtualMachine *g_pVM; + +#endif //_INCLUDE_SOURCEMOD_GLOBALS_H_ diff --git a/core/sm_platform.h b/core/sm_platform.h index eca8070c..c313d084 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -11,6 +11,7 @@ #endif #include #include +#define PLATFORM_LIB_EXT "dll" #define PLATFORM_MAX_PATH MAX_PATH #else if defined __linux__ #define PLATFORM_LINUX @@ -18,6 +19,7 @@ #include #include #define PLATFORM_MAX_PATH PATH_MAX +#define PLATFORM_LIB_EXT "so" #endif #endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 83c871d2..2e862a26 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -1,17 +1,17 @@ #include #include "sourcemm_api.h" #include "sm_version.h" -#include "CTextParsers.h" +#include "sourcemod.h" -SourceMod_Core g_SourceMod; +SourceMod_Core g_SourceMod_Core; -PLUGIN_EXPOSE(SourceMod, g_SourceMod); +PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); - return true; + return g_SourceMod.InitializeSourceMod(error, maxlen, late); } bool SourceMod_Core::Unload(char *error, size_t maxlen) diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 5b230f39..002416fc 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -22,7 +22,7 @@ public: const char *GetLogTag(); }; -extern SourceMod_Core g_SourceMod; +extern SourceMod_Core g_SourceMod_Core; PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp new file mode 100644 index 00000000..69f81f2a --- /dev/null +++ b/core/sourcemod.cpp @@ -0,0 +1,103 @@ +#include +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "systems/LibrarySys.h" +#include "vm/sp_vm_engine.h" +#include + +SourcePawnEngine g_SourcePawn; +SourceModBase g_SourceMod; + +ILibrary *g_pJIT = NULL; +SourceHook::String g_BaseDir; +ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; +IVirtualMachine *g_pVM; + +typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); +typedef unsigned int (*GETEXPORTCOUNT)(); +typedef IVirtualMachine *(*GETEXPORT)(unsigned int); +typedef void (*NOTIFYSHUTDOWN)(); + +void ShutdownJIT() +{ + NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown"); + if (notify) + { + notify(); + } + + g_pJIT->CloseLibrary(); +} + +bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) +{ + //:TODO: we need a localinfo system! + g_BaseDir.assign(g_SMAPI->GetBaseDir()); + + /* Attempt to load the JIT! */ + char file[PLATFORM_MAX_PATH]; + char myerror[255]; + g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/bin/sourcepawn.jit.x86.%s", + g_BaseDir.c_str(), + PLATFORM_LIB_EXT + ); + + g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror)); + if (!g_pJIT) + { + if (error && err_max) + { + snprintf(error, err_max, "%s (failed to load bin/sourcepawn.jit.x86.%s)", + myerror, + PLATFORM_LIB_EXT); + } + return false; + } + + int err; + GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer"); + if (!jit_init) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "Failed to find GiveEnginePointer in JIT!"); + } + return false; + } + + if ((err=jit_init(g_pSourcePawn)) != 0) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "GiveEnginePointer returned %d in the JIT", err); + } + return false; + } + + GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount"); + GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport"); + if (!jit_get) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "JIT is missing a necessary export!"); + } + return false; + } + + unsigned int num = jit_getnum(); + if (!num || ((g_pVM=jit_get(0)) == NULL)) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "JIT did not export any virtual machines!"); + } + return false; + } + + return true; +} diff --git a/core/sourcemod.h b/core/sourcemod.h index deadb72f..143a96ca 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -1,8 +1,17 @@ #ifndef _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ #define _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ -#include -#include +#include "sm_globals.h" +class SourceModBase +{ +public: + /** + * @brief Initializes SourceMod, or returns an error on failure. + */ + bool InitializeSourceMod(char *error, size_t err_max, bool late); +}; + +extern SourceModBase g_SourceMod; #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ From 611ab078d2f1f723529f6dec683b7b808dc0566e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 07:35:16 +0000 Subject: [PATCH 0136/1664] sync'd JIT to API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40166 --- sourcepawn/jit/x86/dll_exports.cpp | 4 +++- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index 1cbaa90a..5df6e0b2 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -5,9 +5,11 @@ SourcePawn::ISourcePawnEngine *engine = NULL; JITX86 jit; -EXPORTFUNC void GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) +EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) { engine = engine_p; + + return 0; } EXPORTFUNC unsigned int GetExportCount() diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index f7e0b79c..7298d68d 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -40,7 +40,7 @@ Date: Wed, 8 Nov 2006 07:44:26 +0000 Subject: [PATCH 0137/1664] added some trivial comments --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40167 --- core/sm_globals.h | 4 ++++ core/sm_platform.h | 4 ++++ core/sm_version.h | 4 ++++ core/sourcemm_api.h | 4 ++++ core/sourcemod.h | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/core/sm_globals.h b/core/sm_globals.h index b89637b7..a69a3abf 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -1,6 +1,10 @@ #ifndef _INCLUDE_SOURCEMOD_GLOBALS_H_ #define _INCLUDE_SOURCEMOD_GLOBALS_H_ +/** + * @file Contains global headers that most files in SourceMod will need. + */ + #include #include #include "sm_platform.h" diff --git a/core/sm_platform.h b/core/sm_platform.h index c313d084..5e7e1962 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -1,6 +1,10 @@ #ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ #define _INCLUDE_SOURCEMOD_PLATFORM_H_ +/** + * @file Contains platform-specific macros for abstraction. + */ + #if defined WIN32 || defined WIN64 #define PLATFORM_WINDOWS #if !defined WIN32_LEAN_AND_MEAN diff --git a/core/sm_version.h b/core/sm_version.h index 91b35912..1aaaa6d4 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -1,6 +1,10 @@ #ifndef _INCLUDE_SOURCEMOD_VERSION_H_ #define _INCLUDE_SOURCEMOD_VERSION_H_ +/** + * @file Contains SourceMod version information. + */ + #define SOURCEMOD_VERSION "0.0.0.0" #define SOURCEMOD_V_MAJOR 0 #define SOURCEMOD_V_MINOR 0 diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 002416fc..3089da9e 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -3,6 +3,10 @@ #include +/** + * @file Contains wrappers around required Metamod:Source API exports + */ + class SourceMod_Core : public ISmmPlugin { public: diff --git a/core/sourcemod.h b/core/sourcemod.h index 143a96ca..f053de65 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -3,6 +3,10 @@ #include "sm_globals.h" +/** + * @brief Implements SourceMod's global overall management, API, and logic + */ + class SourceModBase { public: From 2892ee1fa984536a0e6e139369019f9350215240 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 08:04:57 +0000 Subject: [PATCH 0138/1664] fixed a crash on error --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40168 --- sourcepawn/compiler/sc3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 1c7986f8..5e7a2840 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1751,7 +1751,7 @@ restart: sym=cursym; if (matchtoken('[') || matchtoken('{') || matchtoken('(')) { tok=tokeninfo(&val,&st); /* get token read by matchtoken() */ - magic_string = (sym->tag == pc_tag_string && sym->dim.array.level == 0); + magic_string = (sym && (sym->tag == pc_tag_string && sym->dim.array.level == 0)); if (sym==NULL && symtok!=tSYMBOL) { /* we do not have a valid symbol and we appear not to have read a valid * symbol name (so it is unlikely that we would have read a name of an From e060af14b4099fea07cb8008e3ea313c69a0d076 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 08:41:18 +0000 Subject: [PATCH 0139/1664] updated all api to use new function id system fixed a codegen bug in function ids removed extra native status, simplified native binding --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40169 --- core/vm/sp_vm_basecontext.cpp | 29 +++++++++++-------- core/vm/sp_vm_basecontext.h | 4 +-- sourcepawn/compiler/sc3.c | 4 +-- sourcepawn/include/sp_vm_api.h | 28 +++++++++++++------ sourcepawn/include/sp_vm_types.h | 37 +++++++++++++------------ sourcepawn/jit/x86/jit_x86.cpp | 19 +++++++++---- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 12 +++----- 7 files changed, 77 insertions(+), 56 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index f9961a17..9e82f672 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -48,17 +48,24 @@ IPluginDebugInfo *BaseContext::GetDebugInfo() return this; } -int BaseContext::Execute(uint32_t public_func, cell_t *result) +int BaseContext::Execute(funcid_t funcid, cell_t *result) { IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; uint32_t pushcount = ctx->pushcount; - + uint32_t code_addr; int err; - sp_public_t *pubfunc; - if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERROR_NONE) + + if (funcid & 1) { - return err; + sp_public_t *pubfunc; + if ((err=GetPublicByIndex((funcid>>1), &pubfunc)) != SP_ERROR_NONE) + { + return err; + } + code_addr = pubfunc->code_offs; + } else { + code_addr = funcid >> 1; } PushCell(pushcount++); @@ -67,7 +74,7 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; - err = vm->ContextExecute(ctx, pubfunc->offs, result); + err = vm->ContextExecute(ctx, code_addr, result); /** * :TODO: turn this into an error check @@ -338,7 +345,7 @@ int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int ove for (i=0; inatives[i].status == SP_NATIVE_OKAY) && !overwrite) + if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite) { continue; } @@ -348,7 +355,7 @@ int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int ove if (!strcmp(ctx->natives[i].name, natives[j].name)) { ctx->natives[i].pfn = natives[j].func; - ctx->natives[i].status = SP_NATIVE_OKAY; + ctx->natives[i].status = SP_NATIVE_BOUND; } } } @@ -356,7 +363,7 @@ int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int ove return SP_ERROR_NONE; } -int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) +int BaseContext::BindNative(sp_nativeinfo_t *native) { uint32_t index; int err; @@ -367,7 +374,6 @@ int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status) } ctx->natives[index].pfn = native->func; - ctx->natives[index].status = status; return SP_ERROR_NONE; } @@ -380,10 +386,9 @@ int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) for (i=0; inatives[i].status != SP_NATIVE_OKAY) + if (ctx->natives[i].status == SP_NATIVE_UNBOUND) { ctx->natives[i].pfn = native; - ctx->natives[i].status = SP_NATIVE_PENDING; } } diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 1faf1b81..9fbe2dd6 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -38,9 +38,9 @@ namespace SourcePawn virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); - virtual int BindNative(sp_nativeinfo_t *native, uint32_t status); + virtual int BindNative(sp_nativeinfo_t *native); virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); - virtual int Execute(uint32_t public_func, cell_t *result); + virtual int Execute(funcid_t funcid, cell_t *result); public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); virtual int LookupFunction(ucell_t addr, const char **name); diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 5e7a2840..e31e195c 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1965,10 +1965,10 @@ restart: lval1->ident=iCONSTEXPR; /* Generate a quick pseudo-tag! */ if (usage == uPUBLIC) { - lval1->constval=(n>>1)|(1<<1); + lval1->constval=(n<<1)|1; snprintf(faketag, sizeof(faketag)-1, "$Func@%d", n); } else { - lval1->constval=(code_addr>>1)|(1<<0); + lval1->constval=(code_addr<<1)|0; snprintf(faketag, sizeof(faketag)-1, "$Func!%d", code_addr); } lval1->tag=pc_addfunctag(faketag); diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 56e354de..9a1ba692 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -8,6 +8,9 @@ namespace SourcePawn { class IVirtualMachine; + /** + * @brief Interface to managing a debug context at runtime. + */ class IPluginDebugInfo { public: @@ -36,6 +39,9 @@ namespace SourcePawn virtual int LookupLine(ucell_t addr, uint32_t *line) =0; }; + /** + * @brief Interface to managing a context at runtime. + */ class IPluginContext { public: @@ -260,7 +266,6 @@ namespace SourcePawn /** * Binds a list of native names and their function pointers to a context. * If num is 0, the list is read until an entry with a NULL name is reached. - * All natives are assigned a status of SP_NATIVE_OKAY by default. * If overwrite is non-zero, already registered natives will be overwritten. * * @param natives Array of natives. @@ -272,29 +277,31 @@ namespace SourcePawn /** * Binds a single native. Overwrites any existing bind. * If the context does not contain the native that will be binded the function will return - * with a SP_ERROR_OT_FOUND error. + * with a SP_ERROR_NOT_FOUND error. * * @param native Pointer to native. - * @param status Status value to set (should be SP_NATIVE_OKAY). */ - virtual int BindNative(sp_nativeinfo_t *native, uint32_t status) =0; + virtual int BindNative(sp_nativeinfo_t *native) =0; /** - * Binds a single native to any non-registered or pending native. - * Status is automatically set to pending. + * Binds a single native to any non-registered native. * * @param native Native to bind. */ virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; /** - * Executes a public function. + * Executes a function ID located in this context. + * + * @param funcid Function id to execute. + * @param result Pointer to store the return value (required). + * @return Error code (if any) from the VM. */ - virtual int Execute(uint32_t public_func, cell_t *result) =0; + virtual int Execute(uint32_t funcid, cell_t *result) =0; }; /** - * Contains helper functions used by VMs and the host app + * @brief Contains helper functions used by VMs and the host app */ class ISourcePawnEngine { @@ -379,6 +386,9 @@ namespace SourcePawn virtual ~ICompilation() { }; }; + /** + * @brief Outlines the interface a Virtual Machine (JIT) must expose + */ class IVirtualMachine { public: diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 49cbb984..2c7bea84 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -5,6 +5,7 @@ typedef uint32_t ucell_t; typedef int32_t cell_t; +typedef uint32_t funcid_t; /** * Error codes @@ -17,20 +18,20 @@ typedef int32_t cell_t; #define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ #define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ #define SP_ERROR_INDEX 7 /* Invalid index parameter */ -#define SP_ERROR_NATIVE_PENDING 8 /* A script tried to exec an unbound native */ -#define SP_ERROR_STACKLOW 9 /* Nnot enough space left on the stack */ -#define SP_ERROR_NOTDEBUGGING 10 /* Debug mode was not on or debug section not found */ -#define SP_ERROR_INVALID_INSTRUCTION 11 /* Invalid instruction was encountered */ -#define SP_ERROR_MEMACCESS 12 /* Invalid memory access */ -#define SP_ERROR_STACKMIN 13 /* Stack went beyond its minimum value */ -#define SP_ERROR_HEAPMIN 14 /* Heap went beyond its minimum value */ -#define SP_ERROR_DIVIDE_BY_ZERO 15 /* Division by zero */ -#define SP_ERROR_ARRAY_BOUNDS 16 /* Array index is out of bounds */ -#define SP_ERROR_INSTRUCTION_PARAM 17 /* Instruction had an invalid parameter */ -#define SP_ERROR_STACKLEAK 18 /* A native leaked an item on the stack */ -#define SP_ERROR_HEAPLEAK 19 /* A native leaked an item on the heap */ -#define SP_ERROR_ARRAY_TOO_BIG 20 /* A dynamic array is too big */ -#define SP_ERROR_TRACKER_BOUNDS 21 /* Tracker stack is out of bounds */ +#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ /********************************************** *** The following structures are reference structures. @@ -117,7 +118,8 @@ typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); */ typedef struct sp_public_s { - uint32_t offs; /* code offset */ + funcid_t funcid; /* encoded function id */ + uint32_t code_offs; /* code offset */ const char *name; /* name */ } sp_public_t; @@ -132,9 +134,8 @@ typedef struct sp_pubvar_s const char *name; /* name */ } sp_pubvar_t; -#define SP_NATIVE_NONE (0) /* Native is not yet found */ -#define SP_NATIVE_OKAY (1) /* Native has been added */ -#define SP_NATIVE_PENDING (2) /* Native is marked as usable but replaceable */ +#define SP_NATIVE_UNBOUND (0) /* Native is undefined */ +#define SP_NATIVE_BOUND (1) /* Native is bound */ /** * Native lookup table, by default names diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 07787592..1dfe2d97 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1747,15 +1747,22 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) sp_native_t *native = &ctx->natives[native_idx]; /* Technically both aren't needed, I guess */ - if (native->status == SP_NATIVE_NONE) + if (native->status == SP_NATIVE_UNBOUND) { - ctx->err = SP_ERROR_NATIVE_PENDING; + ctx->err = SP_ERROR_INVALID_NATIVE; return 0; } return native->pfn(ctx, params); } +cell_t InvalidNative(sp_context_t *ctx, cell_t *params) +{ + ctx->err = SP_ERROR_INVALID_NATIVE; + + return 0; +} + cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params) { cell_t save_sp = ctx->sp; @@ -2002,7 +2009,9 @@ jit_rewind: for (iter=0; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; - ctx->publics[iter].offs = RelocLookup(jit, plugin->info.publics[iter].address, false); + ctx->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false); + /* Encode the ID as a straight code offset */ + ctx->publics[iter].funcid = (ctx->publics[iter].code_offs << 1); } } @@ -2025,8 +2034,8 @@ jit_rewind: for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; - ctx->natives[iter].pfn = NULL; - ctx->natives[iter].status = SP_NATIVE_NONE; + ctx->natives[iter].pfn = &InvalidNative; + ctx->natives[iter].status = SP_NATIVE_UNBOUND; } } diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index 7298d68d..537fd87b 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -247,23 +247,19 @@ > - - From 55266ffb80b75e2107b24c88eed55ab0a5b9eced Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 09:28:32 +0000 Subject: [PATCH 0140/1664] sample plugin import --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40170 --- plugins/include/sourcemod.inc | 58 +++++++++++++++++++++++++++++++++++ plugins/test.sma | 16 ++++++++++ 2 files changed, 74 insertions(+) create mode 100644 plugins/include/sourcemod.inc create mode 100644 plugins/test.sma diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc new file mode 100644 index 00000000..dcef839d --- /dev/null +++ b/plugins/include/sourcemod.inc @@ -0,0 +1,58 @@ +/** + * :TODO: license info + */ + +#if defined _sourcemod_included + #endinput +#endif +#define _sourcemod_included + +/** + * Note: A plugin can define the following public strings for external information: + * public String:PLUGIN_AUTHOR[] - Author + * public String:PLUGIN_NAME[] - Name/Title + * public String:PLUGIN_DESCRIPTION[] - Short Description + * public String:PLUGIN_VERSION[] - Version information + * public String:PLUGIN_URL[] - Website URL + */ + + +/** + * Called when the plugin is fully initialized and all known external references are resolved, + * such as dynamic natives. + * + * @noreturn + */ +forward OnPluginInit(); + +/** + * Called before OnPluginInit, in case the plugin wants to check for load failure. + * + * @param myself Handle to the plugin. + * @param late Whether or not the plugin was loaded "late" (after map load). + * @param error Error message buffer in case load failed. + * @param err_max Maximum number of characters for error message buffer. + * @return True if load success, false otherwise. + */ +forward bool:OnPluginLoad(Handle:myself, bool:late, String:error[], err_max); + +/** + * Called when the plugin is first mapped into memory. Use this to set dynamic natives. + * + * @noreturn + */ +forward OnPluginCreated(); + +/** + * Called when the plugin is about to be unloaded. + * + * @noreturn + */ +forward OnPluginUnload(); + +/** + * Called when the plugin's pause status is changing. + * + * @noreturn + */ +forward OnPluginPauseChange(bool:pause); diff --git a/plugins/test.sma b/plugins/test.sma new file mode 100644 index 00000000..e0837709 --- /dev/null +++ b/plugins/test.sma @@ -0,0 +1,16 @@ +#include + +/** + * I don't know if I like this yet.... + */ +public String:PLUGIN_NAME[] = "Testcrab" +public String:PLUGIN_AUTHOR[] = "BAILOPAN" +public String:PLUGIN_VERSION[] = "0.0.0.0" +public String:PLUGIN_URL[] = "http://www.sourcemod.net/" +public String:PUBLIC_DESCRIPTION[] = "A test, fool" + +public OnPluginInit() +{ + /* just a test, mommy */ + return 5 +} From 767f6fa9ab984a48c1be24d319c9153c53abd1ea Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 8 Nov 2006 09:37:16 +0000 Subject: [PATCH 0141/1664] fixed project file using /GL --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40171 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index e430f784..dd1b4e85 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -116,6 +116,10 @@ /> Date: Thu, 9 Nov 2006 22:53:27 +0000 Subject: [PATCH 0142/1664] added very, very primitive, mostly unusable structs. the most these can do so far is expose themselves publically --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40172 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 1 + sourcepawn/compiler/sc.h | 61 ++--- sourcepawn/compiler/sc1.c | 327 +++++++++++++++++++++++- sourcepawn/compiler/sc2.c | 2 +- sourcepawn/compiler/sc5.scp | 2 +- sourcepawn/compiler/sctracker.c | 106 ++++++++ sourcepawn/compiler/sctracker.h | 29 +++ 7 files changed, 490 insertions(+), 38 deletions(-) diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index dd1b4e85..34f0e739 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -144,6 +144,7 @@ SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" + LinkTimeCodeGeneration="0" TargetMachine="1" /> argcount * sizeof(cell)); + found = (cell *)malloc(pstruct->argcount * sizeof(cell)); + + memset(found, 0, sizeof(cell) * pstruct->argcount); + + + /** + * Lastly, very lastly, we will insert a copy of this variable. + * This is soley to expose the pubvar. + */ + usage = uDEFINE|uREAD|uCONST; + if (fpublic) + { + usage |= uPUBLIC; + } + mysym=addsym(name, 0, iVARIABLE, sGLOBAL, pc_addtag(pstruct->name), usage); + + /* Maybe error with "public struct requires initialization?" */ + if (!needtoken('=')) + { + matchtoken(';'); + return; + } + needtoken('{'); + do + { + structarg_t *arg; + /* Detect early exit */ + if (matchtoken('}')) + { + lexpush(); + break; + } + tok=lex(&val,&str); + if (tok != tSYMBOL) + { + error(1, "-identifier-", str); + continue; + } + arg=pstructs_getarg(pstruct,str); + if (arg == NULL) + { + /* :TODO: change to "Could not find member %s in struct %s" */ + error(31); + } + needtoken('='); + cur_litidx = litidx; + tok=lex(&val,&str); + if (!arg) + { + continue; + } + if (tok == tSTRING) + { + assert(litidx != 0); + if (arg->dimcount != 1) + { + error(48); + } else if (arg->tag != pc_tag_string) { + error(213); + } + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += (litidx-cur_litidx); + found[arg->index] = 1; + } else if (tok == tNUMBER || tok == tRATIONAL) { + /* eat optional 'f' */ + matchtoken('f'); + if (arg->ident != iVARIABLE && arg->ident != iREFERENCE) + { + error(23); + } else { + if (arg->tag == pc_addtag("Float") && tok == tNUMBER || + arg->tag == 0 && tok == tRATIONAL) + { + error(213); + } + if (arg->ident == iVARIABLE) + { + values[arg->index] = val; + } else if (arg->ident == iREFERENCE) { + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += 1; + litadd(val); + cur_litidx = litidx; + } + found[arg->index] = 1; + } + } else if (tok == tSYMBOL) { + symbol *sym = NULL; + for (sym=glbtab.next; sym!=NULL; sym=sym->next) + { + if (sym->vclass != sGLOBAL) + { + continue; + } + if (strcmp(sym->name, str) == 0) + { + if (arg->ident == iREFERENCE && sym->ident != iVARIABLE) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } else if (arg->ident == iARRAY) { + if (sym->ident != iARRAY) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } else { + /* :TODO: We should check dimension sizes here... */ + } + } else if (arg->ident == iREFARRAY) { + if (sym->ident != iARRAY) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } + /* :TODO: Check dimension sizes! */ + } else { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } + if (sym->tag != arg->tag) + { + error(213); + } + sym->usage |= uREAD; + values[arg->index] = sym->addr; + found[arg->index] = 1; + refer_symbol(sym, mysym); + break; + } + } + if (!sym) + { + error(17, str); + } + } else { + error(1, "-identifier-", str); + } + } while (matchtoken(',')); + needtoken('}'); + matchtoken(';'); /* eat up optional semicolon */ + + for (i=0; iargcount; i++) + { + if (!found[i]) + { + structarg_t *arg = pstruct->args[i]; + if (arg->ident == iREFARRAY) + { + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += 1; + litadd(0); + cur_litidx = litidx; + } else if (arg->ident == iVARIABLE) { + values[arg->index] = 0; + } else { + /* :TODO: broken for iARRAY! (unused tho) */ + } + } + } + + mysym->addr = glb_declared * sizeof(cell); + glb_declared += pstruct->argcount; + + for (i=0; iargcount; i++) + { + litadd(values[i]); + } + + begdseg(); + dumplits(); + litidx=0; + + free(found); + free(values); +} + /* declglb - declare global symbols * * Declare a static (global) variable. Global variables are stored in @@ -2612,8 +2824,110 @@ static void decl_const(int vclass) needtoken(tTERM); } -/* dofuncenum - declare function enumerations - * +/* + * declstruct - declare a struct type + */ +static void declstruct(void) +{ + cell val; + char *str; + int tok; + pstruct_t *pstruct; + int size; + + /* get the explicit tag (required!) */ + tok = lex(&val,&str); + if (tok != tSYMBOL) + { + error(93); + } + + if (pstructs_find(str) != NULL) + { + /* :TODO: change to "struct requires unique struct name" */ + error(58); + } + + pstruct = pstructs_add(str); + + needtoken('{'); + do + { + structarg_t arg; + if (matchtoken('}')) + { + /* Quick exit */ + lexpush(); + break; + } + memset(&arg, 0, sizeof(structarg_t)); + tok = lex(&val,&str); + if (tok == tCONST) + { + arg.fconst = 1; + tok = lex(&val,&str); + } + arg.ident = 0; + if (tok == '&') + { + arg.ident = iREFERENCE; + tok = lex(&val,&str); + } + if (tok == tLABEL) + { + arg.tag = pc_addtag(str); + tok = lex(&val,&str); + } + if (tok != tSYMBOL) + { + error(1, "-identifier-", str); + continue; + } + strcpy(arg.name, str); + if (matchtoken('[')) + { + if (arg.ident == iREFERENCE) + { + error(67, arg.name); + } + arg.ident = iARRAY; + do + { + constvalue *enumroot; + int ignore_tag; + if (arg.dimcount == sDIMEN_MAX) + { + error(53); + break; + } + size = needsub(&ignore_tag, &enumroot); + arg.dims[arg.dimcount++] = size; + } while (matchtoken('[')); + /* Handle strings */ + if (arg.tag == pc_tag_string && arg.dims[arg.dimcount-1]) + { + arg.dims[arg.dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); + } + if (arg.dimcount == 1 && !arg.dims[arg.dimcount-1]) + { + arg.ident = iREFARRAY; + } + } else if (!arg.ident) { + arg.ident = iVARIABLE; + } + if (pstructs_addarg(pstruct, &arg) == NULL) + { + /* :TODO: change to "struct member name appears more than once" */ + error(58); + } + } while (matchtoken(',')); + needtoken('}'); + matchtoken(';'); /* eat up optional semicolon */ +} + + +/** + * dofuncenum - declare function enumerations */ static void dofuncenum(void) { @@ -2750,7 +3064,8 @@ static void dofuncenum(void) arg->dimcount += 1; } while (matchtoken('[')); /* Handle strings */ - if (arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + if ((arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + && arg->dims[arg->dimcount-1]) { arg->dims[arg->dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); } diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index a65e684f..a1efb2aa 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1880,7 +1880,7 @@ char *sc_tokens[] = { "assert", "*begin", "break", "case", "chars", "const", "continue", "default", "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", - "sleep", "state", "static", "stock", "switch", "tagof", "*then", "while", + "sleep", "state", "static", "stock", "struct", "switch", "tagof", "*then", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", "#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma", "#tryinclude", "#undef", diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index ec3cc398..e2988d75 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -86,7 +86,7 @@ static char *errmsg[] = { /*045*/ "too many function arguments\n", /*046*/ "unknown array size (variable \"%s\")\n", /*047*/ "array sizes do not match, or destination array is too small\n", -/*048*/ "array dimensions do not match\n", +/*048*/ "array (s do not match\n", /*049*/ "invalid line continuation\n", /*050*/ "invalid range\n", /*051*/ "invalid subscript, use \"[ ]\" operators on major dimensions\n", diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 308bd751..5c5693f6 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -8,6 +8,112 @@ memuse_list_t *heapusage = NULL; memuse_list_t *stackusage = NULL; funcenum_t *firstenum = NULL; funcenum_t *lastenum = NULL; +pstruct_t *firststruct = NULL; +pstruct_t *laststruct = NULL; + +structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member) +{ + int i; + + for (i=0; iargcount; i++) + { + if (strcmp(pstruct->args[i]->name, member) == 0) + { + return pstruct->args[i]; + } + } + + return NULL; +} + +pstruct_t *pstructs_add(const char *name) +{ + pstruct_t *p = (pstruct_t *)malloc(sizeof(pstruct_t)); + + memset(p, 0, sizeof(pstruct_t)); + strcpy(p->name, name); + + if (!firststruct) + { + firststruct = p; + laststruct = p; + } else { + laststruct->next = p; + laststruct = p; + } + + return p; +} + +void pstructs_free() +{ + pstruct_t *p, *next; + + p = firststruct; + while (p) + { + while (p->argcount--) + { + free(p->args[p->argcount]); + } + free(p->args); + next = p->next; + free(p); + p = next; + } + firststruct = NULL; + laststruct = NULL; +} + +pstruct_t *pstructs_find(const char *name) +{ + pstruct_t *p = firststruct; + + while (p) + { + if (strcmp(p->name, name) == 0) + { + return p; + } + p = p->next; + } + + return NULL; +} + +structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg) +{ + structarg_t *newarg; + int i; + + for (i=0; iargcount; i++) + { + if (strcmp(pstruct->args[i]->name, arg->name) == 0) + { + /* Don't allow dup names */ + return NULL; + } + } + + newarg = (structarg_t *)malloc(sizeof(structarg_t)); + + memcpy(newarg, arg, sizeof(structarg_t)); + + if (pstruct->argcount == 0) + { + pstruct->args = (structarg_t **)malloc(sizeof(structarg_t *) * 1); + } else { + pstruct->args = (structarg_t **)realloc( + pstruct->args, + sizeof(structarg_t *) * (pstruct->argcount + 1)); + } + + newarg->offs = pstruct->argcount * sizeof(cell); + newarg->index = pstruct->argcount; + pstruct->args[pstruct->argcount++] = newarg; + + return newarg; +} void funcenums_free() { diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 1e05a2c7..ed4576bf 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -46,6 +46,35 @@ typedef struct funcenum_s struct funcenum_s *next; } funcenum_t; +typedef struct structarg_s +{ + int tag; + int dimcount; + cell dims[sDIMEN_MAX]; + char name[sNAMEMAX+1]; + int fconst; + int ident; + unsigned int offs; + int index; +} structarg_t; + +typedef struct pstruct_s +{ + int argcount; + char name[sNAMEMAX+1]; + structarg_t **args; + struct pstruct_s *next; +} pstruct_t; + +/** + * Pawn Structs + */ +pstruct_t *pstructs_add(const char *name); +void pstructs_free(); +pstruct_t *pstructs_find(const char *name); +structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg); +structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member); + /** * Function enumeration tags */ From 73eb8bfd40d9b2f6ccff6ff73a7ec5f997ff789d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 9 Nov 2006 23:05:42 +0000 Subject: [PATCH 0143/1664] removed an assertion that was firing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40173 --- sourcepawn/compiler/sc6.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 970583aa..fc3ae824 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -893,7 +893,8 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY) && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { - assert((sym->usage & uDEFINE)!=0); + //removed until structs don't seem to mess this up + //assert((sym->usage & uDEFINE)!=0); assert(sym->vclass==sGLOBAL); func.address=sym->addr; func.nameofs=nameofs; From f43b4468c62bb9e7462971f2c3dd411d825895c6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 10 Nov 2006 00:16:12 +0000 Subject: [PATCH 0144/1664] added the ability to pre-declare a struct, like extern --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40174 --- sourcepawn/compiler/sc.h | 1 + sourcepawn/compiler/sc1.c | 41 +++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 7a1ebd80..7f78fd4a 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -214,6 +214,7 @@ typedef struct s_symbol { #define uENUMFIELD 0x040 #define uMISSING 0x080 #define uFORWARD 0x100 +#define uSTRUCT 0x200 /* :TODO: make this an ident */ /* uRETNONE is not stored in the "usage" field of a symbol. It is * used during parsing a function, to detect a mix of "return;" and * "return value;" in a few special cases. diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 84fcd25c..7d621142 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1700,7 +1700,7 @@ static void declstructvar(char *firstname,int fpublic, pstruct_t *pstruct) int cur_litidx = 0; cell *values, *found; int usage; - symbol *mysym; + symbol *mysym,*sym; strcpy(name, firstname); @@ -1709,23 +1709,53 @@ static void declstructvar(char *firstname,int fpublic, pstruct_t *pstruct) memset(found, 0, sizeof(cell) * pstruct->argcount); + //:TODO: Make this work with stock /** * Lastly, very lastly, we will insert a copy of this variable. * This is soley to expose the pubvar. */ - usage = uDEFINE|uREAD|uCONST; + usage = uREAD|uCONST|uSTRUCT; if (fpublic) { usage |= uPUBLIC; } - mysym=addsym(name, 0, iVARIABLE, sGLOBAL, pc_addtag(pstruct->name), usage); + mysym = NULL; + for (sym=glbtab.next; sym!=NULL; sym=sym->next) + { + if (strcmp(name, sym->name) == 0) + { + if ((sym->usage & uSTRUCT) && sym->vclass == sGLOBAL) + { + if (sym->usage & uDEFINE) + { + error(21, name); + } else { + if (sym->usage & uPUBLIC && !fpublic) + { + error(42); + } + } + } else { + error(21, name); + } + mysym = sym; + break; + } + } + if (!mysym) + { + mysym=addsym(name, 0, iVARIABLE, sGLOBAL, pc_addtag(pstruct->name), usage); + } - /* Maybe error with "public struct requires initialization?" */ - if (!needtoken('=')) + if (!matchtoken('=')) { matchtoken(';'); + /* Mark it as undefined instead */ + mysym->usage = uSTOCK|uSTRUCT; return; + } else { + mysym->usage = usage; } needtoken('{'); do @@ -1792,7 +1822,6 @@ static void declstructvar(char *firstname,int fpublic, pstruct_t *pstruct) found[arg->index] = 1; } } else if (tok == tSYMBOL) { - symbol *sym = NULL; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->vclass != sGLOBAL) From c89dd6f101a64a6d9e3dd1eafdaa35752003e2f1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 10 Nov 2006 00:16:33 +0000 Subject: [PATCH 0145/1664] imported new API for exposing plugin info --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40175 --- plugins/include/sourcemod.inc | 31 +++++++++++++++++++++---------- plugins/test.sma | 17 ++++++++--------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index dcef839d..7791cd90 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -7,15 +7,26 @@ #endif #define _sourcemod_included -/** - * Note: A plugin can define the following public strings for external information: - * public String:PLUGIN_AUTHOR[] - Author - * public String:PLUGIN_NAME[] - Name/Title - * public String:PLUGIN_DESCRIPTION[] - Short Description - * public String:PLUGIN_VERSION[] - Version information - * public String:PLUGIN_URL[] - Website URL - */ +struct Plugin +{ + const String:name[], /* Plugin Name */ + const String:description[], /* Plugin Description */ + const String:author[], /* Plugin Author */ + const String:version[], /* Plugin Version */ + const String:url[], /* Plugin URL */ +} +/** + * Declare this as a struct in your plugin to expose its information. + * Example: + * + * public Plugin:myinfo = + * { + * name = "My Plugin", + * //etc + * }; + */ +public Plugin:myinfo; /** * Called when the plugin is fully initialized and all known external references are resolved, @@ -37,11 +48,11 @@ forward OnPluginInit(); forward bool:OnPluginLoad(Handle:myself, bool:late, String:error[], err_max); /** - * Called when the plugin is first mapped into memory. Use this to set dynamic natives. + * Called when the plugin is first mapped into memory. Use this to set dynamic natives ONLY. * * @noreturn */ -forward OnPluginCreated(); +forward OnPluginRequirements(); /** * Called when the plugin is about to be unloaded. diff --git a/plugins/test.sma b/plugins/test.sma index e0837709..afab0a4c 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -1,16 +1,15 @@ #include -/** - * I don't know if I like this yet.... - */ -public String:PLUGIN_NAME[] = "Testcrab" -public String:PLUGIN_AUTHOR[] = "BAILOPAN" -public String:PLUGIN_VERSION[] = "0.0.0.0" -public String:PLUGIN_URL[] = "http://www.sourcemod.net/" -public String:PUBLIC_DESCRIPTION[] = "A test, fool" +public Plugin:myinfo +{ + name = "Test Plugin", + author = "BAILOPAN", + description = "Tests Stuff", + version = "1.0.0.0", + url = "http://www.sourceomd.net/" +} public OnPluginInit() { /* just a test, mommy */ - return 5 } From ace0d842e557df900614d81c8ed3fdd700fd630b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 10 Nov 2006 06:07:41 +0000 Subject: [PATCH 0146/1664] fixed silly bugizzle --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40176 --- plugins/test.sma | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/test.sma b/plugins/test.sma index afab0a4c..8be4e022 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -1,6 +1,6 @@ #include -public Plugin:myinfo +public Plugin:myinfo = { name = "Test Plugin", author = "BAILOPAN", From ac761f61ce6fc94fadd214bf7bf21f848858bbb0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 10 Nov 2006 07:49:38 +0000 Subject: [PATCH 0147/1664] initial import of plugin loading code little fixes to API temporarily commented dependency iface until final --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40177 --- core/interfaces/IPluginSys.h | 44 ++++++++++++++++++++-------------- core/msvc8/sourcemod_mm.vcproj | 8 +++++++ core/vm/sp_vm_engine.cpp | 5 ---- plugins/include/sourcemod.inc | 2 +- plugins/test.sma | 2 +- sourcepawn/include/sp_vm_api.h | 2 +- 6 files changed, 37 insertions(+), 26 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 8dce1d39..a82164cb 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -2,7 +2,7 @@ #define _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ #include -#include +#include #define SMINTERFACE_PLUGINMANAGER_NAME "IPluginManager" #define SMINTERFACE_PLUGINMANAGER_VERSION 1 @@ -27,6 +27,7 @@ namespace SourceMod enum PluginStatus { Plugin_Running=0, /* Plugin is running */ + Plugin_Loaded, /* Plugin is loaded but not initialized */ Plugin_Paused, /* Plugin is paused */ Plugin_Stopped, /* Plugin is paused for map changes, too */ Plugin_Error, /* Plugin has a blocking error */ @@ -46,59 +47,66 @@ namespace SourceMod /** * @brief Encapsulates a run-time plugin as maintained by SourceMod. */ - class IPlugin : public IUnloadableParent + class IPlugin /*: public IUnloadableParent*/ { public: - UnloadableParentType GetParentType() + /*UnloadableParentType GetParentType() { return ParentType_Module; - } + }*/ public: /** * @brief Returns the lifetime of a plugin. */ - virtual PluginLifetime GetLifetime() =0; + virtual PluginLifetime GetLifetime() const =0; /** * @brief Returns the current API context being used in the plugin. * * @return Pointer to an IPluginContext, or NULL if not loaded. */ - virtual SourcePawn::IPluginContext *GetBaseContext() =0; + virtual SourcePawn::IPluginContext *GetBaseContext() const =0; /** * @brief Returns the context structure being used in the plugin. * - * @brief Pointer to an sp_context_t, or NULL if not loaded. + * @return Pointer to an sp_context_t, or NULL if not loaded. */ - virtual sp_context_t *GetContext() =0; + virtual sp_context_t *GetContext() const =0; /** - * @brief Returns information about the plugin. + * @brief Returns the plugin file structure. * - * @brief Pointer to an sm_plugininfo_t, or NULL if not loaded. + * @return Pointer to an sp_plugin_t, or NULL if not loaded. */ - virtual sm_plugininfo_t *GetPublicInfo() =0; + virtual const sp_plugin_t *GetPluginStructure() const =0; + + /** + * @brief Returns information about the plugin by reference. + * + * @return Pointer to a sm_plugininfo_t object, NULL if plugin is not loaded. + */ + virtual const sm_plugininfo_t *GetPublicInfo() const =0; /** * @brief Returns the plugin filename (relative to plugins dir). */ - virtual const char *GetFilename() =0; + virtual const char *GetFilename() const =0; /** * @brief Returns true if a plugin is in debug mode, false otherwise. */ - virtual bool IsDebugging() =0; + virtual bool IsDebugging() const =0; /** * @brief Returns the plugin status. */ - virtual PluginStatus GetStatus() =0; + virtual PluginStatus GetStatus() const =0; /** * @brief Sets whether the plugin is paused or not. * - * @return True on successful pause, false otherwise. + * @return True on successful state change, false otherwise. */ virtual bool SetPauseState(bool paused) =0; @@ -110,12 +118,12 @@ namespace SourceMod /** * @brief Returns whether the plugin is locked from being updated on mapchange. */ - virtual bool GetLockForUpdates() =0; + virtual bool GetLockForUpdates() const =0; /** * @brief Returns the unique serial number of a plugin. */ - virtual unsigned int GetSerial() =0; + virtual unsigned int GetSerial() const =0; }; @@ -125,7 +133,7 @@ namespace SourceMod class IPluginIterator { public: - virtual void ~IPluginIterator() + virtual ~IPluginIterator() { }; public: diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 53913af5..d402be95 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -255,6 +255,10 @@ RelativePath="..\systems\LibrarySys.h" > + + + + GetContext(); - IVirtualMachine *vm = ctx->GetVirtualMachine(); - - vm->FreeContext(_ctx); - delete ctx; } diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 7791cd90..ab600e12 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -52,7 +52,7 @@ forward bool:OnPluginLoad(Handle:myself, bool:late, String:error[], err_max); * * @noreturn */ -forward OnPluginRequirements(); +forward OnCreatePlugin(); /** * Called when the plugin is about to be unloaded. diff --git a/plugins/test.sma b/plugins/test.sma index 8be4e022..2803c672 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -6,7 +6,7 @@ public Plugin:myinfo = author = "BAILOPAN", description = "Tests Stuff", version = "1.0.0.0", - url = "http://www.sourceomd.net/" + url = "http://www.sourcemod.net/" } public OnPluginInit() diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 9a1ba692..1859324d 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -343,7 +343,7 @@ namespace SourcePawn virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0; /** - * Frees a context. + * Frees a base context. Does not free the sp_context_t it holds. * * @param ctx Context pointer to free. */ From 30956eae5bb3547d62edbeb286eb361cc3ea3236 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 10 Nov 2006 18:08:13 +0000 Subject: [PATCH 0148/1664] added plugin sys initial import --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40178 --- core/systems/PluginSys.cpp | 170 +++++++++++++++++++++++++++++++++++++ core/systems/PluginSys.h | 52 ++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 core/systems/PluginSys.cpp create mode 100644 core/systems/PluginSys.h diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp new file mode 100644 index 00000000..487ebc32 --- /dev/null +++ b/core/systems/PluginSys.cpp @@ -0,0 +1,170 @@ +#include +#include "PluginSys.h" + +using namespace SourcePawn; + +CPlugin *CPlugin::CreatePlugin(const char *file, + bool debug_default, + PluginLifetime life, + char *error, + size_t maxlen) +{ + static unsigned int MySerial = 0; + FILE *fp = fopen(file, "rb"); + + if (!fp) + { + snprintf(error, maxlen, "Could not open file"); + return NULL; + } + + int err; + sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err); + if (pl == NULL) + { + snprintf(error, maxlen, "Could not load plugin, error %d", err); + return NULL; + } + + fclose(fp); + + ICompilation *co = g_pVM->StartCompilation(pl); + + if (debug_default) + { + if (!g_pVM->SetCompilationOption(co, "debug", "1")) + { + g_pVM->AbortCompilation(co); + snprintf(error, maxlen, "Could not set plugin to debug mode"); + return NULL; + } + } + + sp_context_t *ctx = g_pVM->CompileToContext(co, &err); + if (ctx == NULL) + { + snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err); + return NULL; + } + + IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx); + CPlugin *pPlugin = new CPlugin; + + snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file); + pPlugin->m_debugging = debug_default; + pPlugin->m_ctx_current.base = base; + pPlugin->m_ctx_current.ctx = ctx; + pPlugin->m_lifetime = life; + pPlugin->m_lock = false; + pPlugin->m_serial = ++MySerial; + pPlugin->m_status = Plugin_Loaded; + pPlugin->m_plugin = pl; + + pPlugin->UpdateInfo(); + + return pPlugin; +} + +void CPlugin::UpdateInfo() +{ + /* Now grab the info */ + uint32_t idx; + IPluginContext *base = GetBaseContext(); + int err = base->FindPubvarByName("myinfo", &idx); + + if (err == SP_ERROR_NONE) + { + struct sm_plugininfo_c_t + { + cell_t name; + cell_t description; + cell_t author; + cell_t version; + cell_t url; + }; + sm_plugininfo_c_t *cinfo; + cell_t local_addr; + + base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo); + base->LocalToString(cinfo->name, (char **)&m_info.name); + base->LocalToString(cinfo->description, (char **)&m_info.description); + base->LocalToString(cinfo->author, (char **)&m_info.author); + base->LocalToString(cinfo->url, (char **)&m_info.url); + base->LocalToString(cinfo->version, (char **)&m_info.version); + } + + m_info.author = m_info.author ? m_info.author : ""; + m_info.description = m_info.description ? m_info.description : ""; + m_info.name = m_info.name ? m_info.name : ""; + m_info.url = m_info.url ? m_info.url : ""; + m_info.version = m_info.version ? m_info.version : ""; +} + +const sp_plugin_t *CPlugin::GetPluginStructure() const +{ + return m_plugin; +} + +IPluginContext *CPlugin::GetBaseContext() const +{ + return m_ctx_current.base; +} + +sp_context_t *CPlugin::GetContext() const +{ + return m_ctx_current.ctx; +} + +const char *CPlugin::GetFilename() const +{ + return m_filename; +} + +PluginLifetime CPlugin::GetLifetime() const +{ + return m_lifetime; +} + +bool CPlugin::GetLockForUpdates() const +{ + return m_lock; +} + +const sm_plugininfo_t *CPlugin::GetPublicInfo() const +{ + return &m_info; +} + +unsigned int CPlugin::GetSerial() const +{ + return m_serial; +} + +PluginStatus CPlugin::GetStatus() const +{ + return m_status; +} + +bool CPlugin::IsDebugging() const +{ + return m_debugging; +} + +void CPlugin::SetLockForUpdates(bool lock_status) +{ + m_lock = lock_status; +} + +bool CPlugin::SetPauseState(bool paused) +{ + if (paused && GetStatus() != Plugin_Paused) + { + return false; + } else if (!paused && GetStatus() != Plugin_Running) { + return false; + } + + /* :TODO: execute some forwards or some crap */ + + return true; +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h new file mode 100644 index 00000000..c2d24a5e --- /dev/null +++ b/core/systems/PluginSys.h @@ -0,0 +1,52 @@ +#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ +#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ + +#include +#include "sm_globals.h" + +struct ContextPair +{ + ContextPair() : base(NULL), ctx(NULL) + { + }; + IPluginContext *base; + sp_context_t *ctx; +}; + +class CPlugin : public IPlugin +{ +public: + virtual PluginLifetime GetLifetime() const; + virtual SourcePawn::IPluginContext *GetBaseContext() const; + virtual sp_context_t *GetContext() const; + virtual const sm_plugininfo_t *GetPublicInfo() const; + virtual const char *GetFilename() const; + virtual bool IsDebugging() const; + virtual PluginStatus GetStatus() const; + virtual bool SetPauseState(bool paused); + virtual void SetLockForUpdates(bool lock_status); + virtual bool GetLockForUpdates() const; + virtual unsigned int GetSerial() const; + virtual const sp_plugin_t *GetPluginStructure() const; +public: + static CPlugin *CreatePlugin(const char *file, + bool debug_default, + PluginLifetime life, + char *error, + size_t maxlen); +protected: + void UpdateInfo(); +private: + ContextPair m_ctx_current; + ContextPair m_ctx_backup; + PluginLifetime m_lifetime; + bool m_debugging; + char m_filename[PLATFORM_MAX_PATH+1]; + PluginStatus m_status; + bool m_lock; + unsigned int m_serial; + sm_plugininfo_t m_info; + sp_plugin_t *m_plugin; +}; + +#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ From 50e5307d322a2ff404bc04ec9878d7fe6dd0760b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 01:19:46 +0000 Subject: [PATCH 0149/1664] initial import of proposed forward API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40179 --- core/interfaces/IForwardSys.h | 211 +++++++++++++++++++++++++++++++++ core/interfaces/IPluginSys.h | 133 +++++++++++++++++---- core/msvc8/sourcemod_mm.vcproj | 4 + core/systems/PluginSys.cpp | 168 +++++++++++++++++++++++--- core/systems/PluginSys.h | 61 +++++++++- 5 files changed, 535 insertions(+), 42 deletions(-) create mode 100644 core/interfaces/IForwardSys.h diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h new file mode 100644 index 00000000..ffeb7ee8 --- /dev/null +++ b/core/interfaces/IForwardSys.h @@ -0,0 +1,211 @@ +#ifndef _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ +#define _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ + +#include +#include + +#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" +#define SMINTERFACE_FORWARDMANAGER_VERSION 1 + +namespace SourceMod +{ + enum ResultType + { + Pl_Continue = 0, /* No result */ + Pl_Handled = 1, /* Result was handled, stop at the end */ + Pl_Stop = 2, /* Result was handled, stop now */ + }; + + enum ExecType + { + ET_Ignore = 0, /* Ignore all return values, return 0 */ + ET_Single = 1, /* Only return the first exec, ignore all others */ + ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */ + ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */ + }; + + /** + * @brief Abstracts multiple function calling. + * + * NOTE: Parameters should be pushed in forward order, unlike + * the virtual machine/IPluginContext order. + */ + class IForward : public IPluginFunction + { + public: + /** + * @brief Returns the name of the forward. + * + * @return Forward name. + */ + virtual const char *GetForwardName() =0; + + /** + * @brief Pushes a cell onto the current call. + * + * @param cell Parameter value to push. + * @return True if successful, false if type or count mismatch. + */ + virtual bool PushCell(cell_t cell) =0; + + /** + * @brief Pushes a float onto the current call. + * + * @param float Parameter value to push. + * @return True if successful, false if type or count mismatch. + */ + virtual bool PushFloat(float number) =0; + + /** + * @brief Pushes an array of cells onto the current call, each cell individually. + * NOTE: This is essentially a crippled version of PushArray(). + * + * @param array Array of cells. + * @param numcells Number of cells in array. + * @param each Whether or not to push as an array or individual cells. + * @return True if successful, false if too many cells were pushed. + */ + virtual bool PushCells(cell_t array[], unsigned int numcells, bool each) =0; + + /** + * @brief Pushes an array of cells onto the current call. + * + * @param array Array to copy, NULL if no initial array should be copied. + * @param cells Number of cells to allocate and optionally read from the input array. + * @param phys_addr Optional return address for physical array. + * @param copyback Whether or not changes should be copied back to the input array. + * @return True if successful, false otherwise. + */ + virtual bool PushArray(cell_t *inarray, size_t cells, cell_t **phys_addr, bool copyback) =0; + + /** + * @brief Pushes a string onto the current call. + * + * @param string String to push. + * @return True if successful, false if type or count mismatch. + */ + virtual bool PushString(const char *string) =0; + + /** + * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. + * + * @param result Pointer to store return value in (dependent on forward type). + * @param last_err Pointer to store number of successful executions in. + * @return Error code, if any. + */ + virtual int Execute(cell_t *result, unsigned int *num_functions) =0; + + /** + * @brief Returns the number of functions in this forward. + * + * @return Number of functions in forward. + */ + virtual unsigned int GetFunctionCount() =0; + + /** + * @brief Returns the method of multi-calling this forward has. + * + * @return ResultType of the forward. + */ + virtual ResultType GetResultType() =0; + }; + + + class IChangeableForward : public IForward + { + public: + /** + * @brief Removes a function from the call list. + * + * @param func Function to remove. + */ + virtual void RemoveFunction(IPluginFunction *func) =0; + + /** + * @brief Removes all instances of a plugin from the call list. + * + * @param plugin Plugin to remove instances of. + * @return Number of functions removed therein. + */ + virtual void RemoveFunctionsOfPlugin(IPlugin *plugin) =0; + + /** + * @brief Adds a function to the call list. + * + * @param func Function to add. + */ + virtual void AddFunction(IPluginFunction *func) =0; + }; + + enum ParamType + { + Param_Any = 0, + Param_Cell = 1, + Param_Float = 2, + Param_String = 3, + Param_Array = 4, + Param_VarArgs = 5, + }; + + class IForwardManager : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_FORWARDMANAGER_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_FORWARDMANAGER_VERSION; + } + public: + /** + * @brief Creates a managed forward. This forward exists globally. + * The name used to create the forward is used as its public function in all target plugins. + * As new non-private plugins become loaded or unloaded, they will be automatically added + * or removed. This is ideal for global, static forwards that are never changed. + * + * @param name Name of public function to use in forward. + * @param et Execution type to be used. + * @param num_params Number of parameter this function will have. + * NOTE: For varargs, this should include the vararg parameter. + * @param types Array of type information about each parameter. If NULL, types + * are read off the vararg stream. + * @param ... If types is NULL, num_params ParamTypes should be pushed. + * @return A new IForward on success, NULL if type combination is impossible. + */ + virtual IForward *CreateForward(const char *name, ExecType et, int num_params, ParamType *types, ...) =0; + + /** + * @brief Creates an unmanaged forward. This forward exists privately. + * Unlike managed forwards, no functions are ever added by the Manager. + * However, functions will be removed automatically if their parent plugin is unloaded. + * + * @param name Name of forward (unused except for lookup, can be NULL for anonymous). + * @param et Execution type to be used. + * @param num_params Number of parameter this function will have. + * NOTE: For varargs, this should include the vararg parameter. + * @param types Array of type information about each parameter. If NULL, types + * are read off the vararg stream. + * @param ... If types is NULL, num_params ParamTypes should be pushed. + * @return A new IChangeableForward on success, NULL if type combination is impossible. + */ + virtual IChangeableForward *CreateForwardEx(const char *name, + ExecType et, + int num_params, + ParamType *types, + ...) =0; + + /** + * @brief Finds a forward by name. Does not return anonymous forwards (named NULL or ""). + * + * @param name Name of forward. + * @param ifchng Optionally store either NULL or an IChangeableForward pointer + * depending on type of forward. + * @return IForward pointer, or NULL if none found matching the name. + */ + virtual IForward *FindForward(const char *name, IChangeableForward **ifchng) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index a82164cb..bdd95a92 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -7,6 +7,8 @@ #define SMINTERFACE_PLUGINMANAGER_NAME "IPluginManager" #define SMINTERFACE_PLUGINMANAGER_VERSION 1 +#define SM_CONTEXTVAR_USER 3 + namespace SourceMod { /** @@ -34,31 +36,66 @@ namespace SourceMod Plugin_BadLoad, /* Plugin failed to load */ }; + /** * @brief Describes the object lifetime of a plugin. */ - enum PluginLifetime + enum PluginType { - PluginLifetime_Forever, /* Plugin will never be unloaded */ - PluginLifetime_Map /* Plugin will be unloaded at mapchange */ + PluginType_Private, /* Plugin is privately managed and receives no forwards */ + PluginType_MapUpdated, /* Plugin will never be unloaded unless for updates on mapchange */ + PluginType_MapOnly, /* Plugin will be removed at mapchange */ + PluginType_Global, /* Plugin will never be unloaded or updated */ + }; + + + class IPlugin; + + + /** + * @brief Encapsulates a basic function call. + * NOTE: Function calls must be atomic to one execution context. + * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. + */ + class IPluginFunction + { + public: + virtual ~IPluginFunction() + { + } + + /** + * @brief Executes the function with the given parameter array. + * Parameters are read in forward order (i.e. index 0 is parameter #1) + * + * @param param Array of cell parameters. + * @param num_params Number of parameters to push. + * @param result Pointer to store result of function on return. + * @return SourcePawn error code (if any). + */ + virtual int CallFunction(cell_t *params, unsigned int num_params, cell_t *result) =0; + + /** + * @brief Returns which plugin this function belongs to. + */ + virtual IPlugin *GetParentPlugin() =0; }; /** * @brief Encapsulates a run-time plugin as maintained by SourceMod. */ - class IPlugin /*: public IUnloadableParent*/ + class IPlugin { public: - /*UnloadableParentType GetParentType() + virtual ~IPlugin() { - return ParentType_Module; - }*/ - public: + } + /** * @brief Returns the lifetime of a plugin. */ - virtual PluginLifetime GetLifetime() const =0; + virtual PluginType GetType() const =0; /** * @brief Returns the current API context being used in the plugin. @@ -110,20 +147,26 @@ namespace SourceMod */ virtual bool SetPauseState(bool paused) =0; - /** - * @brief Locks or unlocks the plugin from being updated on mapchange. - */ - virtual void SetLockForUpdates(bool lock_status) =0; - - /** - * @brief Returns whether the plugin is locked from being updated on mapchange. - */ - virtual bool GetLockForUpdates() const =0; - /** * @brief Returns the unique serial number of a plugin. */ virtual unsigned int GetSerial() const =0; + + /** + * @brief Returns a function by name. + * + * @param public_name Name of the function. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionByName(const char *public_name) =0; + + /** + * @brief Returns a function by its id. + * + * @param func_id Function ID. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; }; @@ -159,6 +202,42 @@ namespace SourceMod virtual void Release() =0; }; + /** + * @brief Listens for plugin-oriented events. + */ + class IPluginsListener + { + public: + /** + * @brief Called when a plugin is created/mapped into memory. + */ + virtual void OnPluginCreated(IPlugin *plugin) + { + } + + /** + * @brief Called when a plugin is fully loaded successfully. + */ + virtual void OnPluginLoaded(IPlugin *plugin) + { + } + + /** + * @brief Called when a plugin is unloaded (only if fully loaded). + */ + virtual void OnPluginUnloaded(IPlugin *plugin) + { + } + + /** + * @brief Called when a plugin is destroyed. + * NOTE: Always called if Created, even if load failed. + */ + virtual void OnPluginDestroyed(IPlugin *plugin) + { + } + }; + /** * @brief Manages the runtime loading and unloading of plugins. @@ -188,7 +267,7 @@ namespace SourceMod */ virtual IPlugin *LoadPlugin(const char *path, bool debug, - PluginLifetime lifetime, + PluginType type, char error[], size_t err_max) =0; @@ -221,6 +300,20 @@ namespace SourceMod * Note: This pointer must be freed using EITHER delete OR IPluginIterator::Release(). */ virtual IPluginIterator *GetPluginIterator() =0; + + /** + * @brief Adds a plugin manager listener. + * + * @param listener Pointer to a listener. + */ + virtual void AddPluginsListener(IPluginsListener *listener) =0; + + /** + * @brief Removes a plugin listener. + * + * @param listener Pointer to a listener. + */ + virtual void RemovePluginsListener(IPluginsListener *listener) =0; }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d402be95..7b7451ee 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -224,6 +224,10 @@ + + diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 487ebc32..2b7d2cec 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,11 +1,15 @@ #include #include "PluginSys.h" -using namespace SourcePawn; +CPluginManager g_PluginMngr; + +CPluginManager::CPluginManager() +{ +} CPlugin *CPlugin::CreatePlugin(const char *file, bool debug_default, - PluginLifetime life, + PluginType type, char *error, size_t maxlen) { @@ -54,14 +58,15 @@ CPlugin *CPlugin::CreatePlugin(const char *file, pPlugin->m_debugging = debug_default; pPlugin->m_ctx_current.base = base; pPlugin->m_ctx_current.ctx = ctx; - pPlugin->m_lifetime = life; - pPlugin->m_lock = false; + pPlugin->m_type = type; pPlugin->m_serial = ++MySerial; pPlugin->m_status = Plugin_Loaded; pPlugin->m_plugin = pl; pPlugin->UpdateInfo(); + ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin; + return pPlugin; } @@ -120,14 +125,9 @@ const char *CPlugin::GetFilename() const return m_filename; } -PluginLifetime CPlugin::GetLifetime() const +PluginType CPlugin::GetType() const { - return m_lifetime; -} - -bool CPlugin::GetLockForUpdates() const -{ - return m_lock; + return m_type; } const sm_plugininfo_t *CPlugin::GetPublicInfo() const @@ -150,11 +150,6 @@ bool CPlugin::IsDebugging() const return m_debugging; } -void CPlugin::SetLockForUpdates(bool lock_status) -{ - m_lock = lock_status; -} - bool CPlugin::SetPauseState(bool paused) { if (paused && GetStatus() != Plugin_Paused) @@ -168,3 +163,144 @@ bool CPlugin::SetPauseState(bool paused) return true; } + +/******************* + * PLUGIN ITERATOR * + *******************/ +CPluginManager::CPluginIterator::CPluginIterator(List *_mylist) +{ + mylist = _mylist; +} + +IPlugin *CPluginManager::CPluginIterator::GetPlugin() +{ + return (*current); +} + +bool CPluginManager::CPluginIterator::MorePlugins() +{ + return (current != mylist->end()); +} + +void CPluginManager::CPluginIterator::NextPlugin() +{ + current++; +} + +void CPluginManager::CPluginIterator::Release() +{ + g_PluginMngr.ReleaseIterator(this); +} + +CPluginManager::CPluginIterator::~CPluginIterator() +{ +} + +void CPluginManager::CPluginIterator::Reset() +{ + current = mylist->begin(); +} + +/****************** + * PLUGIN MANAGER * + ******************/ + +IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) +{ + CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max); + + if (!pPlugin) + { + return NULL; + } + + m_plugins.push_back(pPlugin); + + List::iterator iter; + IPluginsListener *pListener; + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) + { + pListener = (*iter); + pListener->OnPluginCreated(pPlugin); + } + + /* :TODO: a lot more... */ + + return pPlugin; +} + +bool CPluginManager::UnloadPlugin(IPlugin *plugin) +{ + CPlugin *pPlugin = (CPlugin *)plugin; + + /* :TODO: More */ + + List::iterator iter; + IPluginsListener *pListener; + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) + { + pListener = (*iter); + pListener->OnPluginDestroyed(pPlugin); + } + + if (pPlugin->m_ctx_current.base) + { + g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base); + } + if (pPlugin->m_ctx_backup.base) + { + g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base); + } + if (pPlugin->m_ctx_current.ctx) + { + pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx); + } + if (pPlugin->m_ctx_backup.ctx) + { + pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx); + } + + g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin); + + delete pPlugin; + + return true; +} + +IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx) +{ + IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF]; + return pl; +} + +unsigned int CPluginManager::GetPluginCount() +{ + return m_plugins.size(); +} + +void CPluginManager::AddPluginsListener(IPluginsListener *listener) +{ + m_listeners.push_back(listener); +} + +void CPluginManager::RemovePluginsListener(IPluginsListener *listener) +{ + m_listeners.remove(listener); +} + +IPluginIterator *CPluginManager::GetPluginIterator() +{ + if (m_iters.empty()) + { + return new CPluginIterator(&m_plugins); + } else { + CPluginIterator *iter = m_iters.front(); + m_iters.pop(); + return iter; + } +} + +void CPluginManager::ReleaseIterator(CPluginIterator *iter) +{ + m_iters.push(iter); +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index c2d24a5e..5705dcc3 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -2,8 +2,14 @@ #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #include +#include +#include #include "sm_globals.h" +using namespace SourceHook; + +#define SM_CONTEXTVAR_MYSELF 0 + struct ContextPair { ContextPair() : base(NULL), ctx(NULL) @@ -15,8 +21,9 @@ struct ContextPair class CPlugin : public IPlugin { + friend class CPluginManager; public: - virtual PluginLifetime GetLifetime() const; + virtual PluginType GetType() const; virtual SourcePawn::IPluginContext *GetBaseContext() const; virtual sp_context_t *GetContext() const; virtual const sm_plugininfo_t *GetPublicInfo() const; @@ -24,14 +31,14 @@ public: virtual bool IsDebugging() const; virtual PluginStatus GetStatus() const; virtual bool SetPauseState(bool paused); - virtual void SetLockForUpdates(bool lock_status); - virtual bool GetLockForUpdates() const; virtual unsigned int GetSerial() const; virtual const sp_plugin_t *GetPluginStructure() const; + virtual IPluginFunction *GetFunctionByName(const char *public_name); + virtual IPluginFunction *GetFunctionById(funcid_t func_id); public: static CPlugin *CreatePlugin(const char *file, bool debug_default, - PluginLifetime life, + PluginType life, char *error, size_t maxlen); protected: @@ -39,14 +46,56 @@ protected: private: ContextPair m_ctx_current; ContextPair m_ctx_backup; - PluginLifetime m_lifetime; + PluginType m_type; bool m_debugging; char m_filename[PLATFORM_MAX_PATH+1]; PluginStatus m_status; - bool m_lock; unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; }; +class CPluginManager : public IPluginManager +{ +public: + CPluginManager(); +public: + class CPluginIterator : public IPluginIterator + { + public: + CPluginIterator(List *mylist); + virtual ~CPluginIterator(); + virtual bool MorePlugins(); + virtual IPlugin *GetPlugin(); + virtual void NextPlugin(); + virtual void Release(); + public: + void Reset(); + private: + List *mylist; + List::iterator current; + }; + friend class CPluginManager::CPluginIterator; +public: + virtual IPlugin *LoadPlugin(const char *path, + bool debug, + PluginType type, + char error[], + size_t err_max); + virtual bool UnloadPlugin(IPlugin *plugin); + virtual IPlugin *FindPluginByContext(const sp_context_t *ctx); + virtual unsigned int GetPluginCount(); + virtual IPluginIterator *GetPluginIterator(); + virtual void AddPluginsListener(IPluginsListener *listener); + virtual void RemovePluginsListener(IPluginsListener *listener); +protected: + void ReleaseIterator(CPluginIterator *iter); +private: + List m_listeners; + List m_plugins; + CStack m_iters; +}; + +extern CPluginManager g_PluginMngr; + #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ From 438ccf39a03a019e60f9e0bd7343f1d5ffcd4565 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 05:47:00 +0000 Subject: [PATCH 0150/1664] added new API for function address lookups. this gives us O(1) code_addr -> sequential index --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40180 --- sourcepawn/compiler/sc1.c | 2 + sourcepawn/include/sp_vm_api.h | 45 +++++++++++++++++----- sourcepawn/include/sp_vm_types.h | 2 +- sourcepawn/jit/x86/jit_x86.cpp | 64 ++++++++++++++++++++++++++++++-- sourcepawn/jit/x86/jit_x86.h | 22 ++++++++++- 5 files changed, 118 insertions(+), 17 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 7d621142..0f678fa1 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -505,6 +505,8 @@ cleanup: delete_pathtable(); delete_sourcefiletable(); delete_dbgstringtable(); + funcenums_free(); + pstructs_free(); #if !defined NO_DEFINE delete_substtable(); #endif diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 1859324d..61cbecfc 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -4,6 +4,8 @@ #include #include "sp_vm_types.h" +#define SOURCEPAWN_VM_API_VERSION 1 + namespace SourcePawn { class IVirtualMachine; @@ -393,12 +395,17 @@ namespace SourcePawn { public: /** - * Returns the string name of a VM implementation. + * @brief Returns the current API version. + */ + virtual unsigned int GetAPIVersion() =0; + + /** + * @brief Returns the string name of a VM implementation. */ virtual const char *GetVMName() =0; /** - * Begins a new compilation + * @brief Begins a new compilation * * @param plugin Pointer to a plugin structure. * @return New compilation pointer. @@ -406,7 +413,7 @@ namespace SourcePawn virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; /** - * Sets a compilation option. + * @brief Sets a compilation option. * * @param co Pointer to a compilation. * @param key Option key name. @@ -416,7 +423,7 @@ namespace SourcePawn virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; /** - * Finalizes a compilation into a new sp_context_t. + * @brief Finalizes a compilation into a new sp_context_t. * Note: This will free the ICompilation pointer. * * @param co Compilation pointer. @@ -426,28 +433,46 @@ namespace SourcePawn virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; /** - * Aborts a compilation and frees the ICompilation pointer. + * @brief Aborts a compilation and frees the ICompilation pointer. * * @param co Compilation pointer. */ virtual void AbortCompilation(ICompilation *co) =0; /** - * Frees any internal variable usage on a context. + * @brief Frees any internal variable usage on a context. * * @param ctx Context structure pointer. */ virtual void FreeContext(sp_context_t *ctx) =0; /** - * Calls the "execute" function on a context. + * @brief Calls the "execute" function on a context. * * @param ctx Executes a function in a context. - * @param code_idx Index into the code section. - * @param result Pointer to store result in. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. * @return Error code (if any). */ - virtual int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) =0; + virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0; + + /** + * @brief Given a context and a code address, returns the index of the function. + * + * @param ctx Context to search. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return True if code index is valid, false otherwise. + */ + virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; + + /** + * @brief Returns the number of functions defined in the context. + * + * @param ctx Context to search. + * @return Number of functions. + */ + virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; }; }; diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 2c7bea84..91117b13 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -104,7 +104,7 @@ namespace SourcePawn struct sp_context_s; -typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); +typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, const cell_t *); /********************************************** *** The following structures are bound to the VM/JIT. diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 1dfe2d97..aedd936a 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -233,6 +233,7 @@ inline void WriteOp_Proc(JitWriter *jit) * Just in case, we guard this memory with INT3 to break into the debugger. */ jitoffs_t cur_offs = jit->get_outputpos(); + CompData *co = (CompData *)jit->data; if (cur_offs % 4) { cur_offs = 4 - (cur_offs % 4); @@ -240,11 +241,25 @@ inline void WriteOp_Proc(JitWriter *jit) { jit->write_ubyte(IA32_INT3); } - /* add this amt to the offset we relocated */ + } + + /* Write the info struct about this function */ + jit->write_uint32(JIT_FUNCMAGIC); + jit->write_uint32(co->func_idx); + + /* Now we have to backpatch our reloction offset! */ + { jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t); jitcode_t rebase = ((CompData *)jit->data)->rebase; *(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos(); } + + /* Lastly, if we're writing, keep track of the function count */ + if (jit->outbase) + { + co->func_idx++; + } + //push old frame on stack: //mov ecx, [esi+frm] //mov [edi-4], ecx @@ -1756,7 +1771,7 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) return native->pfn(ctx, params); } -cell_t InvalidNative(sp_context_t *ctx, cell_t *params) +cell_t InvalidNative(sp_context_t *ctx, const cell_t *params) { ctx->err = SP_ERROR_INVALID_NATIVE; @@ -1877,6 +1892,7 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); + uint32_t codemem = 0; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1957,8 +1973,8 @@ jit_rewind: WriteErrorRoutines(data, jit); /* the total codesize is now known! */ - uint32_t mem = writer.get_outputpos(); - writer.outbase = (jitcode_t)engine->ExecAlloc(mem); + codemem = writer.get_outputpos(); + writer.outbase = (jitcode_t)engine->ExecAlloc(codemem); writer.outptr = writer.outbase; /* go back for third pass */ goto jit_rewind; @@ -2100,6 +2116,11 @@ jit_rewind: trk->pCur = trk->pBase; trk->size = 1024 / sizeof(cell_t); + functracker_t *fnc = new functracker_t; + ctx->vm[JITVARS_FUNCINFO] = fnc; + fnc->code_size = codemem; + fnc->num_functions = data->func_idx; + /* clean up relocation+compilation memory */ AbortCompilation(co); @@ -2172,3 +2193,38 @@ bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char return false; } + +unsigned int JITX86::GetAPIVersion() +{ + return SOURCEPAWN_VM_API_VERSION; +} + +bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) +{ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + + if (code_addr >= fnc->code_size) + { + return false; + } + + funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t)); + if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions) + { + return false; + } + + if (result) + { + *result = f->index; + } + + return true; +} + +unsigned int JITX86::FunctionCount(const sp_context_t *ctx) +{ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + + return fnc->num_functions; +} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index f4f40f4c..5f8eae60 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -9,9 +9,11 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) -#define STACK_MARGIN 64 //8 parameters of safety, I guess +#define STACK_MARGIN 64 //8 parameters of safety, I guess +#define JIT_FUNCMAGIC 0x214D4148 //magic function offset #define JITVARS_TRACKER 0 //important: don't change this to avoid trouble +#define JITVARS_FUNCINFO 1 //important: don't change this aWOAWOGJQG I LIKE HAM typedef struct tracker_s { @@ -20,12 +22,24 @@ typedef struct tracker_s ucell_t *pCur; } tracker_t; +typedef struct funcinfo_s +{ + unsigned int magic; + unsigned int index; +} funcinfo_t; + +typedef struct functracker_s +{ + unsigned int num_functions; + unsigned int code_size; +} functracker_t; + class CompData : public ICompilation { public: CompData() : plugin(NULL), debug(false), inline_level(0), rebase(NULL), - error_set(SP_ERROR_NONE) + error_set(SP_ERROR_NONE), func_idx(0) { }; public: @@ -49,6 +63,7 @@ public: jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ + unsigned int func_idx; /* current function index */ int inline_level; /* inline optimization level */ int error_set; /* error code to halt process */ bool debug; /* whether to compile debug mode */ @@ -64,6 +79,9 @@ public: void AbortCompilation(ICompilation *co); void FreeContext(sp_context_t *ctx); int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); + unsigned int GetAPIVersion(); + bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result); + unsigned int FunctionCount(const sp_context_t *ctx); }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); From c25cc6402481e51415177e08aa3c49de8a235379 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 05:49:52 +0000 Subject: [PATCH 0151/1664] Implemented a lot more of the plugin system added aggressive caching O(1) function object retrieval --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40181 --- core/interfaces/IPluginSys.h | 2 +- core/sourcemod.cpp | 19 +++++ core/systems/PluginSys.cpp | 151 +++++++++++++++++++++++++++++++++++ core/systems/PluginSys.h | 25 ++++++ 4 files changed, 196 insertions(+), 1 deletion(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index bdd95a92..655e98af 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -73,7 +73,7 @@ namespace SourceMod * @param result Pointer to store result of function on return. * @return SourcePawn error code (if any). */ - virtual int CallFunction(cell_t *params, unsigned int num_params, cell_t *result) =0; + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; /** * @brief Returns which plugin this function belongs to. diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 69f81f2a..4c7fca59 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -4,6 +4,7 @@ #include "systems/LibrarySys.h" #include "vm/sp_vm_engine.h" #include +#include "PluginSys.h" SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -99,5 +100,23 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) return false; } + unsigned int api = g_pVM->GetAPIVersion(); + if (api != SOURCEPAWN_VM_API_VERSION) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "JIT is not a compatible version"); + } + return false; + } + + g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str()); + IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max); + IPluginFunction *func = pPlugin->GetFunctionByName("OnPluginInit"); + cell_t result; + func->CallFunction(NULL, 0, &result); + g_PluginMngr.UnloadPlugin(pPlugin); + return true; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2b7d2cec..71cce53d 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -7,6 +7,34 @@ CPluginManager::CPluginManager() { } +void CFunction::Set(funcid_t funcid, CPlugin *plugin) +{ + m_funcid = funcid; + m_pPlugin = plugin; +} + +int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) +{ + IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + + for (unsigned int i=0; iPushCell(params[i]); + } + + return ctx->Execute(m_funcid, result); +} + +IPlugin *CFunction::GetParentPlugin() +{ + return m_pPlugin; +} + +CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : + m_funcid(funcid), m_pPlugin(plugin) +{ +} + CPlugin *CPlugin::CreatePlugin(const char *file, bool debug_default, PluginType type, @@ -67,9 +95,89 @@ CPlugin *CPlugin::CreatePlugin(const char *file, ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin; + /* Build function information loosely */ + pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx); + + if (pPlugin->m_funcsnum) + { + pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum]; + memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum); + } else { + pPlugin->m_priv_funcs = NULL; + } + + if (pl->info.publics_num) + { + pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num]; + memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num); + } else { + pPlugin->m_pub_funcs = NULL; + } + return pPlugin; } +IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) +{ + CFunction *pFunc = NULL; + funcid_t save = func_id; + + if (func_id & 1) + { + func_id >>= 1; + if (func_id >= m_plugin->info.publics_num) + { + return NULL; + } + pFunc = m_pub_funcs[func_id]; + if (!pFunc) + { + pFunc = g_PluginMngr.GetFunctionFromPool(save, this); + m_pub_funcs[func_id] = pFunc; + } + } else { + func_id >>= 1; + unsigned int index; + if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index)) + { + return NULL; + } + pFunc = m_priv_funcs[func_id]; + if (!pFunc) + { + pFunc = g_PluginMngr.GetFunctionFromPool(save, this); + m_priv_funcs[func_id] = pFunc; + } + } + + return pFunc; +} + +IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) +{ + uint32_t index; + IPluginContext *base = m_ctx_current.base; + + if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) + { + return NULL; + } + + CFunction *pFunc = m_pub_funcs[index]; + if (!pFunc) + { + sp_public_t *pub = NULL; + base->GetPublicByIndex(index, &pub); + if (pub) + { + pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this); + m_pub_funcs[index] = pFunc; + } + } + + return pFunc; +} + void CPlugin::UpdateInfo() { /* Now grab the info */ @@ -242,6 +350,26 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener = (*iter); pListener->OnPluginDestroyed(pPlugin); } + + if (pPlugin->m_pub_funcs) + { + for (uint32_t i=0; im_plugin->info.publics_num; i++) + { + delete pPlugin->m_pub_funcs[i]; + } + delete [] pPlugin->m_pub_funcs; + pPlugin->m_pub_funcs = NULL; + } + + if (pPlugin->m_priv_funcs) + { + for (unsigned int i=0; im_funcsnum; i++) + { + delete pPlugin->m_priv_funcs[i]; + } + delete [] pPlugin->m_priv_funcs; + pPlugin->m_priv_funcs = NULL; + } if (pPlugin->m_ctx_current.base) { @@ -304,3 +432,26 @@ void CPluginManager::ReleaseIterator(CPluginIterator *iter) { m_iters.push(iter); } + +void CPluginManager::ReleaseFunctionToPool(CFunction *func) +{ + m_funcpool.push(func); +} + +CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) +{ + if (m_funcpool.empty()) + { + return new CFunction(f, plugin); + } else { + CFunction *func = m_funcpool.front(); + m_funcpool.pop(); + func->Set(f, plugin); + return func; + } +} + +CPluginManager::~CPluginManager() +{ + //:TODO: we need a good way to free what we're holding +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 5705dcc3..25825e0e 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -19,9 +19,26 @@ struct ContextPair sp_context_t *ctx; }; +class CPlugin; + +class CFunction : public IPluginFunction +{ +public: + CFunction(funcid_t funcid, CPlugin *plugin); +public: + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); + virtual IPlugin *GetParentPlugin(); +public: + void Set(funcid_t funcid, CPlugin *plugin); +private: + funcid_t m_funcid; + CPlugin *m_pPlugin; +}; + class CPlugin : public IPlugin { friend class CPluginManager; + friend class CFunction; public: virtual PluginType GetType() const; virtual SourcePawn::IPluginContext *GetBaseContext() const; @@ -53,12 +70,17 @@ private: unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; + unsigned int m_funcsnum; + CFunction **m_priv_funcs; + CFunction **m_pub_funcs; }; class CPluginManager : public IPluginManager { + friend class CPlugin; public: CPluginManager(); + ~CPluginManager(); public: class CPluginIterator : public IPluginIterator { @@ -90,10 +112,13 @@ public: virtual void RemovePluginsListener(IPluginsListener *listener); protected: void ReleaseIterator(CPluginIterator *iter); + CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); + void ReleaseFunctionToPool(CFunction *func); private: List m_listeners; List m_plugins; CStack m_iters; + CStack m_funcpool; }; extern CPluginManager g_PluginMngr; From adc1475b7624a473d4d8256606cd3bd844797e7b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 11:10:24 +0000 Subject: [PATCH 0152/1664] Fleshed out forward system and extensively documented its design considerations Implemented and did basic tests on new IPluginFunction type Split function types into a separate file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40182 --- core/interfaces/IForwardSys.h | 191 +++++++++++++-------- core/interfaces/IPluginFunction.h | 177 +++++++++++++++++++ core/interfaces/IPluginSys.h | 36 +--- core/msvc8/sourcemod_mm.vcproj | 60 ++++--- core/sourcemod.cpp | 11 +- core/systems/CFunction.cpp | 272 ++++++++++++++++++++++++++++++ core/systems/CFunction.h | 55 ++++++ core/systems/PluginSys.cpp | 37 +--- core/systems/PluginSys.h | 17 +- 9 files changed, 686 insertions(+), 170 deletions(-) create mode 100644 core/interfaces/IPluginFunction.h create mode 100644 core/systems/CFunction.cpp create mode 100644 core/systems/CFunction.h diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index ffeb7ee8..a6e17dd3 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -7,6 +7,11 @@ #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" #define SMINTERFACE_FORWARDMANAGER_VERSION 1 +/** + * There is some very important documentation at the bottom of this file. + * Readers interested in knowing more about the forward system, scrolling down is a must! + */ + namespace SourceMod { enum ResultType @@ -25,12 +30,14 @@ namespace SourceMod }; /** + * :TODO: finish this spec * @brief Abstracts multiple function calling. - * * NOTE: Parameters should be pushed in forward order, unlike * the virtual machine/IPluginContext order. + * NOTE: Some functions are repeated in here because their documentation differs + * from their IPluginFunction equivalents. */ - class IForward : public IPluginFunction + class IForward : public ICallable { public: /** @@ -40,61 +47,6 @@ namespace SourceMod */ virtual const char *GetForwardName() =0; - /** - * @brief Pushes a cell onto the current call. - * - * @param cell Parameter value to push. - * @return True if successful, false if type or count mismatch. - */ - virtual bool PushCell(cell_t cell) =0; - - /** - * @brief Pushes a float onto the current call. - * - * @param float Parameter value to push. - * @return True if successful, false if type or count mismatch. - */ - virtual bool PushFloat(float number) =0; - - /** - * @brief Pushes an array of cells onto the current call, each cell individually. - * NOTE: This is essentially a crippled version of PushArray(). - * - * @param array Array of cells. - * @param numcells Number of cells in array. - * @param each Whether or not to push as an array or individual cells. - * @return True if successful, false if too many cells were pushed. - */ - virtual bool PushCells(cell_t array[], unsigned int numcells, bool each) =0; - - /** - * @brief Pushes an array of cells onto the current call. - * - * @param array Array to copy, NULL if no initial array should be copied. - * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Optional return address for physical array. - * @param copyback Whether or not changes should be copied back to the input array. - * @return True if successful, false otherwise. - */ - virtual bool PushArray(cell_t *inarray, size_t cells, cell_t **phys_addr, bool copyback) =0; - - /** - * @brief Pushes a string onto the current call. - * - * @param string String to push. - * @return True if successful, false if type or count mismatch. - */ - virtual bool PushString(const char *string) =0; - - /** - * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. - * - * @param result Pointer to store return value in (dependent on forward type). - * @param last_err Pointer to store number of successful executions in. - * @return Error code, if any. - */ - virtual int Execute(cell_t *result, unsigned int *num_functions) =0; - /** * @brief Returns the number of functions in this forward. * @@ -105,9 +57,18 @@ namespace SourceMod /** * @brief Returns the method of multi-calling this forward has. * - * @return ResultType of the forward. + * @return ExecType of the forward. */ - virtual ResultType GetResultType() =0; + virtual ExecType GetExecType() =0; + + /** + * @brief Executes the forward. + * + * @param result Pointer to store result in. + * @param num_functions Optionally filled with the number of function sucessfully executed. + * @return Error code, if any. + */ + virtual int Execute(cell_t *result, unsigned int *num_functions) =0; }; @@ -127,24 +88,37 @@ namespace SourceMod * @param plugin Plugin to remove instances of. * @return Number of functions removed therein. */ - virtual void RemoveFunctionsOfPlugin(IPlugin *plugin) =0; + virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin) =0; /** * @brief Adds a function to the call list. + * NOTE: Cannot be used during a call. * * @param func Function to add. + * @return True on success, otherwise false. */ - virtual void AddFunction(IPluginFunction *func) =0; + virtual bool AddFunction(IPluginFunction *func) =0; + + /** + * @brief Adds a function to the call list. + * NOTE: Cannot be used during a call. + * + * @param ctx Context to use as a look-up. + * @param funcid Function id to add. + * @return True on success, otherwise false. + */ + virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0; }; enum ParamType { - Param_Any = 0, - Param_Cell = 1, - Param_Float = 2, - Param_String = 3, - Param_Array = 4, - Param_VarArgs = 5, + Param_Any = 0, //Any type will be accepted + Param_Cell = 1, //Only a cell will be accepted + Param_Float = 2, //Only a float value will be accepted + Param_String = 3, //Only a string will be accepted + Param_Array = 4, //Only a 1D array will be accepted + Param_VarArgs = 5, //Anything will be accepted + ParamTypes_Total = 6, }; class IForwardManager : public SMInterface @@ -174,7 +148,11 @@ namespace SourceMod * @param ... If types is NULL, num_params ParamTypes should be pushed. * @return A new IForward on success, NULL if type combination is impossible. */ - virtual IForward *CreateForward(const char *name, ExecType et, int num_params, ParamType *types, ...) =0; + virtual IForward *CreateForward(const char *name, + ExecType et, + unsigned int num_params, + ParamType *types, + ...) =0; /** * @brief Creates an unmanaged forward. This forward exists privately. @@ -208,4 +186,81 @@ namespace SourceMod }; }; +/** + * In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing + * a function ID and an AMX structure. The forward structure itself did very little but hold parameter types. + * An execution call worked like this: + * - executeForward() took in a function id and a list of parameters + * - for each contained plugin: + * - the list of parameters was preprocessed and pushed + * - the call was made + * - the list was freed and copybacks were made + * - return + * + * The advantages to this is that the system is very easy to implement, and it's fast. The disadvantage is + * varargs tend to be very unforgiving and inflexible, and thus weird problems arose with casting. You also + * lose flexibility, type checking, and the ability to reasonably use variable arguments lists in the VM. + * + * SourceMod replaces this forward system with a far more advanced, but a bit bulkier one. The idea is that + * each plugin has a table of functions, and each function is an ICallable object. As well as being an ICallable, + * each function is an IPluginFunction. An ICallable simply describes the process of adding parameters to a + * function call. An IPluginFunction describes the process of actually calling a function and performing allocation, + * copybacks, and deallocations. + * + * A very powerful forward system emerges: a Forward is just a collection of IPluginFunctions. Thus, the same + * API can be easily wrapped around a simple list, and it will look transparent to the user. + * Advantages: + * 1) "SP Forwards" from AMX Mod X are simply IPluginFunctions without a collection. + * 2) Forwards are function based, rather than plugin based, and are thus far more flexible at runtime.. + * 3) [2] Individual functions can be paused and more than one function from the same plugin can be hooked. + * 4) [2] One hook type that used to map to many SP Forwards can now be centralized as one Forward. + * This helps alleviate messes like Fakemeta. + * 5) Parameter pushing is type-checked and allows for variable arguments. + * + * Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system + * object oriented, rather than AMX Mod X, which hides the objects behind static functions. It is entirely a design + * issue, rather than a usability one. The interesting part is when it gets to implementation, which is when the + * problems for SourceMod arise. Specifically, the implementation is easier in GENERAL -- the tough part is the oddball + * cases. + * + * Observe the calling process: + * - Each parameter is pushed using the ICallable interface. For each parameter: + * - For each function in the collection, the parameter is processed and pushed. + * - For each function in the collection: + * - The call is made. + * - Copy backs are performed. + * - Return + * + * Astute readers will note the problems - the parameters are processed individually for each push, + * rather than for each call. This means: + * 1) More memory is used. Specifically, rather than N params of memory, you now have N params * M plugins. + * This is because, again, parameters are processed per function object, per-push, before the call. + * 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual. + * 3) Copybacks won't work as expected. + * + * Number 3 is hard to see. For example, say a forward has two functions, and an array is pushed with copyback. + * The array gets pushed and copied into each plugin. When the call is made, each plugin now has separate copies of + * the array. When the copyback is performed, it gets mirrored to the originall address, but not to the next plugin! + + * Implementing this is "difficult." To be re-entrant, an IPluginFunction can't tell you anything + * about its copybacks after it has returned, because its internal states were reset long ago. + * + * In order to implement this feature, IPluginFunction::Execute function now lets you pass a listener in. + * This listener is notified each time an array parameter is about to be copied back. Specifically, the forward + * uses this to detect when it needs to push a new parameter out to the next plugin. When the forward gets the + * call back, it detects whether there is another plugin in the queue. If there is, it grabs the address it will + * be using for the same arrays, and specifies it as the new copy-back point. If no plugins are left, it allows + * the copyback to chain up to the original address. + * + * This wonderful little hack is somewhat reminiscent of how SourceHook parameter rewrite chains work. It seems + * ugly at first, but it is actually the correct design pattern to apply to an otherwise awful problem. + * + * Note that there are other solutions to this that aren't based on a visitor-like pattern. For example, the Function + * class could expose a "set new original address" function. Then after arrays are pushed, the arrays are re-browsed, + * and function #1 gets function #2's original address, function #2 gets function #3's original address, et cetera. + * This extra browse step is a bit less efficient though, since the "visitor" method implies only taking action when + * necessary. Furthermore, it would require exposing such a "set address" function, which should fire a red flag + * that the API is doing something it shouldn't (namely, exposing the direct setting of very internal properties). + */ + #endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h new file mode 100644 index 00000000..14e34058 --- /dev/null +++ b/core/interfaces/IPluginFunction.h @@ -0,0 +1,177 @@ +#ifndef _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ + +#include + +namespace SourceMod +{ + #define SMFUNC_COPYBACK_NONE (0) /* Never copy an array back */ + #define SMFUNC_COPYBACK_ONCE (1<<0) /* Copy an array back after call */ + #define SMFUNC_COPYBACK_ALWAYS (1<<1) /* Copy an array back after subsequent calls (forwards) */ + + /** + * @brief Represents what a function needs to implement in order to be callable. + */ + class ICallable + { + public: + /** + * @brief Pushes a cell onto the current call. + * + * @param cell Parameter value to push. + * @return Error code, if any. + */ + virtual int PushCell(cell_t cell) =0; + + /** + * @brief Pushes a cell by reference onto the current call. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * + * @param cell Address containing parameter value to push. + * @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushCellByRef(cell_t *cell, int flags) =0; + + /** + * @brief Pushes a float onto the current call. + * + * @param float Parameter value to push. + * @return Error code, if any. + */ + virtual int PushFloat(float number) =0; + + /** + * @brief Pushes a float onto the current call by reference. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * + * @param float Parameter value to push. + & @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushFloatByRef(float *number, int flags) =0; + + /** + * @brief Pushes an array of cells onto the current call, each cell individually. + * NOTE: This is essentially a crippled version of PushArray(). + * + * @param array Array of cells. + * @param numcells Number of cells in array. + * @param each Whether or not to push as an array or individual cells. + * @return Error code, if any. + */ + virtual int PushCells(cell_t array[], unsigned int numcells, bool each) =0; + + /** + * @brief Pushes an array of cells onto the current call. + * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back + * is enabled. + * + * @param array Array to copy, NULL if no initial array should be copied. + * @param cells Number of cells to allocate and optionally read from the input array. + * @param phys_addr Optional return address for physical array (if array was non-NULL, will be array). + * @param flags Whether or not changes should be copied back to the input array. + * @return Error code, if any. + */ + virtual int PushArray(cell_t *inarray, + unsigned int cells, + cell_t **phys_addr, + int flags=SMFUNC_COPYBACK_NONE) =0; + + /** + * @brief Pushes a string onto the current call. + * + * @param string String to push. + * @return Error code, if any. + */ + virtual int PushString(const char *string) =0; + + /** + * @brief Pushes a string onto the current call. + * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. + * + * @param string String to push. + * @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushStringByRef(char *string, int flags) =0; + + /** + * @brief Cancels a function call that is being pushed but not yet executed. + * This can be used be reset for CallFunction() use. + */ + virtual void Cancel() =0; + }; + + + /** + * @brief Used for copy-back notification + */ + class IFunctionCopybackReader + { + public: + /** + * @brief Called before an array is copied back. + * + * @param param Parameter index. + * @param cells Number of cells in the array. + * @param source_addr Source address in the plugin that will be copied. + * @param orig_addr Destination addres in plugin that will be overwritten. + * @param flags Copy flags. + * @return True to copy back, false otherwise. + */ + virtual bool OnCopybackArray(unsigned int param, + unsigned int cells, + cell_t *source_addr, + cell_t *orig_addr, + int flags) =0; + }; + + /** + * @brief Encapsulates a function call in a plugin. + * NOTE: Function calls must be atomic to one execution context. + * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. + */ + class IPluginFunction : public ICallable + { + public: + /** + * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. + * + * @param result Pointer to store return value in. + * @param reader Copy-back listener. NULL to specify + * @return Error code, if any. + */ + virtual int Execute(cell_t *result, IFunctionCopybackReader *reader) =0; + + /** + * @brief Executes the function with the given parameter array. + * Parameters are read in forward order (i.e. index 0 is parameter #1) + * NOTE: You will get an error if you attempt to use CallFunction() with + * previously pushed parameters. + * + * @param param Array of cell parameters. + * @param num_params Number of parameters to push. + * @param result Pointer to store result of function on return. + * @return SourcePawn error code (if any). + */ + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; + + /** + * @brief Returns which plugin this function belongs to. + * + * @return IPlugin pointer to parent plugin. + */ + virtual IPlugin *GetParentPlugin() =0; + + /** + * @brief Returns the physical address of a by-reference parameter. + * + * @param Parameter index to read (beginning at 0). + * @return Address, or NULL if invalid parameter specified. + */ + virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 655e98af..07001bcf 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -11,6 +11,8 @@ namespace SourceMod { + class IPlugin; + /** * @brief Encapsulates plugin public information. */ @@ -48,39 +50,7 @@ namespace SourceMod PluginType_Global, /* Plugin will never be unloaded or updated */ }; - - class IPlugin; - - - /** - * @brief Encapsulates a basic function call. - * NOTE: Function calls must be atomic to one execution context. - * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. - */ - class IPluginFunction - { - public: - virtual ~IPluginFunction() - { - } - - /** - * @brief Executes the function with the given parameter array. - * Parameters are read in forward order (i.e. index 0 is parameter #1) - * - * @param param Array of cell parameters. - * @param num_params Number of parameters to push. - * @param result Pointer to store result of function on return. - * @return SourcePawn error code (if any). - */ - virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; - - /** - * @brief Returns which plugin this function belongs to. - */ - virtual IPlugin *GetParentPlugin() =0; - }; - + class IPluginFunction; /** * @brief Encapsulates a run-time plugin as maintained by SourceMod. diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7b7451ee..8eb18041 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -224,26 +224,6 @@ - - - - - - - - - - @@ -255,6 +235,14 @@ + + + + @@ -267,6 +255,10 @@ + + @@ -276,6 +268,34 @@ > + + + + + + + + + + + + + + PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str()); IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max); - IPluginFunction *func = pPlugin->GetFunctionByName("OnPluginInit"); - cell_t result; - func->CallFunction(NULL, 0, &result); + IPluginFunction *func = pPlugin->GetFunctionByName("Test"); + cell_t result = 2; + cell_t val = 6; + func->PushCell(1); + func->PushCellByRef(&val, SMFUNC_COPYBACK_ONCE); + func->Execute(&result, NULL); g_PluginMngr.UnloadPlugin(pPlugin); +#endif return true; } diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp new file mode 100644 index 00000000..ee187a51 --- /dev/null +++ b/core/systems/CFunction.cpp @@ -0,0 +1,272 @@ +#include +#include "PluginSys.h" + +/******************** +* FUNCTION CALLING * +********************/ + +void CFunction::Set(funcid_t funcid, CPlugin *plugin) +{ + m_funcid = funcid; + m_pPlugin = plugin; + m_curparam = 0; + m_errorstate = SP_ERROR_NONE; +} + +int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) +{ + IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + + while (num_params--) + { + ctx->PushCell(params[num_params]); + } + + return ctx->Execute(m_funcid, result); +} + +IPlugin *CFunction::GetParentPlugin() +{ + return m_pPlugin; +} + +CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : + m_funcid(funcid), m_pPlugin(plugin), m_curparam(0), + m_errorstate(SP_ERROR_NONE) +{ +} + +int CFunction::PushCell(cell_t cell) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + m_info[m_curparam].marked = false; + m_params[m_curparam] = cell; + m_curparam++; + + return SP_ERROR_NONE; +} + +int CFunction::PushCellByRef(cell_t *cell, int flags) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + return PushArray(cell, 1, NULL, flags); +} + +int CFunction::PushFloat(float number) +{ + cell_t val = *(cell_t *)&number; + + return PushCell(val); +} + +int CFunction::PushFloatByRef(float *number, int flags) +{ + return PushCellByRef((cell_t *)number, flags); +} + +int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each) +{ + if (!each) + { + return PushArray(array, numcells, NULL, SMFUNC_COPYBACK_NONE); + } else { + int err; + for (unsigned int i=0; i= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + ParamInfo *info = &m_info[m_curparam]; + int err; + + if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + { + return SetError(err); + } + + info->flags = inarray ? copyback : SMFUNC_COPYBACK_NONE; + info->marked = true; + info->size = cells; + m_params[m_curparam] = info->local_addr; + m_curparam++; + + if (inarray) + { + memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); + info->orig_addr = inarray; + } else { + info->orig_addr = info->phys_addr; + } + + if (phys_addr) + { + *phys_addr = info->phys_addr; + } + + return true; +} + +int CFunction::PushString(const char *string) +{ + return _PushString(string, SMFUNC_COPYBACK_NONE); +} + +int CFunction::PushStringByRef(char *string, int flags) +{ + return _PushString(string, flags); +} + +int CFunction::_PushString(const char *string, int flags) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + IPluginContext *base = m_pPlugin->m_ctx_current.base; + ParamInfo *info = &m_info[m_curparam]; + size_t len = strlen(string); + size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); + int err; + + if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + { + return SetError(err); + } + + info->marked = true; + m_params[m_curparam] = info->local_addr; + m_curparam++; /* Prevent a leak */ + + //:TODO: Use UTF-8 version + if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) + { + return SetError(err); + } + + info->flags = flags; + info->orig_addr = (cell_t *)string; + info->size = cells; + + return SP_ERROR_NONE; +} + +void CFunction::Cancel() +{ + if (!m_curparam) + { + return; + } + + IPluginContext *base = m_pPlugin->m_ctx_current.base; + + while (m_curparam--) + { + if (m_info[m_curparam].marked) + { + base->HeapRelease(m_info[m_curparam].local_addr); + m_info[m_curparam].marked = false; + } + } + + m_errorstate = SP_ERROR_NONE; +} + +int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) +{ + int err; + if (m_errorstate != SP_ERROR_NONE) + { + err = m_errorstate; + Cancel(); + return err; + } + + //This is for re-entrancy! + cell_t temp_params[SP_MAX_EXEC_PARAMS]; + ParamInfo temp_info[SP_MAX_EXEC_PARAMS]; + unsigned int numparams = m_curparam; + bool docopies = true; + + if (numparams) + { + //Save the info locally, then reset it for re-entrant calls. + memcpy(temp_params, m_params, numparams * sizeof(cell_t)); + memcpy(temp_info, m_info, numparams * sizeof(ParamInfo)); + } + m_curparam = 0; + + if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE) + { + docopies = false; + } + + IPluginContext *base = m_pPlugin->m_ctx_current.base; + + while (numparams--) + { + if (!temp_info[numparams].marked) + { + continue; + } + if (docopies && temp_info[numparams].flags) + { + if (reader) + { + if (!reader->OnCopybackArray(numparams, + temp_info[numparams].size, + temp_info[numparams].phys_addr, + temp_info[numparams].orig_addr, + temp_info[numparams].flags)) + { + goto _skipcopy; + } + } + if (temp_info[numparams].orig_addr) + { + memcpy(temp_info[numparams].orig_addr, + temp_info[numparams].phys_addr, + temp_info[numparams].size * sizeof(cell_t)); + } + } +_skipcopy: + base->HeapRelease(temp_info[numparams].local_addr); + temp_info[numparams].marked = false; + } + + return err; +} + +cell_t *CFunction::GetAddressOfPushedParam(unsigned int param) +{ + if (m_errorstate != SP_ERROR_NONE + || param >= m_curparam + || !m_info[param].marked) + { + return NULL; + } + + return m_info[param].phys_addr; +} diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h new file mode 100644 index 00000000..f9b50180 --- /dev/null +++ b/core/systems/CFunction.h @@ -0,0 +1,55 @@ +#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ +#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ + +#include +#include "sm_globals.h" + +struct ParamInfo +{ + int flags; /* Copy-back flags */ + bool marked; /* Whether this is marked as being used */ + cell_t local_addr; /* Local address to free */ + cell_t *phys_addr; /* Physical address of our copy */ + cell_t *orig_addr; /* Original address to copy back to */ + ucell_t size; /* Size of array in cells */ +}; + +class CPlugin; + +class CFunction : public IPluginFunction +{ +public: + CFunction(funcid_t funcid, CPlugin *plugin); +public: + virtual int PushCell(cell_t cell); + virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushFloat(float number); + virtual int PushFloatByRef(float *number, int flags); + virtual int PushCells(cell_t array[], unsigned int numcells, bool each); + virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); + virtual int PushString(const char *string); + virtual int PushStringByRef(char *string, int flags); + virtual cell_t *GetAddressOfPushedParam(unsigned int param); + virtual int Execute(cell_t *result, IFunctionCopybackReader *reader); + virtual void Cancel(); + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); + virtual IPlugin *GetParentPlugin(); +public: + void Set(funcid_t funcid, CPlugin *plugin); +private: + int _PushString(const char *string, int flags); + inline int SetError(int err) + { + m_errorstate = err; + return err; + } +private: + funcid_t m_funcid; + CPlugin *m_pPlugin; + cell_t m_params[SP_MAX_EXEC_PARAMS]; + ParamInfo m_info[SP_MAX_EXEC_PARAMS]; + unsigned int m_curparam; + int m_errorstate; +}; + +#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 71cce53d..405fb5d7 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -7,34 +7,6 @@ CPluginManager::CPluginManager() { } -void CFunction::Set(funcid_t funcid, CPlugin *plugin) -{ - m_funcid = funcid; - m_pPlugin = plugin; -} - -int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) -{ - IPluginContext *ctx = m_pPlugin->m_ctx_current.base; - - for (unsigned int i=0; iPushCell(params[i]); - } - - return ctx->Execute(m_funcid, result); -} - -IPlugin *CFunction::GetParentPlugin() -{ - return m_pPlugin; -} - -CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : - m_funcid(funcid), m_pPlugin(plugin) -{ -} - CPlugin *CPlugin::CreatePlugin(const char *file, bool debug_default, PluginType type, @@ -355,7 +327,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) { for (uint32_t i=0; im_plugin->info.publics_num; i++) { - delete pPlugin->m_pub_funcs[i]; + g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_pub_funcs[i]); } delete [] pPlugin->m_pub_funcs; pPlugin->m_pub_funcs = NULL; @@ -365,7 +337,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) { for (unsigned int i=0; im_funcsnum; i++) { - delete pPlugin->m_priv_funcs[i]; + g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_priv_funcs[i]); } delete [] pPlugin->m_priv_funcs; pPlugin->m_priv_funcs = NULL; @@ -435,6 +407,11 @@ void CPluginManager::ReleaseIterator(CPluginIterator *iter) void CPluginManager::ReleaseFunctionToPool(CFunction *func) { + if (!func) + { + return; + } + func->Cancel(); m_funcpool.push(func); } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 25825e0e..e8ce8108 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -5,6 +5,7 @@ #include #include #include "sm_globals.h" +#include "CFunction.h" using namespace SourceHook; @@ -19,22 +20,6 @@ struct ContextPair sp_context_t *ctx; }; -class CPlugin; - -class CFunction : public IPluginFunction -{ -public: - CFunction(funcid_t funcid, CPlugin *plugin); -public: - virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); - virtual IPlugin *GetParentPlugin(); -public: - void Set(funcid_t funcid, CPlugin *plugin); -private: - funcid_t m_funcid; - CPlugin *m_pPlugin; -}; - class CPlugin : public IPlugin { friend class CPluginManager; From e4ff973dbf3f9571cca3f8548493e3a6ce6d9e2a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 11:10:45 +0000 Subject: [PATCH 0153/1664] synced type changes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40183 --- sourcepawn/include/sp_vm_types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 91117b13..02b90540 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -7,6 +7,8 @@ typedef uint32_t ucell_t; typedef int32_t cell_t; typedef uint32_t funcid_t; +#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ + /** * Error codes */ @@ -32,6 +34,7 @@ typedef uint32_t funcid_t; #define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ #define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ #define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ /********************************************** *** The following structures are reference structures. From 4d89283924d60409fd4ed5379ab034b1489d97c1 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 12 Nov 2006 00:40:58 +0000 Subject: [PATCH 0154/1664] string functions in the VM are now compatible with packed strings added a StringToLocal UTF-8 version to the VM --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40184 --- core/vm/sp_vm_basecontext.cpp | 105 ++++++++++++++++++++++++++++----- core/vm/sp_vm_basecontext.h | 3 +- sourcepawn/include/sp_vm_api.h | 19 ++++-- 3 files changed, 106 insertions(+), 21 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 9e82f672..29a53629 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -481,22 +481,19 @@ int BaseContext::LocalToString(cell_t local_addr, char **addr) return SP_ERROR_NONE; } -int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) { - cell_t *ph_addr; + char *ph_addr; int err; - unsigned int i, numcells = strlen(string); + unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); - if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE) + if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) { return err; } - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { @@ -523,19 +520,97 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *sour } len = strlen(source); - dest = (cell_t *)(ctx->memory + local_addr); + dest = (char *)(ctx->memory + local_addr); if ((size_t)len >= chars) { len = chars - 1; } - - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + len = strlen(source); + dest = (char *)(ctx->memory + local_addr); + + if ((size_t)len >= maxbytes) + { + len = maxbytes - 1; + needtocheck = true; + } + if (len <= 0) + { + return SP_ERROR_NONE; + } + + memcpy(dest, source, len); + if ((dest[len] & 1<<7) && needtocheck) + { + len -= __CheckValidChar(dest+len-1); } dest[len] = '\0'; + if (wrtnbytes) + { + *wrtnbytes = len; + } + return SP_ERROR_NONE; } diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 9fbe2dd6..56c7d14e 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -33,9 +33,10 @@ namespace SourcePawn virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); virtual int LocalToString(cell_t local_addr, char **addr); virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); + virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes); virtual int PushCell(cell_t value); virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string); virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); virtual int BindNative(sp_nativeinfo_t *native); diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 61cbecfc..796a5a31 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -204,10 +204,8 @@ namespace SourcePawn */ virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; - /**:TODO: FIX ALL PACKED STUFF COMMENTS! + /** * Converts a local address to a physical string. - * Note that SourcePawn does not support packed strings, as such this function is - * 'cell to char' only. * * @param local_addr Local address in plugin. * @param addr Destination output pointer. @@ -216,7 +214,6 @@ namespace SourcePawn /** * Converts a physical string to a local address. - * Note that SourcePawn does not support packed strings. * * @param local_addr Local address in plugin. * @param chars Number of chars to write, including NULL terminator. @@ -224,6 +221,18 @@ namespace SourcePawn */ virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + /** + * Converts a physical UTF-8 string to a local address. + * This function is the same as the ANSI version, except it will copy the maximum number of characters possible + * without accidentally chopping a multi-byte character. + * + * @param local_addr Local address in plugin. + * @param maxbytes Number of bytes to write, including NULL terminator. + * @param source Source string to copy. + * @param wrtnbytes Optionally filled with the number of written bytes. + */ + virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) =0; + /** * Pushes a cell onto the stack. Increases the parameter count by one. * @@ -253,7 +262,7 @@ namespace SourcePawn * @param phys_addr Optionally filled with physical address of new array. * @param string Source string to push. */ - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; /** * Individually pushes each cell of an array of cells onto the stack. Increases the From 6bef3c2c5a5f6ee14a39b932e2c06839febba1bb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 12 Nov 2006 01:06:17 +0000 Subject: [PATCH 0155/1664] Initial import of forward system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40185 --- core/interfaces/IForwardSys.h | 122 +++++- core/interfaces/IPluginFunction.h | 24 +- core/msvc8/sourcemod_mm.vcproj | 4 + core/sourcemod.cpp | 15 +- core/systems/CFunction.cpp | 13 +- core/systems/ForwardSys.cpp | 667 ++++++++++++++++++++++++++++++ core/systems/ForwardSys.h | 88 ++++ 7 files changed, 906 insertions(+), 27 deletions(-) create mode 100644 core/systems/ForwardSys.cpp create mode 100644 core/systems/ForwardSys.h diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index a6e17dd3..49e2d16a 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -3,6 +3,7 @@ #include #include +#include #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" #define SMINTERFACE_FORWARDMANAGER_VERSION 1 @@ -24,18 +25,76 @@ namespace SourceMod enum ExecType { ET_Ignore = 0, /* Ignore all return values, return 0 */ - ET_Single = 1, /* Only return the first exec, ignore all others */ + ET_Single = 1, /* Only return the last exec, ignore all others */ ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */ ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */ + ET_Custom = 4, /* Ignored or handled by an IForwardFilter */ + }; + + class IForward; + + class IForwardFilter + { + public: + /** + * @brief Called when an error occurs executing a plugin. + * + * @param fwd IForward pointer. + * @param func IPluginFunction pointer to the failed function. + * @param err Error code. + * @return True to handle, false to pass to global error reporter. + */ + virtual bool OnErrorReport(IForward *fwd, + IPluginFunction *func, + int err) + { + return false; + } + + /** + * @brief Called after each function return during execution. + * NOTE: Only used for ET_Custom. + * + * @param fwd IForward pointer. + * @param func IPluginFunction pointer to the executed function. + * @param retval Pointer to current return value (can be modified). + * @return ResultType denoting the next action to take. + */ + virtual ResultType OnFunctionReturn(IForward *fwd, + IPluginFunction *func, + cell_t *retval) + { + return Pl_Continue; + } + + /** + * @brief Called when execution begins. + */ + virtual void OnExecuteBegin() + { + }; + + /** + * @brief Called when execution ends. + * + * @param final_ret Final return value (modifiable). + * @param success Number of successful execs. + * @param failed Number of failed execs. + */ + virtual void OnExecuteEnd(cell_t *final_ret, unsigned int success, unsigned int failed) + { + } }; /** - * :TODO: finish this spec * @brief Abstracts multiple function calling. + * * NOTE: Parameters should be pushed in forward order, unlike - * the virtual machine/IPluginContext order. - * NOTE: Some functions are repeated in here because their documentation differs - * from their IPluginFunction equivalents. + * the virtual machine/IPluginContext order. + * NOTE: Some functions are repeated in here because their + * documentation differs from their IPluginFunction equivalents. + * Missing are the Push functions, whose only doc change is that + * they throw SP_ERROR_PARAM on type mismatches. */ class IForward : public ICallable { @@ -65,10 +124,25 @@ namespace SourceMod * @brief Executes the forward. * * @param result Pointer to store result in. - * @param num_functions Optionally filled with the number of function sucessfully executed. + * @param filter Optional pointer to an IForwardFilter. * @return Error code, if any. */ - virtual int Execute(cell_t *result, unsigned int *num_functions) =0; + virtual int Execute(cell_t *result, IForwardFilter *filter=NULL) =0; + + /** + * @brief Pushes an array of cells onto the current call. Different rules than ICallable. + * NOTE: On Execute, the pointer passed will be modified according to the copyback rule. + * + * @param array Array to copy. Cannot be NULL, unlike ICallable's version. + * @param cells Number of cells to allocate and optionally read from the input array. + * @param phys_addr Unused. If a value is passed, it will be filled with NULL. + * @param flags Whether or not changes should be copied back to the input array. + * @return Error code, if any. + */ + virtual int PushArray(cell_t *inarray, + unsigned int cells, + cell_t **phys_addr, + int flags=SMFUNC_COPYBACK_NONE) =0; }; @@ -77,10 +151,12 @@ namespace SourceMod public: /** * @brief Removes a function from the call list. + * NOTE: Only removes one instance. * * @param func Function to remove. + * @return Whether or not the function was removed. */ - virtual void RemoveFunction(IPluginFunction *func) =0; + virtual bool RemoveFunction(IPluginFunction *func) =0; /** * @brief Removes all instances of a plugin from the call list. @@ -92,7 +168,9 @@ namespace SourceMod /** * @brief Adds a function to the call list. - * NOTE: Cannot be used during a call. + * NOTE: Cannot be used during an incompleted call. + * NOTE: If used during a call, function is temporarily queued until calls are over. + * NOTE: Adding mulitple copies of the same function is illegal. * * @param func Function to add. * @return True on success, otherwise false. @@ -101,7 +179,8 @@ namespace SourceMod /** * @brief Adds a function to the call list. - * NOTE: Cannot be used during a call. + * NOTE: Cannot be used during an incompleted call. + * NOTE: If used during a call, function is temporarily queued until calls are over. * * @param ctx Context to use as a look-up. * @param funcid Function id to add. @@ -110,15 +189,24 @@ namespace SourceMod virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0; }; + #define SP_PARAMTYPE_ANY 0 + #define SP_PARAMFLAG_BYREF (1<<0) + #define SP_PARAMTYPE_CELL (1<<1) + #define SP_PARAMTYPE_FLOAT (2<<1) + #define SP_PARAMTYPE_STRING (3<<1)|SP_PARAMFLAG_BYREF + #define SP_PARAMTYPE_ARRAY (4<<1)|SP_PARAMFLAG_BYREF + #define SP_PARAMTYPE_VARARG (5<<1) + enum ParamType { - Param_Any = 0, //Any type will be accepted - Param_Cell = 1, //Only a cell will be accepted - Param_Float = 2, //Only a float value will be accepted - Param_String = 3, //Only a string will be accepted - Param_Array = 4, //Only a 1D array will be accepted - Param_VarArgs = 5, //Anything will be accepted - ParamTypes_Total = 6, + Param_Any = SP_PARAMTYPE_ANY, + Param_Cell = SP_PARAMTYPE_CELL, + Param_Float = SP_PARAMTYPE_FLOAT, + Param_String = SP_PARAMTYPE_STRING, + Param_Array = SP_PARAMTYPE_ARRAY, + Param_VarArgs = SP_PARAMTYPE_VARARG, + Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF, + Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF, }; class IForwardManager : public SMInterface diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index 14e34058..c77e9552 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -69,7 +69,7 @@ namespace SourceMod * * @param array Array to copy, NULL if no initial array should be copied. * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Optional return address for physical array (if array was non-NULL, will be array). + * @param phys_addr Optional return address for physical array, if one was made. * @param flags Whether or not changes should be copied back to the input array. * @return Error code, if any. */ @@ -171,6 +171,28 @@ namespace SourceMod * @return Address, or NULL if invalid parameter specified. */ virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; + +#if 0 + /** + * @brief Clones the function object. This can be used to maintain a private copy. + * The copy retains no push states and must be freeed with ReleaseCopy(). + */ + virtual IPluginFunction *Copy() =0; + + /** + * @brief If this object is a clone, this function must be called to destroy it. + */ + virtual void ReleaseCopy() =0; + + /** + * @brief Returns original function pointer, if any. + * Note: IsCopyOf() will return the original non-copy, even if used + * from a copy. + * + * @return The original object that this was sourced from. + */ + virtual IPluginFunction *IsCopyOf() =0; +#endif }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 8eb18041..536548da 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -259,6 +259,10 @@ RelativePath="..\systems\CFunction.cpp" > + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index a10a690b..2d910762 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -5,6 +5,7 @@ #include "vm/sp_vm_engine.h" #include #include "PluginSys.h" +#include "ForwardSys.h" SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -111,17 +112,21 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) return false; } -#if 0 g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str()); IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max); IPluginFunction *func = pPlugin->GetFunctionByName("Test"); + IPluginFunction *func2 = pPlugin->GetFunctionByName("Test2"); cell_t result = 2; cell_t val = 6; - func->PushCell(1); - func->PushCellByRef(&val, SMFUNC_COPYBACK_ONCE); - func->Execute(&result, NULL); + ParamType types[] = {Param_Cell, Param_CellByRef}; + va_list ap = va_start(ap, late); + CForward *fwd = CForward::CreateForward(NULL, ET_Custom, 2, types, ap); + fwd->AddFunction(func); + fwd->AddFunction(func2); + fwd->PushCell(1); + fwd->PushCellByRef(&val, SMFUNC_COPYBACK_ALWAYS); + fwd->Execute(&result, NULL); g_PluginMngr.UnloadPlugin(pPlugin); -#endif return true; } diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index ee187a51..18d01909 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -106,7 +106,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr return SetError(err); } - info->flags = inarray ? copyback : SMFUNC_COPYBACK_NONE; + info->flags = (inarray || (copyback & SMFUNC_COPYBACK_ALWAYS)) ? copyback : SMFUNC_COPYBACK_NONE; info->marked = true; info->size = cells; m_params[m_curparam] = info->local_addr; @@ -246,9 +246,14 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) } if (temp_info[numparams].orig_addr) { - memcpy(temp_info[numparams].orig_addr, - temp_info[numparams].phys_addr, - temp_info[numparams].size * sizeof(cell_t)); + if (temp_info[numparams].size == 1) + { + *temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr; + } else { + memcpy(temp_info[numparams].orig_addr, + temp_info[numparams].phys_addr, + temp_info[numparams].size * sizeof(cell_t)); + } } } _skipcopy: diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp new file mode 100644 index 00000000..428bf31c --- /dev/null +++ b/core/systems/ForwardSys.cpp @@ -0,0 +1,667 @@ +#include +#include "ForwardSys.h" +#include "PluginSys.h" + +CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap) +{ + ParamType _types[SP_MAX_EXEC_PARAMS]; + + if (num_params > SP_MAX_EXEC_PARAMS) + { + return NULL; + } + + if (types == NULL && num_params) + { + for (unsigned int i=0; im_curparam = 0; + pForward->m_ExecType = et; + snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : ""); + + for (unsigned int i=0; im_types[i] = types[i]; + } + + if (num_params && types[num_params-1] == Param_VarArgs) + { + pForward->m_varargs = true; + } else { + pForward->m_varargs = false; + } + + pForward->m_numparams = num_params; + pForward->m_errstate = SP_ERROR_NONE; + pForward->m_CopyBacks.numrecopy = 0; + + return pForward; +} + +bool CForward::OnCopybackArray(unsigned int param, + unsigned int cells, + cell_t *source_addr, + cell_t *orig_addr, + int flags) +{ + /* Check if the stack is empty, this should be an assertion */ + if (m_NextStack.empty()) + { + /* This should never happen! */ + assert(!m_NextStack.empty()); + return true; + } + + /* Check if we even want to copy to the next plugin */ + if (!(flags & SMFUNC_COPYBACK_ALWAYS)) + { + return true; + } + + /* Keep track of the copy back and save the info */ + NextCallInfo &info = m_NextStack.front(); + info.recopy[info.numrecopy++] = param; + info.orig_addrs[param] = orig_addr; + info.sizes[param] = cells; + + /* We don't want to override the copy. */ + return true; +} + +int CForward::Execute(cell_t *result, IForwardFilter *filter) +{ + if (m_errstate) + { + int err = m_errstate; + Cancel(); + return err; + } + + /* Reset marker */ + m_curparam = 0; + + if (filter) + { + filter->OnExecuteBegin(); + } + + FuncIter iter = m_functions.begin(); + IPluginFunction *func; + cell_t cur_result = 0; + cell_t high_result = 0; + int err; + unsigned int failed=0, success=0; + unsigned int save_numcopy = 0; + + /** + * Save copyback into to start the chain, + * then reset it for re-entrancy + */ + m_NextStack.push(m_CopyBacks); + NextCallInfo &info = m_NextStack.front(); + m_CopyBacks.numrecopy = 0; + + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + + /** + * Check if we need to copy a new array back into the plugin. + */ + if (info.numrecopy) + { + /* The last plugin has a chained copyback, we must redirect it here. */ + unsigned int param; + cell_t *orig_addr, *targ_addr; + for (unsigned int i=0; iGetAddressOfPushedParam(param); + orig_addr = info.orig_addrs[param]; + /* Only do the copy for valid targets */ + if (targ_addr && orig_addr) + { + if (info.sizes[param] == 1) + { + *targ_addr = *orig_addr; + } else { + memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t)); + } + } + /* If this failed, the plugin will most likely be failing as well. */ + } + save_numcopy = info.numrecopy; + info.numrecopy = 0; + } + + /* Call the function and deal with the return value. + * :TODO: only pass reader if we know we have an array in the list + */ + if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE) + { + bool handled = false; + if (filter) + { + handled = filter->OnErrorReport(this, func, err); + } + if (!handled) + { + /* :TODO: invoke global error reporting here */ + } + /* If we failed, we're not quite done. The copy chain has been broken. + * We have to restore it so past changes will continue to get mirrored. + */ + info.numrecopy = save_numcopy; + failed++; + } else { + success++; + switch (m_ExecType) + { + case ET_Event: + { + if (cur_result > high_result) + { + high_result = cur_result; + } + break; + } + case ET_Hook: + { + if (cur_result > high_result) + { + high_result = cur_result; + if ((ResultType)high_result == Pl_Stop) + { + iter = m_functions.end(); + break; + } + } + break; + } + case ET_Custom: + { + if (filter) + { + if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop) + { + iter = m_functions.end(); + } + } + break; + } + } + } + } + + m_NextStack.pop(); + + if (m_ExecType == ET_Event || m_ExecType == ET_Hook) + { + cur_result = high_result; + } else if (m_ExecType == ET_Ignore) { + cur_result = 0; + } + + *result = cur_result; + + DumpAdditionQueue(); + + if (filter) + { + filter->OnExecuteEnd(&cur_result, success, failed); + } + + return SP_ERROR_NONE; +} + +int CForward::PushCell(cell_t cell) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushCell(cell); + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushFloat(float number) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushFloat(number); + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushCellByRef(cell_t *cell, int flags) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + if (flags & SMFUNC_COPYBACK_ALWAYS) + { + _Int_PushArray(cell, 1, flags); + } else { + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushCellByRef(cell, flags); + } + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushFloatByRef(float *num, int flags) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + if (flags & SMFUNC_COPYBACK_ALWAYS) + { + _Int_PushArray((cell_t *)num, 1, flags); + } else { + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushFloatByRef(num, flags); + } + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushCells(cell_t array[], unsigned int numcells, bool each) +{ + if (each) + { + /* Type check each cell if we need to! */ + if (m_curparam + numcells >= m_numparams && !m_varargs) + { + return SetError(SP_ERROR_PARAMS_MAX); + } else { + for (unsigned int i=m_curparam; i SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushCells(array, numcells, each); + } + + m_curparam += each ? numcells : 1; + + return SP_ERROR_NONE; +} + +void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) +{ + FuncIter iter; + IPluginFunction *func; + if (flags & SMFUNC_COPYBACK_ALWAYS) + { + /* As a special optimization, we create blank default arrays because they will be + * copied over anyway! + */ + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushArray(NULL, cells, NULL, flags); + } + m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam; + m_CopyBacks.orig_addrs[m_curparam] = inarray; + m_CopyBacks.sizes[m_curparam] = cells; + } else { + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushArray(inarray, cells, NULL, flags); + } + } +} + +int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags) +{ + /* We don't allow this here */ + if (!inarray) + { + return SetError(SP_ERROR_PARAM); + } + + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + if (phys_addr) + { + *phys_addr = NULL; + } + + _Int_PushArray(inarray, cells, flags); + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushString(const char *string) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushString(string); + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +int CForward::PushStringByRef(char *string, int flags) +{ + if (m_curparam < m_numparams) + { + if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) + { + return SetError(SP_ERROR_PARAM); + } + } else { + if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->PushStringByRef(string, flags); + } + + m_curparam++; + + return SP_ERROR_NONE; +} + +void CForward::Cancel() +{ + if (!m_curparam) + { + return; + } + + FuncIter iter; + IPluginFunction *func; + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) + { + func = (*iter); + func->Cancel(); + } + + m_CopyBacks.numrecopy = 0; + + DumpAdditionQueue(); + + m_errstate = SP_ERROR_NONE; +} + +bool CForward::AddFunction(sp_context_t *ctx, funcid_t index) +{ + IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx); + if (!pPlugin) + { + return false; + } + + IPluginFunction *pFunc = pPlugin->GetFunctionById(index); + if (!pFunc) + { + return false; + } + + return AddFunction(pFunc); +} + +bool CForward::RemoveFunction(IPluginFunction *func) +{ + bool found = false; + FuncIter iter; + IPluginFunction *pNext = NULL; + + for (iter=m_functions.begin(); iter!=m_functions.end();) + { + if ((*iter) == func) + { + found = true; + /* If this iterator is being used, swap in a new one !*/ + iter = m_functions.erase(iter); + } else { + iter++; + } + } + + /* Just in case */ + m_AddQueue.remove(func); + + /* Cancel a call, if any */ + if (found && (!m_NextStack.empty() || m_curparam)) + { + func->Cancel(); + } + + return found; +} + +unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) +{ + FuncIter iter; + IPluginFunction *func; + unsigned int removed = 0; + for (iter=m_functions.begin(); iter!=m_functions.end();) + { + func = (*iter); + if (func->GetParentPlugin() == plugin) + { + iter = m_functions.erase(iter); + removed++; + } else { + iter++; + } + } + + for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();) + { + func = (*iter); + if (func->GetParentPlugin() == plugin) + { + /* Don't count these toward the total */ + iter = m_functions.erase(iter); + } else { + iter++; + } + } + + return removed; +} + +void CForward::DumpAdditionQueue() +{ + FuncIter iter = m_AddQueue.begin(); + while (iter != m_AddQueue.end()) + { + m_functions.push_back((*iter)); + //:TODO: eventually we will tell the plugin we're using it + iter = m_AddQueue.erase(iter); + } +} + +bool CForward::AddFunction(IPluginFunction *func) +{ + if (m_curparam) + { + return false; + } + + if (!m_NextStack.empty()) + { + m_AddQueue.push_back(func); + } else { + //:TODO: eventually we will tell the plugin we're using it + m_functions.push_back(func); + } + + return true; +} + +const char *CForward::GetForwardName() +{ + return m_name; +} + +unsigned int CForward::GetFunctionCount() +{ + return m_functions.size(); +} + +ExecType CForward::GetExecType() +{ + return m_ExecType; +} diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h new file mode 100644 index 00000000..17b55a61 --- /dev/null +++ b/core/systems/ForwardSys.h @@ -0,0 +1,88 @@ +#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ +#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ + +#include +#include +#include "sm_globals.h" +#include +#include + +using namespace SourceHook; + +typedef List::iterator FuncIter; + +//:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX +#define FORWARDS_NAME_MAX 64 + +struct NextCallInfo +{ + unsigned int recopy[SP_MAX_EXEC_PARAMS]; + unsigned int sizes[SP_MAX_EXEC_PARAMS]; + cell_t *orig_addrs[SP_MAX_EXEC_PARAMS]; + unsigned int numrecopy; +}; + +class CForward : public IChangeableForward, IFunctionCopybackReader +{ +public: //ICallable + virtual int PushCell(cell_t cell); + virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushFloat(float number); + virtual int PushFloatByRef(float *number, int flags); + virtual int PushCells(cell_t array[], unsigned int numcells, bool each); + virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); + virtual int PushString(const char *string); + virtual int PushStringByRef(char *string, int flags); + virtual void Cancel(); +public: //IForward + virtual const char *GetForwardName(); + virtual unsigned int GetFunctionCount(); + virtual ExecType GetExecType(); + virtual int Execute(cell_t *result, IForwardFilter *filter); +public: //IChangeableForward + virtual bool RemoveFunction(IPluginFunction *func); + virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin); + virtual bool AddFunction(IPluginFunction *func); + virtual bool AddFunction(sp_context_t *ctx, funcid_t index); +public: //IFunctionCopybackReader + virtual bool OnCopybackArray(unsigned int param, + unsigned int cells, + cell_t *source_addr, + cell_t *orig_addr, + int flags); +public: + static CForward *CreateForward(const char *name, + ExecType et, + unsigned int num_params, + ParamType *types, + va_list ap); +private: + void DumpAdditionQueue(); + void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); + inline int SetError(int err) + { + m_errstate = err; + return err; + } +protected: + /* :TODO: I want a caching list type here. + * Destroying these things and using new/delete for their members feels bad. + */ + List m_functions; + + /* Type and name information */ + ParamType m_types[SP_MAX_EXEC_PARAMS]; + char m_name[FORWARDS_NAME_MAX+1]; + unsigned int m_numparams; + bool m_varargs; + ExecType m_ExecType; + + /* State information */ + unsigned int m_curparam; + int m_errstate; + CStack m_NextStack; + List m_AddQueue; + NextCallInfo m_CopyBacks; +}; + +#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ From 94dc5ca298f096c61a62eb4e413da41b9ff92884 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 12 Nov 2006 02:24:45 +0000 Subject: [PATCH 0156/1664] fixed copy backs so they work properly NOTE: heap fails, working on a rewrite --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40186 --- core/interfaces/IPluginFunction.h | 1 + core/systems/CFunction.cpp | 7 +++++-- core/systems/ForwardSys.cpp | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index c77e9552..8002cd9e 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -8,6 +8,7 @@ namespace SourceMod #define SMFUNC_COPYBACK_NONE (0) /* Never copy an array back */ #define SMFUNC_COPYBACK_ONCE (1<<0) /* Copy an array back after call */ #define SMFUNC_COPYBACK_ALWAYS (1<<1) /* Copy an array back after subsequent calls (forwards) */ + #define SMFUNC_ARRAY_NOINIT (1<<2) /* The array is not copied at first, but copyback is performed */ /** * @brief Represents what a function needs to implement in order to be callable. diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 18d01909..851f51be 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -114,7 +114,10 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr if (inarray) { - memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); + if (!(copyback & SMFUNC_ARRAY_NOINIT)) + { + memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); + } info->orig_addr = inarray; } else { info->orig_addr = info->phys_addr; @@ -257,7 +260,7 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) } } _skipcopy: - base->HeapRelease(temp_info[numparams].local_addr); + base->HeapPop(temp_info[numparams].local_addr); temp_info[numparams].marked = false; } diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 428bf31c..99ecdf51 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -418,7 +418,7 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); - func->PushArray(NULL, cells, NULL, flags); + func->PushArray(inarray, cells, NULL, flags|SMFUNC_ARRAY_NOINIT); } m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam; m_CopyBacks.orig_addrs[m_curparam] = inarray; From 442806dd45e84e0dd545e078e4bbc508c8b8f9d7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 12 Nov 2006 02:27:27 +0000 Subject: [PATCH 0157/1664] updated types and test plugin --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40187 --- plugins/test.sma | 13 +++++++++++-- sourcepawn/include/sp_vm_types.h | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/test.sma b/plugins/test.sma index 2803c672..fa317e82 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -9,7 +9,16 @@ public Plugin:myinfo = url = "http://www.sourcemod.net/" } -public OnPluginInit() +public Test(num, &num2) { - /* just a test, mommy */ + num2 += num + + return num +} + +public Test2(num, &num2) +{ + num2 += num + + return num } diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 02b90540..a5987d64 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -16,7 +16,7 @@ typedef uint32_t funcid_t; #define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ #define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ #define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ -#define SP_ERROR_PARAM 4 /* Invalid parameter */ +#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */ #define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ #define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ #define SP_ERROR_INDEX 7 /* Invalid index parameter */ From bad69571b602d4b0ebddd651ccace49a4818141c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 12 Nov 2006 09:51:39 +0000 Subject: [PATCH 0158/1664] rewrote forward API to use cached parameter pushing instead of immediate pushing removed copy back cruft since it's no longer needed removed PushCells() from API requirements, not needed adjusted documentation and added TODO list to ForwardSys.cpp various internal improvements --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40188 --- core/interfaces/IForwardSys.h | 55 ++--- core/interfaces/IPluginFunction.h | 77 ++----- core/msvc8/sourcemod_mm.vcproj | 42 ++-- core/sourcemod.cpp | 2 +- core/systems/CFunction.cpp | 30 +-- core/systems/CFunction.h | 4 +- core/systems/ForwardSys.cpp | 359 ++++++++---------------------- core/systems/ForwardSys.h | 34 ++- sourcepawn/include/sp_vm_api.h | 11 +- 9 files changed, 181 insertions(+), 433 deletions(-) diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index 49e2d16a..789b3fc7 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -142,7 +142,7 @@ namespace SourceMod virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, - int flags=SMFUNC_COPYBACK_NONE) =0; + int flags=0) =0; }; @@ -307,48 +307,33 @@ namespace SourceMod * * Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system * object oriented, rather than AMX Mod X, which hides the objects behind static functions. It is entirely a design - * issue, rather than a usability one. The interesting part is when it gets to implementation, which is when the - * problems for SourceMod arise. Specifically, the implementation is easier in GENERAL -- the tough part is the oddball - * cases. + * issue, rather than a usability one. The interesting part is when it gets to implementation, which has to cache + * parameter pushing until execution. Without this, multiple function calls can be started across one plugin, which + * will result in heap corruption given SourcePawn's implementation. * - * Observe the calling process: - * - Each parameter is pushed using the ICallable interface. For each parameter: - * - For each function in the collection, the parameter is processed and pushed. + * Observe the new calling process: + * - Each parameter is pushed into a local cache using the ICallable interface. * - For each function in the collection: + * - Each parameter is decoded and -pushed into the function. * - The call is made. - * - Copy backs are performed. * - Return * - * Astute readers will note the problems - the parameters are processed individually for each push, - * rather than for each call. This means: + * Astute readers will note the (minor) problems: * 1) More memory is used. Specifically, rather than N params of memory, you now have N params * M plugins. - * This is because, again, parameters are processed per function object, per-push, before the call. + * This is because, again, parameters are cached both per-function and per-forward. * 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual. - * 3) Copybacks won't work as expected. * - * Number 3 is hard to see. For example, say a forward has two functions, and an array is pushed with copyback. - * The array gets pushed and copied into each plugin. When the call is made, each plugin now has separate copies of - * the array. When the copyback is performed, it gets mirrored to the originall address, but not to the next plugin! - - * Implementing this is "difficult." To be re-entrant, an IPluginFunction can't tell you anything - * about its copybacks after it has returned, because its internal states were reset long ago. - * - * In order to implement this feature, IPluginFunction::Execute function now lets you pass a listener in. - * This listener is notified each time an array parameter is about to be copied back. Specifically, the forward - * uses this to detect when it needs to push a new parameter out to the next plugin. When the forward gets the - * call back, it detects whether there is another plugin in the queue. If there is, it grabs the address it will - * be using for the same arrays, and specifies it as the new copy-back point. If no plugins are left, it allows - * the copyback to chain up to the original address. - * - * This wonderful little hack is somewhat reminiscent of how SourceHook parameter rewrite chains work. It seems - * ugly at first, but it is actually the correct design pattern to apply to an otherwise awful problem. - * - * Note that there are other solutions to this that aren't based on a visitor-like pattern. For example, the Function - * class could expose a "set new original address" function. Then after arrays are pushed, the arrays are re-browsed, - * and function #1 gets function #2's original address, function #2 gets function #3's original address, et cetera. - * This extra browse step is a bit less efficient though, since the "visitor" method implies only taking action when - * necessary. Furthermore, it would require exposing such a "set address" function, which should fire a red flag - * that the API is doing something it shouldn't (namely, exposing the direct setting of very internal properties). + * HISTORICAL NOTES: + * There used to be a # about copy backs. + * Note that originally, the Forward implementation was a thin wrapper around IForwards. It did not cache pushes, + * and instead immediately fired them to each internal plugin. This was to allow users to know that pointers would + * be immediately resolved. Unfortunately, this became extremely burdensome on the API and exposed many problems, + * the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same + * plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order + * and become impossible to re-arrange without some global heap tracking mechanis. It also made iterative copy backs + * for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy. + * Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X + * uses. It is both faster and works better. */ #endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index 8002cd9e..d75ccc27 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -5,10 +5,7 @@ namespace SourceMod { - #define SMFUNC_COPYBACK_NONE (0) /* Never copy an array back */ - #define SMFUNC_COPYBACK_ONCE (1<<0) /* Copy an array back after call */ - #define SMFUNC_COPYBACK_ALWAYS (1<<1) /* Copy an array back after subsequent calls (forwards) */ - #define SMFUNC_ARRAY_NOINIT (1<<2) /* The array is not copied at first, but copyback is performed */ + #define SM_FUNCFLAG_COPYBACK (1<<0) /* Copy an array/reference back after call */ /** * @brief Represents what a function needs to implement in order to be callable. @@ -27,6 +24,9 @@ namespace SourceMod /** * @brief Pushes a cell by reference onto the current call. * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. * * @param cell Address containing parameter value to push. * @param flags Copy-back flags. @@ -45,6 +45,9 @@ namespace SourceMod /** * @brief Pushes a float onto the current call by reference. * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. * * @param float Parameter value to push. & @param flags Copy-back flags. @@ -52,21 +55,13 @@ namespace SourceMod */ virtual int PushFloatByRef(float *number, int flags) =0; - /** - * @brief Pushes an array of cells onto the current call, each cell individually. - * NOTE: This is essentially a crippled version of PushArray(). - * - * @param array Array of cells. - * @param numcells Number of cells in array. - * @param each Whether or not to push as an array or individual cells. - * @return Error code, if any. - */ - virtual int PushCells(cell_t array[], unsigned int numcells, bool each) =0; - /** * @brief Pushes an array of cells onto the current call. * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back * is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. * * @param array Array to copy, NULL if no initial array should be copied. * @param cells Number of cells to allocate and optionally read from the input array. @@ -77,7 +72,7 @@ namespace SourceMod virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, - int flags=SMFUNC_COPYBACK_NONE) =0; + int flags=0) =0; /** * @brief Pushes a string onto the current call. @@ -95,7 +90,7 @@ namespace SourceMod * @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushStringByRef(char *string, int flags) =0; + virtual int PushStringEx(char *string, int flags) =0; /** * @brief Cancels a function call that is being pushed but not yet executed. @@ -104,30 +99,6 @@ namespace SourceMod virtual void Cancel() =0; }; - - /** - * @brief Used for copy-back notification - */ - class IFunctionCopybackReader - { - public: - /** - * @brief Called before an array is copied back. - * - * @param param Parameter index. - * @param cells Number of cells in the array. - * @param source_addr Source address in the plugin that will be copied. - * @param orig_addr Destination addres in plugin that will be overwritten. - * @param flags Copy flags. - * @return True to copy back, false otherwise. - */ - virtual bool OnCopybackArray(unsigned int param, - unsigned int cells, - cell_t *source_addr, - cell_t *orig_addr, - int flags) =0; - }; - /** * @brief Encapsulates a function call in a plugin. * NOTE: Function calls must be atomic to one execution context. @@ -143,7 +114,7 @@ namespace SourceMod * @param reader Copy-back listener. NULL to specify * @return Error code, if any. */ - virtual int Execute(cell_t *result, IFunctionCopybackReader *reader) =0; + virtual int Execute(cell_t *result) =0; /** * @brief Executes the function with the given parameter array. @@ -172,28 +143,6 @@ namespace SourceMod * @return Address, or NULL if invalid parameter specified. */ virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; - -#if 0 - /** - * @brief Clones the function object. This can be used to maintain a private copy. - * The copy retains no push states and must be freeed with ReleaseCopy(). - */ - virtual IPluginFunction *Copy() =0; - - /** - * @brief If this object is a clone, this function must be called to destroy it. - */ - virtual void ReleaseCopy() =0; - - /** - * @brief Returns original function pointer, if any. - * Note: IsCopyOf() will return the original non-copy, even if used - * from a copy. - * - * @return The original object that this was sourced from. - */ - virtual IPluginFunction *IsCopyOf() =0; -#endif }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 536548da..6fe6cae6 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -40,7 +40,7 @@ - - - - - - - - - - @@ -449,10 +429,24 @@ + + + + + + + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 2d910762..126d805d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -124,7 +124,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) fwd->AddFunction(func); fwd->AddFunction(func2); fwd->PushCell(1); - fwd->PushCellByRef(&val, SMFUNC_COPYBACK_ALWAYS); + fwd->PushCellByRef(&val, 0); fwd->Execute(&result, NULL); g_PluginMngr.UnloadPlugin(pPlugin); diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 851f51be..66e487cd 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -76,7 +76,7 @@ int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each) { if (!each) { - return PushArray(array, numcells, NULL, SMFUNC_COPYBACK_NONE); + return PushArray(array, numcells, NULL, 0); } else { int err; for (unsigned int i=0; iflags = (inarray || (copyback & SMFUNC_COPYBACK_ALWAYS)) ? copyback : SMFUNC_COPYBACK_NONE; + info->flags = inarray ? copyback : 0; info->marked = true; info->size = cells; m_params[m_curparam] = info->local_addr; @@ -114,10 +114,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr if (inarray) { - if (!(copyback & SMFUNC_ARRAY_NOINIT)) - { - memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); - } + memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); info->orig_addr = inarray; } else { info->orig_addr = info->phys_addr; @@ -133,10 +130,10 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr int CFunction::PushString(const char *string) { - return _PushString(string, SMFUNC_COPYBACK_NONE); + return _PushString(string, 0); } -int CFunction::PushStringByRef(char *string, int flags) +int CFunction::PushStringEx(char *string, int flags) { return _PushString(string, flags); } @@ -163,8 +160,7 @@ int CFunction::_PushString(const char *string, int flags) m_params[m_curparam] = info->local_addr; m_curparam++; /* Prevent a leak */ - //:TODO: Use UTF-8 version - if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) + if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) { return SetError(err); } @@ -197,7 +193,7 @@ void CFunction::Cancel() m_errorstate = SP_ERROR_NONE; } -int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) +int CFunction::Execute(cell_t *result) { int err; if (m_errorstate != SP_ERROR_NONE) @@ -236,17 +232,6 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) } if (docopies && temp_info[numparams].flags) { - if (reader) - { - if (!reader->OnCopybackArray(numparams, - temp_info[numparams].size, - temp_info[numparams].phys_addr, - temp_info[numparams].orig_addr, - temp_info[numparams].flags)) - { - goto _skipcopy; - } - } if (temp_info[numparams].orig_addr) { if (temp_info[numparams].size == 1) @@ -259,7 +244,6 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader) } } } -_skipcopy: base->HeapPop(temp_info[numparams].local_addr); temp_info[numparams].marked = false; } diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h index f9b50180..58fb0f40 100644 --- a/core/systems/CFunction.h +++ b/core/systems/CFunction.h @@ -28,9 +28,9 @@ public: virtual int PushCells(cell_t array[], unsigned int numcells, bool each); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); virtual int PushString(const char *string); - virtual int PushStringByRef(char *string, int flags); + virtual int PushStringEx(char *string, int flags); virtual cell_t *GetAddressOfPushedParam(unsigned int param); - virtual int Execute(cell_t *result, IFunctionCopybackReader *reader); + virtual int Execute(cell_t *result); virtual void Cancel(); virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); virtual IPlugin *GetParentPlugin(); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 99ecdf51..833d5321 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -2,6 +2,30 @@ #include "ForwardSys.h" #include "PluginSys.h" +/** + * Gensis turns to its source, reduction occurs stepwise although the essence is all one. + * End of line. FTL system check. + * + * :TODO: Implement the manager. ho ho ho + * + * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO) + * NORMAL FUNCTIONS: + * X Push cells + * X Push cells byref (copyback tested = yes) + * - Push floats (copyback tested = ??) + * - Push floats byref (copyback tested = ??) + * - Push arrays (copyback tested = ??) + * - Push strings (copyback tested = ??) + * VARARG FUNCTIONS: + * - Pushing no varargs + * - Push vararg cells (copyback should be verified to not happen = ??) + * - Push vararg cells byref (copyback tested = ??) + * - Push vararg floats (copyback should be verified to not happen = ??) + * - Push vararg floats byref (copyback tested = ??) + * - Push vararg arrays (copyback tested = ??) + * - Push vararg strings (copyback tested = ??) + */ + CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap) { ParamType _types[SP_MAX_EXEC_PARAMS]; @@ -50,48 +74,17 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu if (num_params && types[num_params-1] == Param_VarArgs) { - pForward->m_varargs = true; + pForward->m_varargs = num_params--; } else { pForward->m_varargs = false; } pForward->m_numparams = num_params; pForward->m_errstate = SP_ERROR_NONE; - pForward->m_CopyBacks.numrecopy = 0; return pForward; } -bool CForward::OnCopybackArray(unsigned int param, - unsigned int cells, - cell_t *source_addr, - cell_t *orig_addr, - int flags) -{ - /* Check if the stack is empty, this should be an assertion */ - if (m_NextStack.empty()) - { - /* This should never happen! */ - assert(!m_NextStack.empty()); - return true; - } - - /* Check if we even want to copy to the next plugin */ - if (!(flags & SMFUNC_COPYBACK_ALWAYS)) - { - return true; - } - - /* Keep track of the copy back and save the info */ - NextCallInfo &info = m_NextStack.front(); - info.recopy[info.numrecopy++] = param; - info.orig_addrs[param] = orig_addr; - info.sizes[param] = cells; - - /* We don't want to override the copy. */ - return true; -} - int CForward::Execute(cell_t *result, IForwardFilter *filter) { if (m_errstate) @@ -101,9 +94,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) return err; } - /* Reset marker */ - m_curparam = 0; - if (filter) { filter->OnExecuteBegin(); @@ -116,53 +106,53 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) int err; unsigned int failed=0, success=0; unsigned int save_numcopy = 0; + unsigned int num_params = m_curparam; + FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS]; + FwdParamInfo *param; + ParamType type; + + /* Save local, reset */ + memcpy(temp_info, m_params, sizeof(m_params)); + m_curparam = 0; - /** - * Save copyback into to start the chain, - * then reset it for re-entrancy - */ - m_NextStack.push(m_CopyBacks); - NextCallInfo &info = m_NextStack.front(); - m_CopyBacks.numrecopy = 0; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); - - /** - * Check if we need to copy a new array back into the plugin. - */ - if (info.numrecopy) - { - /* The last plugin has a chained copyback, we must redirect it here. */ - unsigned int param; - cell_t *orig_addr, *targ_addr; - for (unsigned int i=0; iGetAddressOfPushedParam(param); - orig_addr = info.orig_addrs[param]; - /* Only do the copy for valid targets */ - if (targ_addr && orig_addr) - { - if (info.sizes[param] == 1) - { - *targ_addr = *orig_addr; - } else { - memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t)); - } - } - /* If this failed, the plugin will most likely be failing as well. */ - } - save_numcopy = info.numrecopy; - info.numrecopy = 0; - } + for (unsigned int i=0; i= m_numparams || m_types[i] == Param_Any) + { + type = param->pushedas; + } else { + type = m_types[i]; + } + if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF)) + { + /* If we're byref or we're vararg, we always push everything by ref. + * Even if they're byval, we must push them byref. + */ + if (type == Param_String) + { + func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags); + } else if (type == Param_Float || type == Param_Cell) { + func->PushCellByRef(¶m->val, 0); + } else { + func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags); + assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef); + } + } else { + /* If we're not byref or not vararg, our job is a bit easier. */ + assert(type == Param_Cell || type == Param_Float); + func->PushCell(param->val); + } + } + /* Call the function and deal with the return value. * :TODO: only pass reader if we know we have an array in the list */ - if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE) + if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE) { bool handled = false; if (filter) @@ -173,10 +163,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) { /* :TODO: invoke global error reporting here */ } - /* If we failed, we're not quite done. The copy chain has been broken. - * We have to restore it so past changes will continue to get mirrored. - */ - info.numrecopy = save_numcopy; failed++; } else { success++; @@ -218,8 +204,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) } } - m_NextStack.pop(); - if (m_ExecType == ET_Event || m_ExecType == ET_Hook) { cur_result = high_result; @@ -229,8 +213,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) *result = cur_result; - DumpAdditionQueue(); - if (filter) { filter->OnExecuteEnd(&cur_result, success, failed); @@ -243,8 +225,10 @@ int CForward::PushCell(cell_t cell) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_Cell; + } else if (m_types[m_curparam] != Param_Cell) { return SetError(SP_ERROR_PARAM); } } else { @@ -252,17 +236,10 @@ int CForward::PushCell(cell_t cell) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_Cell; } - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushCell(cell); - } - - m_curparam++; + m_params[m_curparam++].val = cell; return SP_ERROR_NONE; } @@ -271,8 +248,10 @@ int CForward::PushFloat(float number) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_Float; + } else if (m_types[m_curparam] != Param_Float) { return SetError(SP_ERROR_PARAM); } } else { @@ -280,17 +259,10 @@ int CForward::PushFloat(float number) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_Float; } - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushFloat(number); - } - - m_curparam++; + m_params[m_curparam++].val = *(cell_t *)&number; return SP_ERROR_NONE; } @@ -310,19 +282,7 @@ int CForward::PushCellByRef(cell_t *cell, int flags) } } - if (flags & SMFUNC_COPYBACK_ALWAYS) - { - _Int_PushArray(cell, 1, flags); - } else { - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushCellByRef(cell, flags); - } - } - + _Int_PushArray(cell, 1, flags); m_curparam++; return SP_ERROR_NONE; @@ -343,93 +303,17 @@ int CForward::PushFloatByRef(float *num, int flags) } } - if (flags & SMFUNC_COPYBACK_ALWAYS) - { - _Int_PushArray((cell_t *)num, 1, flags); - } else { - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushFloatByRef(num, flags); - } - } - + _Int_PushArray((cell_t *)num, 1, flags); m_curparam++; return SP_ERROR_NONE; } -int CForward::PushCells(cell_t array[], unsigned int numcells, bool each) -{ - if (each) - { - /* Type check each cell if we need to! */ - if (m_curparam + numcells >= m_numparams && !m_varargs) - { - return SetError(SP_ERROR_PARAMS_MAX); - } else { - for (unsigned int i=m_curparam; i SP_MAX_EXEC_PARAMS) - { - return SetError(SP_ERROR_PARAMS_MAX); - } - } - } - - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushCells(array, numcells, each); - } - - m_curparam += each ? numcells : 1; - - return SP_ERROR_NONE; -} - void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) { - FuncIter iter; - IPluginFunction *func; - if (flags & SMFUNC_COPYBACK_ALWAYS) - { - /* As a special optimization, we create blank default arrays because they will be - * copied over anyway! - */ - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushArray(inarray, cells, NULL, flags|SMFUNC_ARRAY_NOINIT); - } - m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam; - m_CopyBacks.orig_addrs[m_curparam] = inarray; - m_CopyBacks.sizes[m_curparam] = cells; - } else { - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushArray(inarray, cells, NULL, flags); - } - } + m_params[m_curparam].byref.cells = cells; + m_params[m_curparam].byref.flags = flags; + m_params[m_curparam].byref.orig_addr = inarray; } int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags) @@ -442,8 +326,10 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_Array; + } else if (m_types[m_curparam] != Param_Array) { return SetError(SP_ERROR_PARAM); } } else { @@ -451,6 +337,7 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_Array; } if (phys_addr) @@ -469,8 +356,10 @@ int CForward::PushString(const char *string) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_String; + } else if (m_types[m_curparam] == Param_String) { return SetError(SP_ERROR_PARAM); } } else { @@ -478,27 +367,23 @@ int CForward::PushString(const char *string) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_String; } - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushString(string); - } - + _Int_PushArray((cell_t *)string, 0, 0); m_curparam++; return SP_ERROR_NONE; } -int CForward::PushStringByRef(char *string, int flags) +int CForward::PushStringEx(char *string, int flags) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_String; + } else if (m_types[m_curparam] == Param_String) { return SetError(SP_ERROR_PARAM); } } else { @@ -506,16 +391,10 @@ int CForward::PushStringByRef(char *string, int flags) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_String; } - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->PushStringByRef(string, flags); - } - + _Int_PushArray((cell_t *)string, 0, flags); m_curparam++; return SP_ERROR_NONE; @@ -528,18 +407,7 @@ void CForward::Cancel() return; } - FuncIter iter; - IPluginFunction *func; - for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) - { - func = (*iter); - func->Cancel(); - } - - m_CopyBacks.numrecopy = 0; - - DumpAdditionQueue(); - + m_curparam = 0; m_errstate = SP_ERROR_NONE; } @@ -578,11 +446,8 @@ bool CForward::RemoveFunction(IPluginFunction *func) } } - /* Just in case */ - m_AddQueue.remove(func); - /* Cancel a call, if any */ - if (found && (!m_NextStack.empty() || m_curparam)) + if (found || m_curparam) { func->Cancel(); } @@ -607,32 +472,9 @@ unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) } } - for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();) - { - func = (*iter); - if (func->GetParentPlugin() == plugin) - { - /* Don't count these toward the total */ - iter = m_functions.erase(iter); - } else { - iter++; - } - } - return removed; } -void CForward::DumpAdditionQueue() -{ - FuncIter iter = m_AddQueue.begin(); - while (iter != m_AddQueue.end()) - { - m_functions.push_back((*iter)); - //:TODO: eventually we will tell the plugin we're using it - iter = m_AddQueue.erase(iter); - } -} - bool CForward::AddFunction(IPluginFunction *func) { if (m_curparam) @@ -640,13 +482,8 @@ bool CForward::AddFunction(IPluginFunction *func) return false; } - if (!m_NextStack.empty()) - { - m_AddQueue.push_back(func); - } else { - //:TODO: eventually we will tell the plugin we're using it - m_functions.push_back(func); - } + //:TODO: eventually we will tell the plugin we're using it + m_functions.push_back(func); return true; } diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 17b55a61..31a4089d 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -14,25 +14,30 @@ typedef List::iterator FuncIter; //:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX #define FORWARDS_NAME_MAX 64 -struct NextCallInfo +struct ByrefInfo { - unsigned int recopy[SP_MAX_EXEC_PARAMS]; - unsigned int sizes[SP_MAX_EXEC_PARAMS]; - cell_t *orig_addrs[SP_MAX_EXEC_PARAMS]; - unsigned int numrecopy; + unsigned int cells; + cell_t *orig_addr; + int flags; }; -class CForward : public IChangeableForward, IFunctionCopybackReader +struct FwdParamInfo +{ + cell_t val; + ByrefInfo byref; + ParamType pushedas; +}; + +class CForward : public IChangeableForward { public: //ICallable virtual int PushCell(cell_t cell); virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); virtual int PushFloatByRef(float *number, int flags); - virtual int PushCells(cell_t array[], unsigned int numcells, bool each); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); virtual int PushString(const char *string); - virtual int PushStringByRef(char *string, int flags); + virtual int PushStringEx(char *string, int flags); virtual void Cancel(); public: //IForward virtual const char *GetForwardName(); @@ -44,12 +49,6 @@ public: //IChangeableForward virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin); virtual bool AddFunction(IPluginFunction *func); virtual bool AddFunction(sp_context_t *ctx, funcid_t index); -public: //IFunctionCopybackReader - virtual bool OnCopybackArray(unsigned int param, - unsigned int cells, - cell_t *source_addr, - cell_t *orig_addr, - int flags); public: static CForward *CreateForward(const char *name, ExecType et, @@ -57,7 +56,6 @@ public: ParamType *types, va_list ap); private: - void DumpAdditionQueue(); void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); inline int SetError(int err) { @@ -71,18 +69,16 @@ protected: List m_functions; /* Type and name information */ + FwdParamInfo m_params[SP_MAX_EXEC_PARAMS]; ParamType m_types[SP_MAX_EXEC_PARAMS]; char m_name[FORWARDS_NAME_MAX+1]; unsigned int m_numparams; - bool m_varargs; + unsigned int m_varargs; ExecType m_ExecType; /* State information */ unsigned int m_curparam; int m_errstate; - CStack m_NextStack; - List m_AddQueue; - NextCallInfo m_CopyBacks; }; #endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 796a5a31..e4133cc7 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -216,10 +216,10 @@ namespace SourcePawn * Converts a physical string to a local address. * * @param local_addr Local address in plugin. - * @param chars Number of chars to write, including NULL terminator. + * @param bytes Number of chars to write, including NULL terminator. * @param source Source string to copy. */ - virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; /** * Converts a physical UTF-8 string to a local address. @@ -229,9 +229,12 @@ namespace SourcePawn * @param local_addr Local address in plugin. * @param maxbytes Number of bytes to write, including NULL terminator. * @param source Source string to copy. - * @param wrtnbytes Optionally filled with the number of written bytes. + * @param wrtnbytes Optionally set to the number of actual bytes written. */ - virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) =0; + virtual int StringToLocalUTF8(cell_t local_addr, + size_t maxbytes, + const char *source, + size_t *wrtnbytes) =0; /** * Pushes a cell onto the stack. Increases the parameter count by one. From 29431117036b63c29f472a4f28ebe3e0650805b8 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 12 Nov 2006 13:13:12 +0000 Subject: [PATCH 0159/1664] fixed StringToLocalUTF8 evaluating invalid chars --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40189 --- core/vm/sp_vm_basecontext.cpp | 4 ++-- sourcepawn/include/sp_vm_api.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 29a53629..09a23017 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -542,7 +542,7 @@ inline int __CheckValidChar(char *c) int count; int bytecount = 0; - for(count=1; (*c & 0xC0) == 0x80; count++) + for (count=1; (*c & 0xC0) == 0x80; count++) { c--; } @@ -600,7 +600,7 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha } memcpy(dest, source, len); - if ((dest[len] & 1<<7) && needtocheck) + if ((dest[len-1] & 1<<7) && needtocheck) { len -= __CheckValidChar(dest+len-1); } diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index e4133cc7..73db0195 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -229,7 +229,7 @@ namespace SourcePawn * @param local_addr Local address in plugin. * @param maxbytes Number of bytes to write, including NULL terminator. * @param source Source string to copy. - * @param wrtnbytes Optionally set to the number of actual bytes written. + * @param wrtnbytes Optionally set to the number of actual bytes written. */ virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, From cda9c6952db16090f07d778a79d83a18e3f11912 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 13 Nov 2006 13:55:44 +0000 Subject: [PATCH 0160/1664] iface comment fixes and sync --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40190 --- core/interfaces/IForwardSys.h | 2 +- core/interfaces/IPluginFunction.h | 3 +-- core/interfaces/IPluginSys.h | 6 +++--- core/systems/CFunction.cpp | 18 ------------------ core/systems/CFunction.h | 1 - 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index 789b3fc7..e815aee4 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -133,7 +133,7 @@ namespace SourceMod * @brief Pushes an array of cells onto the current call. Different rules than ICallable. * NOTE: On Execute, the pointer passed will be modified according to the copyback rule. * - * @param array Array to copy. Cannot be NULL, unlike ICallable's version. + * @param inarray Array to copy. Cannot be NULL, unlike ICallable's version. * @param cells Number of cells to allocate and optionally read from the input array. * @param phys_addr Unused. If a value is passed, it will be filled with NULL. * @param flags Whether or not changes should be copied back to the input array. diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index d75ccc27..320d54c2 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -63,7 +63,7 @@ namespace SourceMod * This means you cannot push a pointer, change it, and push it again and expect * two different values to come out. * - * @param array Array to copy, NULL if no initial array should be copied. + * @param inarray Array to copy, NULL if no initial array should be copied. * @param cells Number of cells to allocate and optionally read from the input array. * @param phys_addr Optional return address for physical array, if one was made. * @param flags Whether or not changes should be copied back to the input array. @@ -111,7 +111,6 @@ namespace SourceMod * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. * * @param result Pointer to store return value in. - * @param reader Copy-back listener. NULL to specify * @return Error code, if any. */ virtual int Execute(cell_t *result) =0; diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 07001bcf..9e0a86a3 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -230,7 +230,7 @@ namespace SourceMod * * @param path Path and filename of plugin, relative to plugins folder. * @param debug Whether or not to default the plugin into debug mode. - * @param lifetime Lifetime of the plugin. + * @param type Lifetime of the plugin. * @param error Buffer to hold any error message. * @param err_max Maximum length of error message buffer. * @return A new plugin pointer on success, false otherwise. @@ -244,7 +244,7 @@ namespace SourceMod /** * @brief Attempts to unload a plugin. * - * @param Pointer to the plugin handle. + * @param plugin Pointer to the plugin handle. * @return True on success, false otherwise. */ virtual bool UnloadPlugin(IPlugin *plugin) =0; @@ -253,7 +253,7 @@ namespace SourceMod * @brief Finds a plugin by its context. * Note: This function should be considered O(1). * - * @param Pointer to an sp_context_t. + * @param ctx Pointer to an sp_context_t. * @return Pointer to a matching IPlugin, or NULL if none found. */ virtual IPlugin *FindPluginByContext(const sp_context_t *ctx) =0; diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 66e487cd..e032f8ba 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -72,24 +72,6 @@ int CFunction::PushFloatByRef(float *number, int flags) return PushCellByRef((cell_t *)number, flags); } -int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each) -{ - if (!each) - { - return PushArray(array, numcells, NULL, 0); - } else { - int err; - for (unsigned int i=0; i= SP_MAX_EXEC_PARAMS) diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h index 58fb0f40..0deca0de 100644 --- a/core/systems/CFunction.h +++ b/core/systems/CFunction.h @@ -25,7 +25,6 @@ public: virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); virtual int PushFloatByRef(float *number, int flags); - virtual int PushCells(cell_t array[], unsigned int numcells, bool each); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); virtual int PushString(const char *string); virtual int PushStringEx(char *string, int flags); From 13d61ec39f89d54b2c998a099a2b51fada97b8b7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Nov 2006 08:45:21 +0000 Subject: [PATCH 0161/1664] added implementation to the forward manager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40191 --- core/interfaces/IForwardSys.h | 11 ++++ core/systems/ForwardSys.cpp | 98 ++++++++++++++++++++++++++++++++++- core/systems/ForwardSys.h | 27 ++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index e815aee4..d4732899 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -98,6 +98,10 @@ namespace SourceMod */ class IForward : public ICallable { + public: + virtual ~IForward() + { + } public: /** * @brief Returns the name of the forward. @@ -271,6 +275,13 @@ namespace SourceMod * @return IForward pointer, or NULL if none found matching the name. */ virtual IForward *FindForward(const char *name, IChangeableForward **ifchng) =0; + + /** + * @brief Frees and destroys a forward object. + * + * @param forward An IForward created by CreateForward() or CreateForwardEx(). + */ + virtual void ReleaseForward(IForward *forward) =0; }; }; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 833d5321..ad2a8174 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -2,6 +2,8 @@ #include "ForwardSys.h" #include "PluginSys.h" +CForwardManager g_Forwards; + /** * Gensis turns to its source, reduction occurs stepwise although the essence is all one. * End of line. FTL system check. @@ -12,7 +14,7 @@ * NORMAL FUNCTIONS: * X Push cells * X Push cells byref (copyback tested = yes) - * - Push floats (copyback tested = ??) + * - Push floats * - Push floats byref (copyback tested = ??) * - Push arrays (copyback tested = ??) * - Push strings (copyback tested = ??) @@ -26,6 +28,98 @@ * - Push vararg strings (copyback tested = ??) */ +IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...) +{ + CForward *fwd; + va_list ap; + va_start(ap, types); + + fwd = CForward::CreateForward(name, et, num_params, types, ap); + + va_end(ap); + + return fwd; +} + +IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...) +{ + CForward *fwd; + va_list ap; + va_start(ap, types); + + fwd = CForward::CreateForward(name, et, num_params, types, ap); + + va_end(ap); + + return fwd; +} + +IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng) +{ + List::iterator iter; + CForward *fwd; + + for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) + { + fwd = (*iter); + if (strcmp(fwd->GetForwardName(), name) == 0) + { + if (ifchng) + { + *ifchng = NULL; + } + return fwd; + } + } + + for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) + { + fwd = (*iter); + if (strcmp(fwd->GetForwardName(), name) == 0) + { + if (ifchng) + { + *ifchng = fwd; + } + return fwd; + } + } + + if (ifchng) + { + *ifchng = NULL; + } + + return NULL; +} + +void CForwardManager::ReleaseForward(IForward *forward) +{ + ForwardFree(static_cast(forward)); +} + +void CForwardManager::ForwardFree(CForward *fwd) +{ + m_FreeForwards.push(fwd); +} + +CForward *CForwardManager::ForwardMake() +{ + CForward *fwd; + if (m_FreeForwards.empty()) + { + fwd = new CForward; + } else { + fwd = m_FreeForwards.front(); + m_FreeForwards.pop(); + } + return fwd; +} + +/************************************* + * ACTUAL FORWARD API IMPLEMENTATION * + *************************************/ + CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap) { ParamType _types[SP_MAX_EXEC_PARAMS]; @@ -62,7 +156,7 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu return NULL; } - CForward *pForward = new CForward; + CForward *pForward = g_Forwards.ForwardMake(); pForward->m_curparam = 0; pForward->m_ExecType = et; snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : ""); diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 31a4089d..b286284b 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -81,4 +81,31 @@ protected: int m_errstate; }; +class CForwardManager : public IForwardManager +{ + friend class CForward; +public: + virtual IForward *CreateForward(const char *name, + ExecType et, + unsigned int num_params, + ParamType *types, + ...); + virtual IChangeableForward *CreateForwardEx(const char *name, + ExecType et, + int num_params, + ParamType *types, + ...); + virtual IForward *FindForward(const char *name, IChangeableForward **ifchng); + virtual void ReleaseForward(IForward *forward); +protected: + CForward *ForwardMake(); + void ForwardFree(CForward *fwd); +private: + CStack m_FreeForwards; + List m_managed; + List m_unmanaged; +}; + +extern CForwardManager g_Forwards; + #endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ From 34097b1dbaec5fee379bf8f1c9692053ad0e2f60 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 16 Nov 2006 22:37:37 +0000 Subject: [PATCH 0162/1664] tested some forwards --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40192 --- core/systems/ForwardSys.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index ad2a8174..c1dd84a5 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -14,9 +14,9 @@ CForwardManager g_Forwards; * NORMAL FUNCTIONS: * X Push cells * X Push cells byref (copyback tested = yes) - * - Push floats - * - Push floats byref (copyback tested = ??) - * - Push arrays (copyback tested = ??) + * X Push floats + * X Push floats byref (copyback tested = yes) + * X Push arrays (copyback tested = yes) * - Push strings (copyback tested = ??) * VARARG FUNCTIONS: * - Pushing no varargs From a42fa24ef580cbedb270f7d2f6fe9d9253ff3e99 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 17 Nov 2006 23:22:32 +0000 Subject: [PATCH 0163/1664] fixed string pushing fixed CFunction::_PushString not counting the null terminator --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40193 --- core/systems/CFunction.cpp | 4 ++-- core/systems/ForwardSys.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index e032f8ba..5acfa907 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -130,7 +130,7 @@ int CFunction::_PushString(const char *string, int flags) IPluginContext *base = m_pPlugin->m_ctx_current.base; ParamInfo *info = &m_info[m_curparam]; size_t len = strlen(string); - size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); + size_t cells = (len + sizeof(cell_t)) / sizeof(cell_t); int err; if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) @@ -142,7 +142,7 @@ int CFunction::_PushString(const char *string, int flags) m_params[m_curparam] = info->local_addr; m_curparam++; /* Prevent a leak */ - if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) + if ((err=base->StringToLocalUTF8(info->local_addr, len+1, string, NULL)) != SP_ERROR_NONE) { return SetError(err); } diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index c1dd84a5..30fcc56f 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -17,7 +17,7 @@ CForwardManager g_Forwards; * X Push floats * X Push floats byref (copyback tested = yes) * X Push arrays (copyback tested = yes) - * - Push strings (copyback tested = ??) + * X Push strings (copyback tested = yes) * VARARG FUNCTIONS: * - Pushing no varargs * - Push vararg cells (copyback should be verified to not happen = ??) @@ -453,7 +453,7 @@ int CForward::PushString(const char *string) if (m_types[m_curparam] == Param_Any) { m_params[m_curparam].pushedas = Param_String; - } else if (m_types[m_curparam] == Param_String) { + } else if (m_types[m_curparam] != Param_String) { return SetError(SP_ERROR_PARAM); } } else { @@ -477,7 +477,7 @@ int CForward::PushStringEx(char *string, int flags) if (m_types[m_curparam] == Param_Any) { m_params[m_curparam].pushedas = Param_String; - } else if (m_types[m_curparam] == Param_String) { + } else if (m_types[m_curparam] != Param_String) { return SetError(SP_ERROR_PARAM); } } else { From f3bb90924d4bf1a2a56cdd97c680227ad0f01423 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 5 Dec 2006 23:52:43 +0000 Subject: [PATCH 0164/1664] added experimental trie API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40194 --- core/sm_trie.cpp | 665 +++++++++++++++++++++++++++++++++++++++++++++++ core/sm_trie.h | 11 + 2 files changed, 676 insertions(+) create mode 100644 core/sm_trie.cpp create mode 100644 core/sm_trie.h diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp new file mode 100644 index 00000000..ed40182b --- /dev/null +++ b/core/sm_trie.cpp @@ -0,0 +1,665 @@ +#include +#include +#include +#include "sm_trie.h" + +/** + * Double Array Trie algorithm, based on: + * An Efficient Implementation of Trie Structures, by + * Jun-ichi Aoe and Katsushi Maromoto, and Takashi Sato + * from Sofiware - Practice and Experience, Vol. 22(9), 695-721 (September 1992) + * + * A Trie is a simple data structure which stores strings as DFAs, with each + * transition state being a string entry. For example, observe the following strings: + * + * BAILOPAN, BAT, BACON, BACK + * These transition as the follow production rules: + * B -> ... B + * A -> ... BA + * I -> ... BAI + * LOPAN BAILOPAN + * T -> ... BAT + * C -> BAC + * O -> ... BACO + * N BACON + * K BACK + * + * The standard implementation for this - using lists - gives a slow linear lookup, somewhere between + * O(N+M) or O(log n). A faster implementation is proposed in the paper above, which is based on compacting + * the transition states into two arrays. In the paper's implementation, two arrays are used, and thus it is + * called the "Double Array" algorithm. However, the CHECK array's size is maintained the same as BASE, + * so they can be combined into one structure. The array seems complex at first, but is very simple: it is a + * tree structure flattened out into a single vector. I am calling this implementation the Flat Array Trie. + * + * BASE[] is an array where each member is a node in the Trie. The node can either be UNUSED (empty), an ARC + * (containing an offset to the next set of ARCs), or a TERMINATOR (contains the rest of a string). + * Each node has an index which must be interpeted based on the node type. If the node is a TERMINATOR, then the + * index is an index into a string table, to find the rest of the string. + * If the node is an ARC, the index is another index into BASE. For each possible token that can follow the + * current token, the value of those tokens can be added to the index given in the ARC. Thus, given a current + * position and the next desired token, the current arc will jump to another arc which can contain either: + * 1) An invalid production (collision, no entry exists) + * 2) An empty production (no entry exists) + * 3) Another arc label (the string ends here or continues into more productions) + * 4) A TERMINATOR (the string ends here and contains an unused set of productions) + * + * So, given current offset N (starting at N=1), jumping to token C means the next offset will be: + * offs = BASE[n] + C + * Thus, the next node will be at: + * BASE[BASE[n] + C] + * + * This allows each ARC to specify the base offset for any of its ARC children, like a tree. Each node specifies + * its parent ARC -- so if an invalid offset is specified, the parent will not match, and thus no such derived + * string exists. + * + * This means that arrays can be laid out "sparsely," maximizing their usage. Note that N need not be related to + * the range of tokens (1-256). I.e., a base index does not have to be at 1, 256, 512, et cetera. This is because + * insertion comes with a small deal of complexity. To insert a new set of tokens T, the algorithm finds a new + * BASE index N such that BASE[N+T[i]] is unused for each T[i]. Thus, indirection is not necessarily linear; + * traversing a chain of ARC nodes can _and will_ jump around BASE. + * + * Of course, given this level of flexibility in the array organization, there are collisions. This is largely + * where insertions become slow, as the old chain must be relocated before the new one is used. Relocation means + * finding one or more new base indexes, and this means traversing BASE until an acceptable index is found, such + * that each offset is unused (see description in previous paragraph). + * + * However, it is not insertion time we are concerned about. The "trie" name comes from reTRIEval. We are only + * concerned with lookup and deletion. Both lookup and deletion are O(k), where k is relative to the length of the + * input string. Note that it is best case O(1) and worst case O(k). Deleting the entire trie is always O(1). + */ + +/** + * Optimization ideas for the future: + * 1) Store a reference count for each arc, with the count of sub-children. + * This could let us break out of "children searches" for case 4 easily. + * 2) Use a 'free list' so we can easily search the trie for free points. + * This would drastically speed up x_check* + */ + +enum NodeType +{ + Node_Unused = 0, /* Node is not being used (sparse) */ + Node_Arc, /* Node is part of an arc and does not terminate */ + Node_Term, /* Node is a terminator */ +}; + +struct TrieNode +{ + /** + * For Node_Arc, this index stores the 'base' offset to the next arc chain. + * I.e. to jump from this arc to character C, it will be at base[idx+C]. + * For Node_Term, this is an index into the string table. + */ + unsigned int idx; + + /** + * This contains the prior arc that we must have come from. + * For example, if arc 63 has a base jump of index 12, and we want to see if + * there is a valid character C, the parent of 12+C must be 63. + */ + unsigned int parent; + + void *value; /* Value associated with this node */ + NodeType mode; /* Current usage type of the node */ + bool valset; /* Whether or not a value is set */ +}; + +struct Trie +{ + TrieNode *base; /* Base array for the sparse tables */ + char *stringtab; /* String table pointer */ + unsigned int baseSize; /* Size of the base array, in members */ + unsigned int stSize; /* Size of the string table, in bytes */ + unsigned int tail; /* Current unused offset into the string table */ +}; + +inline unsigned char charval(char c) +{ + unsigned char _c = (unsigned char)c; + return _c - 'A' + 2; +} + +unsigned int x_check(Trie *trie, char c) +{ + TrieNode *base = trie->base; + unsigned char _c = charval(c); + unsigned int to_check = trie->baseSize - _c; + for (unsigned int i=1; ibase = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); + memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); + to_check = trie->baseSize; + trie->baseSize *= 2; + + return to_check; +} + +unsigned int x_check2(Trie *trie, char c1, char c2) +{ + TrieNode *base = trie->base; + unsigned char _c1 = charval(c1); + unsigned char _c2 = charval(c2); + unsigned int to_check = trie->baseSize - (_c1 > _c2 ? _c1 : _c2); + for (unsigned int i=1; ibase = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); + memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); + to_check = trie->baseSize; + trie->baseSize *= 2; + + return to_check; +} + +unsigned int x_check_multi(Trie *trie, + unsigned int offsets[], + unsigned int count) +{ + TrieNode *base = trie->base; + TrieNode *cur; + unsigned int to_check = trie->baseSize; + for (unsigned int i=1; imode != Node_Unused) + { + okay = false; + break; + } + } + if (okay) + { + return i; + } + } + + trie->base = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); + memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); + to_check = trie->baseSize; + trie->baseSize *= 2; + + return to_check; +} + +unsigned int x_addstring(Trie *trie, const char *ptr) +{ + size_t len = strlen(ptr) + 1; + + if (len > trie->stSize) + { + while (trie->tail + len >= trie->stSize) + { + trie->stSize *= 2; + } + trie->stringtab = (char *)realloc(trie->stringtab, trie->stSize); + } + + unsigned int tail = trie->tail; + strcpy(&trie->stringtab[tail], ptr); + trie->tail += len; + + return tail; +} + +Trie *sm_trie_create() +{ + Trie *t = new Trie; + + t->base = (TrieNode *)malloc(sizeof(TrieNode) * 256); + t->stringtab = (char *)malloc(sizeof(char) * 256); + t->baseSize = 256; + t->stSize = 256; + t->tail = 0; + + memset(t->base, 0, sizeof(TrieNode) * 256); + memset(t->stringtab, 0, sizeof(char) * 256); + + /* Sentinel root node */ + t->base[1].idx = 1; + t->base[1].mode = Node_Arc; + t->base[1].parent = 1; + + return t; +} + +void sm_trie_destroy(Trie *trie) +{ + free(trie->base); + free(trie->stringtab); + free(trie); +} + +bool sm_trie_retrieve(Trie *trie, const char *key, void **value) +{ + unsigned int lastidx = 1; /* the last node index */ + unsigned int curidx; /* current node index */ + const char *keyptr = key; /* input stream at current token */ + TrieNode *node = NULL; /* current node being processed */ + TrieNode *base = trie->base; + + if (!*key) + { + return false; + } + + /* Start traversing at the root node */ + do + { + /* Find where the next character is, then advance */ + curidx = base[lastidx].idx; + node = &base[curidx]; + curidx += charval(*keyptr); + node = &base[curidx]; + keyptr++; + + /* Check if this slot is supposed to be empty or is a collision */ + if (node->mode == Node_Unused || node->parent != lastidx) + { + return false; + } else if (node->mode == Node_Term) { + char *term = &trie->stringtab[node->idx]; + if (strcmp(keyptr, term) == 0) + { + break; + } + } + lastidx = curidx; + } while (*keyptr != '\0'); + + assert(node != NULL); + + if (!node->valset) + { + return false; + } + + if (value) + { + *value = node->value; + } + + return true; +} + +bool sm_trie_insert(Trie *trie, const char *key, void *value) +{ + unsigned int lastidx = 1; /* the last node index */ + unsigned int curidx; /* current node index */ + const char *keyptr = key; /* input stream at current token */ + TrieNode *node = NULL; /* current node being processed */ + TrieNode *basenode = NULL; /* current base node being processed */ + unsigned int q; /* temporary var for x_check results */ + TrieNode *base = trie->base; + unsigned int curoffs; /* current offset */ + + /* Do not handle empty strings for simplicity */ + if (!*key) + { + return false; + } + + /* Start traversing at the root node (1) */ + do + { + /* Find where the next character is, then advance */ + curidx = base[lastidx].idx; + basenode = &base[curidx]; + curoffs = charval(*keyptr); + curidx += curoffs; + node = &base[curidx]; + keyptr++; + + /* Check if this slot is supposed to be empty. If so, we need to handle CASES 1/2: + * Insertion without collisions + */ + if (node->mode == Node_Unused) + { + /* Assign backcheck reference */ + node->parent = lastidx; + node->idx = x_addstring(trie, keyptr); + node->mode = Node_Term; + node->valset = true; + node->value = value; + + return true; + } else if (node->parent != lastidx) { + /* Collision! We have to split up the tree here. CASE 4: + * Insertion when a new word is inserted with a collision. + * NOTE: This is the hardest case to handle. All below examples are based on: + * BACHELOR, BADGE, inserting BABY. + * The problematic production here is A -> B, where B is already being used. + * + * This process has to rotate one half of the 'A' arc. We generate two lists: + * Outgoing Arcs - Anything leaving this 'A' + * Incoming Arcs - Anything going to this 'A' + * Whichever list is smaller will be moved. Note that this works because the intersection + * affects both arc chains, and moving one will make the slot available to either. + */ + TrieNode *cur; + + /* Find every node arcing from the last node. + * I.e. for BACHELOR, BADGE, BABY, + * The arcs leaving A will be C and D, but our current node is B -> *. + * Thus, we use the last index (A) to find the base for arcs leaving A. + */ + unsigned int outgoing_base = base[lastidx].idx; + unsigned int outgoing_list[256]; + unsigned int outgoing_count = 0; /* count the current index here */ + cur = &base[outgoing_base] + 1; + for (unsigned int i=1; i<=255; i++,cur++) + { + if (cur->mode == Node_Unused || cur->parent != lastidx) + { + continue; + } + outgoing_list[outgoing_count++] = i; + } + outgoing_list[outgoing_count++] = curidx - outgoing_base; + + /* Now we need to find all the arcs leaving our parent... + * Note: the inconsistency is the base of our parent. + */ + unsigned int incoming_list[256]; + unsigned int incoming_base = base[node->parent].idx; + unsigned int incoming_count = 0; + cur = &base[incoming_base] + 1; + for (unsigned int i=1; i<=255; i++,cur++) + { + if (cur->mode == Node_Arc || cur->mode == Node_Term) + { + if (cur->parent == node->parent) + { + incoming_list[incoming_count++] = i; + } + } + } + + if (incoming_count < outgoing_count + 1) + { + unsigned int q = x_check_multi(trie, incoming_list, incoming_count); + + /* If we're incoming, we need to modify our parent */ + base[incoming_base].idx = q; + + /* For each node in the "to move" list, + * Relocate the node's info to the new position. + */ + unsigned int idx, newidx, oldidx; + for (unsigned int i=0; iparent == oldidx) + { + check_base->parent = newidx; + } + } + } + } + } else { + unsigned int q = x_check_multi(trie, outgoing_list, outgoing_count); + + /* If we're outgoing, we need to modify our own base */ + base[lastidx].idx = q; + + /* Take the last index (curidx) out of the list. Technically we are not moving this, + * since it's already being used by something else. + */ + outgoing_count--; + + /* For each node in the "to move" list, + * Relocate the node's info to the new position. + */ + unsigned int idx, newidx, oldidx; + for (unsigned int i=0; iparent == oldidx) + { + check_base->parent = newidx; + } + } + } + } + + /* Take the invisible node and use it as our new node */ + node = &base[q + outgoing_list[outgoing_count]]; + } + + /* We're finally done! */ + node->parent = lastidx; + if (*keyptr == '\0') + { + node->mode = Node_Arc; + } else { + node->idx = x_addstring(trie, keyptr); + node->mode = Node_Term; + } + node->valset = true; + node->value = value; + + return true; + } else { + /* See what's in the next node - special case if terminator! */ + if (node->mode == Node_Term) + { + /* If we're a terminator, we need to handle CASE 3: + * Insertion when a terminating collision occurs + */ + char *term = &trie->stringtab[node->idx]; + /* Do an initial browsing to make sure they're not the same string */ + if (strcmp(keyptr, term) == 0) + { + /* Same string. We can't insert. */ + return false; + } + /* For each matching character pair, we need to disband the terminator. + * This splits the similar prefix into a single arc path. + * First, save the old values so we can move them to a new node. + * Next, for each loop: + * Take the current (invalid) node, and point it to the next arc base. + * Set the current node to the node at the next arc. + */ + void *oldvalue = node->value; + bool oldvalset = node->valset; + while (*term == *keyptr) + { + /* Find the next free slot in the check array. + * This is the "vector base" essentially + */ + q = x_check(trie, *term); + /* Point the node to the next new base */ + node->idx = q; + node->mode = Node_Arc; + node->valset = false; + /* Advance the input stream and local variables */ + lastidx = curidx; + curidx = q + charval(*term); + node = &base[curidx]; + /* Make sure the new current node has its parent set. */ + node->parent = lastidx; + node->mode = Node_Arc; /* Just in case we run x_check again */ + *term = '\0'; /* Unmark the string table here */ + term++; + keyptr++; + } + /* We're done inserting new pairs. If one of them is exhausted, + * we take special shortcuts. + */ + if (*term == '\0') //EX: BADGERHOUSE added over B -> ADGER. + { + /* First backpatch the current node - it ends the newly split terminator. + * In the example, this would mean the node is the production from R -> ? + * This node ends the old BADGER, so we set it here. + */ + node->valset = oldvalset; + node->value = oldvalue; + + /* The terminator was split up, but pieces of keyptr remain. + * We need to generate a new production, in this example, R -> H, + * with H being a terminator to OUSE. Thus we get: + * B,A,D,G,E,R*,H*->OUSE (* = value set). + * NOTE: parent was last set at the end of the while loop. + */ + q = x_check(trie, *keyptr); + node->idx = q; + node->mode = Node_Arc; + lastidx = curidx; + /* Finish the final node */ + curidx = q + charval(*keyptr); + node = &trie->base[curidx]; + keyptr++; + /* Optimize - don't add to string table if there's nothing more to eat */ + if (*keyptr == '\0') + { + node->mode = Node_Arc; + } else { + node->idx = x_addstring(trie, keyptr); + node->mode = Node_Term; + } + node->parent = lastidx; + node->valset = true; + node->value = value; + } else if (*keyptr == '\0') { //EX: BADGER added over B -> ADGERHOUSE + /* First backpatch the current node - it ends newly split input string. + * This is the exact opposite of the above procedure. + */ + node->valset = true; + node->value = value; + + q = x_check(trie, *term); + node->idx = q; + node->mode = Node_Arc; + lastidx = curidx; + /* Finish the final node */ + curidx = q + charval(*term); + node = &trie->base[curidx]; + term++; + /* Optimize - don't add to string table if there's nothing more to eat */ + if (*term == '\0') + { + node->mode = Node_Arc; + } else { + node->idx = (term - trie->stringtab); /* Already in the string table! */ + node->mode = Node_Term; + } + node->parent = lastidx; + node->valset = oldvalset; + node->value = oldvalue; + } else { + /* Finally, we have to create two new nodes instead of just one. */ + node->mode = Node_Arc; + + q = x_check2(trie, *keyptr, *term); + node->idx = q; + lastidx = curidx; + + /* Re-create the old terminated node */ + curidx = q + charval(*term); + node = &trie->base[curidx]; + term++; + node->valset = oldvalset; + node->value = oldvalue; + node->parent = lastidx; + if (*term == '\0') + { + node->mode = Node_Arc; + } else { + node->mode = Node_Term; + node->idx = (term - trie->stringtab); /* Already in the string table! */ + } + + /* Create the new keyed input node */ + curidx = q + charval(*keyptr); + node = &trie->base[curidx]; + keyptr++; + node->valset = true; + node->value = value; + node->parent = lastidx; + if (*keyptr == '\0') + { + node->mode = Node_Arc; + } else { + node->mode = Node_Term; + node->idx = x_addstring(trie, keyptr); + } + } + + /* Phew! */ + return true; + } + } + lastidx = curidx; + } while (*keyptr != '\0'); + + assert(node); + + /* If we've exhausted the string and we have a valid reached node, + * the production rule already existed. Make sure it's valid to set first. + */ + + /* We have to be an Arc. If the last result was anything else, we would have returned a new + * production earlier. + */ + assert(node->mode == Node_Arc); + + /* Furthermore, if this is the last arc label in an arc, we should have a value set. */ + if (node->idx == 0) + { + assert(node->valset == true); + } + + if (!node->valset) + { + /* Insert is only possible if we have no production */ + node->valset = true; + node->value = value; + return true; + } + + return false; +} diff --git a/core/sm_trie.h b/core/sm_trie.h new file mode 100644 index 00000000..9193f59e --- /dev/null +++ b/core/sm_trie.h @@ -0,0 +1,11 @@ +#ifndef _INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ +#define _INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ + +struct Trie; + +Trie *sm_trie_create(); +void sm_trie_destroy(Trie *trie); +bool sm_trie_insert(Trie *trie, const char *key, void *value); +bool sm_trie_retrieve(Trie *trie, const char *key, void **value); + +#endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ From 73e1d4b9ccfed9ec5ebc545b628cbe5f6d822b43 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 6 Dec 2006 00:09:46 +0000 Subject: [PATCH 0165/1664] removed debug code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40195 --- core/sm_trie.cpp | 3 +-- core/systems/PluginSys.cpp | 17 +++++++++++++++++ core/systems/PluginSys.h | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index ed40182b..3f732a92 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -115,8 +115,7 @@ struct Trie inline unsigned char charval(char c) { - unsigned char _c = (unsigned char)c; - return _c - 'A' + 2; + return (unsigned char)c; } unsigned int x_check(Trie *trie, char c) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 405fb5d7..3962ee84 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,5 +1,6 @@ #include #include "PluginSys.h" +#include "LibrarySys.h" CPluginManager g_PluginMngr; @@ -247,6 +248,7 @@ bool CPlugin::SetPauseState(bool paused) /******************* * PLUGIN ITERATOR * *******************/ + CPluginManager::CPluginIterator::CPluginIterator(List *_mylist) { mylist = _mylist; @@ -285,6 +287,21 @@ void CPluginManager::CPluginIterator::Reset() * PLUGIN MANAGER * ******************/ +void CPluginManager::RefreshOrLoadPlugins(const char *basedir) +{ + IDirectory *dir = g_LibSys.OpenDirectory(basedir); + while (dir->MoreFiles()) + { + if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0)) + { + char path[PLATFORM_MAX_PATH+1]; + g_SMAPI->PathFormat(path, sizeof(path)-1, "%s/%s", basedir, dir->GetEntryName()); + RefreshOrLoadPlugins(basedir); + } + } + g_LibSys.CloseDirectory(dir); +} + IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) { CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max); diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index e8ce8108..51dd8fd8 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -95,6 +95,8 @@ public: virtual IPluginIterator *GetPluginIterator(); virtual void AddPluginsListener(IPluginsListener *listener); virtual void RemovePluginsListener(IPluginsListener *listener); +public: + virtual void RefreshOrLoadPlugins(const char *basedir); protected: void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); From f305cafe8cd39eb7ce04d8ae90d410c0c2686e41 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 6 Dec 2006 00:53:34 +0000 Subject: [PATCH 0166/1664] fixed a compiler bug with declaring natives having parameters with no arrays and returning strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40196 --- sourcepawn/compiler/sc1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 0f678fa1..d5de9d8c 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2269,7 +2269,7 @@ static int declloc(int fstatic) } while (matchtoken('[')); if (all_constant) { /* Change the last dimension to be based on chars instead if we have a string */ - if (tag == pc_tag_string && dim[numdim-1]) + if (tag == pc_tag_string && numdim && dim[numdim-1]) dim[numdim-1] = (dim[numdim-1] + sizeof(cell)-1) / sizeof(cell); /* Scrap the code generated */ ident = iARRAY; @@ -3736,7 +3736,7 @@ static void funcstub(int fnative) dim[numdim++]=(int)size; } /* while */ - if (tag == pc_tag_string && dim[numdim-1]) + if (tag == pc_tag_string && numdim && dim[numdim-1]) dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); tok=lex(&val,&str); From f3ad0f5b675731d480c957a3900a3f8fdc5b16d1 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 6 Dec 2006 14:52:11 +0000 Subject: [PATCH 0167/1664] rewritten PushStringEx in Forward and Function systems fixed PushCellByRef and PushFloatByRef in the varargs case where it wouldn't set the pushed type fixed the BindNatives functions not setting the BOUND flag thus making the JIT not exec the natives done the rest of tests with forwards, only left to do string varargs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40197 --- core/interfaces/IPluginFunction.h | 13 ++++++---- core/systems/CFunction.cpp | 31 +++++++++++++++++------- core/systems/CFunction.h | 4 ++-- core/systems/ForwardSys.cpp | 40 +++++++++++++++++++++---------- core/systems/ForwardSys.h | 4 +++- core/vm/sp_vm_basecontext.cpp | 2 ++ 6 files changed, 65 insertions(+), 29 deletions(-) diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index 320d54c2..e0716c79 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -7,6 +7,9 @@ namespace SourceMod { #define SM_FUNCFLAG_COPYBACK (1<<0) /* Copy an array/reference back after call */ + #define SP_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ + #define SP_STRING_COPY (1<<1) /* String should be copied into the plugin */ + /** * @brief Represents what a function needs to implement in order to be callable. */ @@ -83,14 +86,16 @@ namespace SourceMod virtual int PushString(const char *string) =0; /** - * @brief Pushes a string onto the current call. + * @brief Pushes a string or string buffer. * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. * - * @param string String to push. - * @param flags Copy-back flags. + * @param buffer Pointer to string buffer. + * @param length Length of buffer. + * @param sz_flags String flags. + * @param cp_flags Copy-back flags. * @return Error code, if any. */ - virtual int PushStringEx(char *string, int flags) =0; + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0; /** * @brief Cancels a function call that is being pushed but not yet executed. diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 5acfa907..1ad5a5d1 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -112,15 +112,15 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr int CFunction::PushString(const char *string) { - return _PushString(string, 0); + return _PushString(string, SP_STRING_COPY, 0, strlen(string)+1); } -int CFunction::PushStringEx(char *string, int flags) +int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) { - return _PushString(string, flags); + return _PushString(buffer, sz_flags, cp_flags, length); } -int CFunction::_PushString(const char *string, int flags) +int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len) { if (m_curparam >= SP_MAX_EXEC_PARAMS) { @@ -129,8 +129,7 @@ int CFunction::_PushString(const char *string, int flags) IPluginContext *base = m_pPlugin->m_ctx_current.base; ParamInfo *info = &m_info[m_curparam]; - size_t len = strlen(string); - size_t cells = (len + sizeof(cell_t)) / sizeof(cell_t); + size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); int err; if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) @@ -142,12 +141,26 @@ int CFunction::_PushString(const char *string, int flags) m_params[m_curparam] = info->local_addr; m_curparam++; /* Prevent a leak */ - if ((err=base->StringToLocalUTF8(info->local_addr, len+1, string, NULL)) != SP_ERROR_NONE) + if (!(sz_flags & SP_STRING_COPY)) { - return SetError(err); + goto skip_localtostr; } - info->flags = flags; + if (sz_flags & SP_STRING_UTF8) + { + if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) + { + return SetError(err); + } + } else { + if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) + { + return SetError(err); + } + } + +skip_localtostr: + info->flags = cp_flags; info->orig_addr = (cell_t *)string; info->size = cells; diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h index 0deca0de..d68d837d 100644 --- a/core/systems/CFunction.h +++ b/core/systems/CFunction.h @@ -27,7 +27,7 @@ public: virtual int PushFloatByRef(float *number, int flags); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); virtual int PushString(const char *string); - virtual int PushStringEx(char *string, int flags); + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual cell_t *GetAddressOfPushedParam(unsigned int param); virtual int Execute(cell_t *result); virtual void Cancel(); @@ -36,7 +36,7 @@ public: public: void Set(funcid_t funcid, CPlugin *plugin); private: - int _PushString(const char *string, int flags); + int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); inline int SetError(int err) { m_errorstate = err; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 30fcc56f..7e3feb67 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -20,12 +20,12 @@ CForwardManager g_Forwards; * X Push strings (copyback tested = yes) * VARARG FUNCTIONS: * - Pushing no varargs - * - Push vararg cells (copyback should be verified to not happen = ??) - * - Push vararg cells byref (copyback tested = ??) - * - Push vararg floats (copyback should be verified to not happen = ??) - * - Push vararg floats byref (copyback tested = ??) - * - Push vararg arrays (copyback tested = ??) - * - Push vararg strings (copyback tested = ??) + * X Push vararg cells (copyback should be verified to not happen = didnt happen) + * X Push vararg cells byref (copyback tested = yes) + * X Push vararg floats (copyback should be verified to not happen = didnt happen) + * X Push vararg floats byref (copyback tested = yes) + * X Push vararg arrays (copyback tested = yes) + * X Push vararg strings (copyback tested = :TODO:) */ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...) @@ -227,9 +227,9 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) /* If we're byref or we're vararg, we always push everything by ref. * Even if they're byval, we must push them byref. */ - if (type == Param_String) + if (type == Param_String) { - func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags); + func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags); } else if (type == Param_Float || type == Param_Cell) { func->PushCellByRef(¶m->val, 0); } else { @@ -365,8 +365,10 @@ int CForward::PushCellByRef(cell_t *cell, int flags) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_CellByRef; + } else if (m_types[m_curparam] != Param_CellByRef) { return SetError(SP_ERROR_PARAM); } } else { @@ -374,6 +376,7 @@ int CForward::PushCellByRef(cell_t *cell, int flags) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_CellByRef; } _Int_PushArray(cell, 1, flags); @@ -386,8 +389,10 @@ int CForward::PushFloatByRef(float *num, int flags) { if (m_curparam < m_numparams) { - if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any) + if (m_types[m_curparam] == Param_Any) { + m_params[m_curparam].pushedas = Param_FloatByRef; + } else if (m_types[m_curparam] != Param_FloatByRef) { return SetError(SP_ERROR_PARAM); } } else { @@ -395,6 +400,7 @@ int CForward::PushFloatByRef(float *num, int flags) { return SetError(SP_ERROR_PARAMS_MAX); } + m_params[m_curparam].pushedas = Param_FloatByRef; } _Int_PushArray((cell_t *)num, 1, flags); @@ -446,6 +452,14 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, return SP_ERROR_NONE; } +void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags) +{ + m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */ + m_params[m_curparam].byref.flags = cp_flags; + m_params[m_curparam].byref.orig_addr = inarray; + m_params[m_curparam].byref.sz_flags = sz_flags; +} + int CForward::PushString(const char *string) { if (m_curparam < m_numparams) @@ -464,13 +478,13 @@ int CForward::PushString(const char *string) m_params[m_curparam].pushedas = Param_String; } - _Int_PushArray((cell_t *)string, 0, 0); + _Int_PushString((cell_t *)string, strlen(string)+1, SP_STRING_COPY, 0); m_curparam++; return SP_ERROR_NONE; } -int CForward::PushStringEx(char *string, int flags) +int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) { if (m_curparam < m_numparams) { @@ -488,7 +502,7 @@ int CForward::PushStringEx(char *string, int flags) m_params[m_curparam].pushedas = Param_String; } - _Int_PushArray((cell_t *)string, 0, flags); + _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags); m_curparam++; return SP_ERROR_NONE; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index b286284b..a3dfd5c9 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -19,6 +19,7 @@ struct ByrefInfo unsigned int cells; cell_t *orig_addr; int flags; + int sz_flags; }; struct FwdParamInfo @@ -37,7 +38,7 @@ public: //ICallable virtual int PushFloatByRef(float *number, int flags); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); virtual int PushString(const char *string); - virtual int PushStringEx(char *string, int flags); + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual void Cancel(); public: //IForward virtual const char *GetForwardName(); @@ -57,6 +58,7 @@ public: va_list ap); private: void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); + void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags); inline int SetError(int err) { m_errstate = err; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 09a23017..2a4531b4 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -374,6 +374,7 @@ int BaseContext::BindNative(sp_nativeinfo_t *native) } ctx->natives[index].pfn = native->func; + ctx->natives[index].status = SP_NATIVE_BOUND; return SP_ERROR_NONE; } @@ -389,6 +390,7 @@ int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) if (ctx->natives[i].status == SP_NATIVE_UNBOUND) { ctx->natives[i].pfn = native; + ctx->natives[i].status = SP_NATIVE_BOUND; } } From eabc33b4d2e631170a3b78e87012392d98b17ca2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 6 Dec 2006 23:35:51 +0000 Subject: [PATCH 0168/1664] fixed a problem causing the string table to never grow fixed growth and zeroing of the base array (was corrupting) fixed parent being set wrong resulting in node access corruption fixed a really retarded loop bug fixed base array growth invalidating cached pointers fixed insertion of similar strings which both had valid arc paths but no terminators --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40198 --- core/sm_trie.cpp | 103 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 3f732a92..e24bc6d2 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -118,12 +118,31 @@ inline unsigned char charval(char c) return (unsigned char)c; } -unsigned int x_check(Trie *trie, char c) +bool sm_trie_grow(Trie *trie) +{ + /* The current # of nodes in the tree is trie->baseSize + 1 */ + unsigned int curSize = trie->baseSize; + unsigned int newSize = curSize * 2; + + //:TODO: Make functions calling this return failure if this fails + trie->base = (TrieNode *)realloc(trie->base, (newSize + 1) * sizeof(TrieNode)); + if (!trie->base) + { + return false; + } + + memset(&trie->base[curSize+1], 0, (newSize - curSize) * sizeof(TrieNode)); + trie->baseSize = newSize; + + return true; +} + +unsigned int x_check(Trie *trie, char c, unsigned int start=1) { TrieNode *base = trie->base; unsigned char _c = charval(c); unsigned int to_check = trie->baseSize - _c; - for (unsigned int i=1; ibase = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); - memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); - to_check = trie->baseSize; - trie->baseSize *= 2; + sm_trie_grow(trie); - return to_check; + return x_check(trie, c, to_check+1); } -unsigned int x_check2(Trie *trie, char c1, char c2) +unsigned int x_check2(Trie *trie, char c1, char c2, unsigned int start=1) { TrieNode *base = trie->base; unsigned char _c1 = charval(c1); unsigned char _c2 = charval(c2); unsigned int to_check = trie->baseSize - (_c1 > _c2 ? _c1 : _c2); - for (unsigned int i=1; ibase = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); - memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); - to_check = trie->baseSize; - trie->baseSize *= 2; + sm_trie_grow(trie); - return to_check; + return x_check2(trie, c1, c2, to_check+1); } unsigned int x_check_multi(Trie *trie, unsigned int offsets[], - unsigned int count) + unsigned int count, + unsigned int start=1) { TrieNode *base = trie->base; TrieNode *cur; unsigned int to_check = trie->baseSize; - for (unsigned int i=1; i highest) + { + highest = offsets[i]; + } + } + + to_check -= highest; + + for (unsigned int i=start; i<=to_check; i++) { bool okay = true; for (unsigned int j=0; jbase = (TrieNode *)realloc(trie->base, trie->baseSize * sizeof(TrieNode) * 2); - memset(trie->base + trie->baseSize, 0, trie->baseSize * sizeof(TrieNode)); - to_check = trie->baseSize; - trie->baseSize *= 2; + sm_trie_grow(trie); - return to_check; + return x_check_multi(trie, offsets, count, to_check+1); } unsigned int x_addstring(Trie *trie, const char *ptr) { size_t len = strlen(ptr) + 1; - if (len > trie->stSize) + if (trie->tail + len >= trie->stSize) { while (trie->tail + len >= trie->stSize) { @@ -219,13 +242,13 @@ Trie *sm_trie_create() { Trie *t = new Trie; - t->base = (TrieNode *)malloc(sizeof(TrieNode) * 256); + t->base = (TrieNode *)malloc(sizeof(TrieNode) * (256 + 1)); t->stringtab = (char *)malloc(sizeof(char) * 256); t->baseSize = 256; t->stSize = 256; t->tail = 0; - memset(t->base, 0, sizeof(TrieNode) * 256); + memset(t->base, 0, sizeof(TrieNode) * (256 + 1)); memset(t->stringtab, 0, sizeof(char) * 256); /* Sentinel root node */ @@ -373,6 +396,7 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) /* Now we need to find all the arcs leaving our parent... * Note: the inconsistency is the base of our parent. */ + assert(base[node->parent].mode == Node_Arc); unsigned int incoming_list[256]; unsigned int incoming_base = base[node->parent].idx; unsigned int incoming_count = 0; @@ -392,8 +416,11 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) { unsigned int q = x_check_multi(trie, incoming_list, incoming_count); + base = trie->base; + node = &base[curidx]; + /* If we're incoming, we need to modify our parent */ - base[incoming_base].idx = q; + base[node->parent].idx = q; /* For each node in the "to move" list, * Relocate the node's info to the new position. @@ -415,7 +442,7 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) if (base[newidx].mode == Node_Arc) { TrieNode *check_base = &base[base[newidx].idx] + 1; - for (unsigned int i=1; i<=255; i++, check_base++) + for (unsigned int j=1; j<=255; j++, check_base++) { if (check_base->parent == oldidx) { @@ -427,6 +454,9 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) } else { unsigned int q = x_check_multi(trie, outgoing_list, outgoing_count); + base = trie->base; + node = &base[curidx]; + /* If we're outgoing, we need to modify our own base */ base[lastidx].idx = q; @@ -455,7 +485,7 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) if (base[newidx].mode == Node_Arc) { TrieNode *check_base = &base[base[newidx].idx] + 1; - for (unsigned int i=1; i<=255; i++, check_base++) + for (unsigned int j=1; j<=255; j++, check_base++) { if (check_base->parent == oldidx) { @@ -505,12 +535,16 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) */ void *oldvalue = node->value; bool oldvalset = node->valset; + if (*term == *keyptr) + { while (*term == *keyptr) { /* Find the next free slot in the check array. * This is the "vector base" essentially */ q = x_check(trie, *term); + base = trie->base; + node = &base[curidx]; /* Point the node to the next new base */ node->idx = q; node->mode = Node_Arc; @@ -525,6 +559,9 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) *term = '\0'; /* Unmark the string table here */ term++; keyptr++; + } + } else { + node->valset = false; } /* We're done inserting new pairs. If one of them is exhausted, * we take special shortcuts. @@ -544,7 +581,11 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) * B,A,D,G,E,R*,H*->OUSE (* = value set). * NOTE: parent was last set at the end of the while loop. */ + /* Get the new base and apply re-basing */ q = x_check(trie, *keyptr); + base = trie->base; + node = &base[curidx]; + node->idx = q; node->mode = Node_Arc; lastidx = curidx; @@ -570,7 +611,11 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) node->valset = true; node->value = value; + /* Get the new base and apply re-basing */ q = x_check(trie, *term); + base = trie->base; + node = &base[curidx]; + node->idx = q; node->mode = Node_Arc; lastidx = curidx; @@ -593,7 +638,11 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) /* Finally, we have to create two new nodes instead of just one. */ node->mode = Node_Arc; + /* Get the new base and apply re-basing */ q = x_check2(trie, *keyptr, *term); + base = trie->base; + node = &base[curidx]; + node->idx = q; lastidx = curidx; From 5fc2918377a36acf6782816d1127ea35eec19179 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 7 Dec 2006 08:17:19 +0000 Subject: [PATCH 0169/1664] fixed a series of addressing bugs where the indexer could reach past basearray bounds --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40199 --- core/sm_trie.cpp | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index e24bc6d2..a102b868 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -290,7 +290,7 @@ bool sm_trie_retrieve(Trie *trie, const char *key, void **value) keyptr++; /* Check if this slot is supposed to be empty or is a collision */ - if (node->mode == Node_Unused || node->parent != lastidx) + if ((curidx > trie->baseSize) || node->mode == Node_Unused || node->parent != lastidx) { return false; } else if (node->mode == Node_Term) { @@ -349,12 +349,24 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) /* Check if this slot is supposed to be empty. If so, we need to handle CASES 1/2: * Insertion without collisions */ - if (node->mode == Node_Unused) + if ( (curidx > trie->baseSize) || (node->mode == Node_Unused) ) { - /* Assign backcheck reference */ + if (curidx > trie->baseSize) + { + if (!sm_trie_grow(trie)) + { + return false; + } + node = &trie->base[curidx]; + } node->parent = lastidx; - node->idx = x_addstring(trie, keyptr); - node->mode = Node_Term; + if (*keyptr == '\0') + { + node->mode = Node_Arc; + } else { + node->idx = x_addstring(trie, keyptr); + node->mode = Node_Term; + } node->valset = true; node->value = value; @@ -383,7 +395,14 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) unsigned int outgoing_list[256]; unsigned int outgoing_count = 0; /* count the current index here */ cur = &base[outgoing_base] + 1; - for (unsigned int i=1; i<=255; i++,cur++) + unsigned int outgoing_limit = 255; + + if (outgoing_base + outgoing_limit > trie->baseSize) + { + outgoing_limit = trie->baseSize - outgoing_base; + } + + for (unsigned int i=1; i<=outgoing_limit; i++,cur++) { if (cur->mode == Node_Unused || cur->parent != lastidx) { @@ -400,7 +419,14 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) unsigned int incoming_list[256]; unsigned int incoming_base = base[node->parent].idx; unsigned int incoming_count = 0; + unsigned int incoming_limit = 255; cur = &base[incoming_base] + 1; + + if (incoming_base + incoming_limit > trie->baseSize) + { + incoming_limit = trie->baseSize - incoming_limit; + } + for (unsigned int i=1; i<=255; i++,cur++) { if (cur->mode == Node_Arc || cur->mode == Node_Term) @@ -437,6 +463,7 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) lastidx = newidx; } base[newidx] = base[oldidx]; + assert(base[base[newidx].parent].mode == Node_Arc); memset(&base[oldidx], 0, sizeof(TrieNode)); /* If we are not a terminator, we have children we must take care of */ if (base[newidx].mode == Node_Arc) @@ -480,6 +507,7 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) lastidx = newidx; } base[newidx] = base[oldidx]; + assert(base[base[newidx].parent].mode == Node_Arc); memset(&base[oldidx], 0, sizeof(TrieNode)); /* If we are not a terminator, we have children we must take care of */ if (base[newidx].mode == Node_Arc) From ef296710c62a95b6440bf570ef10d0448c963647 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 7 Dec 2006 19:10:26 +0000 Subject: [PATCH 0170/1664] added a few debug checks and a fix for deallocation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40200 --- core/sm_trie.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index a102b868..b0dbd8d5 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -263,7 +263,7 @@ void sm_trie_destroy(Trie *trie) { free(trie->base); free(trie->stringtab); - free(trie); + delete trie; } bool sm_trie_retrieve(Trie *trie, const char *key, void **value) @@ -424,9 +424,11 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) if (incoming_base + incoming_limit > trie->baseSize) { - incoming_limit = trie->baseSize - incoming_limit; + incoming_limit = trie->baseSize - incoming_base; } + assert(incoming_limit > 0 && incoming_limit <= 255); + for (unsigned int i=1; i<=255; i++,cur++) { if (cur->mode == Node_Arc || cur->mode == Node_Term) @@ -707,6 +709,8 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) /* Phew! */ return true; + } else { + assert(node->mode == Node_Arc); } } lastidx = curidx; From d7c3c577ed7a5d5c3e4c074f9e2732c5e2212202 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 8 Dec 2006 03:30:33 +0000 Subject: [PATCH 0171/1664] new config file format --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40201 --- configs/admins_simple.cfg | 6 ++---- configs/permissions.cfg | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/configs/admins_simple.cfg b/configs/admins_simple.cfg index 11b9a1d8..b48f3fff 100644 --- a/configs/admins_simple.cfg +++ b/configs/admins_simple.cfg @@ -39,7 +39,5 @@ * ***************************************/ -FastAdmins: -{ - "127.0.0.1" "z" -} +"127.0.0.1" "z" + diff --git a/configs/permissions.cfg b/configs/permissions.cfg index 971f4926..0a72a3be 100644 --- a/configs/permissions.cfg +++ b/configs/permissions.cfg @@ -21,7 +21,7 @@ * Commands - See the Permissions section. * * Example: - Admin: "BAILOPAN" + "BAILOPAN" { "auth" "steam" "identity" "STEAM_0:1:16" @@ -29,7 +29,7 @@ } * */ -Admins: +Admins { } @@ -38,14 +38,14 @@ Admins: * Use this section to tweak admin permission levels and groupings. * You can also define admin roles in this section. */ -Levels: +Levels { /** * These are the default role flag mappings. * You can assign new letters for custom purposes, however you should * not change the default names, as SourceMod hardcodes these. */ - Flags: + Flags { "reservation" "a" "kick" "b" @@ -78,22 +78,22 @@ Levels: * "CSDM" "i" * "csdm_enable" "j" */ - Overrides: + Overrides { - CommandGroups: + CommandGroups { } - Commands: + Commands { } } } -Permissions: +Permissions { //Lastly, you can define groups for admins. This helps organize large admin lists. - Groups: + Groups { /** * Allowed properties for a group: @@ -103,7 +103,7 @@ Permissions: * "immunity" - Specifies a group to be immune to. Use "*" for all or "" for users with no group. * Note: You can use - to strip immunity from a group, in the case of inheritance. */ - Group: "Sample" + "Sample" { /** * You can override commands and command groups here. @@ -113,10 +113,10 @@ Permissions: * "CSDM" "allow" * "csdm_enable" "deny" */ - CommandGroups: + CommandGroups { } - Commands: + Commands { } } From 89c75b194040806dc9f8cf456840eb00b4637b9b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 8 Dec 2006 20:54:49 +0000 Subject: [PATCH 0172/1664] committed shiny new SMC parser (really Valve XML or whatever) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40202 --- core/CTextParsers.cpp | 568 ++++++++++++++++++++++++++++++++- core/CTextParsers.h | 25 +- core/interfaces/ITextParsers.h | 75 +++-- core/sourcemm_api.cpp | 11 + core/systems/PluginSys.cpp | 1 + 5 files changed, 648 insertions(+), 32 deletions(-) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 9c76d5c1..34f247bf 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "CTextParsers.h" CTextParsers g_TextParse; @@ -33,13 +34,572 @@ unsigned int CTextParsers::GetUTF8CharBytes(const char *stream) return _GetUTF8CharBytes(stream); } -bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col, bool strict) -{ - /* This beast is a lot more rigorous than our INI friend. */ +/** + * Character streams + */ - return false; +struct CharStream +{ + const char *curpos; +}; + +bool CharStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int *read) +{ + CharStream *srdr = (CharStream *)stream; + + const char *ptr = srdr->curpos; + for (size_t i=0; icurpos; + + srdr->curpos = ptr; + + return true; } +SMCParseError CTextParsers::ParseString_SMC(const char *stream, + ITextListener_SMC *smc, + unsigned int *line, + unsigned int *col) +{ + CharStream srdr = { stream }; + + return ParseStream_SMC(&srdr, CharStreamReader, smc, line, col); +} + +/** + * File streams + */ + +bool FileStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int *read) +{ + size_t num = fread(buffer, 1, maxlength, (FILE *)stream); + + *read = static_cast(num); + + if (num == 0 && feof((FILE *)stream)) + { + return true; + } + + return (ferror((FILE *)stream) == 0); +} + +SMCParseError CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, unsigned int *line, unsigned int *col) +{ + FILE *fp = fopen(file, "rt"); + + if (!fp) + { + return SMCParse_StreamOpen; + } + + SMCParseError result = ParseStream_SMC(fp, FileStreamReader, smc, line, col); + + fclose(fp); + + return result; +} + +/** + * Raw parsing of streams with helper functions + */ + +struct StringInfo +{ + StringInfo() : quoted(false), ptr(NULL), end(NULL), special(false) { } + char *ptr; + char *end; + bool special; + bool quoted; +}; + +const char *FixupString(StringInfo &data) +{ + if (!data.ptr) + { + return NULL; + } + + if (data.quoted) + { + data.ptr++; + } +#if defined _DEBUG + else { + /* A string will never have beginning whitespace because we ignore it in the stream. + * Furthermore, if there is trailing whitespace, the end ptr will point to it, so it is valid + * to overwrite! Lastly, the last character must be whitespace or a comment/invalid character. + */ + } +#endif + + if (data.special) + { + //:TODO: this string has special tokens in it, like \, and we must + //resolve these before passing the string back to the app + } + + *(data.end) = '\0'; + + return data.ptr; +} + +const char *rotate(StringInfo info[3]) +{ + if (info[2].ptr != NULL) + { + return info[2].ptr; + } + + if (info[0].ptr != NULL) + { + info[2] = info[1]; + info[1] = info[0]; + info[0] = StringInfo(); + } + + return NULL; +} + +void scrap(StringInfo info[3]) +{ + info[2] = StringInfo(); + info[1] = StringInfo(); + info[0] = StringInfo(); +} + +void reloc(StringInfo &data, unsigned int bytes) +{ + if (data.ptr) + { + data.ptr -= bytes; + } + if (data.end) + { + data.end -= bytes; + } +} + +char *lowstring(StringInfo info[3]) +{ + for (int i=2; i>=0; i--) + { + if (info[i].ptr) + { + return info[i].ptr; + } + } + + return NULL; +} + +SMCParseError CTextParsers::ParseStream_SMC(void *stream, + STREAMREADER srdr, + ITextListener_SMC *smc, + unsigned int *line, + unsigned int *col) +{ + char in_buf[4096]; + char *reparse_point = NULL; + char *parse_point = in_buf; + char *line_begin = in_buf; + unsigned int read; + unsigned int curline = 1; + unsigned int curtok = 0; + unsigned int curlevel = 0; + bool in_quote = false; + bool ignoring = false; + bool eol_comment = false; + bool ml_comment = false; + unsigned int i; + SMCParseError err = SMCParse_Okay; + SMCParseResult res; + char c; + + StringInfo strings[3]; + StringInfo emptystring; + + smc->ReadSMC_ParseStart(); + + while (srdr(stream, parse_point, sizeof(in_buf) - (parse_point - line_begin) - 1, &read)) + { + if (!read) + { + err = SMCParse_StreamError; + goto failed; + } + + /* :TODO: do this outside of the main loop somehow + * This checks for BOM markings + */ + if (curline == 1 && + in_buf[0] == (char)0xEF && + in_buf[1] == (char)0xBB && + in_buf[2] == (char)0xBF) + { + parse_point = &in_buf[3]; + } + + if (reparse_point) + { + read += (parse_point - reparse_point); + parse_point = reparse_point; + reparse_point = NULL; + } + + for (i=0; iReadSMC_RawLine(line_begin, curline)) != SMCParse_Continue) + { + err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + goto failed; + } + + /* Now we check the sanity of our staged strings! */ + if (strings[2].ptr) + { + if (!curlevel) + { + err = SMCParse_InvalidProperty1; + goto failed; + } + /* Assume the next string is a property and pass the info on. */ + if ((res=smc->ReadSMC_KeyValue( + FixupString(strings[2]), + FixupString(strings[1]), + strings[2].quoted, + strings[1].quoted)) != SMCParse_Continue) + { + err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + goto failed; + } + scrap(strings); + } + + /* Change the states for the next line */ + curtok = 0; + curline++; + line_begin = &parse_point[i+1]; //Note: safe because this gets relocated later + } else if (ignoring) { + if (in_quote) + { + /* If i was 0, this case is impossible due to reparsing */ + if ((i != 0) && c == '"' && parse_point[i-1] != '\\') + { + /* If we reached a quote in an ignore phase, + * we're staging a string and we must rotate it out. + */ + in_quote = false; + ignoring = false; + /* Set our info */ + strings[0].end = &parse_point[i]; + strings[0].quoted = true; + if (rotate(strings) != NULL) + { + /* If we rotated too many strings, there was too much crap on one line */ + err = SMCParse_InvalidTokens; + goto failed; + } + } else if (c == '\\' && i == (read - 1)) { + strings[0].special = true; + reparse_point = &parse_point[i]; + break; + } + } else if (ml_comment) { + if (c == '*') + { + /* Check if we need to get more input first */ + if (i == read - 1) + { + reparse_point = &parse_point[i]; + break; + } + if (parse_point[i+1] == '/') + { + ml_comment = false; + ignoring = false; + /* We should not be staging anything right now. */ + assert(strings[0].ptr == NULL); + /* Advance the input stream so we don't choke on this token */ + i++; + curtok++; + } + } + } + } else { + /* Check if we're whitespace or not */ + if (!g_ws_chartable[c]) + { + bool restage = false; + /* Check various special tokens: + * ; + * // + * /* + * { + * } + */ + if (c == ';' || c == '/') + { + /* If it's a line-based comment (that is, ; or //) + * we will need to scrap everything until the end of the line. + */ + if (c == '/') + { + if (i == read - 1) + { + /* If we reached the end of the look-ahead, we need to re-check our input. + * Breaking out will force this to be the new reparse point! + */ + reparse_point = &reparse_point[i]; + break; + } + if (parse_point[i + 1] == '/') + { + /* standard comment */ + ignoring = true; + eol_comment = true; + restage = true; + } else if (parse_point[i+1] == '*') { + /* inline comment - start ignoring */ + ignoring = true; + ml_comment = true; + /* yes, we restage, meaning that: + * STR/*stuff* /ING (space because ml comments don't nest in C++) + * will not generate 'STRING', but rather 'STR' and 'ING'. + * This should be a rare occurrence and is done here for convenience. + */ + restage = true; + } + } else { + ignoring = true; + eol_comment = true; + restage = true; + } + } else if (c == '{') { + /* If we are staging a string, we must rotate here */ + if (strings[0].ptr) + { + /* We have unacceptable tokens on this line */ + if (rotate(strings) != NULL) + { + err = SMCParse_InvalidSection1; + goto failed; + } + } + /* Sections must always be alone */ + if (strings[2].ptr != NULL) + { + err = SMCParse_InvalidSection1; + goto failed; + } else if (strings[1].ptr == NULL) { + err = SMCParse_InvalidSection2; + goto failed; + } + if ((res=smc->ReadSMC_NewSection(FixupString(strings[1]), strings[1].quoted)) + != SMCParse_Continue) + { + err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + goto failed; + } + strings[1] = emptystring; + curlevel++; + } else if (c == '}') { + /* Unlike our matching friend, this can be on the same line as something prior */ + if (rotate(strings) != NULL) + { + err = SMCParse_InvalidSection3; + goto failed; + } + if (strings[2].ptr) + { + if (!curlevel) + { + err = SMCParse_InvalidProperty1; + goto failed; + } + if ((res=smc->ReadSMC_KeyValue( + FixupString(strings[2]), + FixupString(strings[1]), + strings[2].quoted, + strings[1].quoted)) + != SMCParse_Continue) + { + err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + goto failed; + } + } else if (strings[1].ptr) { + err = SMCParse_InvalidSection3; + goto failed; + } else if (!curlevel) { + err = SMCParse_InvalidSection4; + goto failed; + } + /* Now it's safe to leave the section */ + scrap(strings); + if ((res=smc->ReadSMC_LeavingSection()) != SMCParse_Continue) + { + err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + goto failed; + } + curlevel--; + } else if (c == '"') { + /* If we get a quote mark, we always restage, but we need to do it beforehand */ + if (strings[0].ptr) + { + strings[0].end = &parse_point[i]; + if (rotate(strings) != NULL) + { + err = SMCParse_InvalidTokens; + goto failed; + } + } + strings[0].ptr = &parse_point[i]; + in_quote = true; + ignoring = true; + } else if (!strings[0].ptr) { + /* If we have no string, we must start one */ + strings[0].ptr = &parse_point[i]; + } + if (restage && strings[0].ptr) + { + strings[0].end = &parse_point[i]; + if (rotate(strings) != NULL) + { + err = SMCParse_InvalidTokens; + goto failed; + } + } + } else { + /* If we're eating a string and get whitespace, we need to restage. + * (Note that if we are quoted, this is being ignored) + */ + if (strings[0].ptr) + { + /* + * The specification says the second string in a pair does not need to be quoted. + * Thus, we check if there's already a string on the stack. + * If there's a newline, we always rotate so the newline has an empty starter. + */ + if (!strings[1].ptr) + { + /* There's no string, so we must move this one down and eat up another */ + strings[0].end = &parse_point[i]; + rotate(strings); + } else if (!strings[1].quoted) { + err = SMCParse_InvalidTokens; + goto failed; + } + } + } + } + + /* Advance which token we're on */ + curtok++; + } + + if (line_begin != in_buf) + { + /* The line buffer has advanced, so it's safe to copy N bytes back to the beginning. + * What's N? N is the lowest point we're currently relying on. + */ + char *stage = lowstring(strings); + if (!stage || stage > line_begin) + { + stage = line_begin; + } + unsigned int bytes = read - (stage - parse_point); + + /* It is now safe to delete everything before the staged point */ + memmove(in_buf, stage, bytes); + + /* Calculate the number of bytes in the new buffer */ + bytes = stage - in_buf; + /* Relocate all the cached pointers to our new base */ + line_begin -= bytes; + reloc(strings[0], bytes); + reloc(strings[1], bytes); + reloc(strings[2], bytes); + if (reparse_point) + { + reparse_point -= bytes; + } + if (parse_point) + { + parse_point = &parse_point[read]; + parse_point -= bytes; + } + } else if (read == sizeof(in_buf) - 1) { + err = SMCParse_TokenOverflow; + goto failed; + } + } + + /* If we're done parsing and there are tokens left over... */ + if (curlevel) + { + err = SMCParse_InvalidSection5; + goto failed; + } else if (strings[0].ptr || strings[1].ptr) { + err = SMCParse_InvalidTokens; + goto failed; + } + + smc->ReadSMC_ParseEnd(false, false); + + return SMCParse_Okay; + +failed: + if (line) + { + *line = curline; + } + + if (col) + { + *col = curtok; + } + + return err; +} + + +/** + * INI parser + */ + bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col) { FILE *fp = fopen(file, "rt"); diff --git a/core/CTextParsers.h b/core/CTextParsers.h index 111a5c52..0c0f48d0 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -23,6 +23,15 @@ inline unsigned int _GetUTF8CharBytes(const char *stream) return 1; } +/** + * @param void * IN: Stream pointer + * @param char * IN/OUT: Stream buffer + * @param size_t IN: Maximum size of buffer + * @param unsigned int * OUT: Number of bytes read (0 = end of stream) + * @return True on success, false on failure + */ +typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *); + class CTextParsers : public ITextParsers { public: @@ -33,13 +42,23 @@ public: unsigned int *line, unsigned int *col); - virtual bool ParseFile_SMC(const char *file, + virtual SMCParseError ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, - unsigned int *col, - bool strict); + unsigned int *col); virtual unsigned int GetUTF8CharBytes(const char *stream); +private: + SMCParseError ParseString_SMC(const char *stream, + ITextListener_SMC *smc, + unsigned int *line, + unsigned int *col); + SMCParseError ParseStream_SMC(void *stream, + STREAMREADER srdr, + ITextListener_SMC *smc, + unsigned int *line, + unsigned int *col); + }; extern CTextParsers g_TextParse; diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h index c4be06e3..0812cdfc 100644 --- a/core/interfaces/ITextParsers.h +++ b/core/interfaces/ITextParsers.h @@ -102,17 +102,18 @@ namespace SourceMod }; /** - * :TODO: write this in CFG format so it makes sense + * :TODO: write this in CFG (context free grammar) format so it makes sense * * The SMC file format is defined as: * WHITESPACE: 0x20, \n, \t, \r - * IDENTIFIER: Any ASCII character EXCLUDING ", ', :, WHITESPACE - * STRING: Any set of symbols + * IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, /*, or WHITESPACE. + * STRING: Any set of symbols enclosed in quotes. + * Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER. * * Basic syntax is comprised of SECTIONBLOCKs. * A SECTIONBLOCK defined as: * - * SECTION: "SECTIONNAME" + * SECTIONNAME * { * OPTION * } @@ -121,11 +122,14 @@ namespace SourceMod * A new line will terminate an OPTION, but there can be more than one OPTION per line. * OPTION is defined any of: * "KEY" "VALUE" - * "SINGLEKEY" * SECTIONBLOCK * - * SECTION is an IDENTIFIER * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings + * SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed. + * If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace). + * If KEY is not enclosed in quotes, the key is terminated at first whitespace. + * If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace). + * The VALUE may have inner quotes, but the key string may not. * * For an example, see configs/permissions.cfg * @@ -135,17 +139,33 @@ namespace SourceMod * ; * // * /* */ + + enum SMCParseResult + { + SMCParse_Continue, //continue parsing + SMCParse_Halt, //stop parsing here + SMCParse_HaltFail //stop parsing and return failure + }; + + enum SMCParseError + { + SMCParse_Okay, //no error + SMCParse_StreamOpen, //stream failed to open + SMCParse_StreamError, //the stream died... somehow + SMCParse_Custom, //a custom handler threw an error + SMCParse_InvalidSection1, //a section was declared without quotes, and had extra tokens + SMCParse_InvalidSection2, //a section was declared without any header + SMCParse_InvalidSection3, //a section ending was declared with too many unknown tokens + SMCParse_InvalidSection4, //a section ending has no matching beginning + SMCParse_InvalidSection5, //a section beginning has no matching ending + SMCParse_InvalidTokens, //there were too many unidentifiable strings on one line + SMCParse_TokenOverflow, //the token buffer overflowed + SMCParse_InvalidProperty1, //a property was declared outside of any section + }; + class ITextListener_SMC { public: - enum SMCParseResult - { - SMCParse_Continue, //continue parsing - SMCParse_SkipSection, //skip the rest of the current section - SMCParse_Halt, //stop parsing here - SMCParse_HaltFail //stop parsing and return failure - }; - /** * @brief Called when starting parsing. */ @@ -163,17 +183,25 @@ namespace SourceMod { } + /** + * @brief Called when a warning occurs. + * @param error By-reference variable containing the error message of the warning. + * @param tokens Pointer to the token stream causing the error. + * @return SMCParseResult directive. + */ + virtual SMCParseResult ReadSMC_OnWarning(SMCParseError &error, const char *tokens) + { + return SMCParse_HaltFail; + } + /** * @brief Called when entering a new section * * @param name Name of section, with the colon omitted. - * @param option Optional text after the colon, quotes removed. NULL if none. - * @param colon Whether or not the required ':' was encountered. + * @param opt_quotes Whether or not the option string was enclosed in quotes. * @return SMCParseResult directive. */ - virtual SMCParseResult ReadSMC_NewSection(const char *name, - const char *option, - bool colon) + virtual SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes) { return SMCParse_Continue; } @@ -198,7 +226,6 @@ namespace SourceMod /** * @brief Called when leaving the current section. - * Note: Skipping the section has no meaning here. * * @return SMCParseResult directive. */ @@ -259,14 +286,12 @@ namespace SourceMod * @param smc_listener Event handler for reading file. * @param line If non-NULL, will contain last line parsed (0 if file could not be opened). * @param col If non-NULL, will contain last column parsed (undefined if file could not be opened). - * @param strict If strict mode is enabled, the parsing rules are obeyed rigorously rather than loosely. - * @return True if parsing succeded, false if file couldn't be opened or there was a syntax error. + * @return An SMCParseError result code. */ - virtual bool ParseFile_SMC(const char *file, + virtual SMCParseError ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, - unsigned int *col, - bool strict) =0; + unsigned int *col) =0; public: /** * @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream. diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 2e862a26..8aa855f2 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -3,14 +3,25 @@ #include "sm_version.h" #include "sourcemod.h" +#include "CTextParsers.h" + SourceMod_Core g_SourceMod_Core; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); +class Parser : public ITextListener_SMC +{ +public: +}; + bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); + Parser p; + + SMCParseError err = g_TextParse.ParseFile_SMC("c:\\debug.txt", &p, NULL, NULL); + return g_SourceMod.InitializeSourceMod(error, maxlen, late); } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 3962ee84..2a374f35 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,6 +1,7 @@ #include #include "PluginSys.h" #include "LibrarySys.h" +#include "sourcemm_api.h" CPluginManager g_PluginMngr; From bd3effc315f34ce8408c7400c50f72e260469a17 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 8 Dec 2006 20:59:25 +0000 Subject: [PATCH 0173/1664] removed debug code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40203 --- core/sourcemm_api.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 8aa855f2..2e862a26 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -3,25 +3,14 @@ #include "sm_version.h" #include "sourcemod.h" -#include "CTextParsers.h" - SourceMod_Core g_SourceMod_Core; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); -class Parser : public ITextListener_SMC -{ -public: -}; - bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); - Parser p; - - SMCParseError err = g_TextParse.ParseFile_SMC("c:\\debug.txt", &p, NULL, NULL); - return g_SourceMod.InitializeSourceMod(error, maxlen, late); } From 7b2455db2e4ac5286bdbca5e97ff972a39d4660a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 8 Dec 2006 22:15:15 +0000 Subject: [PATCH 0174/1664] added initial plugin settings file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40204 --- configs/plugin_settings.cfg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 configs/plugin_settings.cfg diff --git a/configs/plugin_settings.cfg b/configs/plugin_settings.cfg new file mode 100644 index 00000000..0e97e68d --- /dev/null +++ b/configs/plugin_settings.cfg @@ -0,0 +1,32 @@ +/** + * Each sub-section of "Plugins" should have a title which specifies a plugin filename. + * Filenames have a wildcard of *. Appending .amxx is not required. + * If the filename has no explicit path, it will be patched to any sub-path in the plugins folder. + * + * Available properties for plugins are: + * "pause" - Whether or not the plugin should load paused - "yes" or "no" (defualt) + * "lifetime" - Lifetime of the plugin. Options: + * "private" - Plugin is privately maintained and receives no forwards from Core + * "mapsync" - Plugins should be reloaded on mapchange if changed (default) + * "maponly" - Plugin should be unloaded at the end of the map + * "global" - Plugin will never be unloaded or updated + * + * You can also have an "Options" section declaring options to pass onto the JIT: + * "debug" - Whether or not to load the plugin in debug mode + * "inl_errors" - Internal optimization to inline error checks. Results in larger but faster code. + * "inl_natives" - Internal optimization to inline native calls. Results in larger code (unknown speed effect). + */ + +"Plugins" +{ + "*" + { + "pause" "no" + "lifetime" "mapsync" + + "Options" + { + "debug" "no" + } + } +} From 34c711fffde694406a6d29ab56ad97bfd5acf69b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 9 Dec 2006 01:20:33 +0000 Subject: [PATCH 0175/1664] added size adjustment to dynamic strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40205 --- sourcepawn/compiler/sc.h | 1 + sourcepawn/compiler/sc1.c | 11 ++++++++--- sourcepawn/compiler/sc4.c | 7 +++++++ sourcepawn/compiler/sc6.c | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 7f78fd4a..43d0ae15 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -626,6 +626,7 @@ SC_FUNC void char2addr(void); SC_FUNC void charalign(void); SC_FUNC void addconst(cell value); SC_FUNC void setheap_save(cell value); +SC_FUNC void stradjust(regid reg); /* Code generation functions for arithmetic operators. * diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index d5de9d8c..f221e6fe 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2241,7 +2241,10 @@ static int declloc(int fstatic) if (numdim == sDIMEN_MAX) { error(53); /* exceeding maximum number of dimensions */ return (all_constant ? iARRAY : iREFARRAY); - } /* if */ + } else if (numdim) { /* if */ + /* If we have a dimension on the stack, push it */ + pushreg(sPRI); + } if (matchtoken(']')) { dim[numdim++] = 0; continue; @@ -2249,9 +2252,7 @@ static int declloc(int fstatic) dim_ident = doexpr2(TRUE,FALSE,FALSE,FALSE,&idxtag[numdim],&dim_sym,0,&dim_val); if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION || dim_ident == iARRAYCELL) { all_constant = 0; - pushreg(sPRI); } else if (dim_ident == iCONSTEXPR) { - pushreg(sPRI); dim[numdim] = dim_val.constval; /* :TODO: :URGENT: Make sure this still works */ if (dim_sym && dim_sym->usage & uENUMROOT) @@ -2275,6 +2276,10 @@ static int declloc(int fstatic) ident = iARRAY; stgdel(_index, _code); } else { + if (tag == pc_tag_string && numdim && dim[numdim-1]) { + stradjust(sPRI); + } + pushreg(sPRI); memset(dim, 0, sizeof(int)*sDIMEN_MAX); ident = iREFARRAY; genarray(numdim, autozero); diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index 509b4e06..2f2f51c4 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -593,6 +593,13 @@ SC_FUNC void fillarray(symbol *sym,cell size,cell value) code_idx+=opcodes(2)+opargs(2); } +SC_FUNC void stradjust(regid reg) +{ + assert(reg==sPRI); + stgwrite("\tstradjust.pri\n"); + code_idx+=opcodes(1); +} + /* Instruction to get an immediate value into the primary or the alternate * register */ diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index fc3ae824..011028e4 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -602,6 +602,7 @@ static OPCODEC opcodelist[] = { { 15, "stor.pri", sIN_CSEG, parm1 }, { 18, "stor.s.alt", sIN_CSEG, parm1 }, { 17, "stor.s.pri", sIN_CSEG, parm1 }, + {164, "stradjust.pri", sIN_CSEG, parm0 }, { 24, "strb.i", sIN_CSEG, parm1 }, { 79, "sub", sIN_CSEG, parm0 }, { 80, "sub.alt", sIN_CSEG, parm0 }, From 455c03321c804fd49113446e92d4279e6e51bbec Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 9 Dec 2006 01:47:07 +0000 Subject: [PATCH 0176/1664] added stradjust.pri opcode to the JIT --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40206 --- sourcepawn/jit/x86/jit_x86.cpp | 8 ++++++++ sourcepawn/jit/x86/opcode_helpers.h | 1 + sourcepawn/jit/x86/opcode_switch.inc | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index aedd936a..44d5b33f 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1750,6 +1750,14 @@ inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) IA32_Pop_Reg(jit, AMX_REG_PRI); } +inline void WriteOp_Stradjust_Pri(JitWriter *jit) +{ + //add eax, 4 + //sar eax, 2 + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 4, MOD_REG); + IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 2, MOD_REG); +} + /************************************************* ************************************************* * JIT PROPER ************************************ diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index 2036ead4..f8045c16 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -260,6 +260,7 @@ typedef enum OP_TRACKER_POP_SETHEAP, //VERIFIED OP_GENARRAY, //VERIFIED OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays) + OP_STRADJUST_PRI, //VERIFIED /* ----- */ OP_NUM_OPCODES } OPCODE; diff --git a/sourcepawn/jit/x86/opcode_switch.inc b/sourcepawn/jit/x86/opcode_switch.inc index 7e1ebc0b..69a3db23 100644 --- a/sourcepawn/jit/x86/opcode_switch.inc +++ b/sourcepawn/jit/x86/opcode_switch.inc @@ -673,6 +673,11 @@ WriteOp_GenArray(jit, true); break; } + case OP_STRADJUST_PRI: + { + WriteOp_Stradjust_Pri(jit); + break; + } #if defined USE_UNGEN_OPCODES #include "ungen_opcode_switch.inc" #endif From f80757542944b5ca961e2bbdb650e094b56a4dbe Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 9 Dec 2006 03:18:48 +0000 Subject: [PATCH 0177/1664] fixed arrays using decl being init when assigning a number --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40207 --- sourcepawn/compiler/sc1.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index f221e6fe..91a49386 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2502,6 +2502,10 @@ static void initials(int ident,int tag,cell *size,int dim[],int numdim, int curlit=litidx; int err=0; + if (!autozero) { + return; + } + if (!matchtoken('=')) { assert(ident!=iARRAY || numdim>0); if (ident==iARRAY && dim[numdim-1]==0) { @@ -2662,12 +2666,12 @@ static cell initvector(int ident,int tag,cell size,int fillzero, constvalue *enumroot,int *errorfound) { cell prev1=0,prev2=0; - int ellips=FALSE,hadtoken=0; + int ellips=FALSE; int curlit=litidx; int rtag,ctag; assert(ident==iARRAY || ident==iREFARRAY); - if ((hadtoken=matchtoken('{')) && autozero) { + if (matchtoken('{')) { constvalue *enumfield=(enumroot!=NULL) ? enumroot->next : NULL; do { int fieldlit=litidx; @@ -2729,11 +2733,6 @@ static cell initvector(int ident,int tag,cell size,int fillzero, } while (matchtoken(',')); /* do */ needtoken('}'); } else { - if (hadtoken && !autozero) { - error(10); - lexclr(TRUE); /* drop the rest of the line */ - return 0; - } init(ident,&ctag,errorfound); if (!matchtag(tag,ctag,TRUE)) error(213); /* tagname mismatch */ From a1e58aa9ef6fbcd4bb75f719a9eed83933f854b5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 10 Dec 2006 09:19:59 +0000 Subject: [PATCH 0178/1664] initial import of plugin database (UNTESTED) added file pattern matching routine (TESTED) added memtable caching (UNTESTED) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40208 --- core/CTextParsers.cpp | 2 + core/msvc8/sourcemod_mm.vcproj | 20 ++- core/sm_memtable.cpp | 85 +++++++++ core/sm_memtable.h | 69 ++++++++ core/sm_platform.h | 1 + core/systems/PluginInfoDatabase.cpp | 266 ++++++++++++++++++++++++++++ core/systems/PluginInfoDatabase.h | 74 ++++++++ core/systems/PluginSys.cpp | 226 ++++++++++++++++++++++- core/systems/PluginSys.h | 28 ++- 9 files changed, 764 insertions(+), 7 deletions(-) create mode 100644 core/sm_memtable.cpp create mode 100644 core/sm_memtable.h create mode 100644 core/systems/PluginInfoDatabase.cpp create mode 100644 core/systems/PluginInfoDatabase.h diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 34f247bf..7f922eef 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -587,6 +587,8 @@ failed: *line = curline; } + smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom)); + if (col) { *col = curtok; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 6fe6cae6..0a482bdd 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -41,7 +41,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -118,7 +118,7 @@ + + @@ -204,6 +208,10 @@ RelativePath="..\sm_globals.h" > + + @@ -247,6 +255,10 @@ RelativePath="..\systems\LibrarySys.h" > + + @@ -267,6 +279,10 @@ RelativePath="..\systems\LibrarySys.cpp" > + + diff --git a/core/sm_memtable.cpp b/core/sm_memtable.cpp new file mode 100644 index 00000000..4396eeb0 --- /dev/null +++ b/core/sm_memtable.cpp @@ -0,0 +1,85 @@ +#include +#include +#include "sm_memtable.h" + +BaseMemTable::BaseMemTable(unsigned int init_size) +{ + membase = (unsigned char *)malloc(init_size); + size = init_size; +} + +BaseMemTable::~BaseMemTable() +{ + free(membase); + membase = NULL; +} + +int BaseMemTable::CreateMem(unsigned int addsize, void **addr) +{ + int idx = (int)tail; + + if (idx < 0) + { + return -1; + } + + while (tail + addsize >= size) + { + size *= 2; + membase = (unsigned char *)realloc(membase, size); + } + + tail += addsize; + + if (addr) + { + *addr = (void *)&membase[idx]; + } + + return idx; +} + +void *BaseMemTable::GetAddress(int index) +{ + if (index < 0 || (unsigned int)index >= tail) + { + return NULL; + } + + return &membase[index]; +} + +void BaseMemTable::Reset() +{ + tail = 0; +} + +BaseStringTable::BaseStringTable(unsigned int init_size) : m_table(init_size) +{ +} + +BaseStringTable::~BaseStringTable() +{ +} + +int BaseStringTable::AddString(const char *string) +{ + size_t len = strlen(string) + 1; + int idx; + char *addr; + + idx = m_table.CreateMem(len, (void **)&addr); + strcpy(addr, string); + + return idx; +} + +const char *BaseStringTable::GetString(int str) +{ + return (const char *)m_table.GetAddress(str); +} + +void BaseStringTable::Reset() +{ + m_table.Reset(); +} diff --git a/core/sm_memtable.h b/core/sm_memtable.h new file mode 100644 index 00000000..0fe631a9 --- /dev/null +++ b/core/sm_memtable.h @@ -0,0 +1,69 @@ +#ifndef _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_ +#define _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_ + +class BaseMemTable +{ +public: + BaseMemTable(unsigned int init_size); + ~BaseMemTable(); +public: + /** + * Allocates 'size' bytes of memory. + * Optionally outputs the address through 'addr'. + * Returns an index >= 0 on success, < 0 on failure. + */ + int CreateMem(unsigned int size, void **addr); + + /** + * Given an index into the memory table, returns its address. + * Returns NULL if invalid. + */ + void *GetAddress(int index); + + /** + * Scraps the memory table. For caching purposes, the memory + * is not freed, however subsequent calls to CreateMem() will + * begin at the first index again. + */ + void Reset(); +private: + unsigned char *membase; + unsigned int size; + unsigned int tail; +}; + +class BaseStringTable +{ +public: + BaseStringTable(unsigned int init_size); + ~BaseStringTable(); +public: + /** + * Adds a string to the string table and returns its index. + */ + int AddString(const char *string); + + /** + * Given an index into the string table, returns the associated string. + */ + const char *GetString(int str); + + /** + * Scraps the string table. For caching purposes, the memory + * is not freed, however subsequent calls to AddString() will + * begin at the first index again. + */ + void Reset(); + + /** + * Returns the parent BaseMemTable that this string table uses. + */ + inline BaseMemTable *GetMemTable() + { + return &m_table; + } +private: + BaseMemTable m_table; +}; + +#endif //_INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_ diff --git a/core/sm_platform.h b/core/sm_platform.h index 5e7e1962..1809e908 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -13,6 +13,7 @@ #if !defined snprintf #define snprintf _snprintf #endif +#define strcasecmp strcmpi #include #include #define PLATFORM_LIB_EXT "dll" diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp new file mode 100644 index 00000000..03e43733 --- /dev/null +++ b/core/systems/PluginInfoDatabase.cpp @@ -0,0 +1,266 @@ +#include +#include +#include "PluginInfoDatabase.h" +#include "PluginSys.h" + +void PluginSettings::Init() +{ + name = -1; + pause_val = false; + type_val = PluginType_MapUpdated; + optarray = -1; + opts_num = 0; + opts_size = 0; +} + +/** + * :TODO: write the logger, make these errors log instead of being static + * NOTE: once we do that, we will have to change some code to ignore sections + */ + +CPluginInfoDatabase::CPluginInfoDatabase() +{ + m_strtab = NULL; + m_infodb_count = 0; + m_infodb_size = 0; + m_infodb = -1; +} + +CPluginInfoDatabase::~CPluginInfoDatabase() +{ + delete m_strtab; +} + +void CPluginInfoDatabase::ReadSMC_ParseStart() +{ + /* Create or reset our string table */ + if (m_strtab) + { + m_strtab->Reset(); + } else { + m_strtab = new BaseStringTable(1024); + } + + /* Set our internal states to the beginning */ + in_plugins = false; + cur_plugin = -1; + in_options = false; +} + +SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...) +{ + char buffer[512]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + m_errmsg = m_strtab->AddString(buffer); + + return SMCParse_HaltFail; +} + +unsigned int CPluginInfoDatabase::GetSettingsNum() +{ + return m_infodb_count; +} + +PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename) +{ + BaseMemTable *memtab = m_strtab->GetMemTable(); + PluginSettings *table = (PluginSettings *)memtab->GetAddress(m_infodb); + + if (!table || index >= m_infodb_count) + { + return NULL; + } + + const char *name = m_strtab->GetString(table[index].name); + + if (!name) + { + return NULL; + } + + if (!g_PluginMngr.TestAliasMatch(name, filename)) + { + return NULL; + } + + return &table[index]; +} + +void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val) +{ + PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray); + if (!table) + { + *key = NULL; + *val = NULL; + return; + } + + if (opt_num >= settings->opts_num) + { + *key = NULL; + *val = NULL; + return; + } + + *key = m_strtab->GetString(table[opt_num].key); + *val = m_strtab->GetString(table[opt_num].val); +} + +SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, + const char *value, + bool key_quotes, + bool value_quotes) +{ + if (cur_plugin != -1) + { + PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin); + if (!in_options) + { + if (strcmp(key, "pause") == 0) + { + if (strcasecmp(value, "yes") == 0) + { + plugin->pause_val = true; + } else { + plugin->pause_val = false; + } + } else if (strcmp(key, "lifetime") == 0) { + if (strcasecmp(value, "private") == 0) + { + plugin->type_val = PluginType_Private; + } else if (strcasecmp(value, "mapsync") == 0) { + plugin->type_val = PluginType_MapUpdated; + } else if (strcasecmp(value, "maponly") == 0) { + plugin->type_val = PluginType_MapOnly; + } else if (strcasecmp(value, "global") == 0) { + plugin->type_val = PluginType_Global; + } else { + return MakeError("Unknown value for key \"lifetime\": \"%s\"", value); + } + } else { + return MakeError("Unknown property key: \"%s\"", key); + } + } else { + /* Cache every option, valid or not */ + int keyidx = m_strtab->AddString(key); + int validx = m_strtab->AddString(value); + PluginOpts *table; + BaseMemTable *memtab = m_strtab->GetMemTable(); + if (plugin->opts_num + 1 > plugin->opts_size) + { + unsigned int oldsize = plugin->opts_size; + if (oldsize == 0) + { + //right now we don't have many + plugin->opts_size = 2; + } else { + plugin->opts_size *= 2; + } + int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table); + if (plugin->optarray != -1) + { + void *oldtable = memtab->GetAddress(plugin->optarray); + memcpy(table, oldtable, oldsize * sizeof(PluginOpts)); + } + plugin->optarray = newidx; + } else { + table = (PluginOpts *)memtab->GetAddress(plugin->optarray); + } + PluginOpts *opt = &table[plugin->opts_num++]; + opt->key = keyidx; + opt->val = validx; + } + } else if (in_plugins) { + return MakeError("Unknown property key: \"%s\"", key); + } else { + /* Ignore anything we don't know about! */ + } + + return SMCParse_Continue; +} + +SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection() +{ + if (in_plugins) + { + if (cur_plugin == -1) + { + if (in_options) + { + in_options = false; + } else { + /* If the plugin is ending, add it to the table */ + BaseMemTable *memtab = m_strtab->GetMemTable(); + int *table; + if (m_infodb_count + 1 > m_infodb_size) + { + unsigned int oldsize = m_infodb_size; + if (!m_infodb_size) + { + m_infodb_size = 8; + } else { + m_infodb_size *= 2; + } + int newidx = memtab->CreateMem(m_infodb_size, (void **)&table); + if (m_infodb != -1) + { + void *oldtable = (int *)memtab->GetAddress(m_infodb); + memcpy(table, oldtable, oldsize * sizeof(int)); + } + m_infodb = newidx; + } else { + table = (int *)memtab->GetAddress(m_infodb); + } + /* Assign to table and scrap the current plugin */ + table[m_infodb_count++] = cur_plugin; + cur_plugin = -1; + } + } else { + in_plugins = false; + } + } + + return SMCParse_Continue; +} + +SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool opt_quotes) +{ + if (!in_plugins) + { + /* If we're not in the main Plugins section, and we don't get it for the name, error out */ + if (strcmp(name, "Plugins") != 0) + { + return MakeError("Unknown root section: \"%s\"", name); + } else { + /* Otherwise set our states */ + in_plugins = true; + cur_plugin = -1; + in_options = false; + } + } else { + if (cur_plugin == -1) + { + /* If we get a plugin node and we don't have a current plugin, create a new one */ + PluginSettings *plugin; + cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin); + plugin->Init(); + plugin->name = m_strtab->AddString(name); + in_options = false; + } else { + if (!in_options && strcmp(name, "Options") == 0) + { + in_options = true; + } else { + return MakeError("Unknown plugin sub-section: \"%s\"", name); + } + } + } + + return SMCParse_Continue; +} diff --git a/core/systems/PluginInfoDatabase.h b/core/systems/PluginInfoDatabase.h new file mode 100644 index 00000000..572bb7b7 --- /dev/null +++ b/core/systems/PluginInfoDatabase.h @@ -0,0 +1,74 @@ +#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_ +#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_ + +/** + * This file parses plugin_settings.cfg and stores the information in cached memory. + * It provides simplistic abstraction to retrieving the info. + * :TODO: currently untested + */ + +#include "sm_memtable.h" +#include "ITextParsers.h" +#include "IPluginSys.h" +#include "sm_globals.h" + +struct PluginOpts +{ + int key; + int val; +}; + +struct PluginSettings +{ + void Init(); + int name; + bool pause_val; + PluginType type_val; + int optarray; + size_t opts_num; + size_t opts_size; +}; + +class CPluginInfoDatabase : public ITextListener_SMC +{ +public: + CPluginInfoDatabase(); + ~CPluginInfoDatabase(); +public: //ITextListener_SMC + void ReadSMC_ParseStart(); + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); + SMCParseResult ReadSMC_LeavingSection(); +public: + /** + * Returns the number of plugin settings available. + */ + unsigned int GetSettingsNum(); + + /** + * Given an index, returns the plugin settings block if the filename matches. + * Otherwise, returns NULL. + */ + PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename); + + /** + * Given a plugin settings struct and an index, + * returns the given JIT key/value option pair at that index. + * If the input is invalid, key and val will be set to NULL. + */ + void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val); +private: + SMCParseResult MakeError(const char *fmt, ...); +private: + BaseStringTable *m_strtab; + int m_errmsg; + bool in_plugins; + bool in_options; + unsigned int m_infodb; + size_t m_infodb_count; + size_t m_infodb_size; + int cur_plugin; +}; + + +#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_ diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2a374f35..7b4769ec 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -2,6 +2,7 @@ #include "PluginSys.h" #include "LibrarySys.h" #include "sourcemm_api.h" +#include "CTextParsers.h" CPluginManager g_PluginMngr; @@ -288,9 +289,19 @@ void CPluginManager::CPluginIterator::Reset() * PLUGIN MANAGER * ******************/ -void CPluginManager::RefreshOrLoadPlugins(const char *basedir) +void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir) { - IDirectory *dir = g_LibSys.OpenDirectory(basedir); + /* First read in the database of plugin settings */ + SMCParseError err; + unsigned int line, col; + if ((err=g_TextParse.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) + { + /* :TODO: log the error, don't bail out though */ + } + + + //:TODO: move this to a separate recursive function and do stuff + /*IDirectory *dir = g_LibSys.OpenDirectory(basedir); while (dir->MoreFiles()) { if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0)) @@ -300,7 +311,7 @@ void CPluginManager::RefreshOrLoadPlugins(const char *basedir) RefreshOrLoadPlugins(basedir); } } - g_LibSys.CloseDirectory(dir); + g_LibSys.CloseDirectory(dir);*/ } IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) @@ -446,6 +457,215 @@ CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) } } +bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) +{ + /* As an optimization, we do not call strlen, but compute the length in the first pass */ + size_t alias_len = 0; + size_t local_len = 0; + + const char *ptr = alias; + unsigned int alias_explicit_paths = 0; + unsigned int alias_path_end = 0; + while (*ptr != '\0') + { + if (*ptr == '\\' || *ptr == '/') + { + alias_explicit_paths++; + alias_path_end = alias_len; + } + alias_len++; + ptr++; + } + + if (alias_path_end == alias_len - 1) + { + /* Trailing slash is totally invalid here */ + return false; + } + + ptr = localpath; + unsigned int local_explicit_paths = 0; + unsigned int local_path_end = 0; + while (*ptr != '\0') + { + if (*ptr == '\\' || *ptr == '/') + { + local_explicit_paths++; + local_path_end = local_len; + } + local_len++; + ptr++; + } + + /* If the alias has more explicit paths than the real path, + * no match will be possible. + */ + if (alias_explicit_paths > local_explicit_paths) + { + return false; + } + + if (alias_explicit_paths) + { + /* We need to find if the paths match now. For example, these should all match: + * csdm csdm + * csdm optional/csdm + * csdm/ban optional/crab/csdm/ban + */ + const char *aliasptr = alias; + const char *localptr = localpath; + bool match = true; + do + { + if (*aliasptr != *localptr) + { + /* We have to knock one path off */ + local_explicit_paths--; + if (alias_explicit_paths > local_explicit_paths) + { + /* Skip out if we're gonna have an impossible match */ + return false; + } + /* Eat up localptr tokens until we get a result */ + while (((localptr - localpath) < (int)local_path_end) + && *localptr != '/' + && *localptr != '\\') + { + localptr++; + } + /* Check if we hit the end of our searchable area. + * This probably isn't possible because of the path + * count check, but it's a good idea anyway. + */ + if ((localptr - localpath) >= (int)local_path_end) + { + return false; + } else { + /* Consume the slash token */ + localptr++; + } + /* Reset the alias pointer so we can continue consuming */ + aliasptr = alias; + match = false; + continue; + } + /* Note: + * This is safe because if localptr terminates early, aliasptr will too + */ + do + { + /* We should never reach the end of the string because of this check. */ + bool aliasend = (aliasptr - alias) > (int)alias_path_end; + bool localend = (localptr - localpath) > (int)local_path_end; + if (aliasend || localend) + { + if (aliasend && localend) + { + /* we matched, and we can break out now */ + match = true; + break; + } + /* Otherwise, we've hit the end somehow and rest won't match up. Break out. */ + match = false; + break; + } + + /* If we got here, it's safe to compare the next two tokens */ + if (*localptr != *aliasptr) + { + match = false; + break; + } + localptr++; + aliasptr++; + } while (true); + } while (!match); + } + + /* If we got here, it's time to compare filenames */ + const char *aliasptr = alias; + const char *localptr = localpath; + + if (alias_explicit_paths) + { + aliasptr = &alias[alias_path_end + 1]; + } + + if (local_explicit_paths) + { + localptr = &localpath[local_path_end + 1]; + } + + while (true) + { + if (*aliasptr == '*') + { + /* First, see if this is the last character */ + if (aliasptr - alias == alias_len - 1) + { + /* If so, there's no need to match anything else */ + return true; + } + /* Otherwise, we need to search for an appropriate matching sequence in local. + * Note that we only need to search up to the next asterisk. + */ + aliasptr++; + bool match = true; + const char *local_orig = localptr; + do + { + match = true; + while (*aliasptr != '\0' && *aliasptr != '*') + { + /* Since aliasptr is never '\0', localptr hitting the end will fail */ + if (*aliasptr != *localptr) + { + match = false; + break; + } + aliasptr++; + localptr++; + } + if (!match) + { + /* If we didn't get a match, we need to advance the search stream. + * This will let us skip tokens while still searching for another match. + */ + localptr = ++local_orig; + /* Make sure we don't go out of bounds */ + if (*localptr == '\0') + { + break; + } + } + } while (!match); + + if (!match) + { + return false; + } else { + /* If we got a match, move on to the next token */ + continue; + } + } else if (*aliasptr == '\0') { + if (*localptr == '\0' + || + strcmp(localptr, ".smx") == 0) + { + return true; + } else { + return false; + } + } else if (*aliasptr != *localptr) { + return false; + } + aliasptr++; + localptr++; + } + + return true; +} + CPluginManager::~CPluginManager() { //:TODO: we need a good way to free what we're holding diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 51dd8fd8..ced80618 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -6,6 +6,7 @@ #include #include "sm_globals.h" #include "CFunction.h" +#include "PluginInfoDatabase.h" using namespace SourceHook; @@ -60,6 +61,13 @@ private: CFunction **m_pub_funcs; }; +struct PluginDBInfo +{ + bool pause; + PluginType lifetime; + +}; + class CPluginManager : public IPluginManager { friend class CPlugin; @@ -67,6 +75,7 @@ public: CPluginManager(); ~CPluginManager(); public: + /* Implements iterator class */ class CPluginIterator : public IPluginIterator { public: @@ -83,7 +92,7 @@ public: List::iterator current; }; friend class CPluginManager::CPluginIterator; -public: +public: //IPluginManager virtual IPlugin *LoadPlugin(const char *path, bool debug, PluginType type, @@ -96,7 +105,21 @@ public: virtual void AddPluginsListener(IPluginsListener *listener); virtual void RemovePluginsListener(IPluginsListener *listener); public: - virtual void RefreshOrLoadPlugins(const char *basedir); + /** + * Refreshes and loads plugins, usually used on mapchange + */ + virtual void RefreshOrLoadPlugins(const char *config, const char *basedir); + + /** + * Tests a plugin file mask against a local folder. + * The alias is searched backwards from localdir - i.e., given this input: + * csdm/ban csdm/ban + * ban csdm/ban + * csdm/ban optional/csdm/ban + * All of these will return true for an alias match. + * Wildcards are allowed in the filename. + */ + virtual bool TestAliasMatch(const char *alias, const char *localdir); protected: void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); @@ -106,6 +129,7 @@ private: List m_plugins; CStack m_iters; CStack m_funcpool; + CPluginInfoDatabase m_PluginInfo; }; extern CPluginManager g_PluginMngr; From 1ffa6eac9f834fc32716ba7f33c3d3b38e6b163c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:09:43 +0000 Subject: [PATCH 0179/1664] Fixed silly crash bugs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40209 --- core/sm_memtable.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/sm_memtable.cpp b/core/sm_memtable.cpp index 4396eeb0..f2f4ad63 100644 --- a/core/sm_memtable.cpp +++ b/core/sm_memtable.cpp @@ -6,6 +6,7 @@ BaseMemTable::BaseMemTable(unsigned int init_size) { membase = (unsigned char *)malloc(init_size); size = init_size; + tail = 0; } BaseMemTable::~BaseMemTable() @@ -18,11 +19,6 @@ int BaseMemTable::CreateMem(unsigned int addsize, void **addr) { int idx = (int)tail; - if (idx < 0) - { - return -1; - } - while (tail + addsize >= size) { size *= 2; From 36dc72cf04c9f97333ebcf4538045ca4ef18e0d5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:10:02 +0000 Subject: [PATCH 0180/1664] Fixed bug with info database not reading back table properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40210 --- core/systems/PluginInfoDatabase.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index 03e43733..fb78b69d 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -69,14 +69,16 @@ unsigned int CPluginInfoDatabase::GetSettingsNum() PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename) { BaseMemTable *memtab = m_strtab->GetMemTable(); - PluginSettings *table = (PluginSettings *)memtab->GetAddress(m_infodb); + int *table = (int *)memtab->GetAddress(m_infodb); if (!table || index >= m_infodb_count) { return NULL; } - const char *name = m_strtab->GetString(table[index].name); + PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]); + + const char *name = m_strtab->GetString(plugin->name); if (!name) { @@ -88,7 +90,7 @@ PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, cons return NULL; } - return &table[index]; + return plugin; } void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val) @@ -189,7 +191,7 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection() { if (in_plugins) { - if (cur_plugin == -1) + if (cur_plugin != -1) { if (in_options) { From 36312e9779e112401eaa9804bb0f82bf6eaadac6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:13:50 +0000 Subject: [PATCH 0181/1664] Added path formating to LibrarySystem so we don't have to rely on g_SMAPI --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40211 --- core/systems/LibrarySys.cpp | 16 ++++++++++++++++ core/systems/LibrarySys.h | 1 + 2 files changed, 17 insertions(+) diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 9bce6c88..669e950b 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -276,3 +276,19 @@ ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_m return new CLibrary(lib); } + +void LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) +{ + va_list ap; + va_start(ap,fmt); + size_t mylen = vsnprintf(buffer, len, fmt, ap); + va_end(ap); + + for (size_t i=0; i Date: Wed, 13 Dec 2006 11:14:04 +0000 Subject: [PATCH 0182/1664] added path separator chars --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40212 --- core/sm_platform.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/sm_platform.h b/core/sm_platform.h index 1809e908..5a6ea71f 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -18,6 +18,8 @@ #include #define PLATFORM_LIB_EXT "dll" #define PLATFORM_MAX_PATH MAX_PATH +#define PLATFORM_SEP_CHAR '\\' +#define PLATFORM_SEP_ALTCHAR '/' #else if defined __linux__ #define PLATFORM_LINUX #define PLATFORM_POSIX @@ -25,6 +27,8 @@ #include #define PLATFORM_MAX_PATH PATH_MAX #define PLATFORM_LIB_EXT "so" +#define PLATFORM_SEP_CHAR '/' +#define PLATFORM_SEP_ALTCHAR '\\' #endif #endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ From dc60ae49de97ed12e016b7d957110d281260d804 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:14:25 +0000 Subject: [PATCH 0183/1664] Fixed a bug where EOS/EOF was interpreted as a stream error --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40213 --- core/CTextParsers.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 7f922eef..b0720bad 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -233,8 +233,7 @@ SMCParseError CTextParsers::ParseStream_SMC(void *stream, { if (!read) { - err = SMCParse_StreamError; - goto failed; + break; } /* :TODO: do this outside of the main loop somehow From 23a91de75c87ef2d48299f291c26d41a5ffdb05a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:16:20 +0000 Subject: [PATCH 0184/1664] !Added MOSTLY UNTESTED plugin loading Fixed a match bug in TestAliasMatch() Removed pointless implementation of context switching in CPlugin Redesigned how CPlugins are allocated, deallocated, and instantiated. Added a basedir function so all code can reference relative paths. This may be redesigned. Various other changes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40214 --- core/interfaces/IPluginSys.h | 2 +- core/sourcemm_api.cpp | 4 + core/sourcemm_api.h | 3 + core/sourcemod.cpp | 71 ++++-- core/sourcemod.h | 31 +++ core/systems/CFunction.cpp | 10 +- core/systems/PluginSys.cpp | 431 ++++++++++++++++++++++++++--------- core/systems/PluginSys.h | 91 ++++++-- 8 files changed, 491 insertions(+), 152 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 9e0a86a3..6868d176 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -33,8 +33,8 @@ namespace SourceMod Plugin_Running=0, /* Plugin is running */ Plugin_Loaded, /* Plugin is loaded but not initialized */ Plugin_Paused, /* Plugin is paused */ - Plugin_Stopped, /* Plugin is paused for map changes, too */ Plugin_Error, /* Plugin has a blocking error */ + Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */ Plugin_BadLoad, /* Plugin failed to load */ }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 2e862a26..75652a00 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -4,6 +4,8 @@ #include "sourcemod.h" SourceMod_Core g_SourceMod_Core; +IVEngineServer *engine = NULL; +IServerGameDLL *gamedll = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -11,6 +13,8 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen { PLUGIN_SAVEVARS(); + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + return g_SourceMod.InitializeSourceMod(error, maxlen, late); } diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 3089da9e..dff0a5a8 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -2,6 +2,7 @@ #define _INCLUDE_SOURCEMOD_MM_API_H_ #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -27,6 +28,8 @@ public: }; extern SourceMod_Core g_SourceMod_Core; +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 126d805d..b2759613 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -7,6 +7,8 @@ #include "PluginSys.h" #include "ForwardSys.h" +SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); + SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -31,16 +33,21 @@ void ShutdownJIT() g_pJIT->CloseLibrary(); } +SourceModBase::SourceModBase() +{ + m_IsMapLoading = false; +} + bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) { - //:TODO: we need a localinfo system! g_BaseDir.assign(g_SMAPI->GetBaseDir()); + g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); /* Attempt to load the JIT! */ char file[PLATFORM_MAX_PATH]; char myerror[255]; - g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/bin/sourcepawn.jit.x86.%s", - g_BaseDir.c_str(), + g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s", + GetSMBaseDir(), PLATFORM_LIB_EXT ); @@ -112,21 +119,49 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) return false; } - g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str()); - IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max); - IPluginFunction *func = pPlugin->GetFunctionByName("Test"); - IPluginFunction *func2 = pPlugin->GetFunctionByName("Test2"); - cell_t result = 2; - cell_t val = 6; - ParamType types[] = {Param_Cell, Param_CellByRef}; - va_list ap = va_start(ap, late); - CForward *fwd = CForward::CreateForward(NULL, ET_Custom, 2, types, ap); - fwd->AddFunction(func); - fwd->AddFunction(func2); - fwd->PushCell(1); - fwd->PushCellByRef(&val, 0); - fwd->Execute(&result, NULL); - g_PluginMngr.UnloadPlugin(pPlugin); + StartSourceMod(late); return true; } + +void SourceModBase::StartSourceMod(bool late) +{ + /* First initialize the global hooks we need */ + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); + + /* If we're late, automatically load plugins now */ + DoGlobalPluginLoads(); +} + +bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) +{ + m_IsMapLoading = true; + + DoGlobalPluginLoads(); + + m_IsMapLoading = false; + + RETURN_META_VALUE(MRES_IGNORED, true); +} + +void SourceModBase::DoGlobalPluginLoads() +{ + char config_path[PLATFORM_MAX_PATH]; + char plugins_path[PLATFORM_MAX_PATH]; + + g_SMAPI->PathFormat(config_path, + sizeof(config_path), + "%s/configs/plugin_settings.cfg", + GetSMBaseDir()); + g_SMAPI->PathFormat(plugins_path, + sizeof(plugins_path), + "%s/plugins", + GetSMBaseDir()); + + g_PluginMngr.RefreshOrLoadPlugins(config_path, plugins_path); +} + +const char *SourceModBase::GetSMBaseDir() +{ + return m_SMBaseDir; +} diff --git a/core/sourcemod.h b/core/sourcemod.h index f053de65..c7ecd7e5 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -9,11 +9,42 @@ class SourceModBase { +public: + SourceModBase(); public: /** * @brief Initializes SourceMod, or returns an error on failure. */ bool InitializeSourceMod(char *error, size_t err_max, bool late); + + /** + * @brief Starts everything SourceMod needs to run + */ + void StartSourceMod(bool late); + + /** + * @brief Map change hook + */ + bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); + + /** + * @brief Returns whether or not a mapload is in progress + */ + bool IsMapLoading(); + + /** + * @brief Returns the base SourceMod folder. + */ + const char *GetSMBaseDir(); + +private: + /** + * @brief Loading plugins + */ + void DoGlobalPluginLoads(); +private: + char m_SMBaseDir[PLATFORM_MAX_PATH+1]; + bool m_IsMapLoading; }; extern SourceModBase g_SourceMod; diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 1ad5a5d1..abb27173 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -15,7 +15,7 @@ void CFunction::Set(funcid_t funcid, CPlugin *plugin) int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { - IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + IPluginContext *ctx = m_pPlugin->m_ctx.base; while (num_params--) { @@ -79,7 +79,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + IPluginContext *ctx = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; int err; @@ -127,7 +127,7 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *base = m_pPlugin->m_ctx_current.base; + IPluginContext *base = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); int err; @@ -174,7 +174,7 @@ void CFunction::Cancel() return; } - IPluginContext *base = m_pPlugin->m_ctx_current.base; + IPluginContext *base = m_pPlugin->m_ctx.base; while (m_curparam--) { @@ -217,7 +217,7 @@ int CFunction::Execute(cell_t *result) docopies = false; } - IPluginContext *base = m_pPlugin->m_ctx_current.base; + IPluginContext *base = m_pPlugin->m_ctx.base; while (numparams--) { diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 7b4769ec..2937a103 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -2,6 +2,7 @@ #include "PluginSys.h" #include "LibrarySys.h" #include "sourcemm_api.h" +#include "sourcemod.h" #include "CTextParsers.h" CPluginManager g_PluginMngr; @@ -10,86 +11,204 @@ CPluginManager::CPluginManager() { } -CPlugin *CPlugin::CreatePlugin(const char *file, - bool debug_default, - PluginType type, - char *error, - size_t maxlen) +CPlugin::CPlugin(const char *file) { - static unsigned int MySerial = 0; - FILE *fp = fopen(file, "rb"); + static int MySerial = 0; + + m_type = PluginType_Private; + m_status = Plugin_Uncompiled; + m_serial = ++MySerial; + m_plugin = NULL; + m_funcsnum = 0; + m_priv_funcs = NULL; + m_pub_funcs = NULL; + m_errormsg[256] = '\0'; + snprintf(m_filename, sizeof(m_filename), "%s", file); +} + +CPlugin::~CPlugin() +{ + if (m_ctx.base) + { + g_pSourcePawn->FreeBaseContext(m_ctx.base); + m_ctx.base = NULL; + } + if (m_ctx.ctx) + { + m_ctx.vm->FreeContext(m_ctx.ctx); + m_ctx.ctx = NULL; + } + if (m_ctx.co) + { + m_ctx.vm->AbortCompilation(m_ctx.co); + m_ctx.co = NULL; + } + + if (m_plugin) + { + g_pSourcePawn->FreeFromMemory(m_plugin); + m_plugin = NULL; + } + + if (m_pub_funcs) + { + for (uint32_t i=0; iinfo.publics_num; i++) + { + g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]); + } + delete [] m_pub_funcs; + m_pub_funcs = NULL; + } + + if (m_priv_funcs) + { + for (unsigned int i=0; im_errormsg, sizeof(pPlugin->m_errormsg), "Unable to open file"); + pPlugin->m_status = Plugin_BadLoad; + return pPlugin; + } } int err; sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err); if (pl == NULL) { - snprintf(error, maxlen, "Could not load plugin, error %d", err); - return NULL; + fclose(fp); + if (error) + { + snprintf(error, maxlength, "Error %d while parsing plugin", err); + return NULL; + } else { + CPlugin *pPlugin = new CPlugin(file); + snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Error %d while parsing plugin", err); + pPlugin->m_status = Plugin_BadLoad; + return pPlugin; + } } fclose(fp); - ICompilation *co = g_pVM->StartCompilation(pl); - - if (debug_default) - { - if (!g_pVM->SetCompilationOption(co, "debug", "1")) - { - g_pVM->AbortCompilation(co); - snprintf(error, maxlen, "Could not set plugin to debug mode"); - return NULL; - } - } + CPlugin *pPlugin = new CPlugin(file); + pPlugin->m_plugin = pl; + return pPlugin; +} - sp_context_t *ctx = g_pVM->CompileToContext(co, &err); - if (ctx == NULL) +ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm) +{ + if (!m_plugin) { - snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err); return NULL; } - IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx); - CPlugin *pPlugin = new CPlugin; - - snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file); - pPlugin->m_debugging = debug_default; - pPlugin->m_ctx_current.base = base; - pPlugin->m_ctx_current.ctx = ctx; - pPlugin->m_type = type; - pPlugin->m_serial = ++MySerial; - pPlugin->m_status = Plugin_Loaded; - pPlugin->m_plugin = pl; - - pPlugin->UpdateInfo(); - - ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin; - - /* Build function information loosely */ - pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx); - - if (pPlugin->m_funcsnum) + /* :NOTICE: We will eventually need to change these natives + * for swapping in new contexts + */ + if (m_ctx.co || m_ctx.ctx) { - pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum]; - memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum); - } else { - pPlugin->m_priv_funcs = NULL; + return NULL; } - if (pl->info.publics_num) + m_status = Plugin_Uncompiled; + + m_ctx.vm = vm; + m_ctx.co = vm->StartCompilation(m_plugin); + + return m_ctx.co; +} + +void CPlugin::CancelMyCompile() +{ + if (!m_ctx.co) { - pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num]; - memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num); - } else { - pPlugin->m_pub_funcs = NULL; + return; } - return pPlugin; + m_ctx.vm->AbortCompilation(m_ctx.co); + m_ctx.co = NULL; + m_ctx.vm = NULL; +} + +bool CPlugin::FinishMyCompile(char *error, size_t maxlength) +{ + if (!m_ctx.co) + { + return false; + } + + int err; + m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err); + if (!m_ctx.ctx) + { + memset(&m_ctx, 0, sizeof(m_ctx)); + if (!error) + { + SetErrorState(Plugin_Error, "Failed to compile (error %d)", err); + } else { + snprintf(error, maxlength, "Failed to compile (error %d)", err); + } + return false; + } + + m_ctx.base = g_pSourcePawn->CreateBaseContext(m_ctx.ctx); + m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; + + m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx); + + /** + * Note: Since the m_plugin member will never change, + * it is safe to assume the function count will never change + */ + if (m_funcsnum && m_priv_funcs == NULL) + { + m_priv_funcs = new CFunction *[m_funcsnum]; + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); + } else { + m_priv_funcs = NULL; + } + + if (m_plugin->info.publics_num && m_pub_funcs == NULL) + { + m_pub_funcs = new CFunction *[m_plugin->info.publics_num]; + memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num); + } else { + m_pub_funcs = NULL; + } + + UpdateInfo(); + + return true; +} + +void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) +{ + m_status = status; + + va_list ap; + va_start(ap, error_fmt); + vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); + va_end(ap); } IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) @@ -113,7 +232,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) } else { func_id >>= 1; unsigned int index; - if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index)) + if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index)) { return NULL; } @@ -131,7 +250,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) { uint32_t index; - IPluginContext *base = m_ctx_current.base; + IPluginContext *base = m_ctx.base; if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) { @@ -195,12 +314,12 @@ const sp_plugin_t *CPlugin::GetPluginStructure() const IPluginContext *CPlugin::GetBaseContext() const { - return m_ctx_current.base; + return m_ctx.base; } sp_context_t *CPlugin::GetContext() const { - return m_ctx_current.ctx; + return m_ctx.ctx; } const char *CPlugin::GetFilename() const @@ -230,7 +349,12 @@ PluginStatus CPlugin::GetStatus() const bool CPlugin::IsDebugging() const { - return m_debugging; + if (!m_ctx.ctx) + { + return false; + } + + return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); } bool CPlugin::SetPauseState(bool paused) @@ -299,30 +423,158 @@ void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedi /* :TODO: log the error, don't bail out though */ } + LoadPluginsFromDir(basedir, NULL); +} + +void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath) +{ + char base_path[PLATFORM_MAX_PATH+1]; + + /* Form the current path to start reading from */ + if (localpath == NULL) + { + g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir); + } else { + g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath); + } + + IDirectory *dir = g_LibSys.OpenDirectory(base_path); + + if (!dir) + { + //:TODO: write a logger and LOG THIS UP, BABY + //g_LibSys.GetPlatformError(error, err_max); + return; + } - //:TODO: move this to a separate recursive function and do stuff - /*IDirectory *dir = g_LibSys.OpenDirectory(basedir); while (dir->MoreFiles()) { - if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0)) + if (dir->IsEntryDirectory() + && (strcmp(dir->GetEntryName(), ".") != 0) + && (strcmp(dir->GetEntryName(), "..") != 0) + && (strcmp(dir->GetEntryName(), "disabled") != 0) + && (strcmp(dir->GetEntryName(), "optional") != 0)) { - char path[PLATFORM_MAX_PATH+1]; - g_SMAPI->PathFormat(path, sizeof(path)-1, "%s/%s", basedir, dir->GetEntryName()); - RefreshOrLoadPlugins(basedir); + char new_local[PLATFORM_MAX_PATH+1]; + if (localpath == NULL) + { + /* If no path yet, don't add a former slash */ + snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName()); + } else { + g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName()); + } + LoadPluginsFromDir(basedir, new_local); + } else if (dir->IsEntryFile()) { + const char *name = dir->GetEntryName(); + size_t len = strlen(name); + if (len < 4 + || strcmp(&name[len-4], ".smx") != 0) + { + continue; + } + /* If the filename matches, load the plugin */ + char plugin[PLATFORM_MAX_PATH+1]; + if (localpath == NULL) + { + snprintf(plugin, sizeof(plugin), "%s", name); + } else { + g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name); + } + LoadAutoPlugin(plugin); + } + dir->NextEntry(); + } + g_LibSys.CloseDirectory(dir); +} + +void CPluginManager::LoadAutoPlugin(const char *file) +{ + CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0); + + assert(pPlugin != NULL); + + pPlugin->m_type = PluginType_MapUpdated; + + ICompilation *co = NULL; + + if (pPlugin->m_status == Plugin_Uncompiled) + { + co = pPlugin->StartMyCompile(g_pVM); + } + + PluginSettings *pset; + unsigned int setcount = m_PluginInfo.GetSettingsNum(); + for (unsigned int i=0; im_type = pset->type_val; + if (co) + { + for (unsigned int j=0; jopts_num; j++) + { + const char *key, *val; + m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val); + if (!key || !val) + { + continue; + } + if (!g_pVM->SetCompilationOption(co, key, val)) + { + pPlugin->SetErrorState(Plugin_Error, "Unable to set option (key \"%s\") (value \"%s\")", key, val); + pPlugin->CancelMyCompile(); + co = NULL; + break; + } + } } } - g_LibSys.CloseDirectory(dir);*/ + + if (co) + { + pPlugin->FinishMyCompile(NULL, 0); + co = NULL; + } + + InitAndAddPlugin(pPlugin); } IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) { - CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max); + CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max); if (!pPlugin) { return NULL; } + ICompilation *co = pPlugin->StartMyCompile(g_pVM); + if (!co || (debug && !g_pVM->SetCompilationOption(co, "debug", "1"))) + { + snprintf(error, err_max, "Unable to start%s compilation", debug ? " debug" : ""); + pPlugin->CancelMyCompile(); + delete pPlugin; + return NULL; + } + + if (!pPlugin->FinishMyCompile(error, err_max)) + { + delete pPlugin; + return NULL; + } + + pPlugin->m_type = type; + + InitAndAddPlugin(pPlugin); + + return pPlugin; +} + +void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin) +{ m_plugins.push_back(pPlugin); List::iterator iter; @@ -334,8 +586,6 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ } /* :TODO: a lot more... */ - - return pPlugin; } bool CPluginManager::UnloadPlugin(IPlugin *plugin) @@ -352,45 +602,6 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener->OnPluginDestroyed(pPlugin); } - if (pPlugin->m_pub_funcs) - { - for (uint32_t i=0; im_plugin->info.publics_num; i++) - { - g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_pub_funcs[i]); - } - delete [] pPlugin->m_pub_funcs; - pPlugin->m_pub_funcs = NULL; - } - - if (pPlugin->m_priv_funcs) - { - for (unsigned int i=0; im_funcsnum; i++) - { - g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_priv_funcs[i]); - } - delete [] pPlugin->m_priv_funcs; - pPlugin->m_priv_funcs = NULL; - } - - if (pPlugin->m_ctx_current.base) - { - g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base); - } - if (pPlugin->m_ctx_backup.base) - { - g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base); - } - if (pPlugin->m_ctx_current.ctx) - { - pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx); - } - if (pPlugin->m_ctx_backup.ctx) - { - pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx); - } - - g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin); - delete pPlugin; return true; @@ -477,7 +688,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) ptr++; } - if (alias_path_end == alias_len - 1) + if (alias_explicit_paths && alias_path_end == alias_len - 1) { /* Trailing slash is totally invalid here */ return false; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index ced80618..4791ef2d 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -10,21 +10,47 @@ using namespace SourceHook; +/** + * NOTES: + * + * Currently this system needs a lot of work but it's good skeletally. Plugin creation + * is done without actually compiling anything. This is done by Load functions in the + * manager. This will need a rewrite when we add context switching. + * + * The plugin object itself has a few things to note. The most important is that it stores + * a table of function objects. The manager marshals allocation and freeing of these objects. + * The plugin object can be in erroneous states, they are: + * Plugin_Error --> Some error occurred any time during or after compilation. + * This error can be cleared since the plugin itself is valid. + * However, the state itself being set prevents any runtime action. + * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it. + * + * If a plugin fails to load externally, it is never added to the internal tracker. However, + * plugins that failed to load from the internal loading mechanism are always tracked. This + * allows users to see which automatically loaded plugins failed, and makes the interface a bit + * more flexible. + */ + #define SM_CONTEXTVAR_MYSELF 0 struct ContextPair { - ContextPair() : base(NULL), ctx(NULL) + ContextPair() : base(NULL), ctx(NULL), co(NULL) { }; IPluginContext *base; sp_context_t *ctx; + ICompilation *co; + IVirtualMachine *vm; }; class CPlugin : public IPlugin { friend class CPluginManager; friend class CFunction; +public: + CPlugin(const char *file); + ~CPlugin(); public: virtual PluginType GetType() const; virtual SourcePawn::IPluginContext *GetBaseContext() const; @@ -39,18 +65,34 @@ public: virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); public: - static CPlugin *CreatePlugin(const char *file, - bool debug_default, - PluginType life, - char *error, - size_t maxlen); + /** + * Creates a plugin object with default values. + * If an error buffer is specified, and an error occurs, the error will be copied to the buffer + * and NULL will be returned. + * If an error buffer is not specified, the error will be copied to an internal buffer and + * a valid (but error-stated) CPlugin will be returned. + */ + static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength); +public: + /** + * Starts the initial compilation of a plugin. + * Returns false if another compilation exists or there is a current context set. + */ + ICompilation *StartMyCompile(IVirtualMachine *vm); + /** + * Finalizes a compilation. If error buffer is NULL, the error is saved locally. + */ + bool FinishMyCompile(char *error, size_t maxlength); + void CancelMyCompile(); + /** + * Sets an error state on the plugin + */ + void SetErrorState(PluginStatus status, const char *error_fmt, ...); protected: void UpdateInfo(); private: - ContextPair m_ctx_current; - ContextPair m_ctx_backup; + ContextPair m_ctx; PluginType m_type; - bool m_debugging; char m_filename[PLATFORM_MAX_PATH+1]; PluginStatus m_status; unsigned int m_serial; @@ -59,13 +101,7 @@ private: unsigned int m_funcsnum; CFunction **m_priv_funcs; CFunction **m_pub_funcs; -}; - -struct PluginDBInfo -{ - bool pause; - PluginType lifetime; - + char m_errormsg[256]; }; class CPluginManager : public IPluginManager @@ -108,7 +144,7 @@ public: /** * Refreshes and loads plugins, usually used on mapchange */ - virtual void RefreshOrLoadPlugins(const char *config, const char *basedir); + void RefreshOrLoadPlugins(const char *config, const char *basedir); /** * Tests a plugin file mask against a local folder. @@ -119,8 +155,27 @@ public: * All of these will return true for an alias match. * Wildcards are allowed in the filename. */ - virtual bool TestAliasMatch(const char *alias, const char *localdir); + bool TestAliasMatch(const char *alias, const char *localdir); +private: + /** + * Recursively loads all plugins in the given directory. + */ + void LoadPluginsFromDir(const char *basedir, const char *localdir); + + /** + * Loads a plugin using automatic information. + * The file must be relative to the plugins folder. + */ + void LoadAutoPlugin(const char *file); + + /** + * Adds and initializes a plugin object. This is wrapped by LoadPlugin functions. + */ + void InitAndAddPlugin(CPlugin *pPlugin); protected: + /** + * Caching internal objects + */ void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); void ReleaseFunctionToPool(CFunction *func); From a93faa3cbf1d0715fbe5dda490682e74641b3a8d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 13 Dec 2006 11:19:46 +0000 Subject: [PATCH 0185/1664] exposed new pathformat function to ILibrarySys --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40215 --- core/interfaces/ILibrarySys.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h index aed3379a..c59bc50e 100644 --- a/core/interfaces/ILibrarySys.h +++ b/core/interfaces/ILibrarySys.h @@ -131,6 +131,18 @@ namespace SourceMod * @param err_max Maximum length of error buffer. */ virtual void GetPlatformError(char *error, size_t err_max) =0; + + /** + * @brief Formats a string similar to snprintf(), except + * corrects all non-platform compatible path separators to be + * the correct platform character. + * + * @param buffer Output buffer pointer. + * @param maxlength Output buffer size. + * @param pathfmt Format string of path. + * @param ... Format string arguments. + */ + virtual void PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0; }; }; From 90d1f4495e48d55bff2464aa6aa6f1a321e85353 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 15 Dec 2006 13:38:04 +0000 Subject: [PATCH 0186/1664] Added global class initialization automation Finalized basics of plugin loading Began redoing how dependencies will be tracked Renamed some bad names Finished some stuff in ForwardSys --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40216 --- core/interfaces/IModuleSys.h | 17 +- core/interfaces/IPluginFunction.h | 6 +- core/interfaces/IPluginSys.h | 8 +- core/interfaces/IShareSys.h | 80 ++------- core/msvc8/sourcemod_mm.vcproj | 8 + core/sm_platform.h | 3 + core/sm_trie.cpp | 50 ++++++ core/sm_trie.h | 1 + core/sourcemod.cpp | 22 ++- core/sourcemod.h | 39 +++++ core/systems/CFunction.cpp | 6 +- core/systems/ForwardSys.cpp | 59 ++++++- core/systems/ForwardSys.h | 14 +- core/systems/PluginInfoDatabase.cpp | 2 +- core/systems/PluginSys.cpp | 241 ++++++++++++++++++++++++---- core/systems/PluginSys.h | 84 +++++++++- 16 files changed, 509 insertions(+), 131 deletions(-) diff --git a/core/interfaces/IModuleSys.h b/core/interfaces/IModuleSys.h index 6b4eabe4..fa13f3ba 100644 --- a/core/interfaces/IModuleSys.h +++ b/core/interfaces/IModuleSys.h @@ -8,16 +8,12 @@ namespace SourceMod { class IModuleInterface; - class IModule : public IUnloadableParent + class IModule { - public: - virtual UnloadableParentType GetParentType() - { - return ParentType_Module; - } public: virtual IModuleInterface *GetModuleInfo() =0; virtual const char *GetFilename() =0; + virtual IdentityToken_t GetIdentityToken() =0; }; class IModuleInterface @@ -27,13 +23,19 @@ namespace SourceMod * @brief Called when the module is loaded. * * @param me Pointer back to module. + * @param token Identity token handle. * @param sys Pointer to interface sharing system of SourceMod. * @param error Error buffer to print back to, if any. * @param err_max Maximum size of error buffer. * @param late If this module was loaded "late" (i.e. manually). * @return True if load should continue, false otherwise. */ - virtual bool OnModuleLoad(IModule *me, IShareSys *sys, char *error, size_t err_max, bool late) =0; + virtual bool OnModuleLoad(IModule *me, + IdentityToken_t token, + IShareSys *sys, + char *error, + size_t err_max, + bool late) =0; /** * @brief Called when the module is unloaded. @@ -51,7 +53,6 @@ namespace SourceMod * @param pause True if pausing, false if unpausing. */ virtual void OnPauseChange(bool pause) =0; - public: virtual const char *GetModuleName() =0; virtual const char *GetModuleVersion() =0; diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index e0716c79..7174baf6 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -5,10 +5,10 @@ namespace SourceMod { - #define SM_FUNCFLAG_COPYBACK (1<<0) /* Copy an array/reference back after call */ + #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ - #define SP_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ - #define SP_STRING_COPY (1<<1) /* String should be copied into the plugin */ + #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ + #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ /** * @brief Represents what a function needs to implement in order to be callable. diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 6868d176..b3eac81a 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -25,15 +25,19 @@ namespace SourceMod const char *url; } sm_plugininfo_t; + /** * @brief Describes the usability status of a plugin. */ enum PluginStatus { Plugin_Running=0, /* Plugin is running */ - Plugin_Loaded, /* Plugin is loaded but not initialized */ - Plugin_Paused, /* Plugin is paused */ + /* All states below are unexecutable */ + Plugin_Paused, /* Plugin is loaded but paused */ + /* All states below do not have all natives */ + Plugin_Loaded, /* Plugin has passed loading and can be finalized */ Plugin_Error, /* Plugin has a blocking error */ + Plugin_Created, /* Plugin is created but not initialized */ Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */ Plugin_BadLoad, /* Plugin failed to load */ }; diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index 7e08f72c..d81a0fee 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -1,8 +1,11 @@ #ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ #define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ +#include + namespace SourceMod { + typedef unsigned int IdentityToken_t; /** * @brief Defines the base functionality required by a shared interface. */ @@ -37,48 +40,6 @@ namespace SourceMod } }; - enum UnloadableParentType - { - ParentType_Module, - ParentType_Plugin - }; - - /** - * @brief Denotes a top-level unloadable object. - */ - class IUnloadableParent - { - public: - virtual UnloadableParentType GetParentType() =0; - - virtual void *GetParentToken() =0; - - /** - * @brief Called when an interface this object has requested is removed. - * - * @param pIface Interface being removed. - */ - virtual void OnInterfaceUnlink(SMInterface *pIface) =0; - protected: - void *m_parent_token; - }; - - /** - * @brief Listens for unlinked objects. - */ - class IUnlinkListener - { - public: - /** - * @brief Called when a parent object is unloaded. - * - * @param parent The parent object which is dying. - */ - virtual void OnParentUnlink(IUnloadableParent *parent) - { - } - }; - /** * @brief Tracks dependencies and fires dependency listeners. */ @@ -89,9 +50,9 @@ namespace SourceMod * @brief Adds an interface to the global interface system * * @param iface Interface pointer (must be unique). - * @param parent Parent unloadable token given to the module/interface. + * @param token Parent token of the module/interface. */ - virtual bool AddInterface(SMInterface *iface, IUnloadableParent *parent) =0; + virtual bool AddInterface(SMInterface *iface, IdentityToken_t token) =0; /** * @brief Requests an interface from the global interface system. @@ -99,36 +60,21 @@ namespace SourceMod * * @param iface_name Interface name. * @param iface_vers Interface version to attempt to match. - * @param me Object requesting this interface, in order to track dependencies. + * @param token Object requesting this interface, in order to track dependencies. * @param pIface Pointer to store the return value in. */ virtual bool RequestInterface(const char *iface_name, - unsigned int iface_vers, - IUnloadableParent *me, + unsigned int iface_vers, + IdentityToken_t token, void **pIface) =0; /** - * @brief Unloads an interface. - * - * @param iface Interface pointer. - * @param parent Security token, trivial measure to prevent accidental unloads. - * This token must match the one used with AddInterface(). + * @brief Adds a list of natives to the global native pool. + * + * @param token Identity token of parent object. + * @param natives Array of natives to add, NULL terminated. */ - virtual void RemoveInterface(SMInterface *iface, IUnloadableParent *parent) =0; - - /** - * @brief Adds an unlink listener. - * - * @param pListener Listener pointer. - */ - virtual void AddUnlinkListener(IUnlinkListener *pListener) =0; - - /** - * @brief Removes an unlink listener. - * - * @param pListener Listener pointer. - */ - virtual void RemoveUnlinkListener(IUnlinkListener *pListener) =0; + virtual void AddNatives(IdentityToken_t token, const sp_nativeinfo_t *natives[]) =0; }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0a482bdd..59d92a39 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -186,6 +186,10 @@ RelativePath="..\sm_memtable.cpp" > + + @@ -216,6 +220,10 @@ RelativePath="..\sm_platform.h" > + + diff --git a/core/sm_platform.h b/core/sm_platform.h index 5a6ea71f..2487611f 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -13,6 +13,9 @@ #if !defined snprintf #define snprintf _snprintf #endif +#if !defined stat +#define stat _stat +#endif #define strcasecmp strcmpi #include #include diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index b0dbd8d5..7e92c5d9 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -266,6 +266,56 @@ void sm_trie_destroy(Trie *trie) delete trie; } +bool sm_trie_delete(Trie *trie, const char *key) +{ + unsigned int lastidx = 1; /* the last node index */ + unsigned int curidx; /* current node index */ + const char *keyptr = key; /* input stream at current token */ + TrieNode *node = NULL; /* current node being processed */ + TrieNode *base = trie->base; + + if (!*key) + { + return false; + } + + /* Start traversing at the root node */ + do + { + /* Find where the next character is, then advance */ + curidx = base[lastidx].idx; + node = &base[curidx]; + curidx += charval(*keyptr); + node = &base[curidx]; + keyptr++; + + /* Check if this slot is supposed to be empty or is a collision */ + if ((curidx > trie->baseSize) || node->mode == Node_Unused || node->parent != lastidx) + { + return false; + } else if (node->mode == Node_Term) { + char *term = &trie->stringtab[node->idx]; + if (strcmp(keyptr, term) == 0) + { + break; + } + } + lastidx = curidx; + } while (*keyptr != '\0'); + + assert(node != NULL); + + if (!node->valset) + { + return false; + } + + node->valset = false; + node->value = NULL; + + return true; +} + bool sm_trie_retrieve(Trie *trie, const char *key, void **value) { unsigned int lastidx = 1; /* the last node index */ diff --git a/core/sm_trie.h b/core/sm_trie.h index 9193f59e..a6e0c0fe 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -7,5 +7,6 @@ Trie *sm_trie_create(); void sm_trie_destroy(Trie *trie); bool sm_trie_insert(Trie *trie, const char *key, void *value); bool sm_trie_retrieve(Trie *trie, const char *key, void **value); +bool sm_trie_delete(Trie *trie, const char *key); #endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index b2759613..f8d544dd 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -130,12 +130,17 @@ void SourceModBase::StartSourceMod(bool late) SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); /* If we're late, automatically load plugins now */ - DoGlobalPluginLoads(); + if (late) + { + m_IsLateLoadInMap = late; + DoGlobalPluginLoads(); + } } bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { m_IsMapLoading = true; + m_IsLateLoadInMap = false; DoGlobalPluginLoads(); @@ -158,10 +163,23 @@ void SourceModBase::DoGlobalPluginLoads() "%s/plugins", GetSMBaseDir()); - g_PluginMngr.RefreshOrLoadPlugins(config_path, plugins_path); + g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); +} + +bool SourceModBase::IsLateLoadInMap() +{ + return m_IsLateLoadInMap; } const char *SourceModBase::GetSMBaseDir() { return m_SMBaseDir; } + +SMGlobalClass *SMGlobalClass::head = NULL; + +SMGlobalClass::SMGlobalClass() +{ + m_pGlobalClassNext = SMGlobalClass::head; + SMGlobalClass::head = this; +} diff --git a/core/sourcemod.h b/core/sourcemod.h index c7ecd7e5..238531c4 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -37,6 +37,10 @@ public: */ const char *GetSMBaseDir(); + /** + * @brief Returns whether our load in this map is late. + */ + bool IsLateLoadInMap(); private: /** * @brief Loading plugins @@ -45,6 +49,41 @@ private: private: char m_SMBaseDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; + bool m_IsLateLoadInMap; +}; + +/** + * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod + */ +class SMGlobalClass +{ + friend class SourceModBase; +public: + SMGlobalClass(); +public: + /** + * @brief Called when SourceMod is initially loading + */ + virtual void OnSourceModStartup(bool late) + { + } + + /** + * @brief Called after all global classes have initialized + */ + virtual void OnSourceModAllInitialized() + { + } + + /** + * @brief Called when SourceMod is shutting down + */ + virtual void OnSourceModShutdown() + { + } +private: + SMGlobalClass *m_pGlobalClassNext; + static SMGlobalClass *head; }; extern SourceModBase g_SourceMod; diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index abb27173..1d6bf769 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -112,7 +112,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr int CFunction::PushString(const char *string) { - return _PushString(string, SP_STRING_COPY, 0, strlen(string)+1); + return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1); } int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) @@ -141,12 +141,12 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ m_params[m_curparam] = info->local_addr; m_curparam++; /* Prevent a leak */ - if (!(sz_flags & SP_STRING_COPY)) + if (!(sz_flags & SM_PARAM_STRING_COPY)) { goto skip_localtostr; } - if (sz_flags & SP_STRING_UTF8) + if (sz_flags & SM_PARAM_STRING_UTF8) { if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) { diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 7e3feb67..d0dd7b26 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -28,6 +28,16 @@ CForwardManager g_Forwards; * X Push vararg strings (copyback tested = :TODO:) */ +void CForwardManager::OnSourceModAllInitialized() +{ + g_PluginSys.AddPluginsListener(this); +} + +void CForwardManager::OnSourceModShutdown() +{ + g_PluginSys.RemovePluginsListener(this); +} + IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...) { CForward *fwd; @@ -38,6 +48,11 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned va_end(ap); + if (fwd) + { + m_managed.push_back(fwd); + } + return fwd; } @@ -51,9 +66,43 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType va_end(ap); + if (fwd) + { + m_unmanaged.push_back(fwd); + } + return fwd; } +void CForwardManager::OnPluginLoaded(IPlugin *plugin) +{ + /* Attach any globally managed forwards */ + List::iterator iter; + CForward *fwd; + + for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) + { + fwd = (*iter); + IPluginFunction *pFunc = plugin->GetFunctionByName(fwd->GetForwardName()); + if (pFunc) + { + fwd->AddFunction(pFunc); + } + } +} + +void CForwardManager::OnPluginUnloaded(IPlugin *plugin) +{ + List::iterator iter; + CForward *fwd; + + for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) + { + fwd = (*iter); + fwd->RemoveFunctionsOfPlugin(plugin); + } +} + IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng) { List::iterator iter; @@ -243,9 +292,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) } } - /* Call the function and deal with the return value. - * :TODO: only pass reader if we know we have an array in the list - */ + /* Call the function and deal with the return value. */ if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE) { bool handled = false; @@ -478,7 +525,7 @@ int CForward::PushString(const char *string) m_params[m_curparam].pushedas = Param_String; } - _Int_PushString((cell_t *)string, strlen(string)+1, SP_STRING_COPY, 0); + _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0); m_curparam++; return SP_ERROR_NONE; @@ -521,7 +568,7 @@ void CForward::Cancel() bool CForward::AddFunction(sp_context_t *ctx, funcid_t index) { - IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx); + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); if (!pPlugin) { return false; @@ -590,7 +637,7 @@ bool CForward::AddFunction(IPluginFunction *func) return false; } - //:TODO: eventually we will tell the plugin we're using it + //:TODO: eventually we will tell the plugin we're using it [?] m_functions.push_back(func); return true; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index a3dfd5c9..4748e9fb 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -6,6 +6,7 @@ #include "sm_globals.h" #include #include +#include "sourcemod.h" using namespace SourceHook; @@ -83,10 +84,13 @@ protected: int m_errstate; }; -class CForwardManager : public IForwardManager +class CForwardManager : + public IForwardManager, + public IPluginsListener, + public SMGlobalClass { friend class CForward; -public: +public: //IForwardManager virtual IForward *CreateForward(const char *name, ExecType et, unsigned int num_params, @@ -99,6 +103,12 @@ public: ...); virtual IForward *FindForward(const char *name, IChangeableForward **ifchng); virtual void ReleaseForward(IForward *forward); +public: //IPluginsListener + virtual void OnPluginLoaded(IPlugin *plugin); + virtual void OnPluginUnloaded(IPlugin *plugin); +public: //SMGlobalClass + virtual void OnSourceModAllInitialized(); + virtual void OnSourceModShutdown(); protected: CForward *ForwardMake(); void ForwardFree(CForward *fwd); diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index fb78b69d..5b7d1ac6 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -85,7 +85,7 @@ PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, cons return NULL; } - if (!g_PluginMngr.TestAliasMatch(name, filename)) + if (!g_PluginSys.TestAliasMatch(name, filename)) { return NULL; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2937a103..9cbc5f74 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -5,11 +5,7 @@ #include "sourcemod.h" #include "CTextParsers.h" -CPluginManager g_PluginMngr; - -CPluginManager::CPluginManager() -{ -} +CPluginManager g_PluginSys; CPlugin::CPlugin(const char *file) { @@ -54,7 +50,7 @@ CPlugin::~CPlugin() { for (uint32_t i=0; iinfo.publics_num; i++) { - g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]); + g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]); } delete [] m_pub_funcs; m_pub_funcs = NULL; @@ -64,7 +60,7 @@ CPlugin::~CPlugin() { for (unsigned int i=0; iGetPublicByIndex(index, &pub); if (pub) { - pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this); + pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this); m_pub_funcs[index] = pFunc; } } @@ -307,6 +305,77 @@ void CPlugin::UpdateInfo() m_info.version = m_info.version ? m_info.version : ""; } +void CPlugin::Call_OnPluginInit() +{ + if (m_status != Plugin_Loaded) + { + return; + } + + m_status = Plugin_Running; + + int err; + cell_t result; + IPluginFunction *pFunction = GetFunctionByName("OnPluginInit"); + if (!pFunction) + { + return; + } + + /* :TODO: push our own handle */ + pFunction->PushCell(0); + if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) + { + /* :TODO: log into debugger instead */ + SetErrorState(Plugin_Error, "Runtime error %d", err); + } +} + +bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) +{ + if (m_status != Plugin_Created) + { + return false; + } + + if (!error) + { + error = m_errormsg; + maxlength = sizeof(m_errormsg); + } + + int err; + cell_t result; + IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad"); + + if (!pFunction) + { + return true; + } + + pFunction->PushCell(0); //:TODO: handle to ourself + pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0); + pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK); + pFunction->PushCell(maxlength); + if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) + { + /* :TODO: debugging system */ + snprintf(error, maxlength, "Plugin load returned run time error %d", err); + m_status = Plugin_Error; + return false; + } + + if (!result) + { + m_status = Plugin_Error; + return false; + } + + m_status = Plugin_Loaded; + + return true; +} + const sp_plugin_t *CPlugin::GetPluginStructure() const { return m_plugin; @@ -397,7 +466,7 @@ void CPluginManager::CPluginIterator::NextPlugin() void CPluginManager::CPluginIterator::Release() { - g_PluginMngr.ReleaseIterator(this); + g_PluginSys.ReleaseIterator(this); } CPluginManager::CPluginIterator::~CPluginIterator() @@ -413,7 +482,20 @@ void CPluginManager::CPluginIterator::Reset() * PLUGIN MANAGER * ******************/ -void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir) +CPluginManager::CPluginManager() +{ + m_LoadLookup = sm_trie_create(); + m_AllPluginsLoaded = false; +} + +CPluginManager::~CPluginManager() +{ + //:TODO: we need a good way to free what we're holding + sm_trie_destroy(m_LoadLookup); +} + + +void CPluginManager::LoadAll_FirstPass( const char *config, const char *basedir ) { /* First read in the database of plugin settings */ SMCParseError err; @@ -467,29 +549,51 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa } else if (dir->IsEntryFile()) { const char *name = dir->GetEntryName(); size_t len = strlen(name); - if (len < 4 - || strcmp(&name[len-4], ".smx") != 0) + if (len >= 4 + && strcmp(&name[len-4], ".smx") == 0) { - continue; + /* If the filename matches, load the plugin */ + char plugin[PLATFORM_MAX_PATH+1]; + if (localpath == NULL) + { + snprintf(plugin, sizeof(plugin), "%s", name); + } else { + g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name); + } + LoadAutoPlugin(plugin); } - /* If the filename matches, load the plugin */ - char plugin[PLATFORM_MAX_PATH+1]; - if (localpath == NULL) - { - snprintf(plugin, sizeof(plugin), "%s", name); - } else { - g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name); - } - LoadAutoPlugin(plugin); } dir->NextEntry(); } g_LibSys.CloseDirectory(dir); } +//well i have discovered that gabe newell is very fat, so i wrote this comment now +//:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin() void CPluginManager::LoadAutoPlugin(const char *file) { - CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0); + /** + * Does this plugin already exist? + */ + CPlugin *pPlugin; + if (sm_trie_retrieve(m_LoadLookup, file, (void **)&pPlugin)) + { + /* First check the type */ + PluginType type = pPlugin->GetType(); + if (type == PluginType_Private + || type == PluginType_Global) + { + return; + } + /* Check to see if we should try reloading it */ + if (pPlugin->GetStatus() == Plugin_BadLoad + || pPlugin->GetStatus() == Plugin_Error) + { + UnloadPlugin(pPlugin); + } + } + + pPlugin = CPlugin::CreatePlugin(file, NULL, 0); assert(pPlugin != NULL); @@ -539,12 +643,36 @@ void CPluginManager::LoadAutoPlugin(const char *file) co = NULL; } - InitAndAddPlugin(pPlugin); + /* We don't care about the return value */ + if (pPlugin->GetStatus() == Plugin_Created) + { + AddCoreNativesToPlugin(pPlugin); + pPlugin->Call_AskPluginLoad(NULL, 0); + } + + AddPlugin(pPlugin); } IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) { - CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max); + /* See if this plugin is already loaded... reformat to get sep chars right */ + char checkpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(checkpath, sizeof(checkpath), "%s", path); + + /** + * In manually loading a plugin, any sort of load error causes a deletion. + * This is because it's assumed manually loaded plugins will not be managed. + * For managed plugins, we need the UI to report them properly. + */ + + CPlugin *pPlugin; + if (sm_trie_retrieve(m_LoadLookup, checkpath, (void **)&pPlugin)) + { + snprintf(error, err_max, "Plugin file is alread loaded"); + return NULL; + } + + pPlugin = CPlugin::CreatePlugin(path, error, err_max); if (!pPlugin) { @@ -568,14 +696,24 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ pPlugin->m_type = type; - InitAndAddPlugin(pPlugin); + AddCoreNativesToPlugin(pPlugin); + + /* Finally, ask the plugin if it wants to be loaded */ + if (!pPlugin->Call_AskPluginLoad(error, err_max)) + { + delete pPlugin; + return NULL; + } + + AddPlugin(pPlugin); return pPlugin; } -void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin) +void CPluginManager::AddPlugin(CPlugin *pPlugin) { m_plugins.push_back(pPlugin); + sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin); List::iterator iter; IPluginsListener *pListener; @@ -585,7 +723,43 @@ void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin) pListener->OnPluginCreated(pPlugin); } - /* :TODO: a lot more... */ + /* If the second pass was already completed, we have to run the pass on this plugin */ + if (m_AllPluginsLoaded && pPlugin->GetStatus() == Plugin_Loaded) + { + RunSecondPass(pPlugin); + } +} + +void CPluginManager::RunSecondPass(CPlugin *pPlugin) +{ + /* Tell this plugin to finish initializing itself */ + pPlugin->Call_OnPluginInit(); + + /* Finish by telling all listeners */ + List::iterator iter; + IPluginsListener *pListener; + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) + { + pListener = (*iter); + pListener->OnPluginLoaded(pPlugin); + } +} + +void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) +{ + List::iterator iter; + + for (iter=m_natives.begin(); iter!=m_natives.end(); iter++) + { + sp_nativeinfo_t *natives = (*iter); + IPluginContext *ctx = pPlugin->GetBaseContext(); + unsigned int i=0; + /* Attempt to bind every native! */ + while (natives[i].func != NULL) + { + ctx->BindNative(&natives[i++]); + } + } } bool CPluginManager::UnloadPlugin(IPlugin *plugin) @@ -601,6 +775,9 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener = (*iter); pListener->OnPluginDestroyed(pPlugin); } + + m_plugins.remove(plugin); + sm_trie_delete(m_LoadLookup, pPlugin->m_filename); delete pPlugin; @@ -877,7 +1054,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) return true; } -CPluginManager::~CPluginManager() +bool CPluginManager::IsLateLoadTime() { - //:TODO: we need a good way to free what we're holding + return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap()); } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 4791ef2d..44856ce9 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -1,12 +1,14 @@ #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ +#include #include #include #include #include "sm_globals.h" #include "CFunction.h" #include "PluginInfoDatabase.h" +#include "sm_trie.h" using namespace SourceHook; @@ -29,6 +31,31 @@ using namespace SourceHook; * plugins that failed to load from the internal loading mechanism are always tracked. This * allows users to see which automatically loaded plugins failed, and makes the interface a bit * more flexible. + * + * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid + * for execution. SourceMod is a two pass system, and even though the second pass is not implemented + * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When + * implemented, a Created plugin will be switched to Error in the second pass if it not loadable. + * + * The two pass loading mechanism is described below. Modules/natives are not implemented yet. + * PASS ONE: All loadable plugins are found and have the following steps performed: + * 1. Loading and compilation is attempted. + * 2. If successful, all natives from Core are added. + * 3. OnPluginLoad() is called. + * 4. If failed, any user natives are scrapped and the process halts here. + * 5. If successful, the plugin is ready for Pass 2. + * INTERMEDIATE: + * 1. All forced modules are loaded. + * PASS TWO: All loaded plugins are found and have these steps performed: + * 1. Any modules referenced in the plugin that are not already loaded, are loaded. + * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6. + * 3. If any natives are unresolved, check if they are found in the user-natives pool. + * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter. + * 5. If the filter fails, the plugin is marked as failed. + * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped. + * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran. + * PASS THREE (not a real pass): + * 7. Once all plugins are deemed to be loaded, OnPluginInit() is called */ #define SM_CONTEXTVAR_MYSELF 0 @@ -88,6 +115,24 @@ public: * Sets an error state on the plugin */ void SetErrorState(PluginStatus status, const char *error_fmt, ...); + + /** + * Calls the OnPluginLoad function, and sets any failed states if necessary. + * NOTE: Valid pre-states are: Plugin_Created + * If validated, plugin state is changed to Plugin_Loaded + * + * If the error buffer is NULL, the error message is cached locally. + */ + bool Call_AskPluginLoad(char *error, size_t maxlength); + + /** + * Calls the OnPluginInit function. + * NOTE: Valid pre-states are: Plugin_Created + * NOTE: Pre-state will be changed to Plugin_Running + */ + void Call_OnPluginInit(); +public: + time_t HasUpdatedFile(); protected: void UpdateInfo(); private: @@ -102,6 +147,7 @@ private: CFunction **m_priv_funcs; CFunction **m_pub_funcs; char m_errormsg[256]; + time_t m_LastAccess; }; class CPluginManager : public IPluginManager @@ -142,9 +188,14 @@ public: //IPluginManager virtual void RemovePluginsListener(IPluginsListener *listener); public: /** - * Refreshes and loads plugins, usually used on mapchange + * Loads all plugins not yet loaded */ - void RefreshOrLoadPlugins(const char *config, const char *basedir); + void LoadAll_FirstPass(const char *config, const char *basedir); + + /** + * Runs the second loading pass for all plugins + */ + void LoadAll_SecondPass(); /** * Tests a plugin file mask against a local folder. @@ -156,6 +207,16 @@ public: * Wildcards are allowed in the filename. */ bool TestAliasMatch(const char *alias, const char *localdir); + + /** + * Registers natives in core itself ONLY. + */ + void RegisterGlobalNatives(sp_nativeinfo_t *info[]); + + /** + * Returns whether anything loaded will be a late load. + */ + bool IsLateLoadTime(); private: /** * Recursively loads all plugins in the given directory. @@ -169,9 +230,19 @@ private: void LoadAutoPlugin(const char *file); /** - * Adds and initializes a plugin object. This is wrapped by LoadPlugin functions. + * Adds a plugin object. This is wrapped by LoadPlugin functions. */ - void InitAndAddPlugin(CPlugin *pPlugin); + void AddPlugin(CPlugin *pPlugin); + + /** + * Runs the second loading pass on a plugin. + */ + void RunSecondPass(CPlugin *pPlugin); + + /** + * Adds any globally registered natives to a plugin + */ + void AddCoreNativesToPlugin(CPlugin *pPlugin); protected: /** * Caching internal objects @@ -182,11 +253,14 @@ protected: private: List m_listeners; List m_plugins; + List m_natives; CStack m_iters; CStack m_funcpool; CPluginInfoDatabase m_PluginInfo; + Trie *m_LoadLookup; + bool m_AllPluginsLoaded; }; -extern CPluginManager g_PluginMngr; +extern CPluginManager g_PluginSys; #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ From 8792f0b4f0b5750e04d58bb8f168529dfb30b749 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 15 Dec 2006 13:45:21 +0000 Subject: [PATCH 0187/1664] new plugin API, sample plugin is now a fail load plugin --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40217 --- plugins/include/sourcemod.inc | 24 ++++++++++++------------ plugins/test.sma | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index ab600e12..a799213c 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -29,15 +29,22 @@ struct Plugin public Plugin:myinfo; /** - * Called when the plugin is fully initialized and all known external references are resolved, - * such as dynamic natives. + * Called when the plugin is fully initialized and all known external references are resolved. + * This is called even if the plugin type is "private." + * NOTE: Errors in this function will cause the plugin to stop running. * * @noreturn */ -forward OnPluginInit(); +forward OnPluginInit(Handle:myself); /** - * Called before OnPluginInit, in case the plugin wants to check for load failure. + * Called before OnPluginInit, in case the plugin wants to check for load failure. + * This is called even if the plugin type is "private." Any natives from modules are + * not available at this point. Thus, this forward should only be used for explicit + * pre-emptive things, such as adding dynamic natives, or setting certain types of load filters. + * + * NOTE: It is not safe to call externally resolved natives until OnPluginInit(). + * NOTE: Any sort of RTE in this function will cause the plugin to fail loading. * * @param myself Handle to the plugin. * @param late Whether or not the plugin was loaded "late" (after map load). @@ -45,14 +52,7 @@ forward OnPluginInit(); * @param err_max Maximum number of characters for error message buffer. * @return True if load success, false otherwise. */ -forward bool:OnPluginLoad(Handle:myself, bool:late, String:error[], err_max); - -/** - * Called when the plugin is first mapped into memory. Use this to set dynamic natives ONLY. - * - * @noreturn - */ -forward OnCreatePlugin(); +forward bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max); /** * Called when the plugin is about to be unloaded. diff --git a/plugins/test.sma b/plugins/test.sma index fa317e82..af46f8c6 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -9,16 +9,21 @@ public Plugin:myinfo = url = "http://www.sourcemod.net/" } -public Test(num, &num2) +copy(String:dest[], maxlength, const String:source[]) { - num2 += num + new len - return num + while (source[len] != '\0' && len < maxlength) + { + dest[len] = source[len] + len++ + } + + dest[len] = '\0' } -public Test2(num, &num2) +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) { - num2 += num - - return num + copy(error, err_max, "I don't like food anymore!") + return false } From a9087b13dd41757f48f61212f41fc41c6bc0d85d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 15 Dec 2006 13:53:58 +0000 Subject: [PATCH 0188/1664] added second pass function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40218 --- core/sourcemod.cpp | 3 +++ core/systems/PluginSys.cpp | 21 ++++++++++++++++++--- core/systems/PluginSys.h | 8 ++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index f8d544dd..0e42de2d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -164,6 +164,9 @@ void SourceModBase::DoGlobalPluginLoads() GetSMBaseDir()); g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); + + /* No modules yet, it's safe to call this from here */ + g_PluginSys.LoadAll_SecondPass(); } bool SourceModBase::IsLateLoadInMap() diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 9cbc5f74..db274911 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -444,7 +444,7 @@ bool CPlugin::SetPauseState(bool paused) * PLUGIN ITERATOR * *******************/ -CPluginManager::CPluginIterator::CPluginIterator(List *_mylist) +CPluginManager::CPluginIterator::CPluginIterator(List *_mylist) { mylist = _mylist; } @@ -495,7 +495,7 @@ CPluginManager::~CPluginManager() } -void CPluginManager::LoadAll_FirstPass( const char *config, const char *basedir ) +void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) { /* First read in the database of plugin settings */ SMCParseError err; @@ -730,6 +730,21 @@ void CPluginManager::AddPlugin(CPlugin *pPlugin) } } +void CPluginManager::LoadAll_SecondPass() +{ + List::iterator iter; + CPlugin *pPlugin; + + for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++) + { + pPlugin = (*iter); + if (pPlugin->GetStatus() == Plugin_Loaded) + { + RunSecondPass(pPlugin); + } + } +} + void CPluginManager::RunSecondPass(CPlugin *pPlugin) { /* Tell this plugin to finish initializing itself */ @@ -776,7 +791,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener->OnPluginDestroyed(pPlugin); } - m_plugins.remove(plugin); + m_plugins.remove(pPlugin); sm_trie_delete(m_LoadLookup, pPlugin->m_filename); delete pPlugin; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 44856ce9..22cd8d1b 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -161,7 +161,7 @@ public: class CPluginIterator : public IPluginIterator { public: - CPluginIterator(List *mylist); + CPluginIterator(List *mylist); virtual ~CPluginIterator(); virtual bool MorePlugins(); virtual IPlugin *GetPlugin(); @@ -170,8 +170,8 @@ public: public: void Reset(); private: - List *mylist; - List::iterator current; + List *mylist; + List::iterator current; }; friend class CPluginManager::CPluginIterator; public: //IPluginManager @@ -252,7 +252,7 @@ protected: void ReleaseFunctionToPool(CFunction *func); private: List m_listeners; - List m_plugins; + List m_plugins; List m_natives; CStack m_iters; CStack m_funcpool; From 649b96ac9d97b47ab05d61caf8a52d792b13cbbb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 15 Dec 2006 13:58:22 +0000 Subject: [PATCH 0189/1664] added global class initializers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40219 --- core/sourcemod.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 0e42de2d..a976b417 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -129,10 +129,27 @@ void SourceModBase::StartSourceMod(bool late) /* First initialize the global hooks we need */ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); + m_IsLateLoadInMap = late; + + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModStartup(m_IsLateLoadInMap); + pBase = pBase->m_pGlobalClassNext; + } + + /* Notify! */ + pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModAllInitialized(); + pBase = pBase->m_pGlobalClassNext; + } + /* If we're late, automatically load plugins now */ if (late) { - m_IsLateLoadInMap = late; DoGlobalPluginLoads(); } } From e0bd4f9782f9547e5d2f22bec0ba803534b4aee6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 16 Dec 2006 01:51:45 +0000 Subject: [PATCH 0190/1664] i have changed some letters in these files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40220 --- core/interfaces/IHandleSys.h | 178 +++++++++++++++++++++++++++++++++++ core/interfaces/IShareSys.h | 2 + 2 files changed, 180 insertions(+) create mode 100644 core/interfaces/IHandleSys.h diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h new file mode 100644 index 00000000..a1eeb4a9 --- /dev/null +++ b/core/interfaces/IHandleSys.h @@ -0,0 +1,178 @@ +#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ + +#include +#include + +#define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" +#define SMINTERFACE_HANDLESYSTEM_VERSION 1 + +namespace SourceMod +{ + /** + * Both of these types have invalid values of '0' for error checking. + */ + typedef unsigned int HandleType_t; + typedef unsigned int Handle_t; + + enum HandleError + { + HandleError_None = 0, /* No error */ + HandleError_Changed, /* The handle has been freed and reassigned */ + HandleError_Type, /* The handle has a different type registered */ + HandleError_Freed, /* The handle has been freed */ + HandleError_Index, /* generic internal indexing error */ + HandleError_Access, /* No access permitted to free this handle */ + }; + + struct HandleAccess + { + HandleAccess() : canRead(true), canDelete(true), canInherit(true) + { + } + bool canCreate; /* Instances can be created by other objects */ + bool canRead; /* Handle and type can be read by other objects */ + bool canDelete; /* Handle can be deleted by other objects */ + bool canInherit; /* Handle type can be inherited */ + }; + + struct HandleSecurity + { + IdentityToken_t owner; /* Owner of the handle */ + HandleAccess all; /* Access permissions of everyone */ + }; + + class IHandleTypeDispatch + { + public: + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_HANDLESYSTEM_VERSION; + } + public: + /** + * @brief Called when destroying a handle. Must be implemented. + */ + virtual void OnHandleDestroy(HandleType_t type, void *object) =0; + }; + + class IHandleSys : public SMInterface + { + public: + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_HANDLESYSTEM_VERSION; + } + virtual const char *GetInterfaceName() + { + return SMINTERFACE_HANDLESYSTEM_NAME; + } + public: + /** + * @brief Creates a new Handle type. + * NOTE: Handle names must be unique if not private. + * + * @param name Name of handle type (NULL or "" to be anonymous) + * @param dispatch Pointer to a valid IHandleTypeDispatch object. + * @return A new HandleType_t unique ID. + */ + virtual HandleType_t CreateType(const char *name, + IHandleTypeDispatch *dispatch) =0; + + /** + * @brief Creates a new Handle type. + * NOTE: Currently, a child type may not have its own children. + * NOTE: Handle names must be unique if not private. + * + * @param name Name of handle type (NULL or "" to be anonymous) + * @param dispatch Pointer to a valid IHandleTypeDispatch object. + * @param parent Parent handle to inherit from, 0 for none. + * @param security Pointer to a temporary HandleSecurity object, NULL to use defaults. + * @return A new HandleType_t unique ID. + */ + virtual HandleType_t CreateTypeEx(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const HandleSecurity *security) =0; + + + /** + * @brief Creates a sub-type for a Handle. + * NOTE: Currently, a child type may not have its own children. + * NOTE: Handle names must be unique if not private. + * NOTE: This is a wrapper around the above. + * + * @param name Name of a handle. + * @param parent Parent handle type. + * @param dispatch Pointer to a valid IHandleTypeDispatch object. + * @return A new HandleType_t unique ID. + */ + virtual HandleType_t CreateChildType(const char *name, + HandleType_t parent, + IHandleTypeDispatch *dispatch) =0; + + /** + * @brief Removes a handle type. + * NOTE: This removes all child types. + * + * @param token Identity token. Removal fails if the token does not match. + * @param type Type chain to remove. + * @return True on success, false on failure. + */ + virtual bool RemoveType(HandleType_t type, IdentityToken_t ident) =0; + + /** + * @brief Finds a handle type by name. + * + * @param name Name of handle type to find (anonymous not allowed). + * @param type Address to store found handle in (if not found, undefined). + * @return True if found, false otherwise. + */ + virtual bool FindHandleType(const char *name, HandleType_t *type) =0; + + /** + * @brief Creates a new handle. + * + * @param type Type to use on the handle. + * @param object Object to bind to the handle. + * @param owner Identity token for object using this handle. + * @param ident Identity token if any security rights are needed. + * @return A new Handle_t, or 0 on failure. + */ + virtual Handle_t CreateHandleEx(HandleType_t type, + void *object, + IdentityToken_t owner, + IdentityToken_t ident) =0; + + /** + * @brief Creates a new handle. + * NOTE: This is a wrapper around the above function. + * + * @param type Type to use on the handle. + * @param object Object to bind to the handle. + * @param ctx Plugin context that will own this handle. NULL for none. + * @return A new Handle_t. + */ + virtual Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx) =0; + + /** + * @brief Destroys a handle. + * + * @param type Handle_t identifier to destroy. + * @return A HandleError error code. + */ + virtual HandleError DestroyHandle(Handle_t handle) =0; + + /** + * @brief Retrieves the contents of a handle. + * + * @param handle Handle_t from which to retrieve contents. + * @param type Expected type to read as. + * @param object Address to store object in. + * @return HandleError error code. + */ + virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, void **object) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index d81a0fee..156d0470 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -3,6 +3,8 @@ #include +#define DEFAULT_IDENTITY 0 + namespace SourceMod { typedef unsigned int IdentityToken_t; From c9002c2011ea05cd8e5530ef4fc640ea4e484853 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 16 Dec 2006 02:16:21 +0000 Subject: [PATCH 0191/1664] Added initial console commands for plugins fixed crash in plugin destructor fixed compilation not being freed causing a crash fixed small issues in plugin system fixed plugin iterator not being reseted when freed and not being initialized it's current pointer. fixed a bug where insertion of a prefixed string would not check whether a value could be set. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40221 --- core/msvc8/sourcemod_mm.vcproj | 14 ++- core/sm_srvcmds.cpp | 171 +++++++++++++++++++++++++++++++++ core/sm_srvcmds.h | 16 +++ core/sm_trie.cpp | 6 ++ core/sourcemm_api.cpp | 1 + core/systems/PluginSys.cpp | 23 +++-- 6 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 core/sm_srvcmds.cpp create mode 100644 core/sm_srvcmds.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 59d92a39..3c946012 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -220,6 +224,10 @@ RelativePath="..\sm_platform.h" > + + diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp new file mode 100644 index 00000000..c668067e --- /dev/null +++ b/core/sm_srvcmds.cpp @@ -0,0 +1,171 @@ +#include "sm_srvcmds.h" + +ConVarAccessor g_ConCmdAccessor; + +void ConVarAccessor::OnSourceModStartup(bool late) +{ + ConCommandBaseMgr::OneTimeInit(&g_ConCmdAccessor); +} + +bool ConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand) +{ + META_REGCVAR(pCommand); + + return true; +} + +CON_COMMAND(sm, "SourceMod Menu") +{ + int argnum = engine->Cmd_Argc(); + + if (argnum >= 2) + { + const char *cmd = engine->Cmd_Argv(1); + if (!strcmp("plugins", cmd)) + { + if (argnum >= 3) + { + const char *cmd2 = engine->Cmd_Argv(2); + if (!strcmp("list", cmd2)) + { + char buffer[256]; + unsigned int id = 1; + int plnum = g_PluginSys.GetPluginCount(); + + if (!plnum) + { + META_CONPRINT("[SM] No plugins loaded\n"); + return; + } else { + META_CONPRINTF("[SM] Displaying %d plugin%s:\n", g_PluginSys.GetPluginCount(), (plnum > 1) ? "s" : ""); + } + + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + for (; iter->MorePlugins(); iter->NextPlugin(), id++) + { + assert(iter->GetPlugin()->GetStatus() != Plugin_Created); + int len = 0; + const sm_plugininfo_t *info = iter->GetPlugin()->GetPublicInfo(); + + len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, "status"); //:TODO: status + len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (info->name) ? info->name : iter->GetPlugin()->GetFilename()); + if (info->version) + { + len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); + } + if (info->author) + { + snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); + } + META_CONPRINTF("%s\n", buffer); + } + + iter->Release(); + return; + } else if (!strcmp("load", cmd2)) { + if (argnum < 4) + { + META_CONPRINT("Usage: sm plugins load \n"); + return; + } + + char error[100]; + const char *filename = engine->Cmd_Argv(3); + IPlugin *pl = g_PluginSys.LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error)); + + if (pl) + { + META_CONPRINTF("Loaded plugin %s successfully.\n", filename); + } else { + META_CONPRINTF("Plugin %s failed to load: %s.\n", filename, error); + } + + return; + + } else if (!strcmp("unload", cmd2)) { + if (argnum < 4) + { + META_CONPRINT("Usage: sm plugins unload <#>\n"); + return; + } + + IPlugin *pl = NULL; + int id = 1; + int num = atoi(engine->Cmd_Argv(3)); + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + META_CONPRINT("Plugin index not found.\n"); + return; + } + + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + for (; iter->MorePlugins() && idNextPlugin(), id++) {} + pl = iter->GetPlugin(); + + char name[64]; + const sm_plugininfo_t *info = pl->GetPublicInfo(); + strcpy(name, (info->name) ? info->name : pl->GetFilename()); + + if (g_PluginSys.UnloadPlugin(pl)) + { + META_CONPRINTF("Plugin %s unloaded successfully.\n", name); + } else { + META_CONPRINTF("Failed to unload plugin %s.\n", name); + } + + iter->Release(); + return; + + } else if (!strcmp("info", cmd2)) { + if (argnum < 4) + { + META_CONPRINT("Usage: sm plugins info <#>\n"); + return; + } + + IPlugin *pl = NULL; + int id = 1; + int num = atoi(engine->Cmd_Argv(3)); + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + META_CONPRINT("Plugin index not found.\n"); + return; + } + + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + for (; iter->MorePlugins() && idNextPlugin(), id++) {} + pl = iter->GetPlugin(); + const sm_plugininfo_t *info = pl->GetPublicInfo(); + + META_CONPRINTF(" Filename: %s\n", pl->GetFilename()); + if (info->name) + { + META_CONPRINTF(" Title: %s\n", info->name); + } + if (info->author) + { + META_CONPRINTF(" Author: %s\n", info->author); + } + if (info->version) + { + META_CONPRINTF(" Version: %s\n", info->version); + } + if (info->description) + { + META_CONPRINTF(" Description: %s\n", info->description); + } + if (info->url) + { + META_CONPRINTF(" URL: %s\n", info->url); + } + //:TODO: write if it's in debug mode, or do it inside LIST ? + + iter->Release(); + return; + } + } + //:TODO: print plugins cmd list + } + } + //:TODO: print cmd list or something +} \ No newline at end of file diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h new file mode 100644 index 00000000..62670c3e --- /dev/null +++ b/core/sm_srvcmds.h @@ -0,0 +1,16 @@ +#include "sourcemm_api.h" +#include +#include "sourcemod.h" +#include "PluginSys.h" + +using namespace SourceMod; + +class ConVarAccessor : + public IConCommandBaseAccessor, + public SMGlobalClass +{ +public: // IConCommandBaseAccessor + virtual bool RegisterConCommandBase(ConCommandBase *pCommand); +public: // SMGlobalClass + virtual void OnSourceModStartup(bool late); +}; \ No newline at end of file diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 7e92c5d9..c450d079 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -603,6 +603,12 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) /* Do an initial browsing to make sure they're not the same string */ if (strcmp(keyptr, term) == 0) { + if (!node->valset) + { + node->valset = true; + node->value = value; + return true; + } /* Same string. We can't insert. */ return false; } diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 75652a00..7c701977 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -14,6 +14,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen PLUGIN_SAVEVARS(); GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); return g_SourceMod.InitializeSourceMod(error, maxlen, late); } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index db274911..86f1421a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -40,12 +40,6 @@ CPlugin::~CPlugin() m_ctx.co = NULL; } - if (m_plugin) - { - g_pSourcePawn->FreeFromMemory(m_plugin); - m_plugin = NULL; - } - if (m_pub_funcs) { for (uint32_t i=0; iinfo.publics_num; i++) @@ -56,6 +50,12 @@ CPlugin::~CPlugin() m_pub_funcs = NULL; } + if (m_plugin) + { + g_pSourcePawn->FreeFromMemory(m_plugin); + m_plugin = NULL; + } + if (m_priv_funcs) { for (unsigned int i=0; i *_mylist) { mylist = _mylist; + Reset(); } IPlugin *CPluginManager::CPluginIterator::GetPlugin() @@ -500,6 +502,7 @@ void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) /* First read in the database of plugin settings */ SMCParseError err; unsigned int line, col; + m_AllPluginsLoaded = false; if ((err=g_TextParse.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) { /* :TODO: log the error, don't bail out though */ @@ -668,7 +671,7 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ CPlugin *pPlugin; if (sm_trie_retrieve(m_LoadLookup, checkpath, (void **)&pPlugin)) { - snprintf(error, err_max, "Plugin file is alread loaded"); + snprintf(error, err_max, "Plugin file is already loaded"); return NULL; } @@ -743,6 +746,7 @@ void CPluginManager::LoadAll_SecondPass() RunSecondPass(pPlugin); } } + m_AllPluginsLoaded = true; } void CPluginManager::RunSecondPass(CPlugin *pPlugin) @@ -828,6 +832,7 @@ IPluginIterator *CPluginManager::GetPluginIterator() } else { CPluginIterator *iter = m_iters.front(); m_iters.pop(); + iter->Reset(); return iter; } } From a4737a2808a8aa9f40280cc2ecb2df0b28d101ce Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 16 Dec 2006 02:48:58 +0000 Subject: [PATCH 0192/1664] added status strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40222 --- core/sm_srvcmds.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index c668067e..ecf25c09 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -14,6 +14,25 @@ bool ConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand) return true; } +inline const char *StatusToStr(PluginStatus st) +{ + switch (st) + { + case Plugin_Running: + return "Running"; + case Plugin_Paused: + return "Paused"; + case Plugin_Error: + return "Error"; + case Plugin_Uncompiled: + return "Uncompiled"; + case Plugin_BadLoad: + return "Bad Load"; + default: + return "-"; + } +} + CON_COMMAND(sm, "SourceMod Menu") { int argnum = engine->Cmd_Argc(); @@ -43,11 +62,12 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins(); iter->NextPlugin(), id++) { - assert(iter->GetPlugin()->GetStatus() != Plugin_Created); + IPlugin *pl = iter->GetPlugin(); + assert(pl->GetStatus() != Plugin_Created); int len = 0; - const sm_plugininfo_t *info = iter->GetPlugin()->GetPublicInfo(); + const sm_plugininfo_t *info = pl->GetPublicInfo(); - len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, "status"); //:TODO: status + len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (info->name) ? info->name : iter->GetPlugin()->GetFilename()); if (info->version) { @@ -69,7 +89,7 @@ CON_COMMAND(sm, "SourceMod Menu") return; } - char error[100]; + char error[128]; const char *filename = engine->Cmd_Argv(3); IPlugin *pl = g_PluginSys.LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error)); From c189dfa9913598ae04812e58dd67f27e90037d61 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 16 Dec 2006 22:27:18 +0000 Subject: [PATCH 0193/1664] implemented and finalized initial HandleSystem API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40223 --- core/interfaces/IHandleSys.h | 42 +++- core/msvc8/sourcemod_mm.vcproj | 12 ++ core/systems/HandleSys.cpp | 379 +++++++++++++++++++++++++++++++++ core/systems/HandleSys.h | 75 +++++++ 4 files changed, 497 insertions(+), 11 deletions(-) create mode 100644 core/systems/HandleSys.cpp create mode 100644 core/systems/HandleSys.h diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index a1eeb4a9..2621ba6d 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -15,6 +15,19 @@ namespace SourceMod typedef unsigned int HandleType_t; typedef unsigned int Handle_t; + /** + * About type checking: + * Types can be inherited - a Parent type ("Supertype") can have child types. + * When accessing handles, type checking is done. This table shows how this is resolved: + * + * HANDLE CHECK -> RESULT + * ------ ----- ------ + * Parent Parent Success + * Parent Child Fail + * Child Parent Success + * Child Child Success + */ + enum HandleError { HandleError_None = 0, /* No error */ @@ -27,12 +40,12 @@ namespace SourceMod struct HandleAccess { - HandleAccess() : canRead(true), canDelete(true), canInherit(true) + HandleAccess() : canRead(true), canDelete(true), canInherit(true), canCreate(true) { } - bool canCreate; /* Instances can be created by other objects */ - bool canRead; /* Handle and type can be read by other objects */ - bool canDelete; /* Handle can be deleted by other objects */ + bool canCreate; /* Instances can be created by other objects (this makes it searchable) */ + bool canRead; /* Handles can be read by other objects */ + bool canDelete; /* Handles can be deleted by other objects */ bool canInherit; /* Handle type can be inherited */ }; @@ -87,7 +100,8 @@ namespace SourceMod * @param name Name of handle type (NULL or "" to be anonymous) * @param dispatch Pointer to a valid IHandleTypeDispatch object. * @param parent Parent handle to inherit from, 0 for none. - * @param security Pointer to a temporary HandleSecurity object, NULL to use defaults. + * @param security Pointer to a temporary HandleSecurity object, NULL to use default + * or inherited permissions. * @return A new HandleType_t unique ID. */ virtual HandleType_t CreateTypeEx(const char *name, @@ -135,13 +149,13 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param owner Identity token for object using this handle. + * @param source Identity token for object using this handle (for example, a script). * @param ident Identity token if any security rights are needed. * @return A new Handle_t, or 0 on failure. */ - virtual Handle_t CreateHandleEx(HandleType_t type, + virtual Handle_t CreateHandle(HandleType_t type, void *object, - IdentityToken_t owner, + IdentityToken_t source, IdentityToken_t ident) =0; /** @@ -151,27 +165,33 @@ namespace SourceMod * @param type Type to use on the handle. * @param object Object to bind to the handle. * @param ctx Plugin context that will own this handle. NULL for none. + * @param ident Identity token if any security rights are needed. * @return A new Handle_t. */ - virtual Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx) =0; + virtual Handle_t CreateScriptHandle(HandleType_t type, + void *object, + sp_context_t *ctx, + IdentityToken_t ident) =0; /** * @brief Destroys a handle. * * @param type Handle_t identifier to destroy. + * @param ident Identity token, for destroying secure handles (0 for none). * @return A HandleError error code. */ - virtual HandleError DestroyHandle(Handle_t handle) =0; + virtual HandleError DestroyHandle(Handle_t handle, IdentityToken_t ident) =0; /** * @brief Retrieves the contents of a handle. * * @param handle Handle_t from which to retrieve contents. * @param type Expected type to read as. + * @param ident Identity token to validate as. * @param object Address to store object in. * @return HandleError error code. */ - virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, void **object) =0; + virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object) =0; }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 3c946012..f0900e3f 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -267,6 +267,10 @@ RelativePath="..\systems\ForwardSys.h" > + + @@ -291,6 +295,10 @@ RelativePath="..\systems\ForwardSys.cpp" > + + @@ -311,6 +319,10 @@ RelativePath="..\interfaces\IForwardSys.h" > + + diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp new file mode 100644 index 00000000..78c32af1 --- /dev/null +++ b/core/systems/HandleSys.cpp @@ -0,0 +1,379 @@ +#include "HandleSys.h" +#include "PluginSys.h" + +HandleSystem g_HandleSys; + +HandleSystem::HandleSystem() +{ + m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1]; + memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1)); + + m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE]; + memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE); + + m_TypeLookup = sm_trie_create(); + m_strtab = new BaseStringTable(512); + + m_TypeTail = 0; +} + +HandleSystem::~HandleSystem() +{ + delete [] m_Handles; + delete [] m_Types; + sm_trie_destroy(m_TypeLookup); + delete m_strtab; +} + +HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) +{ + return CreateTypeEx(name, dispatch, 0, NULL); +} + +HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch) +{ + return CreateTypeEx(name, dispatch, parent, NULL); +} + +HandleType_t HandleSystem::CreateTypeEx(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const HandleSecurity *security) +{ + if (!dispatch) + { + return 0; + } + + bool isChild = false; + + if (parent != 0) + { + isChild = true; + if (parent & HANDLESYS_SUBTYPE_MASK) + { + return 0; + } + if (parent >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[parent].dispatch != NULL + || m_Types[parent].sec.all.canInherit == false) + { + return 0; + } + } + + if (!security) + { + if (isChild) + { + security = &m_Types[parent].sec; + } else { + static HandleSecurity def_h = {0, HandleAccess() }; + security = &def_h; + } + } + + if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL)) + { + return 0; + } + + unsigned int index; + + if (isChild) + { + QHandleType *pParent = &m_Types[parent]; + if (pParent->children >= HANDLESYS_MAX_SUBTYPES) + { + return 0; + } + index = 0; + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) + { + if (m_Types[parent + i].dispatch == NULL) + { + index = parent + i; + break; + } + } + if (!index) + { + return 0; + } + pParent->children++; + } else { + if (m_FreeTypes == 0) + { + /* Reserve another index */ + if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE) + { + return 0; + } else { + m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1); + index = m_TypeTail; + } + } else { + /* The "free array" is compacted into the normal array for easiness */ + index = m_Types[m_FreeTypes--].freeID; + } + } + + QHandleType *pType = &m_Types[index]; + + pType->dispatch = dispatch; + if (name && name[0] != '\0') + { + pType->nameIdx = m_strtab->AddString(name); + sm_trie_insert(m_TypeLookup, name, (void *)pType); + } else { + pType->nameIdx = -1; + } + pType->sec = *security; + pType->opened = 0; + + if (!isChild) + { + pType->children = 0; + } + + return index; +} + +bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) +{ + QHandleType *_type; + + if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type)) + { + return false; + } + + unsigned int offset = _type - m_Types; + + if (type) + { + *type = offset; + } + + return true; +} + +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) +{ + if (!type + || type >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[type].dispatch == NULL) + { + return 0; + } + + /* Check the security of this handle */ + QHandleType *pType = &m_Types[type]; + if (!pType->sec.all.canCreate + && pType->sec.owner != ident) + { + return 0; + } + + unsigned int handle = 0; + if (m_FreeHandles == 0) + { + if (m_HandleTail >= HANDLESYS_MAX_HANDLES) + { + return 0; + } + handle = ++m_HandleTail; + } else { + handle = m_Handles[m_FreeHandles--].freeID; + } + + QHandle *pHandle = &m_Handles[handle]; + + pHandle->type = type; + pHandle->source = source; + pHandle->set = true; + pHandle->object = object; + + if (++m_HSerial >= HANDLESYS_MAX_SERIALS) + { + m_HSerial = 1; + } + pHandle->serial = m_HSerial; + + Handle_t hash = pHandle->serial; + hash <<= 16; + hash |= handle; + + pType->opened++; + + return hash; +} + +Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, + void *object, + sp_context_t *ctx, + IdentityToken_t ident) +{ + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); + + return CreateHandle(type, object, pPlugin->GetIdentity(), ident); +} + +HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) +{ + unsigned int serial = (handle >> 16); + unsigned int index = (handle & HANDLESYS_HANDLE_MASK); + + if (index == 0 || index == 0xFFFF) + { + return HandleError_Index; + } + + QHandle *pHandle = &m_Handles[index]; + QHandleType *pType = &m_Types[pHandle->type]; + + if (!pType->sec.all.canDelete + && pType->sec.owner != ident) + { + return HandleError_Access; + } + if (!pHandle->set) + { + return HandleError_Freed; + } + if (pHandle->serial != serial) + { + return HandleError_Changed; + } + + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + pType->opened--; + pHandle->set = false; + m_Handles[++m_FreeTypes].freeID = index; + + return HandleError_None; +} + +inline HandleType_t TypeParent(HandleType_t type) +{ + return (type & ~HANDLESYS_SUBTYPE_MASK); +} + +HandleError HandleSystem::ReadHandle(Handle_t handle, + HandleType_t type, + IdentityToken_t ident, + void **object) +{ + unsigned int serial = (handle >> 16); + unsigned int index = (handle & HANDLESYS_HANDLE_MASK); + + if (index == 0 || index == 0xFFFF) + { + return HandleError_Index; + } + + QHandle *pHandle = &m_Handles[index]; + + /* Do sanity checks first */ + if (!pHandle->set) + { + return HandleError_Freed; + } + if (pHandle->serial != serial) + { + return HandleError_Changed; + } + + /* Check the type inheritance */ + if (pHandle->type & HANDLESYS_SUBTYPE_MASK) + { + if (pHandle->type != type + && (TypeParent(pHandle->type) != TypeParent(type))) + { + return HandleError_Type; + } + } else { + if (pHandle->type != type) + { + return HandleError_Type; + } + } + + /* Now do security checks */ + QHandleType *pType = &m_Types[pHandle->type]; + if (!pType->sec.all.canRead + && pType->sec.owner != ident) + { + return HandleError_Access; + } + + if (object) + { + *object = pHandle->object; + } + + return HandleError_None; +} + +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) +{ + if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) + { + return false; + } + + QHandleType *pType = &m_Types[type]; + + if (pType->sec.owner && pType->sec.owner != ident) + { + return false; + } + + if (pType->dispatch == NULL) + { + return false; + } + + /* Remove children if we have to */ + if (!(type & HANDLESYS_SUBTYPE_MASK)) + { + QHandleType *childType; + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) + { + childType = &m_Types[type + i]; + if (childType->dispatch) + { + RemoveType(type + i, childType->sec.owner); + } + } + /* Link us into the free chain */ + m_Types[++m_FreeTypes].freeID = type; + } + + /* Invalidate the type now */ + IHandleTypeDispatch *dispatch = pType->dispatch; + pType->dispatch = NULL; + + /* Make sure nothing is using this type. */ + if (pType->opened) + { + QHandle *pHandle; + for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++) + { + pHandle = &m_Handles[i]; + if (!pHandle->set || pHandle->type != type) + { + continue; + } + dispatch->OnHandleDestroy(type, pHandle->object); + pHandle->set = false; + m_Handles[++m_FreeHandles].freeID = i; + if (--pType->opened == 0) + { + break; + } + } + } + + return true; +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h new file mode 100644 index 00000000..84a78b55 --- /dev/null +++ b/core/systems/HandleSys.h @@ -0,0 +1,75 @@ +#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ +#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ + +#include +#include "sm_globals.h" +#include "sm_trie.h" +#include "sourcemod.h" +#include "sm_memtable.h" + +#define HANDLESYS_MAX_HANDLES (1<<16) +#define HANDLESYS_MAX_TYPES (1<<9) +#define HANDLESYS_MAX_SUBTYPES 0xF +#define HANDLESYS_SUBTYPE_MASK 0xF +#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1)) +#define HANDLESYS_MAX_SERIALS 0xFFFF +#define HANDLESYS_SERIAL_MASK 0xFFFF0000 +#define HANDLESYS_HANDLE_MASK 0x0000FFFF + +struct QHandle +{ + HandleType_t type; + void *object; + unsigned int freeID; + IdentityToken_t source; + bool set; + unsigned int serial; +}; + +struct QHandleType +{ + IHandleTypeDispatch *dispatch; + unsigned int freeID; + unsigned int children; + HandleSecurity sec; + unsigned int opened; + int nameIdx; +}; + +class HandleSystem : + public IHandleSys +{ +public: + HandleSystem(); + ~HandleSystem(); +public: //IHandleSystem + HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch); + HandleType_t CreateTypeEx(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const HandleSecurity *security); + HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); + bool RemoveType(HandleType_t type, IdentityToken_t ident); + bool FindHandleType(const char *name, HandleType_t *type); + Handle_t CreateHandle(HandleType_t type, + void *object, + IdentityToken_t source, + IdentityToken_t ident); + Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t ident); + HandleError DestroyHandle(Handle_t handle, IdentityToken_t ident); + HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object); +private: + QHandle *m_Handles; + QHandleType *m_Types; + Trie *m_TypeLookup; + unsigned int m_TypeTail; + unsigned int m_FreeTypes; + unsigned int m_HandleTail; + unsigned int m_FreeHandles; + unsigned int m_HSerial; + BaseStringTable *m_strtab; +}; + +extern HandleSystem g_HandleSys; + +#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ From 77ca28b8a3c2e78cfc1b27efea01a2a3fb80837b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 16 Dec 2006 22:30:58 +0000 Subject: [PATCH 0194/1664] each plugin must have its own identity. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40224 --- core/interfaces/IPluginSys.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index b3eac81a..fabf86c1 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -4,8 +4,8 @@ #include #include -#define SMINTERFACE_PLUGINMANAGER_NAME "IPluginManager" -#define SMINTERFACE_PLUGINMANAGER_VERSION 1 +#define SMINTERFACE_PLUGINSYSTEM_NAME "IPluginManager" +#define SMINTERFACE_PLUGINSYSTEM_VERSION 1 #define SM_CONTEXTVAR_USER 3 @@ -141,6 +141,11 @@ namespace SourceMod * @return A new IPluginFunction pointer, NULL if not found. */ virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; + + /** + * @brief Returns a plugin's identity token. + */ + virtual IdentityToken_t GetIdentity() =0; }; @@ -221,12 +226,12 @@ namespace SourceMod public: virtual const char *GetInterfaceName() { - return SMINTERFACE_PLUGINMANAGER_NAME; + return SMINTERFACE_PLUGINSYSTEM_NAME; } virtual unsigned int GetInterfaceVersion() { - return SMINTERFACE_PLUGINMANAGER_VERSION; + return SMINTERFACE_PLUGINSYSTEM_VERSION; } public: /** From 522a1f605f803a246d531e299a3492ae2cd829b5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 16 Dec 2006 22:31:32 +0000 Subject: [PATCH 0195/1664] these should compile now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40225 --- core/systems/PluginSys.cpp | 31 +++++++++++++++++++++++++++++++ core/systems/PluginSys.h | 14 +++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 86f1421a..f03afe53 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,11 +1,13 @@ #include #include "PluginSys.h" #include "LibrarySys.h" +#include "HandleSys.h" #include "sourcemm_api.h" #include "sourcemod.h" #include "CTextParsers.h" CPluginManager g_PluginSys; +HandleType_t g_PluginType = 0; CPlugin::CPlugin(const char *file) { @@ -20,6 +22,8 @@ CPlugin::CPlugin(const char *file) m_pub_funcs = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); + /* :TODO: ShareSys token */ + m_handle = g_HandleSys.CreateHandle(g_PluginType, this, DEFAULT_IDENTITY, 1); } CPlugin::~CPlugin() @@ -441,6 +445,11 @@ bool CPlugin::SetPauseState(bool paused) return true; } +IdentityToken_t CPlugin::GetIdentity() +{ + return 0; +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -1078,3 +1087,25 @@ bool CPluginManager::IsLateLoadTime() { return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap()); } + +void CPluginManager::OnSourceModAllInitialized() +{ + HandleSecurity sec; + + sec.owner = 1; /* :TODO: implement ShareSys */ + sec.all.canCreate = false; + sec.all.canDelete = false; + sec.all.canInherit = false; + + g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec); +} + +void CPluginManager::OnSourceModShutdown() +{ + g_HandleSys.RemoveType(g_PluginType, 1); +} + +void CPluginManager::OnHandleDestroy(HandleType_t type, void *object) +{ + /* We don't care about the internal object, actually */ +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 22cd8d1b..b6e3769f 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -3,12 +3,14 @@ #include #include +#include #include #include #include "sm_globals.h" #include "CFunction.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" +#include "sourcemod.h" using namespace SourceHook; @@ -91,6 +93,7 @@ public: virtual const sp_plugin_t *GetPluginStructure() const; virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); + virtual IdentityToken_t GetIdentity(); public: /** * Creates a plugin object with default values. @@ -148,9 +151,13 @@ private: CFunction **m_pub_funcs; char m_errormsg[256]; time_t m_LastAccess; + Handle_t m_handle; }; -class CPluginManager : public IPluginManager +class CPluginManager : + public IPluginManager, + public SMGlobalClass, + public IHandleTypeDispatch { friend class CPlugin; public: @@ -186,6 +193,11 @@ public: //IPluginManager virtual IPluginIterator *GetPluginIterator(); virtual void AddPluginsListener(IPluginsListener *listener); virtual void RemovePluginsListener(IPluginsListener *listener); +public: //SMGlobalClass + virtual void OnSourceModAllInitialized(); + virtual void OnSourceModShutdown(); +public: //IHandleTypeDispatch + virtual void OnHandleDestroy(HandleType_t type, void *object); public: /** * Loads all plugins not yet loaded From 1e573fe0d0732e54954958209aee2bb83f9aa6c7 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 17 Dec 2006 02:51:35 +0000 Subject: [PATCH 0196/1664] fixed null string condition being always true --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40226 --- core/sm_srvcmds.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index ecf25c09..451b34d0 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -33,6 +33,7 @@ inline const char *StatusToStr(PluginStatus st) } } +#define IS_STR_FILLED(var) (var[0] != '\0') CON_COMMAND(sm, "SourceMod Menu") { int argnum = engine->Cmd_Argc(); @@ -68,12 +69,12 @@ CON_COMMAND(sm, "SourceMod Menu") const sm_plugininfo_t *info = pl->GetPublicInfo(); len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (info->name) ? info->name : iter->GetPlugin()->GetFilename()); - if (info->version) + len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + if (IS_STR_FILLED(info->version)) { len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); } - if (info->author) + if (IS_STR_FILLED(info->author)) { snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); } @@ -101,7 +102,6 @@ CON_COMMAND(sm, "SourceMod Menu") } return; - } else if (!strcmp("unload", cmd2)) { if (argnum < 4) { @@ -109,7 +109,6 @@ CON_COMMAND(sm, "SourceMod Menu") return; } - IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -120,11 +119,11 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - pl = iter->GetPlugin(); + IPlugin *pl = iter->GetPlugin(); char name[64]; const sm_plugininfo_t *info = pl->GetPublicInfo(); - strcpy(name, (info->name) ? info->name : pl->GetFilename()); + strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); if (g_PluginSys.UnloadPlugin(pl)) { @@ -135,7 +134,6 @@ CON_COMMAND(sm, "SourceMod Menu") iter->Release(); return; - } else if (!strcmp("info", cmd2)) { if (argnum < 4) { @@ -143,7 +141,6 @@ CON_COMMAND(sm, "SourceMod Menu") return; } - IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -154,27 +151,28 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - pl = iter->GetPlugin(); + + IPlugin *pl = iter->GetPlugin(); const sm_plugininfo_t *info = pl->GetPublicInfo(); META_CONPRINTF(" Filename: %s\n", pl->GetFilename()); - if (info->name) + if (IS_STR_FILLED(info->name)) { META_CONPRINTF(" Title: %s\n", info->name); } - if (info->author) + if (IS_STR_FILLED(info->author)) { META_CONPRINTF(" Author: %s\n", info->author); } - if (info->version) + if (IS_STR_FILLED(info->version)) { META_CONPRINTF(" Version: %s\n", info->version); } - if (info->description) + if (IS_STR_FILLED(info->description)) { META_CONPRINTF(" Description: %s\n", info->description); } - if (info->url) + if (IS_STR_FILLED(info->url)) { META_CONPRINTF(" URL: %s\n", info->url); } From 352b15c1b7d6e1dbaa1efa1c7739beecaf0e29f7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 17 Dec 2006 09:56:45 +0000 Subject: [PATCH 0197/1664] Added Handle cloning and reference counting in preparation for IShareSys Made the internal code a bit more flexible and improved access security structures --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40227 --- core/interfaces/IHandleSys.h | 50 +++++-- core/systems/HandleSys.cpp | 254 ++++++++++++++++++++++++++--------- core/systems/HandleSys.h | 39 ++++-- core/systems/PluginSys.cpp | 25 ++-- 4 files changed, 270 insertions(+), 98 deletions(-) diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index 2621ba6d..08d0d71e 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -36,29 +36,39 @@ namespace SourceMod HandleError_Freed, /* The handle has been freed */ HandleError_Index, /* generic internal indexing error */ HandleError_Access, /* No access permitted to free this handle */ + HandleError_Limit, /* The limited number of handles has been reached */ }; - struct HandleAccess + enum HandleAccessRight { - HandleAccess() : canRead(true), canDelete(true), canInherit(true), canCreate(true) - { - } - bool canCreate; /* Instances can be created by other objects (this makes it searchable) */ - bool canRead; /* Handles can be read by other objects */ - bool canDelete; /* Handles can be deleted by other objects */ - bool canInherit; /* Handle type can be inherited */ + HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */ + HandleAccess_Read, /* HANDLES: Can be read by other objects */ + HandleAccess_Delete, /* HANDLES: Can be deleted by other objects */ + HandleAccess_Inherit, /* TYPE: Can be inherited by new types */ + HandleAccess_Clone, /* HANDLES: Can be cloned */ + /* ------------- */ + HandleAccess_TOTAL, /* Total number of access rights */ }; struct HandleSecurity { - IdentityToken_t owner; /* Owner of the handle */ - HandleAccess all; /* Access permissions of everyone */ + HandleSecurity() + { + owner = 0; + access[HandleAccess_Create] = true; + access[HandleAccess_Read] = true; + access[HandleAccess_Delete] = true; + access[HandleAccess_Inherit] = true; + access[HandleAccess_Clone] = true; + } + IdentityToken_t owner; /* Owner of the handle */ + bool access[HandleAccess_TOTAL]; /* World access rights */ }; class IHandleTypeDispatch { public: - virtual unsigned int GetInterfaceVersion() + virtual unsigned int GetDispatchVersion() { return SMINTERFACE_HANDLESYSTEM_VERSION; } @@ -174,13 +184,27 @@ namespace SourceMod IdentityToken_t ident) =0; /** - * @brief Destroys a handle. + * @brief Frees the memory associated with a handle and calls any destructors. + * NOTE: This function will decrement the internal reference counter. It will + * only perform any further action if the counter hits 0. * * @param type Handle_t identifier to destroy. * @param ident Identity token, for destroying secure handles (0 for none). * @return A HandleError error code. */ - virtual HandleError DestroyHandle(Handle_t handle, IdentityToken_t ident) =0; + virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t ident) =0; + + /** + * @brief Clones a handle by adding to its internal reference count. Its data, + * type, and security permissions remain the same. + * + * @param handle Handle to duplicate. Any non-free handle target is valid. + * @param newhandle If non-NULL, stores the duplicated handle in the pointer. + * @param source New source of cloned handle. + * @param ident Security token, if needed. + * @return A HandleError error code. + */ + virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident) =0; /** * @brief Retrieves the contents of a handle. diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 78c32af1..35ef4a62 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -1,5 +1,6 @@ #include "HandleSys.h" #include "PluginSys.h" +#include HandleSystem g_HandleSys; @@ -56,7 +57,7 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, } if (parent >= HANDLESYS_TYPEARRAY_SIZE || m_Types[parent].dispatch != NULL - || m_Types[parent].sec.all.canInherit == false) + || m_Types[parent].sec.access[HandleAccess_Inherit] == false) { return 0; } @@ -68,12 +69,13 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, { security = &m_Types[parent].sec; } else { - static HandleSecurity def_h = {0, HandleAccess() }; + static HandleSecurity def_h; security = &def_h; } } - if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL)) + if (security->access[HandleAccess_Create] + && sm_trie_retrieve(m_TypeLookup, name, NULL)) { return 0; } @@ -158,6 +160,54 @@ bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) return true; } +HandleError HandleSystem::MakePrimHandle(HandleType_t type, + QHandle **in_pHandle, + unsigned int *in_index, + Handle_t *in_handle) +{ + unsigned int handle; + if (m_FreeHandles == 0) + { + if (m_HandleTail >= HANDLESYS_MAX_HANDLES) + { + return HandleError_Limit;; + } + handle = ++m_HandleTail; + } else { + handle = m_Handles[m_FreeHandles--].freeID; + } + + QHandle *pHandle = &m_Handles[handle]; + + assert(pHandle->set == false); + + if (++m_HSerial >= HANDLESYS_MAX_SERIALS) + { + m_HSerial = 1; + } + + /* Set essential information */ + pHandle->set = true; + pHandle->refcount = 1; + pHandle->type = type; + pHandle->serial = m_HSerial; + + /* Create the hash value */ + Handle_t hash = pHandle->serial; + hash <<= 16; + hash |= handle; + + /* Add a reference count to the type */ + m_Types[type].opened++; + + /* Output */ + *in_pHandle = pHandle; + *in_index = handle; + *in_handle = hash; + + return HandleError_None; +} + Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) { if (!type @@ -169,44 +219,27 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok /* Check the security of this handle */ QHandleType *pType = &m_Types[type]; - if (!pType->sec.all.canCreate + if (!pType->sec.access[HandleAccess_Create] && pType->sec.owner != ident) { return 0; } - unsigned int handle = 0; - if (m_FreeHandles == 0) + unsigned int index; + Handle_t handle; + QHandle *pHandle; + HandleError err; + + if ((err=MakePrimHandle(type, &pHandle, &index, &handle)) != HandleError_None) { - if (m_HandleTail >= HANDLESYS_MAX_HANDLES) - { - return 0; - } - handle = ++m_HandleTail; - } else { - handle = m_Handles[m_FreeHandles--].freeID; + return 0; } - QHandle *pHandle = &m_Handles[handle]; - - pHandle->type = type; pHandle->source = source; - pHandle->set = true; pHandle->object = object; + pHandle->clone = 0; - if (++m_HSerial >= HANDLESYS_MAX_SERIALS) - { - m_HSerial = 1; - } - pHandle->serial = m_HSerial; - - Handle_t hash = pHandle->serial; - hash <<= 16; - hash |= handle; - - pType->opened++; - - return hash; + return handle; } Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, @@ -219,7 +252,11 @@ Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, return CreateHandle(type, object, pPlugin->GetIdentity(), ident); } -HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) +HandleError HandleSystem::GetHandle(Handle_t handle, + IdentityToken_t ident, + QHandle **in_pHandle, + unsigned int *in_index, + HandleAccessRight access) { unsigned int serial = (handle >> 16); unsigned int index = (handle & HANDLESYS_HANDLE_MASK); @@ -232,8 +269,8 @@ HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) QHandle *pHandle = &m_Handles[index]; QHandleType *pType = &m_Types[pHandle->type]; - if (!pType->sec.all.canDelete - && pType->sec.owner != ident) + if ((access != HandleAccess_TOTAL) + && (!pType->sec.access[access] && pType->sec.owner != ident)) { return HandleError_Access; } @@ -246,10 +283,80 @@ HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) return HandleError_Changed; } - pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); - pType->opened--; - pHandle->set = false; - m_Handles[++m_FreeTypes].freeID = index; + *in_pHandle = pHandle; + *in_index = index; + + return HandleError_None; +} + +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t source, IdentityToken_t ident) +{ + HandleError err; + QHandle *pHandle; + unsigned int index; + + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Clone)) != HandleError_None) + { + return err; + } + + QHandleType *pType = &m_Types[pHandle->type]; + + /* Get a new Handle ID */ + unsigned int new_index; + QHandle *pNewHandle; + Handle_t new_handle; + + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle)) != HandleError_None) + { + return err; + } + + pNewHandle->clone = index; + pNewHandle->source = source; + + if (out_newhandle) + { + *out_newhandle = new_handle; + } + + return HandleError_None; +} + +HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) +{ + unsigned int index; + QHandle *pHandle; + HandleError err; + + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Delete)) != HandleError_None) + { + return err; + } + + QHandleType *pType = &m_Types[pHandle->type]; + + bool dofree = false; + if (pHandle->clone) + { + /* If we're a clone, there's not a lot to do. */ + if (FreeHandle(pHandle->clone, ident) != HandleError_None) + { + assert(false); + } + dofree = true; + } else { + if (--pHandle->refcount == 0) + { + dofree = true; + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + } + } + + if (dofree) + { + ReleasePrimHandle(index); + } return HandleError_None; } @@ -264,24 +371,13 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, IdentityToken_t ident, void **object) { - unsigned int serial = (handle >> 16); - unsigned int index = (handle & HANDLESYS_HANDLE_MASK); + unsigned int index; + QHandle *pHandle; + HandleError err; - if (index == 0 || index == 0xFFFF) + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Read)) != HandleError_None) { - return HandleError_Index; - } - - QHandle *pHandle = &m_Handles[index]; - - /* Do sanity checks first */ - if (!pHandle->set) - { - return HandleError_Freed; - } - if (pHandle->serial != serial) - { - return HandleError_Changed; + return err; } /* Check the type inheritance */ @@ -299,22 +395,28 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, } } - /* Now do security checks */ - QHandleType *pType = &m_Types[pHandle->type]; - if (!pType->sec.all.canRead - && pType->sec.owner != ident) - { - return HandleError_Access; - } - if (object) { + /* if we're a clone, the rules change - object is ONLY in our reference */ + if (pHandle->clone) + { + pHandle = &m_Handles[pHandle->clone]; + } *object = pHandle->object; } return HandleError_None; } +void HandleSystem::ReleasePrimHandle(unsigned int index) +{ + QHandle *pHandle = &m_Handles[index]; + + pHandle->set = false; + m_Types[pHandle->type].opened--; + m_Handles[++m_FreeHandles].freeID = index; +} + bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) { if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) @@ -358,17 +460,37 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) if (pType->opened) { QHandle *pHandle; - for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++) + for (unsigned int i=1; iset || pHandle->type != type) { continue; } - dispatch->OnHandleDestroy(type, pHandle->object); - pHandle->set = false; - m_Handles[++m_FreeHandles].freeID = i; - if (--pType->opened == 0) + if (pHandle->clone) + { + /* Get parent */ + QHandle *pOther = &m_Handles[pHandle->clone]; + if (--pOther->refcount == 0) + { + /* Free! */ + dispatch->OnHandleDestroy(type, pOther->object); + ReleasePrimHandle(pHandle->clone); + } + /* Unlink ourselves since we don't have a reference count */ + ReleasePrimHandle(i); + } else { + /* If it's not a clone, we still have to check the reference count. + * Either way, we'll be destroyed eventually because the handle types do not change. + */ + if (--pHandle->refcount == 0) + { + /* Free! */ + dispatch->OnHandleDestroy(type, pHandle->object); + ReleasePrimHandle(i); + } + } + if (pType->opened == 0) { break; } diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 84a78b55..755de11f 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -7,7 +7,7 @@ #include "sourcemod.h" #include "sm_memtable.h" -#define HANDLESYS_MAX_HANDLES (1<<16) +#define HANDLESYS_MAX_HANDLES (1<<14) #define HANDLESYS_MAX_TYPES (1<<9) #define HANDLESYS_MAX_SUBTYPES 0xF #define HANDLESYS_SUBTYPE_MASK 0xF @@ -18,12 +18,14 @@ struct QHandle { - HandleType_t type; - void *object; - unsigned int freeID; - IdentityToken_t source; - bool set; - unsigned int serial; + HandleType_t type; /* Handle type */ + void *object; /* Unmaintained object pointer */ + unsigned int freeID; /* ID of a free handle in the free handle chain */ + IdentityToken_t source; /* Identity of object which owns this */ + unsigned int serial; /* Serial no. for sanity checking */ + unsigned int refcount; /* Reference count for safe destruction */ + Handle_t clone; /* If non-zero, this is our cloned parent */ + bool set; /* Whether or not this handle is set */ }; struct QHandleType @@ -56,8 +58,29 @@ public: //IHandleSystem IdentityToken_t source, IdentityToken_t ident); Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t ident); - HandleError DestroyHandle(Handle_t handle, IdentityToken_t ident); + HandleError FreeHandle(Handle_t handle, IdentityToken_t ident); + HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident); HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object); +private: + /** + * Decodes a handle with sanity and security checking. + */ + HandleError GetHandle(Handle_t handle, + IdentityToken_t ident, + QHandle **pHandle, + unsigned int *index, + HandleAccessRight access); + + /** + * Creates a basic handle and sets its reference count to 1. + * Does not do any type or security checking. + */ + HandleError MakePrimHandle(HandleType_t type, QHandle **pHandle, unsigned int *index, HandleType_t *handle); + + /** + * Frees a primitive handle. Does no object freeing, only reference count and bookkeepping. + */ + void ReleasePrimHandle(unsigned int index); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index f03afe53..ce10f096 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -54,12 +54,6 @@ CPlugin::~CPlugin() m_pub_funcs = NULL; } - if (m_plugin) - { - g_pSourcePawn->FreeFromMemory(m_plugin); - m_plugin = NULL; - } - if (m_priv_funcs) { for (unsigned int i=0; iFreeFromMemory(m_plugin); + m_plugin = NULL; + } + + g_HandleSys.FreeHandle(m_handle, g_PluginType); } CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) @@ -328,7 +330,7 @@ void CPlugin::Call_OnPluginInit() } /* :TODO: push our own handle */ - pFunction->PushCell(0); + pFunction->PushCell(m_handle); if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) { /* :TODO: log into debugger instead */ @@ -360,7 +362,7 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) return true; } - pFunction->PushCell(0); //:TODO: handle to ourself + pFunction->PushCell(m_handle); pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0); pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK); pFunction->PushCell(maxlength); @@ -1093,9 +1095,10 @@ void CPluginManager::OnSourceModAllInitialized() HandleSecurity sec; sec.owner = 1; /* :TODO: implement ShareSys */ - sec.all.canCreate = false; - sec.all.canDelete = false; - sec.all.canInherit = false; + sec.access[HandleAccess_Create] = false; + sec.access[HandleAccess_Delete] = false; + sec.access[HandleAccess_Inherit] = false; + sec.access[HandleAccess_Clone] = false; g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec); } From 7af40128a3f4387be2eabfa7718eef274c70ff5b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 17 Dec 2006 09:59:01 +0000 Subject: [PATCH 0198/1664] Clarified states a little Fixed include order and double include prevention --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40228 --- core/interfaces/IPluginSys.h | 2 ++ core/sm_srvcmds.cpp | 29 ++++++++++++++++------------- core/sm_srvcmds.h | 11 ++++++++--- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index fabf86c1..037cc33b 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -28,6 +28,8 @@ namespace SourceMod /** * @brief Describes the usability status of a plugin. + * Note: The status "Loaded" and "Created" are only reachable + * during map load. */ enum PluginStatus { diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 451b34d0..8148c8f5 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -29,11 +29,11 @@ inline const char *StatusToStr(PluginStatus st) case Plugin_BadLoad: return "Bad Load"; default: + assert(false); return "-"; } } -#define IS_STR_FILLED(var) (var[0] != '\0') CON_COMMAND(sm, "SourceMod Menu") { int argnum = engine->Cmd_Argc(); @@ -69,12 +69,12 @@ CON_COMMAND(sm, "SourceMod Menu") const sm_plugininfo_t *info = pl->GetPublicInfo(); len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); - if (IS_STR_FILLED(info->version)) + len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (info->name) ? info->name : iter->GetPlugin()->GetFilename()); + if (info->version) { len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); } - if (IS_STR_FILLED(info->author)) + if (info->author) { snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); } @@ -102,6 +102,7 @@ CON_COMMAND(sm, "SourceMod Menu") } return; + } else if (!strcmp("unload", cmd2)) { if (argnum < 4) { @@ -109,6 +110,7 @@ CON_COMMAND(sm, "SourceMod Menu") return; } + IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -119,11 +121,11 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - IPlugin *pl = iter->GetPlugin(); + pl = iter->GetPlugin(); char name[64]; const sm_plugininfo_t *info = pl->GetPublicInfo(); - strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + strcpy(name, (info->name) ? info->name : pl->GetFilename()); if (g_PluginSys.UnloadPlugin(pl)) { @@ -134,6 +136,7 @@ CON_COMMAND(sm, "SourceMod Menu") iter->Release(); return; + } else if (!strcmp("info", cmd2)) { if (argnum < 4) { @@ -141,6 +144,7 @@ CON_COMMAND(sm, "SourceMod Menu") return; } + IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -151,28 +155,27 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - - IPlugin *pl = iter->GetPlugin(); + pl = iter->GetPlugin(); const sm_plugininfo_t *info = pl->GetPublicInfo(); META_CONPRINTF(" Filename: %s\n", pl->GetFilename()); - if (IS_STR_FILLED(info->name)) + if (info->name) { META_CONPRINTF(" Title: %s\n", info->name); } - if (IS_STR_FILLED(info->author)) + if (info->author) { META_CONPRINTF(" Author: %s\n", info->author); } - if (IS_STR_FILLED(info->version)) + if (info->version) { META_CONPRINTF(" Version: %s\n", info->version); } - if (IS_STR_FILLED(info->description)) + if (info->description) { META_CONPRINTF(" Description: %s\n", info->description); } - if (IS_STR_FILLED(info->url)) + if (info->url) { META_CONPRINTF(" URL: %s\n", info->url); } diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 62670c3e..aa4ac340 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -1,7 +1,10 @@ -#include "sourcemm_api.h" -#include +#ifndef _INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ +#define _INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ + #include "sourcemod.h" #include "PluginSys.h" +#include "sourcemm_api.h" +#include using namespace SourceMod; @@ -13,4 +16,6 @@ public: // IConCommandBaseAccessor virtual bool RegisterConCommandBase(ConCommandBase *pCommand); public: // SMGlobalClass virtual void OnSourceModStartup(bool late); -}; \ No newline at end of file +}; + +#endif //_INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ From 2fb3501e0d7ec6c50b4582ee1b5a3e61caf30cc6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 17 Dec 2006 20:33:31 +0000 Subject: [PATCH 0199/1664] recommited this, hi --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40229 --- core/sm_srvcmds.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 8148c8f5..6d8f8ed0 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -34,6 +34,7 @@ inline const char *StatusToStr(PluginStatus st) } } +#define IS_STR_FILLED(var) (var[0] != '\0') CON_COMMAND(sm, "SourceMod Menu") { int argnum = engine->Cmd_Argc(); @@ -69,12 +70,12 @@ CON_COMMAND(sm, "SourceMod Menu") const sm_plugininfo_t *info = pl->GetPublicInfo(); len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (info->name) ? info->name : iter->GetPlugin()->GetFilename()); - if (info->version) + len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + if (IS_STR_FILLED(info->version)) { len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); } - if (info->author) + if (IS_STR_FILLED(info->author)) { snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); } @@ -102,7 +103,6 @@ CON_COMMAND(sm, "SourceMod Menu") } return; - } else if (!strcmp("unload", cmd2)) { if (argnum < 4) { @@ -110,7 +110,6 @@ CON_COMMAND(sm, "SourceMod Menu") return; } - IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -121,11 +120,11 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - pl = iter->GetPlugin(); + IPlugin *pl = iter->GetPlugin(); char name[64]; const sm_plugininfo_t *info = pl->GetPublicInfo(); - strcpy(name, (info->name) ? info->name : pl->GetFilename()); + strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); if (g_PluginSys.UnloadPlugin(pl)) { @@ -136,7 +135,6 @@ CON_COMMAND(sm, "SourceMod Menu") iter->Release(); return; - } else if (!strcmp("info", cmd2)) { if (argnum < 4) { @@ -144,7 +142,6 @@ CON_COMMAND(sm, "SourceMod Menu") return; } - IPlugin *pl = NULL; int id = 1; int num = atoi(engine->Cmd_Argv(3)); if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) @@ -155,27 +152,28 @@ CON_COMMAND(sm, "SourceMod Menu") IPluginIterator *iter = g_PluginSys.GetPluginIterator(); for (; iter->MorePlugins() && idNextPlugin(), id++) {} - pl = iter->GetPlugin(); + + IPlugin *pl = iter->GetPlugin(); const sm_plugininfo_t *info = pl->GetPublicInfo(); META_CONPRINTF(" Filename: %s\n", pl->GetFilename()); - if (info->name) + if (IS_STR_FILLED(info->name)) { META_CONPRINTF(" Title: %s\n", info->name); } - if (info->author) + if (IS_STR_FILLED(info->author)) { META_CONPRINTF(" Author: %s\n", info->author); } - if (info->version) + if (IS_STR_FILLED(info->version)) { META_CONPRINTF(" Version: %s\n", info->version); } - if (info->description) + if (IS_STR_FILLED(info->description)) { META_CONPRINTF(" Description: %s\n", info->description); } - if (info->url) + if (IS_STR_FILLED(info->url)) { META_CONPRINTF(" URL: %s\n", info->url); } From aba273f93d5f6e204f447220ed18c85f0a3dbf69 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 23 Dec 2006 02:20:53 +0000 Subject: [PATCH 0200/1664] IPlugin context pointer is passed now to natives Added basic string natives Added floating point natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40230 --- core/msvc8/sourcemod_mm.vcproj | 8 + core/smn_float.cpp | 280 +++++++++++++++++++++++++++++++ core/smn_string.cpp | 111 ++++++++++++ sourcepawn/include/sp_vm_types.h | 2 +- sourcepawn/jit/x86/jit_x86.cpp | 5 +- 5 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 core/smn_float.cpp create mode 100644 core/smn_string.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index f0900e3f..f729f595 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -194,6 +194,14 @@ RelativePath="..\sm_trie.cpp" > + + + + diff --git a/core/smn_float.cpp b/core/smn_float.cpp new file mode 100644 index 00000000..cba159f9 --- /dev/null +++ b/core/smn_float.cpp @@ -0,0 +1,280 @@ +#include +#include +#include "sp_vm_api.h" + +using namespace SourcePawn; + +#define PI 3.14159265358979323846 + +inline cell_t ftoc(float val) +{ + return *(cell_t *)&val; +} +inline float ctof(cell_t val) +{ + return *(float *)&val; +} + +inline float AngleToRadians(float val, int mode) +{ + switch (mode) + { + case 1: + { + return (float)((val * PI) / 180.0); + } + case 2: + { + return (float)((val * PI) / 200.0); + } + default: + { + return val; + } + } +} + +inline float RadiansToAngle(float val, int mode) +{ + switch (mode) + { + case 1: + { + return (float)((val / PI) * 180.0); + } + case 2: + { + return (float)((val / PI) * 200.0); + } + default: + { + return val; + } + } +} + + +/**************************************** +* * +* FLOATING POINT NATIVE IMPLEMENTATIONS * +* * +****************************************/ + + +static cell_t sm_float(IPluginContext *pCtx, const cell_t *params) +{ + float val = static_cast(params[1]); + + return ftoc(val); +} + +static cell_t sm_floatabs(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = (val >= 0) ? val : -val; + + return ftoc(val); +} + +static cell_t sm_floatadd(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]) + ctof(params[2]); + + return ftoc(val); +} + +static cell_t sm_floatsub(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]) - ctof(params[2]); + + return ftoc(val); +} + +static cell_t sm_floatmul(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]) * ctof(params[2]); + + return ftoc(val); +} + +static cell_t sm_floatdiv(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]) / ctof(params[2]); + + return ftoc(val); +} + +static cell_t sm_floatcmp(IPluginContext *pCtx, const cell_t *params) +{ + float val1 = ctof(params[1]); + float val2 = ctof(params[2]); + + if (val1 > val2) + { + return 1; + } else if (val1 < val2) { + return -1; + } + + return 0; +} + +static cell_t sm_floatlog(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + float base = ctof(params[2]); + + if ((val <= 0) || (base <= 0)) + { + //:TODO: error out! logs cant take in negative numbers and log 0=-inf + } + if (base == 10.0) + { + val = log10(val); + } else { + val = log(val) / log(base); + } + + return ftoc(val); +} + +static cell_t sm_floatexp(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + + return ftoc(exp(val)); +} + +static cell_t sm_floatpower(IPluginContext *pCtx, const cell_t *params) +{ + float base = ctof(params[1]); + float exponent = ctof(params[2]); + + return ftoc(pow(base, exponent)); +} + +static cell_t sm_floatsqroot(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + + if (val < 0.0) + { + //:TODO: error out! we dont support complex numbers + } + + return ftoc(sqrt(val)); +} + +static cell_t sm_floatround(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + + switch (params[2]) + { + case 1: + { + val = floor(val); + break; + } + case 2: + { + val = ceil(val); + break; + } + case 3: + { + if (val >= 0.0) + { + val = floor(val); + } else { + val = ceil(val); + } + break; + } + default: + { + val = (float)floor(val + 0.5); + break; + } + } + + return ftoc(val); +} + +static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + + pCtx->LocalToString(params[1], &str); + if (!strlen(str)) + { + return 0; + } + + return ftoc((float)atof(str)); +} + +static cell_t sm_floatfract(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = val - floor(val); + + return ftoc(val); +} + +static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = sin(AngleToRadians(val, params[2])); + + return ftoc(val); +} + +static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = cos(AngleToRadians(val, params[2])); + + return ftoc(val); +} + +static cell_t sm_floattan(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = tan(AngleToRadians(val, params[2])); + + return ftoc(val); +} + +static cell_t sm_floatasin(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = asin(val); + + return ftoc(RadiansToAngle(val, params[2])); +} + +static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = acos(val); + + return ftoc(RadiansToAngle(val, params[2])); +} + +static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) +{ + float val = ctof(params[1]); + val = atan(val); + + return ftoc(RadiansToAngle(val, params[2])); +} + +static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) +{ + float val1 = ctof(params[1]); + float val2 = ctof(params[2]); + val1 = atan2(val1, val2); + + return ftoc(RadiansToAngle(val1, params[3])); +} diff --git a/core/smn_string.cpp b/core/smn_string.cpp new file mode 100644 index 00000000..627d1a90 --- /dev/null +++ b/core/smn_string.cpp @@ -0,0 +1,111 @@ +#include "sm_platform.h" +#include +#include +#include "sp_vm_api.h" + +using namespace SourcePawn; + +const char *stristr(const char *str, const char *substr) +{ + if (!*substr) + { + return ((char *)str); + } + + char *needle = (char *)substr; + char *prevloc = (char *)str; + char *haystack = (char *)str; + + while (*haystack) + { + if (tolower(*haystack) == tolower(*needle)) + { + haystack++; + if (!*++needle) + { + return prevloc; + } + } else { + haystack = ++prevloc; + needle = (char *)substr; + } + } + + return NULL; +} + +inline const char *_strstr(const char *str, const char *substr) +{ +#ifdef PLATFORM_WINDOWS + return strstr(str, substr); +#elif PLATFORM_LINUX + return (const char *)strstr(str, substr); +#endif +} + +/********************************************* +* * +* STRING MANIPULATION NATIVE IMPLEMENTATIONS * +* * +*********************************************/ + + +static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + pCtx->LocalToString(params[1], &str); + + return strlen(str); +} + +static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params) +{ + typedef const char *(*STRSEARCH)(const char *, const char *); + STRSEARCH func; + char *str, *substr; + + pCtx->LocalToString(params[1], &str); + pCtx->LocalToString(params[2], &substr); + + func = (params[3]) ? _strstr : stristr; + const char *pos = func(str, substr); + if (pos) + { + return (pos - str); + } + + return -1; +} + +static cell_t sm_equal(IPluginContext *pCtx, const cell_t *params) +{ + typedef int (*STRCOMPARE)(const char *, const char *); + STRCOMPARE func; + char *str1, *str2; + + pCtx->LocalToString(params[1], &str1); + pCtx->LocalToString(params[2], &str2); + + func = (params[3]) ? strcmp : stricmp; + + return (func(str1, str2)) ? 0 : 1; +} + +static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) +{ + char *dest, *src, *start; + int len; + + pCtx->LocalToString(params[1], &dest); + pCtx->LocalToString(params[3], &src); + len = params[2]; + + start = dest; + while ((*src) && (len--)) + { + *dest++ = *src++; + } + *dest = '\0'; + + return (dest - start); +} diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index a5987d64..3065915c 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -107,7 +107,7 @@ namespace SourcePawn struct sp_context_s; -typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, const cell_t *); +typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); /********************************************** *** The following structures are bound to the VM/JIT. diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 44d5b33f..3cafd163 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1776,11 +1776,12 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) return 0; } - return native->pfn(ctx, params); + return native->pfn(ctx->context, params); } -cell_t InvalidNative(sp_context_t *ctx, const cell_t *params) +static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params) { + sp_context_t *ctx = pCtx->GetContext(); ctx->err = SP_ERROR_INVALID_NATIVE; return 0; From 5e75d0928c07f67ef04c9106b0082ab15f48495f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 28 Dec 2006 00:48:09 +0000 Subject: [PATCH 0201/1664] Added PlayerManager basic hookings Moved ftoc and ctof to an utility file Added some more string natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40231 --- core/CPlayerManager.cpp | 101 ++++++++++++++++++++++++++++ core/CPlayerManager.h | 29 ++++++++ core/msvc8/sourcemod_mm.vcproj | 12 ++++ core/smn_float.cpp | 10 +-- core/smn_string.cpp | 46 +++++++++++++ core/sourcemm_api.cpp | 4 +- core/sourcemm_api.h | 1 + core/systems/ForwardSys.cpp | 3 + sourcepawn/include/sp_vm_typeutil.h | 15 +++++ 9 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 core/CPlayerManager.cpp create mode 100644 core/CPlayerManager.h create mode 100644 sourcepawn/include/sp_vm_typeutil.h diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp new file mode 100644 index 00000000..968e18af --- /dev/null +++ b/core/CPlayerManager.cpp @@ -0,0 +1,101 @@ +#include "CPlayerManager.h" +#include "ForwardSys.h" + +SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int); +SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *); +SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *); +SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *); + +void CPlayerManager::OnSourceModAllInitialized() +{ + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); + + /* Register OnClientConnect */ + ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; + m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1); + + /* Register OnClientPutInServer */ + ParamType p2[] = {Param_Cell}; + m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2); + + /* Register OnClientDisconnect */ + m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2); + + /* Register OnClientDisconnect_Post */ + m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2); + + /* Register OnClientCommand */ + m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2); + + /* Register OnClientAuthorized */ + //:TODO: +} + +void CPlayerManager::OnSourceModShutdown() +{ + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); + + /* Release forwards */ + g_Forwards.ReleaseForward(m_clconnect); + g_Forwards.ReleaseForward(m_clputinserver); + g_Forwards.ReleaseForward(m_cldisconnect); + g_Forwards.ReleaseForward(m_cldisconnect_post); + g_Forwards.ReleaseForward(m_clcommand); +} + +bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) +{ + cell_t res = 1; + + m_clconnect->PushCell(engine->IndexOfEdict(pEntity)); + m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK); + m_clconnect->PushCell(maxrejectlen); + m_clconnect->Execute(&res, NULL); + + return (res) ? true : false; +} + +void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername) +{ + cell_t res; + + m_clputinserver->PushCell(engine->IndexOfEdict(pEntity)); + m_clputinserver->Execute(&res, NULL); +} + +void CPlayerManager::OnClientAuthorized() +{ + //:TODO: +} + +void CPlayerManager::OnClientDisconnect(edict_t *pEntity) +{ + cell_t res; + + m_cldisconnect->PushCell(engine->IndexOfEdict(pEntity)); + m_cldisconnect->Execute(&res, NULL); +} + +void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) +{ + cell_t res; + + m_cldisconnect_post->PushCell(engine->IndexOfEdict(pEntity)); + m_cldisconnect_post->Execute(&res, NULL); +} + +void CPlayerManager::OnClientCommand(edict_t *pEntity) +{ + cell_t res; + + m_clcommand->PushCell(engine->IndexOfEdict(pEntity)); + m_clcommand->Execute(&res, NULL); +} \ No newline at end of file diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h new file mode 100644 index 00000000..b11b233c --- /dev/null +++ b/core/CPlayerManager.h @@ -0,0 +1,29 @@ +#ifndef _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ + +#include "sourcemod.h" +#include +#include "sourcemm_api.h" +#include + +class CPlayerManager : public SMGlobalClass +{ +public: //SMGlobalClass + virtual void OnSourceModAllInitialized(); + virtual void OnSourceModShutdown(); +public: + bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); + void OnClientPutInServer(edict_t *pEntity, char const *playername); + void OnClientDisconnect(edict_t *pEntity); + void OnClientDisconnect_Post(edict_t *pEntity); + void OnClientAuthorized(); //:TODO: any args needed? + void OnClientCommand(edict_t *pEntity); +private: + IForward *m_clconnect; + IForward *m_cldisconnect; + IForward *m_cldisconnect_post; + IForward *m_clputinserver; + IForward *m_clcommand; +}; + +#endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ \ No newline at end of file diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index f729f595..79ece72c 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -178,6 +178,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -216,6 +220,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + @@ -499,6 +507,10 @@ RelativePath="..\..\sourcepawn\include\sp_vm_types.h" > + + diff --git a/core/smn_float.cpp b/core/smn_float.cpp index cba159f9..96a4d129 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,20 +1,12 @@ #include #include #include "sp_vm_api.h" +#include "sp_vm_typeutil.h" using namespace SourcePawn; #define PI 3.14159265358979323846 -inline cell_t ftoc(float val) -{ - return *(cell_t *)&val; -} -inline float ctof(cell_t val) -{ - return *(float *)&val; -} - inline float AngleToRadians(float val, int mode) { switch (mode) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 627d1a90..b76c485f 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -1,7 +1,9 @@ #include "sm_platform.h" #include #include +#include #include "sp_vm_api.h" +#include "sp_vm_typeutil.h" using namespace SourcePawn; @@ -43,6 +45,18 @@ inline const char *_strstr(const char *str, const char *substr) #endif } +inline int StrConvInt(const char *str) +{ + char *dummy; + return strtol(str, &dummy, 10); +} + +inline float StrConvFloat(const char *str) +{ + char *dummy; + return (float)strtod(str, &dummy); +} + /********************************************* * * * STRING MANIPULATION NATIVE IMPLEMENTATIONS * @@ -109,3 +123,35 @@ static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) return (dest - start); } + +static cell_t sm_strtonum(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + pCtx->LocalToString(params[1], &str); + + return StrConvInt(str); +} + +static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + pCtx->LocalToString(params[2], &str); + + return snprintf(str, params[3], "%d", params[1]); +} + +static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + pCtx->LocalToString(params[1], &str); + + return ftoc(StrConvFloat(str)); +} + +static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) +{ + char *str; + pCtx->LocalToString(params[2], &str); + + return snprintf(str, params[3], "%f", ctof(params[1])); +} diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 7c701977..1b593456 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -6,6 +6,7 @@ SourceMod_Core g_SourceMod_Core; IVEngineServer *engine = NULL; IServerGameDLL *gamedll = NULL; +IServerGameClients *serverClients = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -15,11 +16,12 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); return g_SourceMod.InitializeSourceMod(error, maxlen, late); } -bool SourceMod_Core::Unload(char *error, size_t maxlen) +bool SourceMod_Core::Unload(char *error, size_t maxlen) { return true; } diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index dff0a5a8..8dea8b0b 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -30,6 +30,7 @@ public: extern SourceMod_Core g_SourceMod_Core; extern IVEngineServer *engine; extern IServerGameDLL *gamedll; +extern IServerGameClients *serverClients; PLUGIN_GLOBALVARS(); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index d0dd7b26..0a3bb6b1 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -28,6 +28,9 @@ CForwardManager g_Forwards; * X Push vararg strings (copyback tested = :TODO:) */ +// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails +// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS! + void CForwardManager::OnSourceModAllInitialized() { g_PluginSys.AddPluginsListener(this); diff --git a/sourcepawn/include/sp_vm_typeutil.h b/sourcepawn/include/sp_vm_typeutil.h new file mode 100644 index 00000000..40987e4d --- /dev/null +++ b/sourcepawn/include/sp_vm_typeutil.h @@ -0,0 +1,15 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ +#define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ + +#include "sp_vm_types.h" + +inline cell_t ftoc(float val) +{ + return *(cell_t *)&val; +} +inline float ctof(cell_t val) +{ + return *(float *)&val; +} + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ \ No newline at end of file From 6e7e89e9cffd0a467923efb2220b0cde76b65334 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 29 Dec 2006 03:21:09 +0000 Subject: [PATCH 0202/1664] added atcprintf --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40232 --- core/sm_stringutil.cpp | 425 +++++++++++++++++++++++++++++++++++++++++ core/sm_stringutil.h | 12 ++ 2 files changed, 437 insertions(+) create mode 100644 core/sm_stringutil.cpp create mode 100644 core/sm_stringutil.h diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp new file mode 100644 index 00000000..6b817cda --- /dev/null +++ b/core/sm_stringutil.cpp @@ -0,0 +1,425 @@ +#include "sm_stringutil.h" + +#define ALT 0x00000001 /* alternate form */ +#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ +#define LADJUST 0x00000004 /* left adjustment */ +#define LONGDBL 0x00000008 /* long double */ +#define LONGINT 0x00000010 /* long integer */ +#define QUADINT 0x00000020 /* quad integer */ +#define SHORTINT 0x00000040 /* short integer */ +#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ +#define FPT 0x00000100 /* floating point number */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +//:TODO: fix this macro when we have a debugger + +#define CHECK_ARGS(n)/* \ + if ((arg+n) > args) { \ + LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ + return 0; \ + } +*/ + +void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) +{ + int size = 0; + char *buf; + static char nlstr[] = {'(','n','u','l','l',')','\0'}; + + buf = *buf_p; + + if (string == NULL) + { + string = nlstr; + prec = -1; + } + + if (prec >= 0) + { + for (size = 0; size < prec; size++) + { + if (string[size] == '\0') + { + break; + } + } + } else { + while (string[size++]); + size--; + } + + if (size > (int)maxlen) + { + size = maxlen; + } + + maxlen -= size; + width -= size; + + while (size--) + { + *buf++ = *string++; + } + + while ((width-- > 0) && maxlen) + { + *buf++ = ' '; + maxlen--; + } + + *buf_p = buf; +} + +void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec) +{ + char text[32]; + int digits; + double signedVal; + char *buf; + int val; + + // get the sign + signedVal = fval; + if (fval < 0) + { + fval = -fval; + } + + // write the float number + digits = 0; + val = (int)fval; + do + { + text[digits++] = '0' + val % 10; + val /= 10; + } while (val); + + if (signedVal < 0) + { + text[digits++] = '-'; + } + + buf = *buf_p; + + while ((digits < width) && maxlen) + { + *buf++ = ' '; + width--; + maxlen--; + } + + while ((digits--) && maxlen) + { + *buf++ = text[digits]; + maxlen--; + } + + *buf_p = buf; + + if (prec < 0) + { + prec = 6; + } + // write the fraction + digits = 0; + while (digits < prec) + { + fval -= (int)fval; + fval *= 10.0; + val = (int)fval; + text[digits++] = '0' + val % 10; + } + + if ((digits > 0) && maxlen) + { + buf = *buf_p; + *buf++ = '.'; + maxlen--; + for (prec = 0; maxlen && (prec < digits); prec++) + { + *buf++ = text[prec]; + maxlen--; + } + *buf_p = buf; + } +} + +void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags) +{ + char text[32]; + int digits; + char *buf; + + digits = 0; + do + { + text[digits++] = '0' + val % 10; + val /= 10; + } while (val); + + buf = *buf_p; + + if (!(flags & LADJUST)) + { + while (digits < width && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + width--; + maxlen--; + } + } + + while (digits-- && maxlen) + { + *buf++ = text[digits]; + width--; + maxlen--; + } + + if (flags & LADJUST) + { + while (width-- && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + maxlen--; + } + } + + *buf_p = buf; +} + +void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags) +{ + char text[32]; + int digits; + int signedVal; + char *buf; + unsigned int unsignedVal; + + digits = 0; + signedVal = val; + if (val < 0) + { + /* we want the unsigned version */ + unsignedVal = abs(val); + } else { + unsignedVal = val; + } + do + { + text[digits++] = '0' + unsignedVal % 10; + unsignedVal /= 10; + } while (unsignedVal); + + if (signedVal < 0) + { + text[digits++] = '-'; + } + + buf = *buf_p; + + if (!(flags & LADJUST)) + { + while ((digits < width) && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + width--; + maxlen--; + } + } + + while (digits-- && maxlen) + { + *buf++ = text[digits]; + width--; + maxlen--; + } + + if (flags & LADJUST) + { + while (width-- && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + maxlen--; + } + } + + *buf_p = buf; +} + +size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param) +{ + int arg; + //int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count + // either way this is only used when the above macro is fixed, until then not needed + char *buf_p; + char ch; + int flags; + int width; + int prec; + int n; + char sign; + const char *fmt; + size_t llen = maxlen; + + buf_p = buffer; + arg = *param; + fmt = format; + + while (true) + { + // run through the format string until we hit a '%' or '\0' + for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++) + { + *buf_p++ = ch; + llen--; + } + if ((ch == '\0') || (llen <= 0)) + { + goto done; + } + + // skip over the '%' + fmt++; + + // reset formatting state + flags = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: + ch = *fmt++; +reswitch: + switch(ch) + { + case '-': + { + flags |= LADJUST; + goto rflag; + } + case '.': + { + n = 0; + while(is_digit((ch = *fmt++))) + { + n = 10 * n + (ch - '0'); + } + prec = (n < 0) ? -1 : n; + goto reswitch; + } + case '0': + { + flags |= ZEROPAD; + goto rflag; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + n = 0; + do + { + n = 10 * n + (ch - '0'); + ch = *fmt++; + } while(is_digit(ch)); + width = n; + goto reswitch; + } + case 'c': + { + CHECK_ARGS(0); + if (llen <= 1) + { + goto done; + } + char *c; + pCtx->LocalToString(params[arg], &c); + *buf_p++ = *c; + llen--; + arg++; + break; + } + case 'd': + case 'i': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddInt(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } + case 'u': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddUInt(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } + case 'f': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddFloat(&buf_p, llen, ctof(*value), width, prec); + arg++; + break; + } + case 's': + { + CHECK_ARGS(0); + char *str; + pCtx->LocalToString(params[arg], &str); + AddString(&buf_p, llen, str, width, prec); + arg++; + break; + } + case '%': + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + case '\0': + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = '%'; + llen--; + goto done; + } + default: + { + if (llen <= 1) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + } + } + +done: + *buf_p = '\0'; + *param = arg; + return (maxlen - llen); +} diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h new file mode 100644 index 00000000..b9ae216a --- /dev/null +++ b/core/sm_stringutil.h @@ -0,0 +1,12 @@ +#ifndef _INCLUDE_SOURCEMOD_STRINGUTIL_H_ +#define _INCLUDE_SOURCEMOD_STRINGUTIL_H_ + +#include +#include "sp_vm_api.h" +#include "sp_vm_typeutil.h" + +using namespace SourcePawn; + +size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); + +#endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ From 5b331ca858cde4a04100b28d863effa8f1751b3d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 29 Dec 2006 03:29:17 +0000 Subject: [PATCH 0203/1664] added atcprintf --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40233 --- core/msvc8/sourcemod_mm.vcproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 79ece72c..91c0557c 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -194,6 +194,10 @@ RelativePath="..\sm_srvcmds.cpp" > + + @@ -244,6 +248,10 @@ RelativePath="..\sm_srvcmds.h" > + + From f068587ecce2a03e6f071061e600a26c86c3716e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 29 Dec 2006 23:18:13 +0000 Subject: [PATCH 0204/1664] initial import of sharesystem (unfinished) final revision of handle system (I hope!) initial import of plugin handles --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40234 --- core/interfaces/IHandleSys.h | 29 +++--- core/interfaces/IPluginSys.h | 2 +- core/interfaces/IShareSys.h | 64 ++++++++++-- core/sm_globals.h | 34 ++++++ core/sourcemod.h | 34 ------ core/systems/HandleSys.cpp | 185 ++++++++++++++++++++++++++++----- core/systems/HandleSys.h | 80 +++++++++++--- core/systems/PluginSys.cpp | 40 +++++-- core/systems/PluginSys.h | 14 ++- core/systems/ShareSys.cpp | 195 +++++++++++++++++++++++++++++++++++ core/systems/ShareSys.h | 69 +++++++++++++ 11 files changed, 644 insertions(+), 102 deletions(-) create mode 100644 core/systems/ShareSys.cpp create mode 100644 core/systems/ShareSys.h diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index 08d0d71e..d2b2c297 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -7,6 +7,8 @@ #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" #define SMINTERFACE_HANDLESYSTEM_VERSION 1 +#define DEFAULT_IDENTITY NULL + namespace SourceMod { /** @@ -37,6 +39,7 @@ namespace SourceMod HandleError_Index, /* generic internal indexing error */ HandleError_Access, /* No access permitted to free this handle */ HandleError_Limit, /* The limited number of handles has been reached */ + HandleError_Identity, /* The identity token was not usable */ }; enum HandleAccessRight @@ -54,14 +57,14 @@ namespace SourceMod { HandleSecurity() { - owner = 0; + owner = NULL; access[HandleAccess_Create] = true; access[HandleAccess_Read] = true; access[HandleAccess_Delete] = true; access[HandleAccess_Inherit] = true; access[HandleAccess_Clone] = true; } - IdentityToken_t owner; /* Owner of the handle */ + IdentityToken_t *owner; /* Owner of the handle */ bool access[HandleAccess_TOTAL]; /* World access rights */ }; @@ -112,12 +115,14 @@ namespace SourceMod * @param parent Parent handle to inherit from, 0 for none. * @param security Pointer to a temporary HandleSecurity object, NULL to use default * or inherited permissions. + * @param ident Security token for any permissions. * @return A new HandleType_t unique ID. */ virtual HandleType_t CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security) =0; + const HandleSecurity *security, + IdentityToken_t *ident) =0; /** @@ -143,7 +148,7 @@ namespace SourceMod * @param type Type chain to remove. * @return True on success, false on failure. */ - virtual bool RemoveType(HandleType_t type, IdentityToken_t ident) =0; + virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0; /** * @brief Finds a handle type by name. @@ -159,14 +164,14 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param source Identity token for object using this handle (for example, a script). + * @param owner Owner for the handle. * @param ident Identity token if any security rights are needed. * @return A new Handle_t, or 0 on failure. */ virtual Handle_t CreateHandle(HandleType_t type, void *object, - IdentityToken_t source, - IdentityToken_t ident) =0; + IdentityToken_t *owner, + IdentityToken_t *ident) =0; /** * @brief Creates a new handle. @@ -181,7 +186,7 @@ namespace SourceMod virtual Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, - IdentityToken_t ident) =0; + IdentityToken_t *ident) =0; /** * @brief Frees the memory associated with a handle and calls any destructors. @@ -192,7 +197,7 @@ namespace SourceMod * @param ident Identity token, for destroying secure handles (0 for none). * @return A HandleError error code. */ - virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t ident) =0; + virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident) =0; /** * @brief Clones a handle by adding to its internal reference count. Its data, @@ -200,11 +205,11 @@ namespace SourceMod * * @param handle Handle to duplicate. Any non-free handle target is valid. * @param newhandle If non-NULL, stores the duplicated handle in the pointer. - * @param source New source of cloned handle. + * @param owner New owner of cloned handle. * @param ident Security token, if needed. * @return A HandleError error code. */ - virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident) =0; + virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *owner, IdentityToken_t *ident) =0; /** * @brief Retrieves the contents of a handle. @@ -215,7 +220,7 @@ namespace SourceMod * @param object Address to store object in. * @return HandleError error code. */ - virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object) =0; + virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object) =0; }; }; diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 037cc33b..dca8e2db 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -147,7 +147,7 @@ namespace SourceMod /** * @brief Returns a plugin's identity token. */ - virtual IdentityToken_t GetIdentity() =0; + virtual IdentityToken_t *GetIdentity() =0; }; diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index 156d0470..d4f6db0f 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -3,11 +3,13 @@ #include -#define DEFAULT_IDENTITY 0 +#define NO_IDENTITY 0 namespace SourceMod { - typedef unsigned int IdentityToken_t; + struct IdentityToken_t; + typedef unsigned int HandleType_t; + typedef HandleType_t IdentityType_t; /** * @brief Defines the base functionality required by a shared interface. */ @@ -49,12 +51,13 @@ namespace SourceMod { public: /** - * @brief Adds an interface to the global interface system + * @brief Adds an interface to the global interface system. * * @param iface Interface pointer (must be unique). * @param token Parent token of the module/interface. + * @return True on success, false otherwise. */ - virtual bool AddInterface(SMInterface *iface, IdentityToken_t token) =0; + virtual bool AddInterface(SMInterface *iface, IdentityToken_t *token) =0; /** * @brief Requests an interface from the global interface system. @@ -67,8 +70,8 @@ namespace SourceMod */ virtual bool RequestInterface(const char *iface_name, unsigned int iface_vers, - IdentityToken_t token, - void **pIface) =0; + IdentityToken_t *token, + SMInterface **pIface) =0; /** * @brief Adds a list of natives to the global native pool. @@ -76,7 +79,54 @@ namespace SourceMod * @param token Identity token of parent object. * @param natives Array of natives to add, NULL terminated. */ - virtual void AddNatives(IdentityToken_t token, const sp_nativeinfo_t *natives[]) =0; + virtual void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) =0; + + /** + * @brief Creates a new identity type. + * NOTE: Module authors should never need to use this. Due to the current implementation, + * there is a hardcoded limit of 15 types. Core uses up a few, so think carefully! + * + * @param name String containing type name. Must not be empty or NULL. + * @return A new HandleType_t identifier, or 0 on failure. + */ + virtual IdentityType_t CreateIdentType(const char *name) =0; + + /** + * @brief Finds an identity type by name. + * DEFAULT IDENTITY TYPES: + * "PLUGIN" - An IPlugin object. + * "MODULE" - An IModule object. + * "CORE" - An SMGlobalClass or other singleton. + * + * @param name String containing type name to search for. + * @return A HandleType_t identifier if found, 0 otherwise. + */ + virtual IdentityType_t FindIdentType(const char *name) =0; + + /** + * @brief Creates a new identity token. This token is guaranteed to be unique + * amongst all other open identities. + * + * @param type Identity type. + * @return A new IdentityToken_t identifier. + */ + virtual IdentityToken_t *CreateIdentity(IdentityType_t type) =0; + + /** + * @brief Destroys an identity type. Note that this will delete any identities + * that are under this type. + * + * @param type Identity type. + */ + virtual void DestroyIdentType(IdentityType_t type) =0; + + /** + * @brief Destroys an identity token. Any handles being owned by this token, or + * any handles being + * + * @param identity Identity to remove. + */ + virtual void DestroyIdentity(IdentityToken_t *identity) =0; }; }; diff --git a/core/sm_globals.h b/core/sm_globals.h index a69a3abf..8426b0bd 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -13,6 +13,40 @@ using namespace SourcePawn; using namespace SourceMod; +/** + * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod + */ +class SMGlobalClass +{ + friend class SourceModBase; +public: + SMGlobalClass(); +public: + /** + * @brief Called when SourceMod is initially loading + */ + virtual void OnSourceModStartup(bool late) + { + } + + /** + * @brief Called after all global classes have initialized + */ + virtual void OnSourceModAllInitialized() + { + } + + /** + * @brief Called when SourceMod is shutting down + */ + virtual void OnSourceModShutdown() + { + } +private: + SMGlobalClass *m_pGlobalClassNext; + static SMGlobalClass *head; +}; + extern ISourcePawnEngine *g_pSourcePawn; extern IVirtualMachine *g_pVM; diff --git a/core/sourcemod.h b/core/sourcemod.h index 238531c4..0405cefd 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -52,40 +52,6 @@ private: bool m_IsLateLoadInMap; }; -/** - * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod - */ -class SMGlobalClass -{ - friend class SourceModBase; -public: - SMGlobalClass(); -public: - /** - * @brief Called when SourceMod is initially loading - */ - virtual void OnSourceModStartup(bool late) - { - } - - /** - * @brief Called after all global classes have initialized - */ - virtual void OnSourceModAllInitialized() - { - } - - /** - * @brief Called when SourceMod is shutting down - */ - virtual void OnSourceModShutdown() - { - } -private: - SMGlobalClass *m_pGlobalClassNext; - static SMGlobalClass *head; -}; - extern SourceModBase g_SourceMod; #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 35ef4a62..be91460a 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -1,9 +1,22 @@ #include "HandleSys.h" +#include "ShareSys.h" #include "PluginSys.h" #include HandleSystem g_HandleSys; +QHandle *ignore_handle; + +inline HandleType_t TypeParent(HandleType_t type) +{ + return (type & ~HANDLESYS_SUBTYPE_MASK); +} + +inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index) +{ + return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index, HandleAccess_Read); +} + HandleSystem::HandleSystem() { m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1]; @@ -28,18 +41,19 @@ HandleSystem::~HandleSystem() HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) { - return CreateTypeEx(name, dispatch, 0, NULL); + return CreateTypeEx(name, dispatch, 0, NULL, NULL); } HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch) { - return CreateTypeEx(name, dispatch, parent, NULL); + return CreateTypeEx(name, dispatch, parent, NULL, NULL); } HandleType_t HandleSystem::CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security) + const HandleSecurity *security, + IdentityToken_t *ident) { if (!dispatch) { @@ -56,8 +70,9 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, return 0; } if (parent >= HANDLESYS_TYPEARRAY_SIZE - || m_Types[parent].dispatch != NULL - || m_Types[parent].sec.access[HandleAccess_Inherit] == false) + || m_Types[parent].dispatch == NULL + || (m_Types[parent].sec.access[HandleAccess_Inherit] == false + && m_Types[parent].sec.owner != ident)) { return 0; } @@ -163,8 +178,16 @@ bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) HandleError HandleSystem::MakePrimHandle(HandleType_t type, QHandle **in_pHandle, unsigned int *in_index, - Handle_t *in_handle) + Handle_t *in_handle, + IdentityToken_t *owner) { + unsigned int owner_index = 0; + + if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None)) + { + return HandleError_Identity; + } + unsigned int handle; if (m_FreeHandles == 0) { @@ -187,10 +210,12 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, } /* Set essential information */ - pHandle->set = true; + pHandle->set = HandleSet_Used;; pHandle->refcount = 1; pHandle->type = type; pHandle->serial = m_HSerial; + pHandle->owner = owner; + pHandle->ch_next = 0; /* Create the hash value */ Handle_t hash = pHandle->serial; @@ -205,10 +230,44 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, *in_index = handle; *in_handle = hash; + /* Decode the identity token */ + if (owner) + { + QHandle *pIdentity = &m_Handles[owner_index]; + if (pIdentity->ch_prev == 0) + { + pIdentity->ch_prev = handle; + pIdentity->ch_next = handle; + pHandle->ch_prev = 0; + } else { + /* Link previous node to us (forward) */ + m_Handles[pIdentity->ch_next].ch_next = handle; + /* Link us to previous node (backwards) */ + pHandle->ch_prev = pIdentity->ch_next; + /* Set new tail */ + pIdentity->ch_next = handle; + } + pIdentity->refcount++; + } else { + pHandle->ch_prev = 0; + } + return HandleError_None; } -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) +void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken) +{ + if (!type + || type >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[type].dispatch == NULL) + { + return; + } + + m_Types[type].sec.owner = pToken; +} + +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *source, IdentityToken_t *ident) { if (!type || type >= HANDLESYS_TYPEARRAY_SIZE @@ -230,12 +289,11 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok QHandle *pHandle; HandleError err; - if ((err=MakePrimHandle(type, &pHandle, &index, &handle)) != HandleError_None) + if ((err=MakePrimHandle(type, &pHandle, &index, &handle, source)) != HandleError_None) { return 0; } - pHandle->source = source; pHandle->object = object; pHandle->clone = 0; @@ -245,15 +303,35 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, - IdentityToken_t ident) + IdentityToken_t *ident) { IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); return CreateHandle(type, object, pPlugin->GetIdentity(), ident); } +bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) +{ + /* Check the type inheritance */ + if (intype & HANDLESYS_SUBTYPE_MASK) + { + if (intype != outtype + && (TypeParent(intype) != TypeParent(outtype))) + { + return false; + } + } else { + if (intype != outtype) + { + return false; + } + } + + return true; +} + HandleError HandleSystem::GetHandle(Handle_t handle, - IdentityToken_t ident, + IdentityToken_t *ident, QHandle **in_pHandle, unsigned int *in_index, HandleAccessRight access) @@ -277,6 +355,11 @@ HandleError HandleSystem::GetHandle(Handle_t handle, if (!pHandle->set) { return HandleError_Freed; + } else if (pHandle->set == HandleSet_Identity + && ident != g_ShareSys.GetIdentRoot()) + { + /* Only IdentityHandle() can read this! */ + return HandleError_Identity; } if (pHandle->serial != serial) { @@ -289,7 +372,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle, return HandleError_None; } -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t source, IdentityToken_t ident) +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t *source, IdentityToken_t *ident) { HandleError err; QHandle *pHandle; @@ -307,13 +390,12 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, QHandle *pNewHandle; Handle_t new_handle; - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle)) != HandleError_None) + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, source)) != HandleError_None) { return err; } pNewHandle->clone = index; - pNewHandle->source = source; if (out_newhandle) { @@ -323,7 +405,7 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return HandleError_None; } -HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) +HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *ident) { unsigned int index; QHandle *pHandle; @@ -361,14 +443,9 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) return HandleError_None; } -inline HandleType_t TypeParent(HandleType_t type) -{ - return (type & ~HANDLESYS_SUBTYPE_MASK); -} - HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, - IdentityToken_t ident, + IdentityToken_t *ident, void **object) { unsigned int index; @@ -412,12 +489,59 @@ void HandleSystem::ReleasePrimHandle(unsigned int index) { QHandle *pHandle = &m_Handles[index]; - pHandle->set = false; + pHandle->set = HandleSet_None; m_Types[pHandle->type].opened--; m_Handles[++m_FreeHandles].freeID = index; + + /* Unlink us if necessary */ + if (pHandle->owner) + { + unsigned int ident_index; + if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None) + { + /* Uh-oh! */ + assert(pHandle->owner == 0); + return; + } + /* Note that since 0 is an invalid handle, if any of these links are 0, + * the data can still be set. + */ + QHandle *pIdentity = &m_Handles[ident_index]; + + /* Unlink case: We're the head AND tail node */ + if (index == pIdentity->ch_prev && index == pIdentity->ch_next) + { + pIdentity->ch_prev = 0; + pIdentity->ch_next = 0; + } + /* Unlink case: We're the head node */ + else if (index == pIdentity->ch_prev) { + /* Link us to the next in the chain */ + pIdentity->ch_prev = pHandle->ch_next; + /* Patch up the previous link */ + m_Handles[pHandle->ch_next].ch_prev = 0; + } + /* Unlink case: We're the tail node */ + else if (index == pIdentity->ch_next) { + /* Link us to the previous in the chain */ + pIdentity->ch_next = pHandle->ch_prev; + /* Patch up the next link */ + m_Handles[pHandle->ch_prev].ch_next = 0; + } + /* Unlink case: We're in the middle! */ + else { + /* Patch the forward reference */ + m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev; + /* Patch the backward reference */ + m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next; + } + + /* Lastly, decrease the reference count */ + pIdentity->refcount--; + } } -bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) { if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) { @@ -499,3 +623,16 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) return true; } + +void HandleSystem::MarkHandleAsIdentity(Handle_t handle) +{ + QHandle *pHandle; + unsigned int index; + + if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index, HandleAccess_Read) != HandleError_None) + { + return; + } + + pHandle->set = HandleSet_Identity; +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 755de11f..ec88d6ca 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -16,16 +16,46 @@ #define HANDLESYS_SERIAL_MASK 0xFFFF0000 #define HANDLESYS_HANDLE_MASK 0x0000FFFF +/** + * The QHandle is a nasty structure that compacts the handle system into a big vector. + * The members of the vector each encapsulate one Handle, however, they also act as nodes + * in an inlined linked list and an inlined vector. + * + * The first of these lists is the 'freeID' list. Each node from 1 to N (where N + * is the number of free nodes) has a 'freeID' that specifies a free Handle ID. This + * is a quick hack to get around allocating a second base vector. + * + * The second vector is the identity linked list. An identity has its own handle, so + * these handles are used as sentinel nodes for index linking. They point to the first and last + * index into the handle array. Each subsequent Handle who is owned by that indentity is mapped into + * that list. This lets owning identities be unloaded in O(n) time. + * + * Eventually, there may be a third list for type chains. + */ + +enum HandleSet +{ + HandleSet_None = 0, + HandleSet_Used, + HandleSet_Identity +}; + struct QHandle { HandleType_t type; /* Handle type */ void *object; /* Unmaintained object pointer */ - unsigned int freeID; /* ID of a free handle in the free handle chain */ - IdentityToken_t source; /* Identity of object which owns this */ + IdentityToken_t *owner; /* Identity of object which owns this */ unsigned int serial; /* Serial no. for sanity checking */ unsigned int refcount; /* Reference count for safe destruction */ Handle_t clone; /* If non-zero, this is our cloned parent */ - bool set; /* Whether or not this handle is set */ + HandleSet set; /* Information about the handle's state */ + /* The following variables are unrelated to the Handle array, and used + * as an inlined chain of information */ + unsigned int freeID; /* ID of a free handle in the free handle chain */ + /* Indexes into the handle array for owner membership. + * For identity roots, these are treated as the head/tail. */ + unsigned int ch_prev; /* chained previous handle or HEAD */ + unsigned int ch_next; /* chained next handle or TAIL */ }; struct QHandleType @@ -41,6 +71,8 @@ struct QHandleType class HandleSystem : public IHandleSys { + friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index); + friend class ShareSystem; public: HandleSystem(); ~HandleSystem(); @@ -49,24 +81,26 @@ public: //IHandleSystem HandleType_t CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security); + const HandleSecurity *security, + IdentityToken_t *ident); HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); - bool RemoveType(HandleType_t type, IdentityToken_t ident); + bool RemoveType(HandleType_t type, IdentityToken_t *ident); bool FindHandleType(const char *name, HandleType_t *type); Handle_t CreateHandle(HandleType_t type, void *object, - IdentityToken_t source, - IdentityToken_t ident); - Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t ident); - HandleError FreeHandle(Handle_t handle, IdentityToken_t ident); - HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident); - HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object); -private: + IdentityToken_t *source, + IdentityToken_t *ident); + Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t *ident); + HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident); + HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); + HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); + bool TypeCheck(HandleType_t intype, HandleType_t outtype); +protected: /** * Decodes a handle with sanity and security checking. */ HandleError GetHandle(Handle_t handle, - IdentityToken_t ident, + IdentityToken_t *ident, QHandle **pHandle, unsigned int *index, HandleAccessRight access); @@ -75,12 +109,28 @@ private: * Creates a basic handle and sets its reference count to 1. * Does not do any type or security checking. */ - HandleError MakePrimHandle(HandleType_t type, QHandle **pHandle, unsigned int *index, HandleType_t *handle); + HandleError MakePrimHandle(HandleType_t type, + QHandle **pHandle, + unsigned int *index, + HandleType_t *handle, + IdentityToken_t *owner); /** - * Frees a primitive handle. Does no object freeing, only reference count and bookkeepping. + * Frees a primitive handle. Does no object freeing, only reference count, bookkeepping, + * and linked list maintenance. */ void ReleasePrimHandle(unsigned int index); + + /** + * Sets the security owner of a type + */ + void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken); + + /** + * Marks a handle as an identity. + * This prevents it from being tampered with by outside stuff + */ + void MarkHandleAsIdentity(Handle_t handle); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index ce10f096..6524fac4 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,5 +1,6 @@ #include #include "PluginSys.h" +#include "ShareSys.h" #include "LibrarySys.h" #include "HandleSys.h" #include "sourcemm_api.h" @@ -8,6 +9,7 @@ CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; +IdentityType_t g_PluginIdent = 0; CPlugin::CPlugin(const char *file) { @@ -22,8 +24,8 @@ CPlugin::CPlugin(const char *file) m_pub_funcs = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); - /* :TODO: ShareSys token */ - m_handle = g_HandleSys.CreateHandle(g_PluginType, this, DEFAULT_IDENTITY, 1); + m_handle = 0; + m_ident = NULL; } CPlugin::~CPlugin() @@ -70,7 +72,20 @@ CPlugin::~CPlugin() m_plugin = NULL; } - g_HandleSys.FreeHandle(m_handle, g_PluginType); + if (m_handle) + { + g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity()); + g_ShareSys.DestroyIdentity(m_ident); + } +} + +void CPlugin::InitIdentity() +{ + if (!m_handle) + { + m_ident = g_ShareSys.CreateIdentity(g_PluginIdent); + m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); + } } CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) @@ -447,9 +462,9 @@ bool CPlugin::SetPauseState(bool paused) return true; } -IdentityToken_t CPlugin::GetIdentity() +IdentityToken_t *CPlugin::GetIdentity() { - return 0; + return m_ident; } /******************* @@ -499,6 +514,7 @@ CPluginManager::CPluginManager() { m_LoadLookup = sm_trie_create(); m_AllPluginsLoaded = false; + m_MyIdent = NULL; } CPluginManager::~CPluginManager() @@ -661,6 +677,7 @@ void CPluginManager::LoadAutoPlugin(const char *file) if (pPlugin->GetStatus() == Plugin_Created) { AddCoreNativesToPlugin(pPlugin); + pPlugin->InitIdentity(); pPlugin->Call_AskPluginLoad(NULL, 0); } @@ -712,6 +729,8 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ AddCoreNativesToPlugin(pPlugin); + pPlugin->InitIdentity(); + /* Finally, ask the plugin if it wants to be loaded */ if (!pPlugin->Call_AskPluginLoad(error, err_max)) { @@ -1092,20 +1111,25 @@ bool CPluginManager::IsLateLoadTime() void CPluginManager::OnSourceModAllInitialized() { + m_MyIdent = g_ShareSys.CreateCoreIdentity(); + HandleSecurity sec; - sec.owner = 1; /* :TODO: implement ShareSys */ + sec.owner = m_MyIdent; /* :TODO: implement ShareSys */ sec.access[HandleAccess_Create] = false; sec.access[HandleAccess_Delete] = false; sec.access[HandleAccess_Inherit] = false; sec.access[HandleAccess_Clone] = false; - g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec); + g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec, NULL); + g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); } void CPluginManager::OnSourceModShutdown() { - g_HandleSys.RemoveType(g_PluginType, 1); + g_HandleSys.RemoveType(g_PluginType, m_MyIdent); + g_ShareSys.DestroyIdentType(g_PluginIdent); + g_ShareSys.DestroyIdentity(m_MyIdent); } void CPluginManager::OnHandleDestroy(HandleType_t type, void *object) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index b6e3769f..6f58880a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -93,7 +93,7 @@ public: virtual const sp_plugin_t *GetPluginStructure() const; virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); - virtual IdentityToken_t GetIdentity(); + virtual IdentityToken_t *GetIdentity(); public: /** * Creates a plugin object with default values. @@ -114,11 +114,17 @@ public: */ bool FinishMyCompile(char *error, size_t maxlength); void CancelMyCompile(); + /** * Sets an error state on the plugin */ void SetErrorState(PluginStatus status, const char *error_fmt, ...); + /** + * Initializes the plugin's identity information + */ + void InitIdentity(); + /** * Calls the OnPluginLoad function, and sets any failed states if necessary. * NOTE: Valid pre-states are: Plugin_Created @@ -151,6 +157,7 @@ private: CFunction **m_pub_funcs; char m_errormsg[256]; time_t m_LastAccess; + IdentityToken_t *m_ident; Handle_t m_handle; }; @@ -262,6 +269,10 @@ protected: void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); void ReleaseFunctionToPool(CFunction *func); + inline IdentityToken_t *GetIdentity() + { + return m_MyIdent; + } private: List m_listeners; List m_plugins; @@ -271,6 +282,7 @@ private: CPluginInfoDatabase m_PluginInfo; Trie *m_LoadLookup; bool m_AllPluginsLoaded; + IdentityToken_t *m_MyIdent; }; extern CPluginManager g_PluginSys; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp new file mode 100644 index 00000000..073a5e6b --- /dev/null +++ b/core/systems/ShareSys.cpp @@ -0,0 +1,195 @@ +#include "ShareSys.h" +#include "HandleSys.h" + +ShareSystem g_ShareSys; + +ShareSystem::ShareSystem() +{ + m_IdentRoot.ident = 0; + m_TypeRoot = 0; + m_IfaceType = 0; + m_CoreType = 0; +} + +IdentityToken_t *ShareSystem::CreateCoreIdentity() +{ + if (!m_CoreType) + { + m_CoreType = CreateIdentType("CORE"); + } + + return CreateIdentity(m_CoreType); +} + +void ShareSystem::OnSourceModStartup(bool late) +{ + HandleSecurity sec; + + sec.owner = GetIdentRoot(); + sec.access[HandleAccess_Inherit] = false; + sec.access[HandleAccess_Delete] = false; + + m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL); + m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL); + + /* Initialize our static identity handle */ + m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, NULL); +} + +void ShareSystem::OnSourceModShutdown() +{ + if (m_CoreType) + { + g_HandleSys.RemoveType(m_CoreType, GetIdentRoot()); + } + + g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot()); + g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot()); +} + +IdentityType_t ShareSystem::FindIdentType(const char *name) +{ + HandleType_t type; + + if (g_HandleSys.FindHandleType(name, &type)) + { + if (g_HandleSys.TypeCheck(type, m_TypeRoot)) + { + return type; + } + } + + return 0; +} + +IdentityType_t ShareSystem::CreateIdentType(const char *name) +{ + if (!m_TypeRoot) + { + return 0; + } + + return g_HandleSys.CreateTypeEx(name, this, m_TypeRoot, NULL, GetIdentRoot()); +} + +void ShareSystem::OnHandleDestroy(HandleType_t type, void *object) +{ + /* We don't care here */ +} + +IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) +{ + if (!m_TypeRoot) + { + return 0; + } + + /* :TODO: Cache? */ + IdentityToken_t *pToken = new IdentityToken_t; + pToken->ident = g_HandleSys.CreateHandle(type, NULL, NULL, GetIdentRoot()); + + return pToken; +} + +bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) +{ + if (!iface) + { + return false; + } + + IfaceInfo info; + + info.iface = iface; + info.token = token; + + if (token) + { + /* If we're an external object, we have to do this */ + info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot()); + } else { + info.handle = 0; + } + + m_Interfaces.push_back(info); + + return true; +} + +bool ShareSystem::RequestInterface(const char *iface_name, + unsigned int iface_vers, + IdentityToken_t *token, + SMInterface **pIface) +{ + /* If Some yahoo.... SOME HOOLIGAN... some NO GOOD DIRTY + * HORRIBLE PERSON passed in a token that we don't recognize.... + * Punish them. + */ + if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, GetIdentRoot(), NULL)) + { + return false; + } + + /* See if the interface exists */ + List::iterator iter; + SMInterface *iface; + IdentityToken_t *iface_owner; + Handle_t iface_handle; + bool found = false; + for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++) + { + IfaceInfo &info = (*iter); + iface = info.iface; + if (strcmp(iface->GetInterfaceName(), iface_name) == 0) + { + if (iface->GetInterfaceVersion() == iface_vers + || iface->IsVersionCompatible(iface_vers)) + { + iface_owner = info.token; + iface_handle = info.handle; + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + + /* If something external owns this, we need to track it. */ + if (iface_owner) + { + Handle_t newhandle; + if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, GetIdentRoot()) + != HandleError_None) + { + return false; + } + /** + * Now we can deny module loads based on dependencies. + */ + } + + /* :TODO: finish */ + + return NULL; +} + +void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) +{ + /* :TODO: implement */ +} + +void ShareSystem::DestroyIdentity(IdentityToken_t *identity) +{ + g_HandleSys.FreeHandle(identity->ident, GetIdentRoot()); + delete identity; +} + +void ShareSystem::DestroyIdentType(IdentityType_t type) +{ + g_HandleSys.RemoveType(type, GetIdentRoot()); +} + diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h new file mode 100644 index 00000000..c8b8aecf --- /dev/null +++ b/core/systems/ShareSys.h @@ -0,0 +1,69 @@ +#ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ +#define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ + +#include +#include +#include +#include "sm_globals.h" +#include "sourcemod.h" + +using namespace SourceHook; + +namespace SourceMod +{ + struct IdentityToken_t + { + Handle_t ident; + }; +}; + +struct IfaceInfo +{ + SMInterface *iface; + IdentityToken_t *token; + Handle_t handle; +}; + +class ShareSystem : + public IShareSys, + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + ShareSystem(); +public: //IShareSys + bool AddInterface(SMInterface *iface, IdentityToken_t *token); + bool RequestInterface(const char *iface_name, + unsigned int iface_vers, + IdentityToken_t *token, + SMInterface **pIface); + void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]); + IdentityType_t CreateIdentType(const char *name); + IdentityType_t FindIdentType(const char *name); + IdentityToken_t *CreateIdentity(IdentityType_t type); + void DestroyIdentType(IdentityType_t type); + void DestroyIdentity(IdentityToken_t *identity); +public: //SMGlobalClass + /* Pre-empt in case anything tries to register idents early */ + void OnSourceModStartup(bool late); + void OnSourceModShutdown(); +public: //IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: + IdentityToken_t *CreateCoreIdentity(); +public: + inline IdentityToken_t *GetIdentRoot() + { + return &m_IdentRoot; + } +private: + List m_Interfaces; + HandleType_t m_TypeRoot; + IdentityToken_t m_IdentRoot; + HandleType_t m_IfaceType; + IdentityType_t m_CoreType; +}; + +extern ShareSystem g_ShareSys; + +#endif //_INCLUDE_SOURCEMOD_SHARESYSTEM_H_ From 4153221ca8cc235558e3d54697a8221d174ff422 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 29 Dec 2006 23:28:44 +0000 Subject: [PATCH 0205/1664] fixed a "-1" bug in atcprintf moved string functions to the stringutils file added strncopy --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40235 --- core/sm_stringutil.cpp | 70 +++++++++++++++++++++++++++++++++++++++--- core/sm_stringutil.h | 4 +++ core/smn_string.cpp | 56 ++------------------------------- 3 files changed, 72 insertions(+), 58 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 6b817cda..adca1a57 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1,3 +1,5 @@ +#include +#include #include "sm_stringutil.h" #define ALT 0x00000001 /* alternate form */ @@ -262,7 +264,7 @@ size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext int n; char sign; const char *fmt; - size_t llen = maxlen; + size_t llen = maxlen - 1; buf_p = buffer; arg = *param; @@ -337,7 +339,7 @@ reswitch: case 'c': { CHECK_ARGS(0); - if (llen <= 1) + if (!llen) { goto done; } @@ -387,7 +389,7 @@ reswitch: } case '%': { - if (llen <= 1) + if (!llen) { goto done; } @@ -397,7 +399,7 @@ reswitch: } case '\0': { - if (llen <= 1) + if (!llen) { goto done; } @@ -407,7 +409,7 @@ reswitch: } default: { - if (llen <= 1) + if (!llen) { goto done; } @@ -423,3 +425,61 @@ done: *param = arg; return (maxlen - llen); } + +const char *stristr(const char *str, const char *substr) +{ + if (!*substr) + { + return ((char *)str); + } + + char *needle = (char *)substr; + char *prevloc = (char *)str; + char *haystack = (char *)str; + + while (*haystack) + { + if (tolower(*haystack) == tolower(*needle)) + { + haystack++; + if (!*++needle) + { + return prevloc; + } + } else { + haystack = ++prevloc; + needle = (char *)substr; + } + } + + return NULL; +} + +inline int StrConvInt(const char *str) +{ + char *dummy; + return strtol(str, &dummy, 10); +} + +inline float StrConvFloat(const char *str) +{ + char *dummy; + return (float)strtod(str, &dummy); +} + +int strncopy(char *dest, const char *src, size_t count) +{ + if (!count) + { + return 0; + } + + char *start = dest; + while ((*src) && (--count)) + { + *dest++ = *src++; + } + *dest = '\0'; + + return (dest - start); +} diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index b9ae216a..2ac314c0 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -8,5 +8,9 @@ using namespace SourcePawn; size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); +const char *stristr(const char *str, const char *substr); +int StrConvInt(const char *str); +float StrConvFloat(const char *str); +int strncopy(char *dest, const char *src, size_t count); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/smn_string.cpp b/core/smn_string.cpp index b76c485f..e41df049 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -1,41 +1,11 @@ #include "sm_platform.h" -#include #include -#include #include "sp_vm_api.h" #include "sp_vm_typeutil.h" +#include "sm_stringutil.h" using namespace SourcePawn; -const char *stristr(const char *str, const char *substr) -{ - if (!*substr) - { - return ((char *)str); - } - - char *needle = (char *)substr; - char *prevloc = (char *)str; - char *haystack = (char *)str; - - while (*haystack) - { - if (tolower(*haystack) == tolower(*needle)) - { - haystack++; - if (!*++needle) - { - return prevloc; - } - } else { - haystack = ++prevloc; - needle = (char *)substr; - } - } - - return NULL; -} - inline const char *_strstr(const char *str, const char *substr) { #ifdef PLATFORM_WINDOWS @@ -45,17 +15,6 @@ inline const char *_strstr(const char *str, const char *substr) #endif } -inline int StrConvInt(const char *str) -{ - char *dummy; - return strtol(str, &dummy, 10); -} - -inline float StrConvFloat(const char *str) -{ - char *dummy; - return (float)strtod(str, &dummy); -} /********************************************* * * @@ -107,21 +66,12 @@ static cell_t sm_equal(IPluginContext *pCtx, const cell_t *params) static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) { - char *dest, *src, *start; - int len; + char *dest, *src; pCtx->LocalToString(params[1], &dest); pCtx->LocalToString(params[3], &src); - len = params[2]; - start = dest; - while ((*src) && (len--)) - { - *dest++ = *src++; - } - *dest = '\0'; - - return (dest - start); + return strncopy(dest, src, params[2]); } static cell_t sm_strtonum(IPluginContext *pCtx, const cell_t *params) From 307d5b20c2a02886ba09b5a2612d1d0d0d85af05 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 30 Dec 2006 00:18:06 +0000 Subject: [PATCH 0206/1664] updated project file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40236 --- core/msvc8/sourcemod_mm.vcproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 91c0557c..9c5b1610 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + Date: Sat, 30 Dec 2006 06:07:32 +0000 Subject: [PATCH 0207/1664] unmanaged forwards need to be pruned for dead plugins too --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40237 --- core/systems/ForwardSys.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 0a3bb6b1..76acd0ab 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -104,6 +104,12 @@ void CForwardManager::OnPluginUnloaded(IPlugin *plugin) fwd = (*iter); fwd->RemoveFunctionsOfPlugin(plugin); } + + for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) + { + fwd = (*iter); + fwd->RemoveFunctionsOfPlugin(plugin); + } } IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng) From 388c062c96c59c40b0a3eef45e32754b6d46acb1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 30 Dec 2006 07:23:17 +0000 Subject: [PATCH 0208/1664] added automatic native registration added string include file renamed typeutil and its functions redid a bunch of the string natives string natives now register --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40238 --- core/msvc8/sourcemod_mm.vcproj | 12 ++ core/sm_autonatives.cpp | 7 ++ core/sm_autonatives.h | 22 ++++ core/sm_globals.h | 2 + core/sm_stringutil.cpp | 4 +- core/sm_stringutil.h | 6 +- core/smn_float.cpp | 88 +++++++------- core/smn_string.cpp | 37 ++++-- core/systems/PluginSys.cpp | 5 + core/systems/PluginSys.h | 10 +- plugins/include/string.inc | 111 ++++++++++++++++++ plugins/test.sma | 3 +- .../{sp_vm_typeutil.h => sp_typeutil.h} | 4 +- sourcepawn/include/sp_vm_types.h | 2 + 14 files changed, 242 insertions(+), 71 deletions(-) create mode 100644 core/sm_autonatives.cpp create mode 100644 core/sm_autonatives.h create mode 100644 plugins/include/string.inc rename sourcepawn/include/{sp_vm_typeutil.h => sp_typeutil.h} (58%) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 9c5b1610..aaf946b4 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -186,6 +186,10 @@ RelativePath="..\CTextParsers.cpp" > + + @@ -232,6 +236,10 @@ RelativePath="..\CTextParsers.h" > + + @@ -479,6 +487,10 @@ + + diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp new file mode 100644 index 00000000..370386a6 --- /dev/null +++ b/core/sm_autonatives.cpp @@ -0,0 +1,7 @@ +#include "sm_autonatives.h" +#include "PluginSys.h" + +void CoreNativesToAdd::OnSourceModAllInitialized() +{ + g_PluginSys.RegisterNativesFromCore(m_NativeList); +} diff --git a/core/sm_autonatives.h b/core/sm_autonatives.h new file mode 100644 index 00000000..8b3c06ad --- /dev/null +++ b/core/sm_autonatives.h @@ -0,0 +1,22 @@ +#ifndef _INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ +#define _INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ + +#include "sm_globals.h" + +#define REGISTER_NATIVES(globname) \ + extern sp_nativeinfo_t globNatives##globname[]; \ + CoreNativesToAdd globNativesCls##globname(globNatives##globname); \ + sp_nativeinfo_t globNatives##globname[] = + +class CoreNativesToAdd : public SMGlobalClass +{ +public: + CoreNativesToAdd(sp_nativeinfo_t *pList) + : m_NativeList(pList) + { + } + void OnSourceModAllInitialized(); + sp_nativeinfo_t *m_NativeList; +}; + +#endif //_INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ diff --git a/core/sm_globals.h b/core/sm_globals.h index 8426b0bd..87c45daf 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -50,4 +50,6 @@ private: extern ISourcePawnEngine *g_pSourcePawn; extern IVirtualMachine *g_pVM; +#include "sm_autonatives.h" + #endif //_INCLUDE_SOURCEMOD_GLOBALS_H_ diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index adca1a57..00601603 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -374,7 +374,7 @@ reswitch: CHECK_ARGS(0); cell_t *value; pCtx->LocalToPhysAddr(params[arg], &value); - AddFloat(&buf_p, llen, ctof(*value), width, prec); + AddFloat(&buf_p, llen, sp_ctof(*value), width, prec); arg++; break; } @@ -467,7 +467,7 @@ inline float StrConvFloat(const char *str) return (float)strtod(str, &dummy); } -int strncopy(char *dest, const char *src, size_t count) +unsigned int strncopy(char *dest, const char *src, size_t count) { if (!count) { diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 2ac314c0..5dce299f 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -3,14 +3,12 @@ #include #include "sp_vm_api.h" -#include "sp_vm_typeutil.h" +#include "sp_typeutil.h" using namespace SourcePawn; size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); -int StrConvInt(const char *str); -float StrConvFloat(const char *str); -int strncopy(char *dest, const char *src, size_t count); +unsigned int strncopy(char *dest, const char *src, size_t count); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 96a4d129..a76e25cd 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,7 +1,7 @@ #include #include #include "sp_vm_api.h" -#include "sp_vm_typeutil.h" +#include "sp_typeutil.h" using namespace SourcePawn; @@ -57,49 +57,49 @@ static cell_t sm_float(IPluginContext *pCtx, const cell_t *params) { float val = static_cast(params[1]); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatabs(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = (val >= 0) ? val : -val; - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatadd(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]) + ctof(params[2]); + float val = sp_ctof(params[1]) + sp_ctof(params[2]); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatsub(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]) - ctof(params[2]); + float val = sp_ctof(params[1]) - sp_ctof(params[2]); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatmul(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]) * ctof(params[2]); + float val = sp_ctof(params[1]) * sp_ctof(params[2]); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatdiv(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]) / ctof(params[2]); + float val = sp_ctof(params[1]) / sp_ctof(params[2]); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatcmp(IPluginContext *pCtx, const cell_t *params) { - float val1 = ctof(params[1]); - float val2 = ctof(params[2]); + float val1 = sp_ctof(params[1]); + float val2 = sp_ctof(params[2]); if (val1 > val2) { @@ -113,8 +113,8 @@ static cell_t sm_floatcmp(IPluginContext *pCtx, const cell_t *params) static cell_t sm_floatlog(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); - float base = ctof(params[2]); + float val = sp_ctof(params[1]); + float base = sp_ctof(params[2]); if ((val <= 0) || (base <= 0)) { @@ -127,39 +127,39 @@ static cell_t sm_floatlog(IPluginContext *pCtx, const cell_t *params) val = log(val) / log(base); } - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatexp(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); - return ftoc(exp(val)); + return sp_ftoc(exp(val)); } static cell_t sm_floatpower(IPluginContext *pCtx, const cell_t *params) { - float base = ctof(params[1]); - float exponent = ctof(params[2]); + float base = sp_ctof(params[1]); + float exponent = sp_ctof(params[2]); - return ftoc(pow(base, exponent)); + return sp_ftoc(pow(base, exponent)); } static cell_t sm_floatsqroot(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); if (val < 0.0) { //:TODO: error out! we dont support complex numbers } - return ftoc(sqrt(val)); + return sp_ftoc(sqrt(val)); } static cell_t sm_floatround(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); switch (params[2]) { @@ -190,7 +190,7 @@ static cell_t sm_floatround(IPluginContext *pCtx, const cell_t *params) } } - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) @@ -203,70 +203,70 @@ static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) return 0; } - return ftoc((float)atof(str)); + return sp_ftoc((float)atof(str)); } static cell_t sm_floatfract(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = val - floor(val); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = sin(AngleToRadians(val, params[2])); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = cos(AngleToRadians(val, params[2])); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floattan(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = tan(AngleToRadians(val, params[2])); - return ftoc(val); + return sp_ftoc(val); } static cell_t sm_floatasin(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = asin(val); - return ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(RadiansToAngle(val, params[2])); } static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = acos(val); - return ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(RadiansToAngle(val, params[2])); } static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) { - float val = ctof(params[1]); + float val = sp_ctof(params[1]); val = atan(val); - return ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(RadiansToAngle(val, params[2])); } static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) { - float val1 = ctof(params[1]); - float val2 = ctof(params[2]); + float val1 = sp_ctof(params[1]); + float val2 = sp_ctof(params[2]); val1 = atan2(val1, val2); - return ftoc(RadiansToAngle(val1, params[3])); + return sp_ftoc(RadiansToAngle(val1, params[3])); } diff --git a/core/smn_string.cpp b/core/smn_string.cpp index e41df049..e5dbfd23 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -1,7 +1,7 @@ #include "sm_platform.h" #include -#include "sp_vm_api.h" -#include "sp_vm_typeutil.h" +#include +#include "sm_globals.h" #include "sm_stringutil.h" using namespace SourcePawn; @@ -15,14 +15,12 @@ inline const char *_strstr(const char *str, const char *substr) #endif } - /********************************************* * * * STRING MANIPULATION NATIVE IMPLEMENTATIONS * * * *********************************************/ - static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params) { char *str; @@ -50,7 +48,7 @@ static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params) return -1; } -static cell_t sm_equal(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params) { typedef int (*STRCOMPARE)(const char *, const char *); STRCOMPARE func; @@ -61,7 +59,7 @@ static cell_t sm_equal(IPluginContext *pCtx, const cell_t *params) func = (params[3]) ? strcmp : stricmp; - return (func(str1, str2)) ? 0 : 1; + return (func(str1, str2)); } static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) @@ -74,12 +72,12 @@ static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) return strncopy(dest, src, params[2]); } -static cell_t sm_strtonum(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params) { - char *str; + char *str, *dummy; pCtx->LocalToString(params[1], &str); - return StrConvInt(str); + return static_cast(strtol(str, &dummy, params[2])); } static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) @@ -92,10 +90,12 @@ static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params) { - char *str; + char *str, *dummy; pCtx->LocalToString(params[1], &str); - return ftoc(StrConvFloat(str)); + float val = (float)strtod(str, &dummy); + + return sp_ftoc(val); } static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) @@ -103,5 +103,18 @@ static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) char *str; pCtx->LocalToString(params[2], &str); - return snprintf(str, params[3], "%f", ctof(params[1])); + return snprintf(str, params[3], "%f", sp_ctof(params[1])); } + +REGISTER_NATIVES(basicstrings) +{ + {"strlen", sm_strlen}, + {"StrContains", sm_contain}, + {"StrCompare", sm_strcmp}, + {"StrCopy", sm_strcopy}, + {"StringToInt", sm_strconvint}, + {"IntToString", sm_numtostr}, + {"StringToFloat", sm_strtofloat}, + {"FloatToString", sm_floattostr}, + {NULL, NULL}, +}; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6524fac4..2f087967 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1136,3 +1136,8 @@ void CPluginManager::OnHandleDestroy(HandleType_t type, void *object) { /* We don't care about the internal object, actually */ } + +void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives) +{ + m_natives.push_back(natives); +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 6f58880a..f5e5c462 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -227,15 +227,15 @@ public: */ bool TestAliasMatch(const char *alias, const char *localdir); - /** - * Registers natives in core itself ONLY. - */ - void RegisterGlobalNatives(sp_nativeinfo_t *info[]); - /** * Returns whether anything loaded will be a late load. */ bool IsLateLoadTime(); + + /** + * Adds natives from core into the native pool. + */ + void RegisterNativesFromCore(sp_nativeinfo_t *natives); private: /** * Recursively loads all plugins in the given directory. diff --git a/plugins/include/string.inc b/plugins/include/string.inc new file mode 100644 index 00000000..4a8e4e96 --- /dev/null +++ b/plugins/include/string.inc @@ -0,0 +1,111 @@ +/** + * :TODO: license info + */ + +#if defined _string_included + #endinput +#endif +#define _string_included + +/** + * @GLOBAL@ + * Unless otherwise noted, all string functions which take in a writable buffer and maximum length + * should have the null terminator INCLUDED in the length. This means that this is valid: + * StrCopy(string, sizeof(string), ...) + */ + +/** + * Calculates the length of a string. + * + * @param str String to check. + * @return Length of string, in cells (NOT characters). + */ +native strlen(const String:str[]); + +/** + * Tests whether a string is found inside another string. + * + * @param str String to search in. + * @param substr Substring to find inside the original string. + * @param caseSensitive If true (default), search is case sensitive. + * If false, search is case insensitive. + * @return -1 on failure (no match found). Any other value + * indicates a position in the string where the match starts. + */ +native StrContains(const String:str[], const String:substr[], bool:caseSensitive=true); + +/** + * Compares two strings lexographically. + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return -1 if str1 < str2 + * 0 if str1 == str2 + * 1 if str1 > str2 + */ +native StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=true); + +/** + * Returns whether two strings are equal. + * + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return True if equal, false otherwise. + */ +stock StrEqual(const String:str1[], const String:str2[], bool:caseSensitive=true) +{ + return (StrCompare(str1, str2, caseSensitive)); +} + +/** + * Copies one string to another string. + * NOTE: If the destination buffer is too small to hold the source string, + * the destination will be truncated. + * + * @param dest Destination string buffer to copy to. + * @param destlen Destination buffer length (includes null terminator). + * @param source Source string buffer to copy from. + * @return Number of cells written. + */ +native StrCopy(String:dest[], destLen, const String:source[]); + +/** + * Converts a string to an integer. + * + * @param str String to convert. + * @param nBase Numerical base to use. 10 is default. + * @return Integer conversion of string, or 0 on failure. + */ +native StringToInt(const String:str[], nBase=10); + +/** + * Converts an integer to a string. + * + * @param str Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @param num Integer to convert. + * @return Number of cells written to buffer. + */ +native IntToString(String:str[], maxlength, num); + +/** + * Converts a string to a floating point number. + * + * @param str String to convert to a foat. + * @return Floating point result, or 0.0 on error. + */ +native Float:StringToFloat(const String:str[]); + +/** + * Converts a floating point number to a string. + * + * @param str Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @param num Floating point number to convert. + */ +native Float:FloatToString(String:str[], maxlength, Float:num); diff --git a/plugins/test.sma b/plugins/test.sma index af46f8c6..c3354368 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -24,6 +24,5 @@ copy(String:dest[], maxlength, const String:source[]) public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) { - copy(error, err_max, "I don't like food anymore!") - return false + return true } diff --git a/sourcepawn/include/sp_vm_typeutil.h b/sourcepawn/include/sp_typeutil.h similarity index 58% rename from sourcepawn/include/sp_vm_typeutil.h rename to sourcepawn/include/sp_typeutil.h index 40987e4d..921f9f74 100644 --- a/sourcepawn/include/sp_vm_typeutil.h +++ b/sourcepawn/include/sp_typeutil.h @@ -3,11 +3,11 @@ #include "sp_vm_types.h" -inline cell_t ftoc(float val) +inline cell_t sp_ftoc(float val) { return *(cell_t *)&val; } -inline float ctof(cell_t val) +inline float sp_ctof(cell_t val) { return *(float *)&val; } diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 3065915c..e2f94114 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -7,6 +7,8 @@ typedef uint32_t ucell_t; typedef int32_t cell_t; typedef uint32_t funcid_t; +#include "sp_typeutil.h" + #define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ /** From 2e835df3809bfd35b99282759fd64786f594bf40 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 30 Dec 2006 19:01:23 +0000 Subject: [PATCH 0209/1664] tiny fixes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40239 --- plugins/include/string.inc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 4a8e4e96..7498a575 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -57,9 +57,9 @@ native StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=t * If false, comparison is case insensitive. * @return True if equal, false otherwise. */ -stock StrEqual(const String:str1[], const String:str2[], bool:caseSensitive=true) +stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive=true) { - return (StrCompare(str1, str2, caseSensitive)); + return (StrCompare(str1, str2, caseSensitive) == 0); } /** @@ -107,5 +107,6 @@ native Float:StringToFloat(const String:str[]); * @param str Buffer to store string in. * @param maxlength Maximum length of string buffer. * @param num Floating point number to convert. + * @return Number of cells written to buffer. */ -native Float:FloatToString(String:str[], maxlength, Float:num); +native FloatToString(String:str[], maxlength, Float:num); From 8c09e0c50d00aff990d8f83db49fd42bfd975a4f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 30 Dec 2006 22:16:53 +0000 Subject: [PATCH 0210/1664] removed radix stuff from trig natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40240 --- core/sm_stringutil.cpp | 12 ---------- core/smn_float.cpp | 54 ++++++------------------------------------ 2 files changed, 7 insertions(+), 59 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 00601603..5edf6c3f 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -455,18 +455,6 @@ const char *stristr(const char *str, const char *substr) return NULL; } -inline int StrConvInt(const char *str) -{ - char *dummy; - return strtol(str, &dummy, 10); -} - -inline float StrConvFloat(const char *str) -{ - char *dummy; - return (float)strtod(str, &dummy); -} - unsigned int strncopy(char *dest, const char *src, size_t count) { if (!count) diff --git a/core/smn_float.cpp b/core/smn_float.cpp index a76e25cd..851a5fed 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -5,46 +5,6 @@ using namespace SourcePawn; -#define PI 3.14159265358979323846 - -inline float AngleToRadians(float val, int mode) -{ - switch (mode) - { - case 1: - { - return (float)((val * PI) / 180.0); - } - case 2: - { - return (float)((val * PI) / 200.0); - } - default: - { - return val; - } - } -} - -inline float RadiansToAngle(float val, int mode) -{ - switch (mode) - { - case 1: - { - return (float)((val / PI) * 180.0); - } - case 2: - { - return (float)((val / PI) * 200.0); - } - default: - { - return val; - } - } -} - /**************************************** * * @@ -217,7 +177,7 @@ static cell_t sm_floatfract(IPluginContext *pCtx, const cell_t *params) static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); - val = sin(AngleToRadians(val, params[2])); + val = sin(val); return sp_ftoc(val); } @@ -225,7 +185,7 @@ static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); - val = cos(AngleToRadians(val, params[2])); + val = cos(val); return sp_ftoc(val); } @@ -233,7 +193,7 @@ static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) static cell_t sm_floattan(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); - val = tan(AngleToRadians(val, params[2])); + val = tan(val); return sp_ftoc(val); } @@ -243,7 +203,7 @@ static cell_t sm_floatasin(IPluginContext *pCtx, const cell_t *params) float val = sp_ctof(params[1]); val = asin(val); - return sp_ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(val); } static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) @@ -251,7 +211,7 @@ static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) float val = sp_ctof(params[1]); val = acos(val); - return sp_ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(val); } static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) @@ -259,7 +219,7 @@ static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) float val = sp_ctof(params[1]); val = atan(val); - return sp_ftoc(RadiansToAngle(val, params[2])); + return sp_ftoc(val); } static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) @@ -268,5 +228,5 @@ static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) float val2 = sp_ctof(params[2]); val1 = atan2(val1, val2); - return sp_ftoc(RadiansToAngle(val1, params[3])); + return sp_ftoc(val1); } From cf15783eb036e245ebd88b47e96071209779e0f9 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 31 Dec 2006 03:02:40 +0000 Subject: [PATCH 0211/1664] fixed atcprintf counting the null terminator for the return value added format and formatex natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40241 --- core/sm_stringutil.cpp | 2 +- core/smn_string.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 5edf6c3f..25a37ba0 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -423,7 +423,7 @@ reswitch: done: *buf_p = '\0'; *param = arg; - return (maxlen - llen); + return (maxlen - llen - 1); } const char *stristr(const char *str, const char *substr) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index e5dbfd23..168ff923 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -106,6 +106,55 @@ static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) return snprintf(str, params[3], "%f", sp_ctof(params[1])); } +static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params) +{ + char *buf, *fmt; + size_t res; + int arg = 4; + + pCtx->LocalToString(params[1], &buf); + pCtx->LocalToString(params[3], &fmt); + res = atcprintf(buf, static_cast(params[2]), fmt, pCtx, params, &arg); + + return static_cast(res); +} + +static char g_formatbuf[2048]; +static cell_t sm_format(IPluginContext *pCtx, const cell_t *params) +{ + char *buf, *fmt, *destbuf; + cell_t start_addr, end_addr, maxparam; + size_t res, maxlen; + int arg = 4; + bool copy = false; + + pCtx->LocalToString(params[1], &destbuf); + pCtx->LocalToString(params[3], &fmt); + + maxlen = static_cast(params[2]); + start_addr = params[1]; + end_addr = params[1] + maxlen; + maxparam = params[0]; + + for (cell_t i=3; i<=maxparam; i++) + { + if ((params[i] >= start_addr) && (params[i] <= end_addr)) + { + copy = true; + break; + } + } + buf = (copy) ? g_formatbuf : destbuf; + res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg); + + if (copy) + { + memcpy(destbuf, g_formatbuf, res+1); + } + + return static_cast(res); +} + REGISTER_NATIVES(basicstrings) { {"strlen", sm_strlen}, From a7fe40899597d4132d4b9bb91c1c29f7f45c0ea0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 31 Dec 2006 22:33:47 +0000 Subject: [PATCH 0212/1664] debug break now uses context struct instead of context interface err is renamed to 'n_err' 'n_err' is now a 'native only' member, for native errors only --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40242 --- sourcepawn/include/sp_vm_api.h | 126 +++++++++++++++++++++++--- sourcepawn/include/sp_vm_base.h | 2 + sourcepawn/include/sp_vm_types.h | 6 +- sourcepawn/jit/x86/jit_x86.cpp | 42 +++++---- sourcepawn/jit/x86/opcode_helpers.cpp | 36 ++++---- sourcepawn/jit/x86/opcode_helpers.h | 4 +- 6 files changed, 165 insertions(+), 51 deletions(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 73db0195..a144d6d7 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -314,6 +314,67 @@ namespace SourcePawn virtual int Execute(uint32_t funcid, cell_t *result) =0; }; + struct ErrorTraceInfo + { + const char *filename; + unsigned int line; + const char *function; + }; + + class IContextErrorInfo + { + /** + * @brief Returns the integer error code. + * + * @return Integer error code. + */ + virtual int GetErrorCode() =0; + + /** + * @brief Returns a string describing the error. + * + * @return Error string. + */ + virtual const char *GetErrorString() =0; + + /** + * @brief Returns whether debug info is available. + * + * @return True if debug info is available, false otherwise. + */ + virtual bool DebugInfoAvailable() =0; + + /** + * @brief Returns a custom error message. + * + * @return A pointer to a custom error message, or NULL otherwise. + */ + virtual const char *GetCustomErrorString() =0; + + /** + * @brief Returns the number of calls in the call backtrace. + * NOTE: Tracers are ordered from 0 to N-1, where 0 is the top of the trace. + * + * @return Number of calls in the trace. + */ + virtual unsigned int TraceCallCount() =0; + + /** + * @brief Returns trace info for a specific point in the backtrace. + * + * @param call The call trace index (from 0 to N-1). + * @param trace An ErrorTraceInfo buffer to store information. + * @return True if successful, false otherwise. + */ + virtual bool GetTraceInfo(unsigned int call, ErrorTraceInfo *trace) =0; + }; + + class IDebugListener + { + public: + virtual void OnContextExecuteError(IPluginContext *ctx, IContextErrorInfo *error) =0; + }; + /** * @brief Contains helper functions used by VMs and the host app */ @@ -321,17 +382,17 @@ namespace SourcePawn { public: /** - * Loads a named file from a file pointer. - * Using this means base memory will be allocated by the VM. - * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. - */ + * @brief Loads a named file from a file pointer. + * Note: Using this means the memory will be allocated by the VM. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; /** - * Loads a file from a base memory address. + * @brief Loads a file from a base memory address. * * @param base Base address of the plugin's memory region. * @param plugin If NULL, a new plugin pointer is returned. @@ -349,7 +410,7 @@ namespace SourcePawn virtual int FreeFromMemory(sp_plugin_t *plugin) =0; /** - * Creates a new IContext from a context handle. + * @brief Creates a new IContext from a context handle. * * @param ctx Context to use as a basis for the IPluginContext. * @return New IPluginContext handle. @@ -357,14 +418,14 @@ namespace SourcePawn virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0; /** - * Frees a base context. Does not free the sp_context_t it holds. + * @brief Frees a base context. Does not free the sp_context_t it holds. * * @param ctx Context pointer to free. */ virtual void FreeBaseContext(IPluginContext *ctx) =0; /** - * Allocates large blocks of temporary memory. + * @brief Allocates large blocks of temporary memory. * * @param size Size of memory to allocate. * @return Pointer to memory, NULL if allocation failed. @@ -372,14 +433,14 @@ namespace SourcePawn virtual void *BaseAlloc(size_t size) =0; /** - * Frees memory allocated with BaseAlloc. + * @brief Frees memory allocated with BaseAlloc. * * @param memory Memory address to free. */ virtual void BaseFree(void *memory) =0; /** - * Allocates executable memory. + * @brief Allocates executable memory. * * @param size Size of memory to allocate. * @return Pointer to memory, NULL if allocation failed. @@ -387,13 +448,50 @@ namespace SourcePawn virtual void *ExecAlloc(size_t size) =0; /** - * Frees executable memory. + * @brief Frees executable memory. * * @param address Address to free. */ virtual void ExecFree(void *address) =0; + + /** + * @brief Sets the debug listener. + * + * @param listener Pointer to an IDebugListener. + * @return Old IDebugListener, or NULL if none. + */ + virtual IDebugListener *SetDebugListener(IDebugListener *pListener) =0; + + /** + * @brief Returns the number of plugins on the call stack. + * + * @return Number of contexts in the call stack. + */ + virtual unsigned int GetContextCallCount() =0; + + /** + * @brief Throws an error and halts any current execution. + * + * @param error The error number to set. + * @param msg Custom error message format. NULL to use default. + * @param ... Message format arguments, if any. + */ + virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; + + /** + * @brief Throws a native error and halts any current execution. + * NOTE: This is a wrapper around ThrowError() for convenience. + * + * @param msg Custom error message format. NULL to set no message. + * @param ... Message format arguments, if any. + * @return 0 for convenience. + */ + virtual void ThrowNativeError(const char *msg, ...) =0; }; + /** + * @brief Dummy class for encapsulating private compilation data. + */ class ICompilation { public: diff --git a/sourcepawn/include/sp_vm_base.h b/sourcepawn/include/sp_vm_base.h index 63dc63b9..4fff0f4c 100644 --- a/sourcepawn/include/sp_vm_base.h +++ b/sourcepawn/include/sp_vm_base.h @@ -3,6 +3,8 @@ #include +/* :TODO: rename this to sp_vm_linkage.h */ + #if defined WIN32 #define EXPORT_LINK extern "C" __declspec(dllexport) #else if defined __GNUC__ diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index e2f94114..4bb95964 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -37,6 +37,7 @@ typedef uint32_t funcid_t; #define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ #define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ #define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /* Error originates from a native */ /********************************************** *** The following structures are reference structures. @@ -204,7 +205,7 @@ typedef struct sp_debug_symbol_s * [1] - frm * [2] - cip */ -typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t); +typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); #define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ @@ -234,8 +235,9 @@ typedef struct sp_context_s cell_t hp; /* heap pointer */ cell_t sp; /* stack pointer */ cell_t frm; /* frame pointer */ - int32_t err; /* error code */ uint32_t pushcount; /* push count */ + int32_t n_err; /* error code set by a native */ + uint32_t n_idx; /* current native index being executed */ /* context rebased database */ sp_public_t *publics; /* public functions table */ sp_pubvar_t *pubvars; /* public variables table */ diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 3cafd163..593567ce 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1631,7 +1631,7 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -1678,12 +1678,14 @@ inline void WriteOp_Tracker_Push_C(JitWriter *jit) IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); /* Check for errors */ - //pop eax - //cmp [eax+err], 0 + //cmp eax, 0 //jnz :error + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); + + /* Restore */ + //pop eax IA32_Pop_Reg(jit, REG_EAX); - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); /* Push the value into the stack and increment pCur */ //mov edx, [eax+vm[]] @@ -1722,12 +1724,14 @@ inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker); /* Check for errors */ - //pop eax - //cmp [eax+err], 0 + //cmp eax, 0 //jnz :error + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); + + /* Restore */ + //pop eax IA32_Pop_Reg(jit, REG_EAX); - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); /* Pop the value from the stack and decrease the heap by it*/ //mov edx, [eax+vm[]] @@ -1768,11 +1772,13 @@ inline void WriteOp_Stradjust_Pri(JitWriter *jit) cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) { sp_native_t *native = &ctx->natives[native_idx]; + + ctx->n_idx = native_idx; /* Technically both aren't needed, I guess */ if (native->status == SP_NATIVE_UNBOUND) { - ctx->err = SP_ERROR_INVALID_NATIVE; + ctx->n_err = SP_ERROR_INVALID_NATIVE; return 0; } @@ -1782,7 +1788,7 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params) { sp_context_t *ctx = pCtx->GetContext(); - ctx->err = SP_ERROR_INVALID_NATIVE; + ctx->n_err = SP_ERROR_INVALID_NATIVE; return 0; } @@ -1792,37 +1798,39 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; + ctx->n_idx = native_idx; + if (ctx->hp < ctx->heap_base) { - ctx->err = SP_ERROR_HEAPMIN; + ctx->n_err = SP_ERROR_HEAPMIN; return 0; } if (ctx->hp + STACK_MARGIN > ctx->sp) { - ctx->err = SP_ERROR_STACKLOW; + ctx->n_err = SP_ERROR_STACKLOW; return 0; } if ((uint32_t)ctx->sp >= ctx->mem_size) { - ctx->err = SP_ERROR_STACKMIN; + ctx->n_err = SP_ERROR_STACKMIN; return 0; } cell_t result = NativeCallback(ctx, native_idx, params); - if (ctx->err != SP_ERROR_NONE) + if (ctx->n_err != SP_ERROR_NONE) { return result; } if (save_sp != ctx->sp) { - ctx->err = SP_ERROR_STACKLEAK; + ctx->n_err = SP_ERROR_STACKLEAK; return result; } else if (save_hp != ctx->hp) { - ctx->err = SP_ERROR_HEAPLEAK; + ctx->n_err = SP_ERROR_HEAPLEAK; return result; } diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 6b366ade..c7609032 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -146,7 +146,7 @@ void Write_BreakDebug(JitWriter *jit) //add esp, 8 //popad IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0 - IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context)); + IA32_Push_Reg(jit, AMX_REG_TMP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); IA32_Call_Reg(jit, AMX_REG_TMP); IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG); @@ -166,7 +166,7 @@ void Write_GetError(JitWriter *jit) //mov eax, [eax+ctx.error] //jmp [jit_return] IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, err)); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err)); IA32_Jump_Imm32_Abs(jit, data->jit_return); } @@ -435,7 +435,7 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -662,7 +662,7 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) //cmp [ecx+err], 0 //jnz :error IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); /* restore what we damaged */ @@ -713,13 +713,15 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); /* Check for errors */ - //pop eax - //cmp [eax+err], 0 + //cmp eax, 0 //jnz :error - IA32_Pop_Reg(jit, REG_EAX); - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + /* Restore */ + //pop eax + IA32_Pop_Reg(jit, REG_EAX); + /* Push the register into the stack and increment pCur */ //mov edx, [eax+vm[]] //mov eax, [edx+pcur] @@ -742,14 +744,13 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) IA32_Pop_Reg(jit, AMX_REG_PRI); } -void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) +int JIT_VerifyOrAllocateTracker(sp_context_t *ctx) { tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); if ((size_t)(trk->pCur - trk->pBase) >= trk->size) { - ctx->err = SP_ERROR_TRACKER_BOUNDS; - return; + return SP_ERROR_TRACKER_BOUNDS; } if (trk->pCur+1 - (trk->pBase + trk->size) == 0) @@ -760,20 +761,23 @@ void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) if (!trk->pBase) { - ctx->err = SP_ERROR_TRACKER_BOUNDS; - return; + return SP_ERROR_TRACKER_BOUNDS; } trk->pCur = trk->pBase + disp; } + + return SP_ERROR_NONE; } -void JIT_VerifyLowBoundTracker(sp_context_t *ctx) +int JIT_VerifyLowBoundTracker(sp_context_t *ctx) { tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); if (trk->pCur <= trk->pBase) { - ctx->err = SP_ERROR_TRACKER_BOUNDS; + return SP_ERROR_TRACKER_BOUNDS; } -} \ No newline at end of file + + return SP_ERROR_NONE; +} diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index f8045c16..4ee72424 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -69,8 +69,8 @@ void Macro_PushN(JitWriter *jit, int i); /** * Bound checking for the tracker stack, */ -void JIT_VerifyLowBoundTracker(sp_context_t *ctx); -void JIT_VerifyOrAllocateTracker(sp_context_t *ctx); +int JIT_VerifyLowBoundTracker(sp_context_t *ctx); +int JIT_VerifyOrAllocateTracker(sp_context_t *ctx); /** * Writes the push into tracker function. From fed813155e51967fed864a1fa572a3235ccf9143 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 31 Dec 2006 23:28:40 +0000 Subject: [PATCH 0213/1664] removed tracker error --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40243 --- sourcepawn/jit/x86/jit_x86.cpp | 7 ++----- sourcepawn/jit/x86/jit_x86.h | 1 - sourcepawn/jit/x86/opcode_helpers.cpp | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 593567ce..32b675c8 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1680,7 +1680,7 @@ inline void WriteOp_Tracker_Push_C(JitWriter *jit) /* Check for errors */ //cmp eax, 0 //jnz :error - IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); + IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); /* Restore */ @@ -1726,7 +1726,7 @@ inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) /* Check for errors */ //cmp eax, 0 //jnz :error - IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); + IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); /* Restore */ @@ -1884,9 +1884,6 @@ void WriteErrorRoutines(CompData *data, JitWriter *jit) data->jit_error_array_too_big = jit->get_outputpos(); Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG); - data->jit_error_tracker_bounds = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_TRACKER_BOUNDS); - data->jit_extern_error = jit->get_outputpos(); Write_GetError(jit); } diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 5f8eae60..05d3a2a8 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -59,7 +59,6 @@ public: jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; jitoffs_t jit_error_array_too_big; - jitoffs_t jit_error_tracker_bounds; jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index c7609032..88e1b969 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -140,7 +140,7 @@ void Write_BreakDebug(JitWriter *jit) IA32_Pushad(jit); //push [esi+frm] - //push [ecx+context] + //push ctx //mov ecx, [ecx+dbreak] //call ecx //add esp, 8 @@ -715,8 +715,8 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) /* Check for errors */ //cmp eax, 0 //jnz :error - IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); /* Restore */ //pop eax From 610f628298ed06a69c6041e2ca2130d61a9b563c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 01:08:36 +0000 Subject: [PATCH 0214/1664] finalize new API and type information --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40244 --- sourcepawn/include/sp_vm_api.h | 82 ++++++++++++++++++-------------- sourcepawn/include/sp_vm_types.h | 1 + 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index a144d6d7..a178a049 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -312,16 +312,42 @@ namespace SourcePawn * @return Error code (if any) from the VM. */ virtual int Execute(uint32_t funcid, cell_t *result) =0; + + + /** + * @brief Throws a error and halts any current execution. + * + * @param error The error number to set. + * @param msg Custom error message format. NULL to use default. + * @param ... Message format arguments, if any. + */ + virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; + + /** + * @brief Throws a generic native error and halts any current execution. + * + * @param msg Custom error message format. NULL to set no message. + * @param ... Message format arguments, if any. + * @return 0 for convenience. + */ + virtual cell_t ThrowNativeError(const char *msg, ...) =0; }; - struct ErrorTraceInfo + + /** + * @brief Information about a position in a call stack. + */ + struct CallStackInfo { - const char *filename; - unsigned int line; - const char *function; + const char *filename; /* NULL if not found */ + unsigned int line; /* 0 if not found */ + const char *function; /* NULL if not found */ }; - class IContextErrorInfo + /** + * @brief Retrieves error information from a debug hook. + */ + class IContextTrace { /** * @brief Returns the integer error code. @@ -352,29 +378,32 @@ namespace SourcePawn virtual const char *GetCustomErrorString() =0; /** - * @brief Returns the number of calls in the call backtrace. - * NOTE: Tracers are ordered from 0 to N-1, where 0 is the top of the trace. + * @brief Returns trace info for a specific point in the backtrace, if any. + * The next subsequent call to GetTraceInfo() will return the next item in the call stack. + * Calls are retrieved in descending order (i.e. the first item is at the top of the stack/call sequence). * - * @return Number of calls in the trace. + * @param trace An ErrorTraceInfo buffer to store information (NULL to ignore). + * @return True if successful, false if there are no more traces. */ - virtual unsigned int TraceCallCount() =0; + virtual bool GetTraceInfo(CallStackInfo *trace) =0; /** - * @brief Returns trace info for a specific point in the backtrace. - * - * @param call The call trace index (from 0 to N-1). - * @param trace An ErrorTraceInfo buffer to store information. - * @return True if successful, false otherwise. + * @brief Resets the trace to its original position (the call on the top of the stack). */ - virtual bool GetTraceInfo(unsigned int call, ErrorTraceInfo *trace) =0; + virtual void ResetTrace() =0; }; + + /** + * @brief Provides callbacks for debug information. + */ class IDebugListener { public: - virtual void OnContextExecuteError(IPluginContext *ctx, IContextErrorInfo *error) =0; + virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0; }; + /** * @brief Contains helper functions used by VMs and the host app */ @@ -468,27 +497,9 @@ namespace SourcePawn * @return Number of contexts in the call stack. */ virtual unsigned int GetContextCallCount() =0; - - /** - * @brief Throws an error and halts any current execution. - * - * @param error The error number to set. - * @param msg Custom error message format. NULL to use default. - * @param ... Message format arguments, if any. - */ - virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; - - /** - * @brief Throws a native error and halts any current execution. - * NOTE: This is a wrapper around ThrowError() for convenience. - * - * @param msg Custom error message format. NULL to set no message. - * @param ... Message format arguments, if any. - * @return 0 for convenience. - */ - virtual void ThrowNativeError(const char *msg, ...) =0; }; + /** * @brief Dummy class for encapsulating private compilation data. */ @@ -498,6 +509,7 @@ namespace SourcePawn virtual ~ICompilation() { }; }; + /** * @brief Outlines the interface a Virtual Machine (JIT) must expose */ diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 4bb95964..2436144d 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -13,6 +13,7 @@ typedef uint32_t funcid_t; /** * Error codes + * NOTE: Be sure to update the error string table when changing these */ #define SP_ERROR_NONE 0 #define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ From 378e4d20f3c5f18aa9c4f50bd7697a4a76147285 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 01:09:53 +0000 Subject: [PATCH 0215/1664] initial import of new debugger API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40245 --- core/interfaces/IHandleSys.h | 4 +- core/msvc8/sourcemod_mm.vcproj | 12 +- core/vm/sp_vm_basecontext.cpp | 78 +++++++++- core/vm/sp_vm_basecontext.h | 7 + core/vm/sp_vm_engine.cpp | 274 +++++++++++++++++++++++++++++++++ core/vm/sp_vm_engine.h | 121 +++++++-------- 6 files changed, 421 insertions(+), 75 deletions(-) diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index d2b2c297..f5fc71a2 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -100,7 +100,7 @@ namespace SourceMod * * @param name Name of handle type (NULL or "" to be anonymous) * @param dispatch Pointer to a valid IHandleTypeDispatch object. - * @return A new HandleType_t unique ID. + * @return A new HandleType_t unique ID, or 0 on failure. */ virtual HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch) =0; @@ -116,7 +116,7 @@ namespace SourceMod * @param security Pointer to a temporary HandleSecurity object, NULL to use default * or inherited permissions. * @param ident Security token for any permissions. - * @return A new HandleType_t unique ID. + * @return A new HandleType_t unique ID, or 0 on failure. */ virtual HandleType_t CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index aaf946b4..5300a0ac 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -487,10 +487,6 @@ - - @@ -519,6 +515,10 @@ RelativePath="..\..\sourcepawn\include\sp_file_headers.h" > + + @@ -531,10 +531,6 @@ RelativePath="..\..\sourcepawn\include\sp_vm_types.h" > - - diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 2a4531b4..2a496b56 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -1,18 +1,32 @@ #include +#include #include #include #include "sp_vm_api.h" #include "sp_vm_basecontext.h" +#include "sp_vm_engine.h" using namespace SourcePawn; +extern SourcePawnEngine g_SourcePawn; + #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) #define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) +int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip) +{ + g_SourcePawn.RunTracer(ctx, frm, cip); + + return SP_ERROR_NONE; +} + BaseContext::BaseContext(sp_context_t *_ctx) { ctx = _ctx; ctx->context = this; + ctx->dbreak = GlobalDebugBreak; + m_InExec = false; + m_CustomMsg = false; } IVirtualMachine *BaseContext::GetVirtualMachine() @@ -74,11 +88,26 @@ int BaseContext::Execute(funcid_t funcid, cell_t *result) cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; + bool wasExec = m_InExec; + + /* Clear the error state, if any */ + ctx->n_err = SP_ERROR_NONE; + ctx->n_idx = 0; + m_InExec = true; + m_MsgCache[0] = '\0'; + m_CustomMsg = false; + + g_SourcePawn.PushTracer(ctx); + err = vm->ContextExecute(ctx, code_addr, result); - + + m_InExec = wasExec; + /** - * :TODO: turn this into an error check + * :TODO: Calling from a plugin in here will erase the cached message... + * Should that be documented? */ + g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); #if defined _DEBUG if (err == SP_ERROR_NONE) @@ -96,6 +125,51 @@ int BaseContext::Execute(funcid_t funcid, cell_t *result) return err; } +void BaseContext::SetErrorMessage(const char *msg, va_list ap) +{ + m_CustomMsg = true; + + vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); +} + +void BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) +{ + if (!m_InExec) + { + return; + } + + ctx->n_err = error; + + if (msg) + { + va_list ap; + va_start(ap, msg); + SetErrorMessage(msg, ap); + va_end(ap); + } +} + +cell_t BaseContext::ThrowNativeError(const char *msg, ...) +{ + if (!m_InExec) + { + return 0; + } + + ctx->n_err = SP_ERROR_NATIVE; + + if (msg) + { + va_list ap; + va_start(ap, msg); + SetErrorMessage(msg, ap); + va_end(ap); + } + + return 0; +} + int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) { cell_t *addr; diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 56c7d14e..44f7e6af 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -42,12 +42,19 @@ namespace SourcePawn virtual int BindNative(sp_nativeinfo_t *native); virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); virtual int Execute(funcid_t funcid, cell_t *result); + virtual void ThrowNativeErrorEx(int error, const char *msg, ...); + virtual cell_t ThrowNativeError(const char *msg, ...); public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); virtual int LookupFunction(ucell_t addr, const char **name); virtual int LookupLine(ucell_t addr, uint32_t *line); + private: + void SetErrorMessage(const char *msg, va_list ap); private: sp_context_t *ctx; + char m_MsgCache[1024]; + bool m_CustomMsg; + bool m_InExec; }; }; diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index 0ca4161f..ae5e0c1a 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "sp_file_headers.h" #include "sp_vm_types.h" #include "sp_vm_engine.h" @@ -13,8 +14,60 @@ #include #endif +#define INVALID_CIP 0xFFFFFFFF + using namespace SourcePawn; +#define ERROR_MESSAGE_MAX 23 +static const char *g_ErrorMsgTable[] = +{ + NULL, + "Unrecognizable file format", + "Decompressor was not found", + "Not enough space on the heap", + "Invalid parameter or parameter type", + "Invalid plugin address", + "Object or index not found", + "Invalid index or index not found", + "Not enough space on the stack", + "Debug section not found or debug not enabled", + "Invalid instruction", + "Invalid memory access", + "Stack went below stack boundary", + "Heap went below heap boundary", + "Divide by zero", + "Array index is out of bounds", + "Instruction contained invalid parameter", + "Stack memory leaked by native", + "Heap memory leaked by native", + "Dynamic array is too big", + "Tracker stack is out of bounds", + "Native was never bound", + "Maximum number of parameters reached", + "Native detected error", +}; + +SourcePawnEngine::SourcePawnEngine() +{ + m_pDebugHook = NULL; + m_CallStack = NULL; + m_FreedCalls = NULL; + m_CurChain = 0; +} + +SourcePawnEngine::~SourcePawnEngine() +{ + assert(m_CallStack == NULL); + + TracedCall *pTemp; + while (m_FreedCalls) + { + pTemp = m_FreedCalls->next; + delete pTemp; + m_FreedCalls = pTemp; + } +} + void *SourcePawnEngine::ExecAlloc(size_t size) { #if defined WIN32 @@ -302,3 +355,224 @@ int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) return SP_ERROR_NONE; } + +IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) +{ + IDebugListener *old = m_pDebugHook; + + m_pDebugHook = pListener; + + return old; +} + +unsigned int SourcePawnEngine::GetContextCallCount() +{ + if (!m_CallStack) + { + return 0; + } + + return m_CallStack->chain; +} + +TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain) +{ + TracedCall *pCall; + + if (!m_FreedCalls) + { + pCall = new TracedCall; + } else { + /* Unlink the head node from the free list */ + pCall = m_FreedCalls; + m_FreedCalls = m_FreedCalls->next; + if (m_FreedCalls) + { + m_FreedCalls->prev = NULL; + } + } + + /* Link as the head node into the call stack */ + pCall->next = m_CallStack; + pCall->prev = NULL; + + if (new_chain) + { + pCall->chain = ++m_CurChain; + } else { + pCall->chain = m_CurChain; + } + + if (m_CallStack) + { + m_CallStack->prev = pCall; + } + m_CallStack = pCall; + + return pCall; +} + +void SourcePawnEngine::FreeTracedCall(TracedCall *pCall) +{ + /* Check if this is the top of the call stack */ + if (pCall == m_CallStack) + { + m_CallStack = m_CallStack->next; + if (m_CallStack) + { + m_CallStack->prev = NULL; + } + } + + /* Add this to our linked list of freed calls */ + if (!m_FreedCalls) + { + m_FreedCalls = pCall; + m_FreedCalls->next = NULL; + m_FreedCalls->prev = NULL; + } else { + pCall->next = m_FreedCalls; + pCall->prev = NULL; + m_FreedCalls->prev = pCall; + m_FreedCalls = pCall; + } +} + +void SourcePawnEngine::PushTracer(sp_context_t *ctx) +{ + TracedCall *pCall = MakeTracedCall(true); + + pCall->cip = INVALID_CIP; + pCall->ctx = ctx; + pCall->frm = INVALID_CIP; +} + +void SourcePawnEngine::RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip) +{ + assert(m_CallStack != NULL); + assert(m_CallStack->ctx == ctx); + assert(m_CallStack->chain == m_CurChain); + + if (m_CallStack->cip == INVALID_CIP) + { + /* We aren't logging anything yet, so begin the trace */ + m_CallStack->cip = codeip; + m_CallStack->frm = frame; + } else { + if (m_CallStack->frm > frame) + { + /* The last frame has moved down the stack, + * so we have to push a new call onto our list. + */ + TracedCall *pCall = MakeTracedCall(false); + pCall->frm = frame; + } else if (m_CallStack->frm < frame) { + /* The last frame has moved up the stack, + * so we have to pop the call from our list. + */ + FreeTracedCall(m_CallStack); + } + /* no matter where we are, update the cip */ + m_CallStack->cip = codeip; + } +} + +void SourcePawnEngine::PopTracer(int error, const char *msg) +{ + assert(m_CallStack != NULL); + + if (error != SP_ERROR_NONE && m_pDebugHook) + { + CContextTrace trace(m_CallStack, error, msg); + m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace); + } + + /* Now pop the error chain */ + while (m_CallStack && m_CallStack->chain == m_CurChain) + { + FreeTracedCall(m_CallStack); + } + + m_CurChain--; +} + +CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg) : + m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart) +{ +} + +bool CContextTrace::DebugInfoAvailable() +{ + return ((m_pStart->ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); +} + +const char *CContextTrace::GetCustomErrorString() +{ + return m_pMsg; +} + +int CContextTrace::GetErrorCode() +{ + return m_Error; +} + +const char *CContextTrace::GetErrorString() +{ + if (m_Error > ERROR_MESSAGE_MAX || + m_Error < 1) + { + return "Invalid error code"; + } else { + return g_ErrorMsgTable[m_Error]; + } +} + +void CContextTrace::ResetTrace() +{ + m_pIterator = m_pStart; +} + +bool CContextTrace::GetTraceInfo(CallStackInfo *trace) +{ + if (m_pIterator->chain != m_pStart->chain) + { + return false; + } + + if (m_pIterator->cip == INVALID_CIP) + { + return false; + } + + IPluginContext *pContext = m_pIterator->ctx->context; + IPluginDebugInfo *pInfo = pContext->GetDebugInfo(); + + m_pIterator = m_pIterator->next; + + if (!pInfo) + { + return false; + } + + if (!trace) + { + return true; + } + + if (pInfo->LookupFile(m_pIterator->cip, &(trace->filename)) != SP_ERROR_NONE) + { + trace->filename = NULL; + } + + if (pInfo->LookupFunction(m_pIterator->cip, &(trace->function)) != SP_ERROR_NONE) + { + trace->function = NULL; + } + + if (pInfo->LookupLine(m_pIterator->cip, &(trace->line)) != SP_ERROR_NONE) + { + trace->line = 0; + } + + return true; +} diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index fb13f405..b25ec729 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -5,83 +5,78 @@ namespace SourcePawn { + struct TracedCall + { + uint32_t cip; + uint32_t frm; + sp_context_t *ctx; + TracedCall *next; + TracedCall *prev; + unsigned int chain; + }; + + + class CContextTrace : public IContextTrace + { + public: + CContextTrace(TracedCall *pStart, int error, const char *msg); + public: + virtual int GetErrorCode(); + virtual const char *GetErrorString(); + virtual bool DebugInfoAvailable(); + virtual const char *GetCustomErrorString(); + virtual bool GetTraceInfo(CallStackInfo *trace); + virtual void ResetTrace(); + private: + TracedCall *m_pStart; + TracedCall *m_pIterator; + const char *m_pMsg; + int m_Error; + }; + + class SourcePawnEngine : public ISourcePawnEngine { public: - /** - * Loads a named file from a file pointer. - * Using this means base memory will be allocated by the VM. - * Note: The file handle position may be undefined on entry, and is - * always undefined on conclusion. - * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. - */ + SourcePawnEngine(); + ~SourcePawnEngine(); + public: //ISourcePawnEngine sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); - - /** - * Loads a file from a base memory address. - * - * @param base Base address of the plugin's memory region. - * @param plugin If NULL, a new plugin pointer is returned. - * Otherwise, the passed pointer is used. - * @param err Optional error code pointer. - * @return The resulting plugin pointer. - */ sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); - - /** - * Frees all of the memory associated with a plugin file. - * If allocated using SP_LoadFromMemory, the base and plugin pointer - * itself are not freed (so this may end up doing nothing). - */ int FreeFromMemory(sp_plugin_t *plugin); - - /** - * Creates a new IContext from a context handle. - * - * @param ctx Context to use as a basis for the IPluginContext. - * @return New IPluginContext handle. - */ IPluginContext *CreateBaseContext(sp_context_t *ctx); - - /** - * Frees a context. - * - * @param ctx Context pointer to free. - */ void FreeBaseContext(IPluginContext *ctx); - - /** - * Allocates memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ void *BaseAlloc(size_t size); - - /** - * Frees memory allocated with BaseAlloc. - * - * @param memory Memory address to free. - */ void BaseFree(void *memory); - - /** - * Allocates executable memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ void *ExecAlloc(size_t size); + void ExecFree(void *address); + IDebugListener *SetDebugListener(IDebugListener *pListener); + unsigned int GetContextCallCount(); + public: //Debugger Stuff + /** + * @brief Pushes a context onto the top of the call tracer. + * + * @param ctx Plugin context. + */ + void PushTracer(sp_context_t *ctx); /** - * Frees executable memory. - * - * @param address Address to free. + * @brief Pops a plugin off the call tracer. */ - void ExecFree(void *address); + void PopTracer(int error, const char *msg); + + /** + * @brief Runs tracer from a debug break. + */ + void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); + private: + TracedCall *MakeTracedCall(bool new_chain); + void FreeTracedCall(TracedCall *pCall); + private: + IDebugListener *m_pDebugHook; + TracedCall *m_FreedCalls; + TracedCall *m_CallStack; + unsigned int m_CurChain; }; }; From 2a8542f7a487cfac4d55efdf36d9428a55131d5a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 03:23:57 +0000 Subject: [PATCH 0216/1664] JIT now properly handles debug mode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40246 --- sourcepawn/jit/x86/jit_x86.cpp | 29 ++++++++++++++++++++++----- sourcepawn/jit/x86/opcode_helpers.cpp | 16 +++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 32b675c8..f8e7af27 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1306,11 +1306,12 @@ inline void WriteOp_Break(JitWriter *jit) CompData *data = (CompData *)jit->data; if (data->debug) { + jit->write_ubyte(IA32_INT3); //mov ecx, jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); jitoffs_t save = jit->get_outputpos(); jit->set_outputpos(wr); - jit->write_uint32((uint32_t)(jit->outbase + wr)); + jit->write_uint32((uint32_t)(wr)); jit->set_outputpos(save); wr = IA32_Call_Imm32(jit, 0); @@ -1849,8 +1850,8 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) */ pcode_offs += jit->get_inputpos(); } - /* Offset must always be 1)positive and 2)less than the codesize */ - assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize); + /* Offset must always be 1)positive and 2)less than or equal to the codesize */ + assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->codesize); /* Do the lookup in the native dictionary. */ return *(jitoffs_t *)(data->rebase + pcode_offs); } else { @@ -1916,7 +1917,8 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) writer.inbase = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; - data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size); + /* Allocate relocation. One extra cell for final CIP. */ + data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size + sizeof(cell_t)); /* We will jump back here for second pass */ jit_rewind: @@ -1935,6 +1937,13 @@ jit_rewind: WriteOp_Sysreq_N_Function(jit); } + /* Write the debug section if we need it */ + if (data->debug == true) + { + data->jit_break = jit->get_outputpos(); + Write_BreakDebug(jit); + } + /* Plugins compiled with -O0 will need this! */ data->jit_sysreq_c = jit->get_outputpos(); WriteOp_Sysreq_C_Function(jit); @@ -1986,6 +1995,11 @@ jit_rewind: /* Write these last because error jumps should be unpredicted, and thus forward */ WriteErrorRoutines(data, jit); + /* Write the final CIP to the last position in the reloc array */ + pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); + native_offs = jit->get_outputpos(); + *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; + /* the total codesize is now known! */ codemem = writer.get_outputpos(); writer.outbase = (jitcode_t)engine->ExecAlloc(codemem); @@ -2196,7 +2210,12 @@ bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char if (strcmp(key, "debug") == 0) { - data->debug = (atoi(val) == 1); + if ((atoi(val) == 1) || !strcmp(val, "yes")) + { + data->debug = true; + } else { + data->debug = false; + } if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG)) { data->debug = false; diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 88e1b969..fda9a347 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -127,24 +127,26 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) void Write_BreakDebug(JitWriter *jit) { - //push ecx + //push edi + //mov edi, ecx //mov ecx, [esi+ctx] //cmp [ecx+dbreak], 0 //jnz :nocall - IA32_Push_Reg(jit, AMX_REG_TMP); + IA32_Push_Reg(jit, REG_EDI); + IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0); + /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */ //pushad - IA32_Pushad(jit); - //push [esi+frm] //push ctx //mov ecx, [ecx+dbreak] //call ecx //add esp, 8 //popad + IA32_Pushad(jit); IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0 IA32_Push_Reg(jit, AMX_REG_TMP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); @@ -153,8 +155,10 @@ void Write_BreakDebug(JitWriter *jit) IA32_Popad(jit); //:nocall + //pop edi + //ret + IA32_Pop_Reg(jit, REG_EDI); IA32_Send_Jump8_Here(jit, jmp); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG); IA32_Return(jit); } From 86f9be571452f487483d53fd8c715bc08772befe Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 1 Jan 2007 03:33:14 +0000 Subject: [PATCH 0217/1664] Added CPlayer class Added new player natives Fixed floatround returning a float instead of an int Added new float.inc file Added OnClientSettingsChanged forward --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40247 --- core/CPlayer.cpp | 44 +++++ core/CPlayer.h | 80 +++++++++ core/CPlayerManager.cpp | 55 +++++- core/CPlayerManager.h | 37 +++- core/msvc8/sourcemod_mm.vcproj | 18 +- core/smn_float.cpp | 2 +- core/smn_player.cpp | 107 ++++++++++++ plugins/include/float.inc | 300 +++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 131 +++++++++++++- 9 files changed, 763 insertions(+), 11 deletions(-) create mode 100644 core/CPlayer.cpp create mode 100644 core/CPlayer.h create mode 100644 core/smn_player.cpp create mode 100644 plugins/include/float.inc diff --git a/core/CPlayer.cpp b/core/CPlayer.cpp new file mode 100644 index 00000000..fd4f9aef --- /dev/null +++ b/core/CPlayer.cpp @@ -0,0 +1,44 @@ +#include "CPlayer.h" + +CPlayer::CPlayer() +{ + m_IsConnected = false; + m_IsInGame = false; + m_IsAuthorized = false; + m_PlayerEdict = NULL; +} + +void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) +{ + m_IsConnected = true; + m_Name.assign(name); + m_Ip.assign(ip); + m_PlayerEdict = pEntity; +} + +void CPlayer::Connect() +{ + m_IsInGame = true; +} + +void CPlayer::Authorize(const char *steamid) +{ + m_IsAuthorized = true; + m_AuthID.assign(steamid); +} + +void CPlayer::Disconnect() +{ + m_IsConnected = false; + m_IsInGame = false; + m_IsAuthorized = false; + m_Name.clear(); + m_Ip.clear(); + m_AuthID.clear(); + m_PlayerEdict = NULL; +} + +void CPlayer::SetName(const char *name) +{ + m_Name.assign(name); +} diff --git a/core/CPlayer.h b/core/CPlayer.h new file mode 100644 index 00000000..1fb23a2e --- /dev/null +++ b/core/CPlayer.h @@ -0,0 +1,80 @@ +#ifndef _INCLUDE_SOURCEMOD_CPLAYER_H_ +#define _INCLUDE_SOURCEMOD_CPLAYER_H_ + +#include +#include + +using namespace SourceHook; + +class CPlayer +{ + friend class CPlayerManager; +public: + CPlayer(); +public: + const char *PlayerName() const; + const char *PlayerIP() const; + const char *PlayerAuthString() const; + edict_t *GetPlayerEdict() const; + bool IsPlayerInGame() const; + bool IsPlayerConnected() const; + bool IsPlayerAuthorized() const; + bool IsPlayerFakeClient() const; + //:TODO: is user alive function +private: + void Initialize(const char *name, const char *ip, edict_t *pEntity); + void Connect(); + void Authorize(const char *steamid); + void Disconnect(); + void SetName(const char *name); +private: + bool m_IsConnected; + bool m_IsInGame; + bool m_IsAuthorized; + String m_Name; + String m_Ip; + String m_AuthID; + edict_t *m_PlayerEdict; +}; + +inline const char *CPlayer::PlayerName() const +{ + return m_Name.c_str(); +} + +inline const char *CPlayer::PlayerIP() const +{ + return m_Ip.c_str(); +} + +inline const char *CPlayer::PlayerAuthString() const +{ + return m_AuthID.c_str(); +} + +inline edict_t *CPlayer::GetPlayerEdict() const +{ + return m_PlayerEdict; +} + +inline bool CPlayer::IsPlayerInGame() const +{ + return m_IsInGame; +} + +inline bool CPlayer::IsPlayerConnected() const +{ + return m_IsConnected; +} + +inline bool CPlayer::IsPlayerAuthorized() const +{ + return m_IsAuthorized; +} + +inline bool CPlayer::IsPlayerFakeClient() const +{ + return (strcmp(m_AuthID.c_str(), "BOT") == 0); +} + +#endif // _INCLUDE_SOURCEMOD_CPLAYER_H_ diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 968e18af..2158648f 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -1,10 +1,13 @@ #include "CPlayerManager.h" #include "ForwardSys.h" +CPlayerManager g_PlayerManager; + SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int); SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *); SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *); +SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *); void CPlayerManager::OnSourceModAllInitialized() { @@ -13,6 +16,7 @@ void CPlayerManager::OnSourceModAllInitialized() SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); /* Register OnClientConnect */ ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; @@ -31,8 +35,16 @@ void CPlayerManager::OnSourceModAllInitialized() /* Register OnClientCommand */ m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2); + /* Register OnClientSettingsChanged */ + m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); + /* Register OnClientAuthorized */ //:TODO: + + /* Initialize all players */ + m_maxClients = g_SMAPI->pGlobals()->maxClients; + m_PlayerCount = 0; + m_Players = new CPlayer[m_maxClients]; } void CPlayerManager::OnSourceModShutdown() @@ -42,6 +54,7 @@ void CPlayerManager::OnSourceModShutdown() SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); /* Release forwards */ g_Forwards.ReleaseForward(m_clconnect); @@ -49,13 +62,18 @@ void CPlayerManager::OnSourceModShutdown() g_Forwards.ReleaseForward(m_cldisconnect); g_Forwards.ReleaseForward(m_cldisconnect_post); g_Forwards.ReleaseForward(m_clcommand); + g_Forwards.ReleaseForward(m_clinfochanged); + + delete [] m_Players; } bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { cell_t res = 1; + int client = engine->IndexOfEdict(pEntity); - m_clconnect->PushCell(engine->IndexOfEdict(pEntity)); + m_Players[client].Initialize(pszName, pszAddress, pEntity); + m_clconnect->PushCell(client); m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK); m_clconnect->PushCell(maxrejectlen); m_clconnect->Execute(&res, NULL); @@ -66,8 +84,11 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername) { cell_t res; + int client = engine->IndexOfEdict(pEntity); - m_clputinserver->PushCell(engine->IndexOfEdict(pEntity)); + m_Players[client].Connect(); + m_PlayerCount++; + m_clputinserver->PushCell(client); m_clputinserver->Execute(&res, NULL); } @@ -79,9 +100,18 @@ void CPlayerManager::OnClientAuthorized() void CPlayerManager::OnClientDisconnect(edict_t *pEntity) { cell_t res; + int client = engine->IndexOfEdict(pEntity); - m_cldisconnect->PushCell(engine->IndexOfEdict(pEntity)); - m_cldisconnect->Execute(&res, NULL); + if (m_Players[client].IsPlayerConnected()) + { + m_cldisconnect->PushCell(client); + m_cldisconnect->Execute(&res, NULL); + } + if (m_Players[client].IsPlayerInGame()) + { + m_PlayerCount--; + } + m_Players[client].Disconnect(); } void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) @@ -98,4 +128,19 @@ void CPlayerManager::OnClientCommand(edict_t *pEntity) m_clcommand->PushCell(engine->IndexOfEdict(pEntity)); m_clcommand->Execute(&res, NULL); -} \ No newline at end of file + + //:TODO: res should be evaluated here for something, DOCUMENT this in the INC FILE! +} + +void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) +{ + cell_t res; + int client = engine->IndexOfEdict(pEntity); + + m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity)); + m_clinfochanged->Execute(&res, NULL); + if (m_Players[client].IsPlayerInGame()) + { + m_Players[client].SetName(engine->GetClientConVarValue(client, "name")); + } +} diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index b11b233c..ed482517 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -1,16 +1,23 @@ #ifndef _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ #define _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ -#include "sourcemod.h" +#include "sm_globals.h" #include #include "sourcemm_api.h" #include +#include "CPlayer.h" + +class CPlayer; class CPlayerManager : public SMGlobalClass { public: //SMGlobalClass virtual void OnSourceModAllInitialized(); virtual void OnSourceModShutdown(); +public: + int GetMaxClients() const; + CPlayer *GetPlayerByIndex(int client) const; + int GetPlayerCount() const; public: bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); void OnClientPutInServer(edict_t *pEntity, char const *playername); @@ -18,12 +25,38 @@ public: void OnClientDisconnect_Post(edict_t *pEntity); void OnClientAuthorized(); //:TODO: any args needed? void OnClientCommand(edict_t *pEntity); + void OnClientSettingsChanged(edict_t *pEntity); private: IForward *m_clconnect; IForward *m_cldisconnect; IForward *m_cldisconnect_post; IForward *m_clputinserver; IForward *m_clcommand; + IForward *m_clinfochanged; + CPlayer *m_Players; + int m_maxClients; + int m_PlayerCount; }; -#endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ \ No newline at end of file +extern CPlayerManager g_PlayerManager; + +inline int CPlayerManager::GetMaxClients() const +{ + return m_maxClients; +} + +inline CPlayer *CPlayerManager::GetPlayerByIndex(int client) const +{ + if (client > m_maxClients || client < 0) + { + return NULL; + } + return &m_Players[client]; +} + +inline int CPlayerManager::GetPlayerCount() const +{ + return m_PlayerCount; +} + +#endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 5300a0ac..7f9ac9f3 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -210,6 +214,10 @@ RelativePath="..\smn_float.cpp" > + + @@ -228,6 +236,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + @@ -315,6 +327,10 @@ RelativePath="..\systems\PluginSys.h" > + + (val); } static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) diff --git a/core/smn_player.cpp b/core/smn_player.cpp new file mode 100644 index 00000000..ad7bdcb5 --- /dev/null +++ b/core/smn_player.cpp @@ -0,0 +1,107 @@ +#include "CPlayerManager.h" + +static cell_t sm_getclientcount(IPluginContext *pCtx, const cell_t *params) +{ + if (params[1]) + { + return g_PlayerManager.GetPlayerCount(); + } + + int maxplayers = g_PlayerManager.GetMaxClients(); + int count = 0; + for (int i=1; i<=maxplayers; ++i) + { + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(i); + if ((pPlayer->IsPlayerConnected()) && !(pPlayer->IsPlayerInGame())) + { + count++; + } + } + + return (g_PlayerManager.GetPlayerCount() + count); +} + +static cell_t sm_getmaxclients(IPluginContext *pCtx, const cell_t *params) +{ + return g_PlayerManager.GetMaxClients(); +} + +static cell_t sm_getclientname(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerName(), NULL); + return 1; +} + +static cell_t sm_getclientip(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + pCtx->StringToLocal(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerIP()); + return 1; +} + +static cell_t sm_getclientauthstr(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + pCtx->StringToLocal(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerAuthString()); + return 1; +} + +static cell_t sm_isplayerconnected(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerConnected()) ? 1 : 0; +} + +static cell_t sm_isplayeringame(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerInGame()) ? 1 : 0; +} + +static cell_t sm_isplayerauthorized(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerAuthorized()) ? 1 : 0; +} + +static cell_t sm_isplayerfakeclient(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + //:TODO: runtime error + } + + return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerFakeClient()) ? 1 : 0; +} \ No newline at end of file diff --git a/plugins/include/float.inc b/plugins/include/float.inc new file mode 100644 index 00000000..04fb6bb5 --- /dev/null +++ b/plugins/include/float.inc @@ -0,0 +1,300 @@ +/** + * :TODO: license info + */ + +#if defined _float_included + #endinput +#endif +#define _float_included + +/** + * @GLOBAL@ + * All the trigonometric functions take in or return its values in RADIANS. + * Use DegToRad or RadToDeg stocks to convert the radix units. + */ + +/* Different methods of rounding */ +enum floatround_method +{ + floatround_round = 0, + floatround_floor, + floatround_ceil, + floatround_tozero +}; + +/** + * Converts an integer into a floating point value. + * + * @param value Integer to convert. + * @return Floating point value. + */ +native Float:float(value); + +/** + * Converts a string into a floating point value. + * + * @param str String to convert. + * @return Converted floating point number. + */ +native Float:FloatStr(const String:str[]); + +/** + * Multiplies two floats together. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1*oper2. + */ +native Float:FloatMul(Float:oper1, Float:oper2); + +/** + * Divides the dividend by the divisor. + * + * @param dividend First value. + * @param divisor Second value. + * @return dividend/divisor. + */ +native Float:FloatDiv(Float:dividend, Float:divisor); + +/** + * Adds two floats together. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1+oper2. + */ +native Float:FloatAdd(Float:oper1, Float:oper2); + +/** + * Subtracts oper2 from oper1. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1-oper2. + */ +native Float:FloatSub(Float:oper1, Float:oper2); + +/** + * Returns the decimal part of a float. + * + * @param value Input value. + * @return Decimal part. + */ +native Float:FloatFraction(Float:value); + +/** + * Rounds a float into an integer number. + * + * @param value Input value to be rounded. + * @param method Rounding method to use. + * @return Rounded value. + */ +native FloatRound(Float:value, floatround_method:method=floatround_round); + +/** + * Compares two floats. + * + * @param fOne First value. + * @param fTwo Second value. + * @return Returns 1 if the first argument is greater than the second argument. + * Returns -1 if the first argument is smaller than the second argument. + * Returns 0 if both arguments are equal. + */ +native FloatCompare(Float:fOne, Float:fTwo); + +/** + * Returns the square root of the input value, equivalent to floatpower(value, 0.5). + * + * @param value Input value. + * @return Square root of the value. + */ +native Float:SquareRoot(Float:value); + +/** + * Returns the value raised to the power of the exponent. + * + * @param value Value to be raised. + * @param exponent Value to raise the base. + * @return value^exponent. + */ +native Float:Pow(Float:value, Float:exponent); + +/** + * Returns the value of raising the input by e. + * + * @param value Input value. + * @return exp(value). + */ +native Float:Exponential(Float:value); + +/** + * Returns the logarithm of any base specified. + * + * @param value Input value. + * @param base Logarithm base to use, default is 10. + * @return log(value)/log(base). + */ +native Float:Logarithm(Float:value, Float:base=10.0); + +/** + * Returns the sine of the argument. + * + * @param value Input value in radians. + * @return sin(value). + */ +native Float:Sine(Float:value); + +/** + * Returns the cosine of the argument. + * + * @param value Input value in radians. + * @return cos(value). + */ +native Float:Cosine(Float:value); + +/** + * Returns the tangent of the argument. + * + * @param value Input value in radians. + * @return tan(value). + */ +native Float:Tangent(Float:value); + +/** + * Returns the absolute value. + * + * @param value Input value. + * @return abs(value). + */ +native Float:FloatAbs(Float:value); + +/** + * Returns the arctangent of the input value. + * + * @param angle Input value. + * @return atan(value) in radians. + */ +native Float:ArcTangent(Float:angle); + +/** + * Returns the arccosine of the input value. + * + * @param angle Input value. + * @return acos(value) in radians. + */ +native Float:ArcCosine(Float:angle); + +/** + * Returns the arcsine of the input value. + * + * @param angle Input value. + * @return asin(value) in radians. + */ +native Float:ArcSine(Float:angle); + +/** + * Returns the arctangent2 of the input values. + * + * @param x Horizontal value. + * @param y Vertical value. + * @return atan2(value) in radians. + */ +native Float:ArcAtan2(Float:x, Float:y); + +/** + * User defined operators. + * + */ +#pragma rational Float + +native Float:operator*(Float:oper1, Float:oper2) = FloatMul; +native Float:operator/(Float:oper1, Float:oper2) = FloatDiv; +native Float:operator+(Float:oper1, Float:oper2) = FloatAdd; +native Float:operator-(Float:oper1, Float:oper2) = FloatSub; + +stock Float:operator++(Float:oper) + return oper+1.0; + +stock Float:operator--(Float:oper) + return oper-1.0; + +stock Float:operator-(Float:oper) + return oper^Float:((-1)^((-1)/2)); /* IEEE values are sign/magnitude */ + +stock Float:operator*(Float:oper1, oper2) + return FloatMul(oper1, float(oper2)); /* "*" is commutative */ + +stock Float:operator/(Float:oper1, oper2) + return FloatDiv(oper1, float(oper2)); + +stock Float:operator/(oper1, Float:oper2) + return FloatDiv(float(oper1), oper2); + +stock Float:operator+(Float:oper1, oper2) + return FloatAdd(oper1, float(oper2)); /* "+" is commutative */ + +stock Float:operator-(Float:oper1, oper2) + return FloatSub(oper1, float(oper2)); + +stock Float:operator-(oper1, Float:oper2) + return FloatSub(float(oper1), oper2); + +stock bool:operator==(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) == 0; + +stock bool:operator==(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) == 0; /* "==" is commutative */ + +stock bool:operator!=(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) != 0; + +stock bool:operator!=(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) != 0; /* "==" is commutative */ + +stock bool:operator>(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) > 0; + +stock bool:operator>(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) > 0; + +stock bool:operator>(oper1, Float:oper2) + return FloatCompare(float(oper1), oper2) > 0; + +stock bool:operator>=(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) >= 0; + +stock bool:operator>=(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) >= 0; + +stock bool:operator>=(oper1, Float:oper2) + return FloatCompare(float(oper1), oper2) >= 0; + +stock bool:operator<(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) < 0; + +stock bool:operator<(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) < 0; + +stock bool:operator<(oper1, Float:oper2) + return FloatCompare(float(oper1), oper2) < 0; + +stock bool:operator<=(Float:oper1, Float:oper2) + return FloatCompare(oper1, oper2) <= 0; + +stock bool:operator<=(Float:oper1, oper2) + return FloatCompare(oper1, float(oper2)) <= 0; + +stock bool:operator<=(oper1, Float:oper2) + return FloatCompare(float(oper1), oper2) <= 0; + +stock bool:operator!(Float:oper) + return (_:oper & ((-1)/2)) == 0; /* -1 = all bits to 1; /2 = remove most significant bit (sign) + works on both 32bit and 64bit systems; no constant required */ + +/** + * Forbidden operators. + * + */ +forward operator%(Float:oper1, Float:oper2); +forward operator%(Float:oper1, oper2); +forward operator%(oper1, Float:oper2); \ No newline at end of file diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index a799213c..3d3a17a9 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -14,7 +14,7 @@ struct Plugin const String:author[], /* Plugin Author */ const String:version[], /* Plugin Version */ const String:url[], /* Plugin URL */ -} +}; /** * Declare this as a struct in your plugin to expose its information. @@ -50,7 +50,7 @@ forward OnPluginInit(Handle:myself); * @param late Whether or not the plugin was loaded "late" (after map load). * @param error Error message buffer in case load failed. * @param err_max Maximum number of characters for error message buffer. - * @return True if load success, false otherwise. + * @return True if load success, false otherwise. */ forward bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max); @@ -67,3 +67,130 @@ forward OnPluginUnload(); * @noreturn */ forward OnPluginPauseChange(bool:pause); + +/** + * Called on client connection. + * + * @param client Player index. + * @param rejectmsg Buffer to store the rejection message when the connection is refused. + * @param maxlen Maximum number of characters for rejection buffer. + * @return True to validate client's connection, false to refuse it. + */ +forward bool:OnClientConnect(client, String:rejectmsg[], maxlen); + +/** + * Called when a client is entering to the game. + * + * @param client Player index. + * @noreturn + */ +forward OnClientPutInServer(client); + +/** + * Called when a client is disconnecting from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect(client); + +/** + * Called when a client is disconnected from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect_Post(client); + +/** + * Called when a client is sending a command. + * + * @param client Player index. + * @noreturn + */ +forward OnClientCommand(client); + +/** + * Called whenever the client's settings are changed. + * + * @param client Player index. + * @noreturn + */ +forward OnClientSettingsChanged(client); + +/** + * Returns the maximum number of clients allowed on the server. + * + * @return Maximum number of clients allowed. + */ +native GetMaxClients(); + +/** + * Returns the client count put in the server. + * + * @param inGameOnly If false connecting players are also counted. + * @return Client count in the server. + */ +native GetClientCount(bool:inGameOnly=true); + +/** + * Returns the client's name. + * + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @noreturn + */ +native GetClientName(client, String:name[], maxlen); + +/** + * Returns the client's Ip address. + * + * @param client Player index. + * @param name Buffer to store the client's ip address. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @noreturn + */ +native GetClientIp(client, String:ip[], maxlen); + +/** + * Returns the client's authindex. + * + * @param client Player index. + * @param auth Buffer to store the client's auth string. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return Returns 0 on failure, non-zero otherwise. + */ +native GetClientAuthString(client, String:auth[], maxlen); + +/** + * Returns if a certain player is connected. + * + * @param client Player index. + * @return True if player is connected to the server, false otherwise. + */ +native bool:IsPlayerConnected(client); + +/** + * Returns if a certain player has entered the game. + * + * @param client Player index. + * @return True if player has entered the game, false otherwise. + */ +native bool:IsPlayerInGame(client); + +/** + * Returns if a certain player has been authenticated. + * + * @param client Player index. + * @return True if player has been authenticated, false otherwise. + */ +native bool:IsPlayerAuthorized(client); + +/** + * Returns if a certain player is a fake client. + * + * @param client Player index. + * @return True if player is a fake client, false otherwise. + */ +native bool:IsPlayerFakeClient(client); From 6df0fa6e973daea325215ebfbeddee274af03e6a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 03:34:06 +0000 Subject: [PATCH 0218/1664] removed debug code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40248 --- sourcepawn/jit/x86/jit_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index f8e7af27..fb71321c 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1306,7 +1306,7 @@ inline void WriteOp_Break(JitWriter *jit) CompData *data = (CompData *)jit->data; if (data->debug) { - jit->write_ubyte(IA32_INT3); + //jit->write_ubyte(IA32_INT3); //mov ecx, jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); jitoffs_t save = jit->get_outputpos(); From 553cd022aea7d1270700a66e5df2544efe479a59 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 1 Jan 2007 03:39:53 +0000 Subject: [PATCH 0219/1664] typo fiz --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40249 --- plugins/include/float.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/float.inc b/plugins/include/float.inc index 04fb6bb5..9e222c2b 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -199,7 +199,7 @@ native Float:ArcSine(Float:angle); * @param y Vertical value. * @return atan2(value) in radians. */ -native Float:ArcAtan2(Float:x, Float:y); +native Float:ArcTangent2(Float:x, Float:y); /** * User defined operators. From 9ad824fe7a3ee90e4fd0abbbe9331ebabb1a18bf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 03:40:17 +0000 Subject: [PATCH 0220/1664] final API touches --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40250 --- sourcepawn/include/sp_vm_api.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index a178a049..93fedf57 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -349,6 +349,7 @@ namespace SourcePawn */ class IContextTrace { + public: /** * @brief Returns the integer error code. * @@ -391,6 +392,15 @@ namespace SourcePawn * @brief Resets the trace to its original position (the call on the top of the stack). */ virtual void ResetTrace() =0; + + /** + * @brief Retrieves the name of the last native called. + * Returns NULL if there was no native that caused the error. + * + * @param index Opterional pointer to store index. + * @return Native name, or NULL if none. + */ + virtual const char *GetLastNative(uint32_t *index) =0; }; @@ -484,7 +494,10 @@ namespace SourcePawn virtual void ExecFree(void *address) =0; /** - * @brief Sets the debug listener. + * @brief Sets the debug listener. This should only be called once. + * If called successively (using manual chaining), only the last function should + * attempt to call back into the same plugin. Otherwise, globally cached states + * can be accidentally overwritten. * * @param listener Pointer to an IDebugListener. * @return Old IDebugListener, or NULL if none. From f8c88a75df041348be8426c6dc2c0ba99e571ad4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 03:40:29 +0000 Subject: [PATCH 0221/1664] implemented debugger --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40251 --- core/vm/sp_vm_basecontext.cpp | 3 +- core/vm/sp_vm_engine.cpp | 60 +++++++++++++++++++++-------------- core/vm/sp_vm_engine.h | 5 +-- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 2a496b56..76b97240 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -767,7 +767,8 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) return SP_ERROR_NOT_FOUND; } - *line = ctx->lines[low].line; + /* Since the CIP occurs BEFORE the line, we have to add one */ + *line = ctx->lines[low].line + 1; return SP_ERROR_NONE; } diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index ae5e0c1a..cb6cf700 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -63,7 +63,7 @@ SourcePawnEngine::~SourcePawnEngine() while (m_FreedCalls) { pTemp = m_FreedCalls->next; - delete pTemp; + delete m_FreedCalls; m_FreedCalls = pTemp; } } @@ -386,15 +386,10 @@ TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain) /* Unlink the head node from the free list */ pCall = m_FreedCalls; m_FreedCalls = m_FreedCalls->next; - if (m_FreedCalls) - { - m_FreedCalls->prev = NULL; - } } /* Link as the head node into the call stack */ pCall->next = m_CallStack; - pCall->prev = NULL; if (new_chain) { @@ -403,10 +398,6 @@ TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain) pCall->chain = m_CurChain; } - if (m_CallStack) - { - m_CallStack->prev = pCall; - } m_CallStack = pCall; return pCall; @@ -418,10 +409,6 @@ void SourcePawnEngine::FreeTracedCall(TracedCall *pCall) if (pCall == m_CallStack) { m_CallStack = m_CallStack->next; - if (m_CallStack) - { - m_CallStack->prev = NULL; - } } /* Add this to our linked list of freed calls */ @@ -429,11 +416,8 @@ void SourcePawnEngine::FreeTracedCall(TracedCall *pCall) { m_FreedCalls = pCall; m_FreedCalls->next = NULL; - m_FreedCalls->prev = NULL; } else { pCall->next = m_FreedCalls; - pCall->prev = NULL; - m_FreedCalls->prev = pCall; m_FreedCalls = pCall; } } @@ -465,6 +449,7 @@ void SourcePawnEngine::RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t cod * so we have to push a new call onto our list. */ TracedCall *pCall = MakeTracedCall(false); + pCall->ctx = ctx; pCall->frm = frame; } else if (m_CallStack->frm < frame) { /* The last frame has moved up the stack, @@ -483,7 +468,14 @@ void SourcePawnEngine::PopTracer(int error, const char *msg) if (error != SP_ERROR_NONE && m_pDebugHook) { - CContextTrace trace(m_CallStack, error, msg); + uint32_t native = INVALID_CIP; + + if (m_CallStack->ctx->n_err) + { + native = m_CallStack->ctx->n_idx; + } + + CContextTrace trace(m_CallStack, error, msg, native); m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace); } @@ -496,8 +488,8 @@ void SourcePawnEngine::PopTracer(int error, const char *msg) m_CurChain--; } -CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg) : - m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart) +CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native) : + m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart), m_Native(native) { } @@ -534,7 +526,7 @@ void CContextTrace::ResetTrace() bool CContextTrace::GetTraceInfo(CallStackInfo *trace) { - if (m_pIterator->chain != m_pStart->chain) + if (!m_pIterator || (m_pIterator->chain != m_pStart->chain)) { return false; } @@ -547,8 +539,6 @@ bool CContextTrace::GetTraceInfo(CallStackInfo *trace) IPluginContext *pContext = m_pIterator->ctx->context; IPluginDebugInfo *pInfo = pContext->GetDebugInfo(); - m_pIterator = m_pIterator->next; - if (!pInfo) { return false; @@ -556,6 +546,7 @@ bool CContextTrace::GetTraceInfo(CallStackInfo *trace) if (!trace) { + m_pIterator = m_pIterator->next; return true; } @@ -574,5 +565,28 @@ bool CContextTrace::GetTraceInfo(CallStackInfo *trace) trace->line = 0; } + m_pIterator = m_pIterator->next; + return true; } + +const char *CContextTrace::GetLastNative(uint32_t *index) +{ + if (m_Native == INVALID_CIP) + { + return NULL; + } + + sp_native_t *native; + if (m_pIterator->ctx->context->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE) + { + return NULL; + } + + if (index) + { + *index = m_Native; + } + + return native->name; +} diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index b25ec729..ca0ac7f3 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -11,7 +11,6 @@ namespace SourcePawn uint32_t frm; sp_context_t *ctx; TracedCall *next; - TracedCall *prev; unsigned int chain; }; @@ -19,7 +18,7 @@ namespace SourcePawn class CContextTrace : public IContextTrace { public: - CContextTrace(TracedCall *pStart, int error, const char *msg); + CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); public: virtual int GetErrorCode(); virtual const char *GetErrorString(); @@ -27,11 +26,13 @@ namespace SourcePawn virtual const char *GetCustomErrorString(); virtual bool GetTraceInfo(CallStackInfo *trace); virtual void ResetTrace(); + virtual const char *GetLastNative(uint32_t *index); private: TracedCall *m_pStart; TracedCall *m_pIterator; const char *m_pMsg; int m_Error; + uint32_t m_Native; }; From 9f7c852c77fbc49a5d2079d74a48b936cc9f0939 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 10:33:51 +0000 Subject: [PATCH 0222/1664] initial import of handle natives and a few minor API changes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40252 --- core/interfaces/IHandleSys.h | 6 +-- core/smn_handles.cpp | 72 ++++++++++++++++++++++++++++++++++++ core/systems/HandleSys.cpp | 2 +- core/systems/PluginSys.cpp | 18 +++++++++ core/systems/PluginSys.h | 5 +++ plugins/include/handles.h | 58 +++++++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 core/smn_handles.cpp create mode 100644 plugins/include/handles.h diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index f5fc71a2..ab77a428 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -194,7 +194,7 @@ namespace SourceMod * only perform any further action if the counter hits 0. * * @param type Handle_t identifier to destroy. - * @param ident Identity token, for destroying secure handles (0 for none). + * @param ident Identity token, for destroying secure handles (NULL for none). * @return A HandleError error code. */ virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident) =0; @@ -215,9 +215,9 @@ namespace SourceMod * @brief Retrieves the contents of a handle. * * @param handle Handle_t from which to retrieve contents. - * @param type Expected type to read as. + * @param type Expected type to read as. 0 ignores typing rules. * @param ident Identity token to validate as. - * @param object Address to store object in. + * @param object Optional address to store object in. * @return HandleError error code. */ virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object) =0; diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp new file mode 100644 index 00000000..ca60e8c5 --- /dev/null +++ b/core/smn_handles.cpp @@ -0,0 +1,72 @@ +#include "sm_globals.h" +#include "HandleSys.h" +#include "PluginSys.h" + +static cell_t sm_IsValidHandle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + + HandleError err = g_HandleSys.ReadHandle(hndl, 0, NULL, NULL); + + if (err != HandleError_Access + && err != HandleError_None) + { + return 0; + } + + return 1; +} + +static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + + HandleError err = g_HandleSys.FreeHandle(hndl, NULL); + + if (err == HandleError_None) + { + return 1; + } else if (err == HandleError_Access) { + return 0; + } else { + return pContext->ThrowNativeError("Handle %x is invalid (error %d)", hndl, err); + } +} + +static cell_t sm_CloneHandle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t new_hndl; + Handle_t hndl = static_cast(params[1]); + IPlugin *pPlugin; + HandleError err; + + if (params[2] == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + Handle_t hPlugin = static_cast(params[2]); + pPlugin = g_PluginSys.PluginFromHandle(hPlugin, &err); + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err); + } + } + + err = g_HandleSys.CloneHandle(hndl, &new_hndl, pPlugin->GetIdentity(), NULL); + + if (err == HandleError_Access) + { + return 0; + } else if (err == HandleError_None) { + return new_hndl; + } else { + return pContext->ThrowNativeError("Handle to clone %x is invalid (error %d)", hndl, err); + } +} + +REGISTER_NATIVES(handles) +{ + {"IsValidHandle", sm_IsValidHandle}, + {"CloseHandle", sm_CloseHandle}, + {"CloneHandle", sm_CloneHandle}, +}; diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index be91460a..b4ffa916 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -465,7 +465,7 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, { return HandleError_Type; } - } else { + } else if (type) { if (pHandle->type != type) { return HandleError_Type; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2f087967..03ece023 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1141,3 +1141,21 @@ void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives) { m_natives.push_back(natives); } + +IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) +{ + IPlugin *pPlugin; + HandleError _err; + + if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, m_MyIdent, (void **)&pPlugin)) != HandleError_None) + { + pPlugin = NULL; + } + + if (err) + { + *err = _err; + } + + return pPlugin; +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index f5e5c462..904cd127 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -236,6 +236,11 @@ public: * Adds natives from core into the native pool. */ void RegisterNativesFromCore(sp_nativeinfo_t *natives); + + /** + * Converts a Handle to an IPlugin if possible. + */ + IPlugin *PluginFromHandle(Handle_t handle, HandleError *err); private: /** * Recursively loads all plugins in the given directory. diff --git a/plugins/include/handles.h b/plugins/include/handles.h new file mode 100644 index 00000000..be3640b8 --- /dev/null +++ b/plugins/include/handles.h @@ -0,0 +1,58 @@ +/** + * :TODO: license info + */ + + +#if defined _handles_included + #endinput +#endif +#define _handles_included + +enum Handle +{ + INVALID_HANDLE = 0, +}; + +/** + * @brief Returns if a handle is valid or not. + * @note It is not a good idea to call this on every Handle. If you code properly, + * all of your Handles will either be valid or will expose important bugs to fix. + * This is provided for situations only where testing for handle validity is needed. + * + * @param hndl Handle to test for validity. + * @return True if handle is valid, false otherwise. + */ +native bool:IsValidHandle(Handle:hndl); + +/** + * @brief Closes a Handle. If the handle has multiple copies open, + * it is not destroyed unless all copies are closed. + * + * @note Closing a Handle has a different meaning for each Handle type. Make + * sure you read the documentation on whatever provided the Handle. + * + * @param hndl Handle to close. + * @return True if successful, false if not closeable. + * @error Invalid handles will cause a run time error. + */ +native bool:CloseHandle(Handle:hndl); + +/** + * @brief Clones a Handle. When passing handles in between plugins, caching handles + * can result in accidental invalidation when one plugin releases the Handle, or is its owner + * is unloaded from memory. To prevent this, the Handle may be "cloned" with a new owner. + * + * @note Usually, you will be cloning Handles for other plugins. This means that if you clone + * the Handle without specifying the new owner, it will assume the identity of your original calling + * plugin, which is not very useful. You should either specify that the receiving plugin should + * clone the handle on its own, or you should explicitly clone the Handle using the receiving plugin's + * identity Handle. + * + * @param hndl Handle to clone/duplicate. + * @param plugin Optional Handle to another plugin to mark as the new owner. + * If no owner is passed, the owner becomes the calling plugin. + * @return Handle on success, INVALID_HANDLE if not cloneable. + * @error Invalid handles will cause a run time error. + */ +native Handle:CloneHandle(Handle:hndl, Handle:plugin=INVALID_HANDLE); + From 271fba7b5078629fcffa7ec23d563f9375c9b287 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 10:35:15 +0000 Subject: [PATCH 0223/1664] updated project file added todo for floats --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40253 --- core/msvc8/sourcemod_mm.vcproj | 7 ++++++- core/smn_float.cpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7f9ac9f3..3ea688f5 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/smn_float.cpp b/core/smn_float.cpp index cab961a2..875f0b4d 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -5,6 +5,7 @@ using namespace SourcePawn; +//:TODO: these need to be registered.... /**************************************** * * From 80b75f21969914ac62d45f4c61ca47fc6fafdb2c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 10:36:29 +0000 Subject: [PATCH 0224/1664] added note for player natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40254 --- core/smn_player.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index ad7bdcb5..d8c64dcb 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1,5 +1,7 @@ #include "CPlayerManager.h" +//:TODO: register these and use the same capitalization conventions as the natives + static cell_t sm_getclientcount(IPluginContext *pCtx, const cell_t *params) { if (params[1]) From a46c500e6895b7c11b8ea75fb39f8d2c59123143 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 18:03:43 +0000 Subject: [PATCH 0225/1664] little fixes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40255 --- plugins/include/sourcemod.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 3d3a17a9..de440a2f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -144,17 +144,17 @@ native GetClientCount(bool:inGameOnly=true); native GetClientName(client, String:name[], maxlen); /** - * Returns the client's Ip address. + * Retrieves a client's IP address. * * @param client Player index. * @param name Buffer to store the client's ip address. * @param maxlen Maximum length of string buffer (includes NULL terminator). * @noreturn */ -native GetClientIp(client, String:ip[], maxlen); +native GetClientIP(client, String:ip[], maxlen); /** - * Returns the client's authindex. + * Retrieves a client's authentication string (SteamID). * * @param client Player index. * @param auth Buffer to store the client's auth string. From a4363dfa4f7c6e801b2f31d57f45a44c255962cf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 18:36:27 +0000 Subject: [PATCH 0226/1664] whoa, wrong name --HG-- rename : plugins/include/handles.h => plugins/include/handles.inc extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40256 --- plugins/include/{handles.h => handles.inc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/include/{handles.h => handles.inc} (100%) diff --git a/plugins/include/handles.h b/plugins/include/handles.inc similarity index 100% rename from plugins/include/handles.h rename to plugins/include/handles.inc From 2fc806542a2c68707ac57b5a8f8de291ab3c52e4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 19:50:16 +0000 Subject: [PATCH 0227/1664] added usage of the Handle System to begin experimenting --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40257 --- core/interfaces/IHandleSys.h | 6 +- core/interfaces/ILibrarySys.h | 6 ++ core/msvc8/sourcemod_mm.vcproj | 4 ++ core/sm_globals.h | 1 + core/smn_filesystem.cpp | 114 +++++++++++++++++++++++++++++++++ core/smn_handles.cpp | 1 + core/sourcemod.cpp | 6 +- core/systems/HandleSys.cpp | 4 +- core/systems/HandleSys.h | 2 +- core/systems/LibrarySys.cpp | 5 ++ core/systems/LibrarySys.h | 1 + plugins/include/files.inc | 42 ++++++++++++ plugins/include/sourcemod.inc | 4 ++ 13 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 core/smn_filesystem.cpp create mode 100644 plugins/include/files.inc diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index ab77a428..67bdf206 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -17,6 +17,8 @@ namespace SourceMod typedef unsigned int HandleType_t; typedef unsigned int Handle_t; + class SourcePawn::IPluginContext; + /** * About type checking: * Types can be inherited - a Parent type ("Supertype") can have child types. @@ -179,13 +181,13 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param ctx Plugin context that will own this handle. NULL for none. + * @param pOwner Plugin context that will own this handle. NULL for none. * @param ident Identity token if any security rights are needed. * @return A new Handle_t. */ virtual Handle_t CreateScriptHandle(HandleType_t type, void *object, - sp_context_t *ctx, + SourcePawn::IPluginContext *pOwner, IdentityToken_t *ident) =0; /** diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h index c59bc50e..94a00bb6 100644 --- a/core/interfaces/ILibrarySys.h +++ b/core/interfaces/ILibrarySys.h @@ -64,6 +64,12 @@ namespace SourceMod * @brief Returns whether the current entry is a file. */ virtual bool IsEntryFile() =0; + + /** + * @brief Returns true if the current entry is valid + * (Used similarly to MoreFiles). + */ + virtual bool IsEntryValid() =0; }; /** diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 3ea688f5..a88b4467 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -211,6 +211,10 @@ RelativePath="..\sm_trie.cpp" > + + diff --git a/core/sm_globals.h b/core/sm_globals.h index 87c45daf..226ef801 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -49,6 +49,7 @@ private: extern ISourcePawnEngine *g_pSourcePawn; extern IVirtualMachine *g_pVM; +extern IdentityToken_t *g_pCoreIdent; #include "sm_autonatives.h" diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp new file mode 100644 index 00000000..d43c2c15 --- /dev/null +++ b/core/smn_filesystem.cpp @@ -0,0 +1,114 @@ +#include "sm_globals.h" +#include "HandleSys.h" +#include "LibrarySys.h" + +HandleType_t g_FileType; +HandleType_t g_DirType; + +class FileNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + virtual void OnSourceModAllInitialized() + { + HandleSecurity sec; + sec.owner = g_pCoreIdent; + sec.access[HandleAccess_Inherit] = false; + sec.access[HandleAccess_Create] = false; + + g_FileType = g_HandleSys.CreateTypeEx("File", this, 0, &sec, NULL); + g_DirType = g_HandleSys.CreateTypeEx("Directory", this, 0, &sec, NULL); + } + virtual void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_DirType, g_pCoreIdent); + g_HandleSys.RemoveType(g_FileType, g_pCoreIdent); + g_DirType = 0; + g_FileType = 0; + } + virtual void OnHandleDestroy(HandleType_t type, void *object) + { + if (type == g_FileType) + { + FILE *fp = (FILE *)object; + fclose(fp); + } else if (type == g_DirType) { + IDirectory *pDir = (IDirectory *)object; + g_LibSys.CloseDirectory(pDir); + } + } +}; + + +cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) +{ + char *path; + int err; + if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + IDirectory *pDir = g_LibSys.OpenDirectory(path); + if (!pDir) + { + return 0; + } + + return g_HandleSys.CreateScriptHandle(g_DirType, pDir, pContext, g_pCoreIdent); +} + +cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + + IDirectory *pDir; + HandleError herr; + int err; + if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, g_pCoreIdent, (void **)&pDir)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + if (!pDir->MoreFiles()) + { + return false; + } + + cell_t *filetype; + if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if (pDir->IsEntryDirectory()) + { + *filetype = 1; + } else if (pDir->IsEntryFile()) { + *filetype = 2; + } else { + *filetype = 0; + } + + const char *path = pDir->GetEntryName(); + if ((err=pContext->StringToLocalUTF8(params[2], params[3],path, NULL)) + != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + return true; +} + + +REGISTER_NATIVES(filesystem) +{ + {"OpenDirectory", sm_OpenDirectory}, + {"ReadDirEntry", sm_ReadDirEntry}, + {NULL, NULL}, +}; diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index ca60e8c5..ad9324a8 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -69,4 +69,5 @@ REGISTER_NATIVES(handles) {"IsValidHandle", sm_IsValidHandle}, {"CloseHandle", sm_CloseHandle}, {"CloneHandle", sm_CloneHandle}, + {NULL, NULL}, }; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index a976b417..6a1d679d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -5,7 +5,7 @@ #include "vm/sp_vm_engine.h" #include #include "PluginSys.h" -#include "ForwardSys.h" +#include "ShareSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -16,6 +16,7 @@ ILibrary *g_pJIT = NULL; SourceHook::String g_BaseDir; ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; IVirtualMachine *g_pVM; +IdentityToken_t *g_pCoreIdent = NULL; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef unsigned int (*GETEXPORTCOUNT)(); @@ -139,6 +140,9 @@ void SourceModBase::StartSourceMod(bool late) pBase = pBase->m_pGlobalClassNext; } + /* Make the global core identity */ + g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); + /* Notify! */ pBase = SMGlobalClass::head; while (pBase) diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index b4ffa916..f2e1b2a8 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -302,10 +302,10 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, void *object, - sp_context_t *ctx, + IPluginContext *pContext, IdentityToken_t *ident) { - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); return CreateHandle(type, object, pPlugin->GetIdentity(), ident); } diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index ec88d6ca..36629e7c 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -90,7 +90,7 @@ public: //IHandleSystem void *object, IdentityToken_t *source, IdentityToken_t *ident); - Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t *ident); + Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, IdentityToken_t *ident); HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident); HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 669e950b..6fc467b1 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -93,6 +93,11 @@ void CDirectory::NextEntry() #endif } +bool CDirectory::IsEntryValid() +{ + return IsValid(); +} + bool CDirectory::IsEntryDirectory() { #if defined PLATFORM_WINDOWS diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index 83d6fcb9..9c89c0c6 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -23,6 +23,7 @@ public: virtual const char *GetEntryName(); virtual bool IsEntryDirectory(); virtual bool IsEntryFile(); + virtual bool IsEntryValid(); public: bool IsValid(); private: diff --git a/plugins/include/files.inc b/plugins/include/files.inc new file mode 100644 index 00000000..bd4ec8d3 --- /dev/null +++ b/plugins/include/files.inc @@ -0,0 +1,42 @@ +/** + * :TODO: license info + */ + +#if defined _files_included + #endinput +#endif +#define _files_included + +/* @note All paths in SourceMod natives are relative to the mod folder unless otherwise noted. */ + +enum FileType +{ + FileType_Unknown = 0, /* Unknown file type (device/socket) */ + FileType_Directory = 1, /* File is a directory */ + FileType_File = 2, /* File is a file */ +}; + + +/** + * @brief Opens a directory/folder for contents enumeration. + * @note Directories are closed with CloseHandle(). + * @note Directories Handles can be cloned. + * + * @param path Path to open. + * @return A Handle to the directory, INVALID_HANDLE on open error. + */ +native Handle:OpenDirectory(const String:path[]); + +/** + * @brief Reads the current directory entry as a local filename, then moves to the next file. + * @note Contents of buffers are undefined when returning false. + * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. + * + * @param dir Handle to a directory. + * @param buffer String buffer to hold directory name. + * @param maxlength Maximum size of string buffer. + * @param type Optional variable to store the file type. + * @return True on success, false if there are no more files to read. + * @error Invalid or corrupt Handle. + */ +native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=0); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index de440a2f..00d61855 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -16,6 +16,10 @@ struct Plugin const String:url[], /* Plugin URL */ }; +#include +#include +#include + /** * Declare this as a struct in your plugin to expose its information. * Example: From 473550130c03963d4329fbae5a95a0562286dc49 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 20:58:02 +0000 Subject: [PATCH 0228/1664] some more API calls fixed another bug in debug section --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40258 --- sourcepawn/include/sp_vm_api.h | 14 ++++++++++++++ sourcepawn/jit/x86/jit_x86.cpp | 29 +++++++++++++++++++++++++++-- sourcepawn/jit/x86/jit_x86.h | 2 ++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 93fedf57..b576d849 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -608,6 +608,20 @@ namespace SourcePawn * @return Number of functions. */ virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; + + /** + * @brief Returns a version string. + * + * @return Versioning string. + */ + virtual const char *GetVersionString() =0; + + /** + * @brief Returns a string describing optimizations. + * + * @return String describing CPU specific optimizations. + */ + virtual const char *GetCPUOptimizations() =0; }; }; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index fb71321c..346cacfb 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2119,8 +2119,23 @@ jit_rewind: { sym = (sp_fdbg_symbol_t *)cursor; - ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); - ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false); + /** + * @brief There is an "issue" where the compiler will give totally bogus code + * address because codegeneration is still being calculated. A simple fix for + * this is to coerce the codestart value to 0 when it's invalid. + */ + if (sym->codestart > data->codesize) + { + ctx->symbols[iter].codestart = 0; + } else { + ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); + } + if (sym->codeend > data->codesize) + { + ctx->symbols[iter].codeend = data->codesize; + } else { + ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false); + } ctx->symbols[iter].name = strbase + sym->name; ctx->symbols[iter].sym = sym; @@ -2261,3 +2276,13 @@ unsigned int JITX86::FunctionCount(const sp_context_t *ctx) return fnc->num_functions; } + +const char *JITX86::GetVersionString() +{ + return "1.0.0.0"; +} + +const char *JITX86::GetCPUOptimizations() +{ + return "Generic 80486"; +} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 05d3a2a8..fcdcbccf 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -81,6 +81,8 @@ public: unsigned int GetAPIVersion(); bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result); unsigned int FunctionCount(const sp_context_t *ctx); + const char *GetVersionString(); + const char *GetCPUOptimizations(); }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); From f072110a4463e3d409b282c605fb57323951eb78 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 21:18:35 +0000 Subject: [PATCH 0229/1664] temporarily disabled binary search code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40259 --- core/vm/sp_vm_basecontext.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 76b97240..d261292e 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -258,6 +258,7 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) high = ctx->plugin->info.natives_num - 1; low = 0; +#if 0 while (low <= high) { mid = (low + high) / 2; @@ -275,6 +276,19 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) high = mid - 1; } } +#else + for (uint32_t i=0; iplugin->info.natives_num; i++) + { + if (strcmp(ctx->natives[i].name, name) == 0) + { + if (index) + { + *index = i; + } + return SP_ERROR_NONE; + } + } +#endif return SP_ERROR_NOT_FOUND; } From 929957643f36f2731280570b034d261a47957b32 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 21:18:56 +0000 Subject: [PATCH 0230/1664] tested file natives and handle system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40260 --- core/smn_filesystem.cpp | 23 +++++++++++++++++++++-- core/smn_string.cpp | 2 ++ core/sourcemod.cpp | 5 +++++ core/sourcemod.h | 5 +++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index d43c2c15..773c340f 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -51,7 +51,10 @@ cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return 0; } - IDirectory *pDir = g_LibSys.OpenDirectory(path); + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), path); + + IDirectory *pDir = g_LibSys.OpenDirectory(realpath); if (!pDir) { return 0; @@ -95,20 +98,36 @@ cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) } const char *path = pDir->GetEntryName(); - if ((err=pContext->StringToLocalUTF8(params[2], params[3],path, NULL)) + if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL)) != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return 0; } + pDir->NextEntry(); + return true; } +cell_t PrintStuff(IPluginContext *pContext, const cell_t *params) +{ + char *stuff; + pContext->LocalToString(params[1], &stuff); + + FILE *fp = fopen("c:\\debug.txt", "at"); + fprintf(fp, "%s\n", stuff); + fclose(fp); + + return 0; +} + +static FileNatives s_FileNatives; REGISTER_NATIVES(filesystem) { {"OpenDirectory", sm_OpenDirectory}, {"ReadDirEntry", sm_ReadDirEntry}, + {"PrintStuff", PrintStuff}, {NULL, NULL}, }; diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 168ff923..d8b7436c 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -165,5 +165,7 @@ REGISTER_NATIVES(basicstrings) {"IntToString", sm_numtostr}, {"StringToFloat", sm_strtofloat}, {"FloatToString", sm_floattostr}, + {"Format", sm_format}, + {"FormatEx", sm_formatex}, {NULL, NULL}, }; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 6a1d679d..150b68d2 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -200,6 +200,11 @@ const char *SourceModBase::GetSMBaseDir() return m_SMBaseDir; } +const char *SourceModBase::GetBaseDir() +{ + return g_BaseDir.c_str(); +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index 0405cefd..1dcec7c3 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -37,6 +37,11 @@ public: */ const char *GetSMBaseDir(); + /** + * @brief Returns the base folder for file natives. + */ + const char *GetBaseDir(); + /** * @brief Returns whether our load in this map is late. */ From 5d23974a3ea152c3d9388922790d97498b648f44 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 1 Jan 2007 21:31:09 +0000 Subject: [PATCH 0231/1664] typo fix --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40261 --- sourcepawn/include/sp_vm_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index b576d849..16d5d1ee 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -397,7 +397,7 @@ namespace SourcePawn * @brief Retrieves the name of the last native called. * Returns NULL if there was no native that caused the error. * - * @param index Opterional pointer to store index. + * @param index Optional pointer to store index. * @return Native name, or NULL if none. */ virtual const char *GetLastNative(uint32_t *index) =0; From 2a7f0b985434b888d9ae17f8450fe2987685c1c2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 1 Jan 2007 21:46:33 +0000 Subject: [PATCH 0232/1664] more natives touchups/additions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40262 --- plugins/include/files.inc | 3 ++- plugins/include/sourcemod.inc | 13 +++++++------ plugins/include/string.inc | 22 ++++++++++++++++++++++ plugins/test.sma | 30 ++++++++++++++++-------------- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/plugins/include/files.inc b/plugins/include/files.inc index bd4ec8d3..1ad4fb99 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -16,6 +16,7 @@ enum FileType FileType_File = 2, /* File is a file */ }; +#define PLATFORM_MAX_PATH 256 /** * @brief Opens a directory/folder for contents enumeration. @@ -39,4 +40,4 @@ native Handle:OpenDirectory(const String:path[]); * @return True on success, false if there are no more files to read. * @error Invalid or corrupt Handle. */ -native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=0); +native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=FileType_Unknown); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 00d61855..a0d93225 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -19,6 +19,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -143,9 +144,9 @@ native GetClientCount(bool:inGameOnly=true); * @param client Player index. * @param name Buffer to store the client's name. * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @noreturn + * @return True on success, false otherwise. */ -native GetClientName(client, String:name[], maxlen); +native bool:GetClientName(client, String:name[], maxlen); /** * Retrieves a client's IP address. @@ -153,9 +154,9 @@ native GetClientName(client, String:name[], maxlen); * @param client Player index. * @param name Buffer to store the client's ip address. * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @noreturn + * @return True on success, false otherwise. */ -native GetClientIP(client, String:ip[], maxlen); +native bool:GetClientIP(client, String:ip[], maxlen); /** * Retrieves a client's authentication string (SteamID). @@ -163,9 +164,9 @@ native GetClientIP(client, String:ip[], maxlen); * @param client Player index. * @param auth Buffer to store the client's auth string. * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return Returns 0 on failure, non-zero otherwise. + * @return True on success, false otherwise. */ -native GetClientAuthString(client, String:auth[], maxlen); +native bool:GetClientAuthString(client, String:auth[], maxlen); /** * Returns if a certain player is connected. diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 7498a575..de4c72b5 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -74,6 +74,28 @@ stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive */ native StrCopy(String:dest[], destLen, const String:source[]); +/** + * Formats a string according to the SourceMod format rules (see documentation). + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); + +/** + * Formats a string according to the SourceMod format rules (see documentation). + * @note This is the same as Format(), except none of the input buffers can overlap the same + * memory as the output buffer. Since this security check is removed, it is slightly faster. + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); + /** * Converts a string to an integer. * diff --git a/plugins/test.sma b/plugins/test.sma index c3354368..8143007f 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -1,4 +1,5 @@ #include +#include public Plugin:myinfo = { @@ -7,22 +8,23 @@ public Plugin:myinfo = description = "Tests Stuff", version = "1.0.0.0", url = "http://www.sourcemod.net/" -} +}; -copy(String:dest[], maxlength, const String:source[]) -{ - new len - - while (source[len] != '\0' && len < maxlength) - { - dest[len] = source[len] - len++ - } - - dest[len] = '\0' -} +native PrintStuff(const String:buffer[]); public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) { - return true + new String:buffer[PLATFORM_MAX_PATH]; + new FileType:type; + + new Handle:dir = OpenDirectory("addons/stripper"); + while (ReadDirEntry(dir, buffer, sizeof(buffer), type)) + { + decl String:stuff[1024]; + Format(stuff, sizeof(stuff), "Type: %d Dir: %s", _:type, buffer) + PrintStuff(stuff); + } + CloseHandle(dir); + + return true; } From 0f711cd47912575ba304b1c0c0de69446f19fd48 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 1 Jan 2007 23:14:20 +0000 Subject: [PATCH 0233/1664] more comments --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40263 --- plugins/include/sourcemod.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index a0d93225..deef6f13 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -145,6 +145,7 @@ native GetClientCount(bool:inGameOnly=true); * @param name Buffer to store the client's name. * @param maxlen Maximum length of string buffer (includes NULL terminator). * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. */ native bool:GetClientName(client, String:name[], maxlen); @@ -155,6 +156,7 @@ native bool:GetClientName(client, String:name[], maxlen); * @param name Buffer to store the client's ip address. * @param maxlen Maximum length of string buffer (includes NULL terminator). * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. */ native bool:GetClientIP(client, String:ip[], maxlen); @@ -165,6 +167,7 @@ native bool:GetClientIP(client, String:ip[], maxlen); * @param auth Buffer to store the client's auth string. * @param maxlen Maximum length of string buffer (includes NULL terminator). * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. */ native bool:GetClientAuthString(client, String:auth[], maxlen); From 32a2aa75e310a3f0b9be7dbd841e21cb28677e4e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 2 Jan 2007 01:44:46 +0000 Subject: [PATCH 0234/1664] fixed various issues in the handle system with cloning fixed plugins being able to free each other's handles --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40264 --- core/interfaces/IHandleSys.h | 12 ++++--- core/smn_handles.cpp | 5 ++- core/systems/HandleSys.cpp | 61 ++++++++++++++++++++++++++---------- core/systems/HandleSys.h | 10 +++--- core/systems/PluginSys.cpp | 4 +-- core/systems/ShareSys.cpp | 4 +-- 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index 67bdf206..b0d71a38 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -42,13 +42,15 @@ namespace SourceMod HandleError_Access, /* No access permitted to free this handle */ HandleError_Limit, /* The limited number of handles has been reached */ HandleError_Identity, /* The identity token was not usable */ + HandleError_Owner, /* Owners do not match for this operation */ }; enum HandleAccessRight { HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */ HandleAccess_Read, /* HANDLES: Can be read by other objects */ - HandleAccess_Delete, /* HANDLES: Can be deleted by other objects */ + HandleAccess_IdentDelete, /* HANDLES: Can be deleted by other identities */ + HandleAccess_OwnerDelete, /* HANDLES: Can be deleted by other owners */ HandleAccess_Inherit, /* TYPE: Can be inherited by new types */ HandleAccess_Clone, /* HANDLES: Can be cloned */ /* ------------- */ @@ -62,9 +64,10 @@ namespace SourceMod owner = NULL; access[HandleAccess_Create] = true; access[HandleAccess_Read] = true; - access[HandleAccess_Delete] = true; + access[HandleAccess_IdentDelete] = true; access[HandleAccess_Inherit] = true; access[HandleAccess_Clone] = true; + access[HandleAccess_OwnerDelete] = false; } IdentityToken_t *owner; /* Owner of the handle */ bool access[HandleAccess_TOTAL]; /* World access rights */ @@ -166,7 +169,7 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param owner Owner for the handle. + * @param owner Owner for the handle. NULL means anonymous (no owner). * @param ident Identity token if any security rights are needed. * @return A new Handle_t, or 0 on failure. */ @@ -196,10 +199,11 @@ namespace SourceMod * only perform any further action if the counter hits 0. * * @param type Handle_t identifier to destroy. + * @param owner Owner of handle (NULL for none). * @param ident Identity token, for destroying secure handles (NULL for none). * @return A HandleError error code. */ - virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident) =0; + virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident) =0; /** * @brief Clones a handle by adding to its internal reference count. Its data, diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index ad9324a8..5f3e7b88 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -21,8 +21,11 @@ static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - HandleError err = g_HandleSys.FreeHandle(hndl, NULL); + /* :TODO: make this a little bit cleaner, eh? */ + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + HandleError err = g_HandleSys.FreeHandle(hndl, pPlugin->GetIdentity(), NULL); + if (err == HandleError_None) { return 1; diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index f2e1b2a8..90034a97 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -334,7 +334,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle, IdentityToken_t *ident, QHandle **in_pHandle, unsigned int *in_index, - HandleAccessRight access) + HandleAccessRight access, + bool ignoreFree) { unsigned int serial = (handle >> 16); unsigned int index = (handle & HANDLESYS_HANDLE_MASK); @@ -352,7 +353,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle, { return HandleError_Access; } - if (!pHandle->set) + if (!pHandle->set + || (pHandle->set == HandleSet_Freed && !ignoreFree)) { return HandleError_Freed; } else if (pHandle->set == HandleSet_Identity @@ -383,6 +385,12 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return err; } + /* Identities cannot be cloned */ + if (pHandle->set == HandleSet_Identity) + { + return HandleError_Identity; + } + QHandleType *pType = &m_Types[pHandle->type]; /* Get a new Handle ID */ @@ -395,7 +403,8 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return err; } - pNewHandle->clone = index; + pNewHandle->clone = handle; + pHandle->refcount++; if (out_newhandle) { @@ -405,41 +414,60 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return HandleError_None; } -HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *ident) +HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, IdentityToken_t *ident) { unsigned int index; QHandle *pHandle; HandleError err; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Delete)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_IdentDelete)) != HandleError_None) { return err; } QHandleType *pType = &m_Types[pHandle->type]; + if (pType->sec.access[HandleAccess_OwnerDelete] == false + && pHandle->owner + && pHandle->owner != pOwner) + { + return HandleError_Access; + } + bool dofree = false; if (pHandle->clone) { - /* If we're a clone, there's not a lot to do. */ - if (FreeHandle(pHandle->clone, ident) != HandleError_None) + /* If we're a clone, decrease the parent reference count */ + QHandle *pMaster; + unsigned int master; + + /* This call should not return an error, it'd be a corruption sign */ + err = GetHandle(pHandle->clone, ident, &pMaster, &master, HandleAccess_IdentDelete, true); + assert(err == HandleError_None); + + /* Release the clone now */ + ReleasePrimHandle(index); + + /* Decrement the master's reference count */ + if (--pMaster->refcount == 0) { - assert(false); + /* Type should be the same but do this anyway... */ + pType = &m_Types[pMaster->type]; + pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); + ReleasePrimHandle(master); } - dofree = true; } else { + /* Decrement, free if necessary */ if (--pHandle->refcount == 0) { - dofree = true; pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + ReleasePrimHandle(index); + } else { + /* We must be cloned, so mark ourselves as freed */ + pHandle->set = HandleSet_Freed; } } - if (dofree) - { - ReleasePrimHandle(index); - } - return HandleError_None; } @@ -477,7 +505,8 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, /* if we're a clone, the rules change - object is ONLY in our reference */ if (pHandle->clone) { - pHandle = &m_Handles[pHandle->clone]; + /* :TODO: optimize this */ + return ReadHandle(pHandle->clone, pHandle->type, ident, object); } *object = pHandle->object; } diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 36629e7c..5f23cdf1 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -36,8 +36,9 @@ enum HandleSet { HandleSet_None = 0, - HandleSet_Used, - HandleSet_Identity + HandleSet_Used, /* The Handle is in use */ + HandleSet_Freed, /* The "master" Handle of a clone chain is freed */ + HandleSet_Identity, /* The Handle is a special identity */ }; struct QHandle @@ -91,7 +92,7 @@ public: //IHandleSystem IdentityToken_t *source, IdentityToken_t *ident); Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, IdentityToken_t *ident); - HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident); + HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident); HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); bool TypeCheck(HandleType_t intype, HandleType_t outtype); @@ -103,7 +104,8 @@ protected: IdentityToken_t *ident, QHandle **pHandle, unsigned int *index, - HandleAccessRight access); + HandleAccessRight access, + bool ignoreFree=false); /** * Creates a basic handle and sets its reference count to 1. diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 03ece023..71d8f0d3 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -74,7 +74,7 @@ CPlugin::~CPlugin() if (m_handle) { - g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity()); + g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); g_ShareSys.DestroyIdentity(m_ident); } } @@ -1117,7 +1117,7 @@ void CPluginManager::OnSourceModAllInitialized() sec.owner = m_MyIdent; /* :TODO: implement ShareSys */ sec.access[HandleAccess_Create] = false; - sec.access[HandleAccess_Delete] = false; + sec.access[HandleAccess_IdentDelete] = false; sec.access[HandleAccess_Inherit] = false; sec.access[HandleAccess_Clone] = false; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 073a5e6b..049ca6a2 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -27,7 +27,7 @@ void ShareSystem::OnSourceModStartup(bool late) sec.owner = GetIdentRoot(); sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_Delete] = false; + sec.access[HandleAccess_IdentDelete] = false; m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL); m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL); @@ -184,7 +184,7 @@ void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *nati void ShareSystem::DestroyIdentity(IdentityToken_t *identity) { - g_HandleSys.FreeHandle(identity->ident, GetIdentRoot()); + g_HandleSys.FreeHandle(identity->ident, NULL, GetIdentRoot()); delete identity; } From 5c6bc80f20c9481c6b8131e84c4bbfc4ef066386 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 2 Jan 2007 02:40:32 +0000 Subject: [PATCH 0235/1664] Registered player and float natives. Added error strings to these natives. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40265 --- core/smn_float.cpp | 73 ++++++++++++++++++++++----------- core/smn_player.cpp | 82 +++++++++++++++++++++++++++----------- plugins/include/string.inc | 2 + 3 files changed, 110 insertions(+), 47 deletions(-) diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 875f0b4d..baadc443 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,12 +1,11 @@ #include #include +#include "sm_autonatives.h" #include "sp_vm_api.h" #include "sp_typeutil.h" using namespace SourcePawn; -//:TODO: these need to be registered.... - /**************************************** * * * FLOATING POINT NATIVE IMPLEMENTATIONS * @@ -21,7 +20,7 @@ static cell_t sm_float(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatabs(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatAbs(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = (val >= 0) ? val : -val; @@ -29,35 +28,35 @@ static cell_t sm_floatabs(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatadd(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatAdd(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]) + sp_ctof(params[2]); return sp_ftoc(val); } -static cell_t sm_floatsub(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatSub(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]) - sp_ctof(params[2]); return sp_ftoc(val); } -static cell_t sm_floatmul(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatMul(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]) * sp_ctof(params[2]); return sp_ftoc(val); } -static cell_t sm_floatdiv(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatDiv(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]) / sp_ctof(params[2]); return sp_ftoc(val); } -static cell_t sm_floatcmp(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatCompare(IPluginContext *pCtx, const cell_t *params) { float val1 = sp_ctof(params[1]); float val2 = sp_ctof(params[2]); @@ -72,14 +71,14 @@ static cell_t sm_floatcmp(IPluginContext *pCtx, const cell_t *params) return 0; } -static cell_t sm_floatlog(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Logarithm(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); float base = sp_ctof(params[2]); if ((val <= 0) || (base <= 0)) { - //:TODO: error out! logs cant take in negative numbers and log 0=-inf + return pCtx->ThrowNativeError("Cannot evaluate the logarithm of zero or a negative number (val:%f base:%f).", val, base); } if (base == 10.0) { @@ -91,14 +90,14 @@ static cell_t sm_floatlog(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatexp(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Exponential(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); return sp_ftoc(exp(val)); } -static cell_t sm_floatpower(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Pow(IPluginContext *pCtx, const cell_t *params) { float base = sp_ctof(params[1]); float exponent = sp_ctof(params[2]); @@ -106,19 +105,19 @@ static cell_t sm_floatpower(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(pow(base, exponent)); } -static cell_t sm_floatsqroot(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_SquareRoot(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); if (val < 0.0) { - //:TODO: error out! we dont support complex numbers + return pCtx->ThrowNativeError("Cannot evaluate the square root of a negative number (val:%f).", val); } return sp_ftoc(sqrt(val)); } -static cell_t sm_floatround(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatRound(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); @@ -154,7 +153,7 @@ static cell_t sm_floatround(IPluginContext *pCtx, const cell_t *params) return static_cast(val); } -static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatStr(IPluginContext *pCtx, const cell_t *params) { char *str; @@ -167,7 +166,7 @@ static cell_t sm_floatstr(IPluginContext *pCtx, const cell_t *params) return sp_ftoc((float)atof(str)); } -static cell_t sm_floatfract(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_FloatFraction(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = val - floor(val); @@ -175,7 +174,7 @@ static cell_t sm_floatfract(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Sine(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = sin(val); @@ -183,7 +182,7 @@ static cell_t sm_floatsin(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Cosine(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = cos(val); @@ -191,7 +190,7 @@ static cell_t sm_floatcos(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floattan(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_Tangent(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = tan(val); @@ -199,7 +198,7 @@ static cell_t sm_floattan(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatasin(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_ArcSine(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = asin(val); @@ -207,7 +206,7 @@ static cell_t sm_floatasin(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_ArcCosine(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = acos(val); @@ -215,7 +214,7 @@ static cell_t sm_floatacos(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_ArcTangent(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); val = atan(val); @@ -223,7 +222,7 @@ static cell_t sm_floatatan(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val); } -static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_ArcTangent2(IPluginContext *pCtx, const cell_t *params) { float val1 = sp_ctof(params[1]); float val2 = sp_ctof(params[2]); @@ -231,3 +230,29 @@ static cell_t sm_floatatan2(IPluginContext *pCtx, const cell_t *params) return sp_ftoc(val1); } + +REGISTER_NATIVES(floatnatives) +{ + {"float", sm_float}, + {"FloatStr", sm_FloatStr}, + {"FloatMul", sm_FloatMul}, + {"FloatDiv", sm_FloatDiv}, + {"FloatAdd", sm_FloatAdd}, + {"FloatSub", sm_FloatSub}, + {"FloatFraction", sm_FloatFraction}, + {"FloatRound", sm_FloatRound}, + {"FloatCompare", sm_FloatCompare}, + {"SquareRoot", sm_SquareRoot}, + {"Pow", sm_Pow}, + {"Exponential", sm_Exponential}, + {"Logarithm", sm_Logarithm}, + {"Sine", sm_Sine}, + {"Cosine", sm_Cosine}, + {"Tangent", sm_Tangent}, + {"FloatAbs", sm_FloatAbs}, + {"ArcTangent", sm_ArcTangent}, + {"ArcCosine", sm_ArcCosine}, + {"ArcSine", sm_ArcSine}, + {"ArcTangent2", sm_ArcTangent2}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/core/smn_player.cpp b/core/smn_player.cpp index d8c64dcb..441d0ec4 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1,8 +1,6 @@ #include "CPlayerManager.h" -//:TODO: register these and use the same capitalization conventions as the natives - -static cell_t sm_getclientcount(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) { if (params[1]) { @@ -23,87 +21,125 @@ static cell_t sm_getclientcount(IPluginContext *pCtx, const cell_t *params) return (g_PlayerManager.GetPlayerCount() + count); } -static cell_t sm_getmaxclients(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params) { return g_PlayerManager.GetMaxClients(); } -static cell_t sm_getclientname(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } - pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerName(), NULL); + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + if (!pPlayer->IsPlayerConnected()) + { + return pCtx->ThrowNativeError("Client %d is not connected.", index); + } + + pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), pPlayer->PlayerName(), NULL); return 1; } -static cell_t sm_getclientip(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } - pCtx->StringToLocal(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerIP()); + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + if (!pPlayer->IsPlayerConnected()) + { + return pCtx->ThrowNativeError("Client %d is not connected.", index); + } + + pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->PlayerIP()); return 1; } -static cell_t sm_getclientauthstr(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } - pCtx->StringToLocal(params[2], static_cast(params[3]), g_PlayerManager.GetPlayerByIndex(index)->PlayerAuthString()); + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + if (!pPlayer->IsPlayerConnected()) + { + return pCtx->ThrowNativeError("Client %d is not connected.", index); + } + + pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->PlayerAuthString()); return 1; } -static cell_t sm_isplayerconnected(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerConnected()) ? 1 : 0; } -static cell_t sm_isplayeringame(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerInGame()) ? 1 : 0; } -static cell_t sm_isplayerauthorized(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerAuthorized()) ? 1 : 0; } -static cell_t sm_isplayerfakeclient(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) { - //:TODO: runtime error + return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerFakeClient()) ? 1 : 0; -} \ No newline at end of file + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + if (!pPlayer->IsPlayerConnected()) + { + return pCtx->ThrowNativeError("Client %d is not connected.", index); + } + + return (pPlayer->IsPlayerFakeClient()) ? 1 : 0; +} + +REGISTER_NATIVES(playernatives) +{ + {"GetMaxClients", sm_GetMaxClients}, + {"GetClientCount", sm_GetClientCount}, + {"GetClientName", sm_GetClientName}, + {"GetClientIP", sm_GetClientIP}, + {"GetClientAuthString", sm_GetClientAuthStr}, + {"IsPlayerConnected", sm_IsPlayerConnected}, + {"IsPlayerInGame", sm_IsPlayerIngame}, + {"IsPlayerAuthorized", sm_IsPlayerAuthorized}, + {"IsPlayerFakeClient", sm_IsPlayerFakeClient}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/plugins/include/string.inc b/plugins/include/string.inc index de4c72b5..639dd8b7 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -81,6 +81,7 @@ native StrCopy(String:dest[], destLen, const String:source[]); * @param maxlength Maximum length of output string buffer. * @param format Formatting rules. * @param ... Variable number of format parameters. + * @return Number of cells written. */ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); @@ -93,6 +94,7 @@ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,S * @param maxlength Maximum length of output string buffer. * @param format Formatting rules. * @param ... Variable number of format parameters. + * @return Number of cells written. */ native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); From 15beb5afb0ea545ccdefad19bb9cf29fea79500c Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 2 Jan 2007 02:59:49 +0000 Subject: [PATCH 0236/1664] Added radix conversion stocks --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40266 --- plugins/include/float.inc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/include/float.inc b/plugins/include/float.inc index 9e222c2b..ca9588cf 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -297,4 +297,16 @@ stock bool:operator!(Float:oper) */ forward operator%(Float:oper1, Float:oper2); forward operator%(Float:oper1, oper2); -forward operator%(oper1, Float:oper2); \ No newline at end of file +forward operator%(oper1, Float:oper2); + +#define FLOAT_PI 3.1415926535897932384626433832795 + +stock Float:DegToRad(Float:angle) +{ + return (angle*FLOAT_PI)/180; +} + +stock Float:RadToDeg(Float:angle) +{ + return (angle*180)/FLOAT_PI; +} \ No newline at end of file From 4bd40d69e18b42035c8b5eaa9d472dfee9805a6f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 Jan 2007 02:08:27 +0000 Subject: [PATCH 0237/1664] restructure of HandleSys admin permissions and interface removal of HandleSys helper functions removed useless BaseContext stuff from Engine put SourceMod specific stuff in BaseContext cleaned up broken Handle code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40267 --- core/interfaces/IHandleSys.h | 181 +++++++++++---------- core/msvc8/sourcemod_mm.vcproj | 2 +- core/smn_filesystem.cpp | 19 ++- core/smn_handles.cpp | 7 +- core/systems/HandleSys.cpp | 278 +++++++++++++++++++++++---------- core/systems/HandleSys.h | 51 ++++-- core/systems/PluginSys.cpp | 34 ++-- core/systems/PluginSys.h | 3 +- core/systems/ShareSys.cpp | 37 +++-- core/vm/sp_vm_basecontext.cpp | 16 +- core/vm/sp_vm_basecontext.h | 7 + plugins/test.sma | 9 +- sourcepawn/include/sp_vm_api.h | 32 ++-- 13 files changed, 436 insertions(+), 240 deletions(-) diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index b0d71a38..6f105f1c 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -43,34 +43,72 @@ namespace SourceMod HandleError_Limit, /* The limited number of handles has been reached */ HandleError_Identity, /* The identity token was not usable */ HandleError_Owner, /* Owners do not match for this operation */ + HandleError_Version, /* Unrecognized security structure version */ + HandleError_Parameter, /* An invalid parameter was passed */ + HandleError_NoInherit, /* This type cannot be inherited */ }; + /** + * Access rights specific to a type + */ + enum HTypeAccessRight + { + HTypeAccess_Create = 0, /* Handles of this type can be created (DEFAULT=false) */ + HTypeAccess_Inherit, /* Sub-types can inherit this type (DEFAULT=false) */ + /* -------------- */ + HTypeAccess_TOTAL, /* Total number of type access rights */ + }; + + /** + * Access rights specific to a Handle. These rights are exclusive. + * For example, you do not need "read" access to delete or clone. + */ enum HandleAccessRight { - HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */ - HandleAccess_Read, /* HANDLES: Can be read by other objects */ - HandleAccess_IdentDelete, /* HANDLES: Can be deleted by other identities */ - HandleAccess_OwnerDelete, /* HANDLES: Can be deleted by other owners */ - HandleAccess_Inherit, /* TYPE: Can be inherited by new types */ - HandleAccess_Clone, /* HANDLES: Can be cloned */ + HandleAccess_Read, /* Can be read (DEFAULT=ident only) */ + HandleAccess_Delete, /* Can be deleted (DEFAULT=owner only) */ + HandleAccess_Clone, /* Can be cloned (DEFAULT=any) */ /* ------------- */ HandleAccess_TOTAL, /* Total number of access rights */ }; + #define HANDLE_RESTRICT_IDENTITY (1<<0) /* Access is restricted to the identity */ + #define HANDLE_RESTRICT_OWNER (1<<1) /* Access is restricted to the owner */ + + /** + * This is used to define per-type access rights. + */ + struct TypeAccess + { + TypeAccess() + { + hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; + } + unsigned int hsVersion; + IdentityToken_t *ident; + bool access[HTypeAccess_TOTAL]; + }; + + /** + * This is used to define per-Handle access rights. + */ + struct HandleAccess + { + HandleAccess() + { + hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; + } + unsigned int hsVersion; + unsigned int access[HandleAccess_TOTAL]; + }; + + /** + * This pair of tokens is used for identification. + */ struct HandleSecurity { - HandleSecurity() - { - owner = NULL; - access[HandleAccess_Create] = true; - access[HandleAccess_Read] = true; - access[HandleAccess_IdentDelete] = true; - access[HandleAccess_Inherit] = true; - access[HandleAccess_Clone] = true; - access[HandleAccess_OwnerDelete] = false; - } - IdentityToken_t *owner; /* Owner of the handle */ - bool access[HandleAccess_TOTAL]; /* World access rights */ + IdentityToken_t *pOwner; /* Owner of the Handle */ + IdentityToken_t *pIdentity; /* Owner of the Type */ }; class IHandleTypeDispatch @@ -99,17 +137,6 @@ namespace SourceMod return SMINTERFACE_HANDLESYSTEM_NAME; } public: - /** - * @brief Creates a new Handle type. - * NOTE: Handle names must be unique if not private. - * - * @param name Name of handle type (NULL or "" to be anonymous) - * @param dispatch Pointer to a valid IHandleTypeDispatch object. - * @return A new HandleType_t unique ID, or 0 on failure. - */ - virtual HandleType_t CreateType(const char *name, - IHandleTypeDispatch *dispatch) =0; - /** * @brief Creates a new Handle type. * NOTE: Currently, a child type may not have its own children. @@ -118,39 +145,30 @@ namespace SourceMod * @param name Name of handle type (NULL or "" to be anonymous) * @param dispatch Pointer to a valid IHandleTypeDispatch object. * @param parent Parent handle to inherit from, 0 for none. - * @param security Pointer to a temporary HandleSecurity object, NULL to use default - * or inherited permissions. - * @param ident Security token for any permissions. + * @param typeAccess Pointer to a TypeAccess object, NULL to use default + * or inherited permissions. Pointer can be temporary. + * @param hndlAccess Pointer to a HandleAccess object to define default + * default permissions on each Handle. NULL to use default + * permissions. + * @param ident Security token for any permissions. If typeAccess is NULL, this + * becomes the owning identity. + * @param err Optional pointer to store an error code. * @return A new HandleType_t unique ID, or 0 on failure. */ - virtual HandleType_t CreateTypeEx(const char *name, + virtual HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident) =0; - - - /** - * @brief Creates a sub-type for a Handle. - * NOTE: Currently, a child type may not have its own children. - * NOTE: Handle names must be unique if not private. - * NOTE: This is a wrapper around the above. - * - * @param name Name of a handle. - * @param parent Parent handle type. - * @param dispatch Pointer to a valid IHandleTypeDispatch object. - * @return A new HandleType_t unique ID. - */ - virtual HandleType_t CreateChildType(const char *name, - HandleType_t parent, - IHandleTypeDispatch *dispatch) =0; + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err) =0; /** * @brief Removes a handle type. * NOTE: This removes all child types. * - * @param token Identity token. Removal fails if the token does not match. * @param type Type chain to remove. + * @param ident Identity token. Removal fails if the token does not match. * @return True on success, false on failure. */ virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0; @@ -169,29 +187,16 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param owner Owner for the handle. NULL means anonymous (no owner). - * @param ident Identity token if any security rights are needed. + * @param owner Owner of the new Handle (may be NULL). + * @param ident Identity for type access if needed (may be NULL). + * @param err Optional pointer to store an error code. * @return A new Handle_t, or 0 on failure. */ virtual Handle_t CreateHandle(HandleType_t type, - void *object, - IdentityToken_t *owner, - IdentityToken_t *ident) =0; - - /** - * @brief Creates a new handle. - * NOTE: This is a wrapper around the above function. - * - * @param type Type to use on the handle. - * @param object Object to bind to the handle. - * @param pOwner Plugin context that will own this handle. NULL for none. - * @param ident Identity token if any security rights are needed. - * @return A new Handle_t. - */ - virtual Handle_t CreateScriptHandle(HandleType_t type, - void *object, - SourcePawn::IPluginContext *pOwner, - IdentityToken_t *ident) =0; + void *object, + IdentityToken_t *owner, + IdentityToken_t *ident, + HandleError *err) =0; /** * @brief Frees the memory associated with a handle and calls any destructors. @@ -199,34 +204,48 @@ namespace SourceMod * only perform any further action if the counter hits 0. * * @param type Handle_t identifier to destroy. - * @param owner Owner of handle (NULL for none). - * @param ident Identity token, for destroying secure handles (NULL for none). + * @param pSecurity Security information struct (may be NULL). * @return A HandleError error code. */ - virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident) =0; + virtual HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) =0; /** * @brief Clones a handle by adding to its internal reference count. Its data, * type, and security permissions remain the same. * * @param handle Handle to duplicate. Any non-free handle target is valid. - * @param newhandle If non-NULL, stores the duplicated handle in the pointer. - * @param owner New owner of cloned handle. - * @param ident Security token, if needed. + * @param newhandle Stores the duplicated handle in the pointer (must not be NULL). + * @param newOwner New owner of cloned handle. + * @param pSecurity Security information struct (may be NULL). * @return A HandleError error code. */ - virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *owner, IdentityToken_t *ident) =0; + virtual HandleError CloneHandle(Handle_t handle, + Handle_t *newhandle, + IdentityToken_t *newOwner, + const HandleSecurity *pSecurity) =0; /** * @brief Retrieves the contents of a handle. * * @param handle Handle_t from which to retrieve contents. * @param type Expected type to read as. 0 ignores typing rules. - * @param ident Identity token to validate as. + * @param pSecurity Security information struct (may be NULL). * @param object Optional address to store object in. * @return HandleError error code. */ - virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object) =0; + virtual HandleError ReadHandle(Handle_t handle, + HandleType_t type, + const HandleSecurity *pSecurity, + void **object) =0; + + /** + * @brief Sets access permissions on one or more structures. + * + * @param pTypeAccess Optional TypeAccess buffer to initialize with the default values. + * @param pHandleAccess Optional HandleAccess buffer to initialize with the default values. + * @return True on success, false if version is unsupported. + */ + virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a88b4467..ddef6937 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -41,7 +41,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 773c340f..75db63f2 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -12,13 +12,8 @@ class FileNatives : public: virtual void OnSourceModAllInitialized() { - HandleSecurity sec; - sec.owner = g_pCoreIdent; - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_Create] = false; - - g_FileType = g_HandleSys.CreateTypeEx("File", this, 0, &sec, NULL); - g_DirType = g_HandleSys.CreateTypeEx("Directory", this, 0, &sec, NULL); + g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL); } virtual void OnSourceModShutdown() { @@ -60,17 +55,21 @@ cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return 0; } - return g_HandleSys.CreateScriptHandle(g_DirType, pDir, pContext, g_pCoreIdent); + return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); } cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - IDirectory *pDir; HandleError herr; + HandleSecurity sec; int err; - if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, g_pCoreIdent, (void **)&pDir)) + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir)) != HandleError_None) { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 5f3e7b88..9d0105d9 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -24,7 +24,12 @@ static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params) /* :TODO: make this a little bit cleaner, eh? */ IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); - HandleError err = g_HandleSys.FreeHandle(hndl, pPlugin->GetIdentity(), NULL); + HandleSecurity sec; + + sec.pIdentity = NULL; + sec.pOwner = pContext->GetIdentity(); + + HandleError err = g_HandleSys.FreeHandle(hndl, &sec); if (err == HandleError_None) { diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 90034a97..4c25ca7b 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -14,7 +14,7 @@ inline HandleType_t TypeParent(HandleType_t type) inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index) { - return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index, HandleAccess_Read); + return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index); } HandleSystem::HandleSystem() @@ -39,24 +39,39 @@ HandleSystem::~HandleSystem() delete m_strtab; } -HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) -{ - return CreateTypeEx(name, dispatch, 0, NULL, NULL); -} -HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch) -{ - return CreateTypeEx(name, dispatch, parent, NULL, NULL); -} - -HandleType_t HandleSystem::CreateTypeEx(const char *name, - IHandleTypeDispatch *dispatch, - HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident) +HandleType_t HandleSystem::CreateType(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err) { if (!dispatch) { + if (err) + { + *err = HandleError_Parameter; + } + return 0; + } + + if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + if (err) + { + *err = HandleError_Version; + } + return 0; + } + + if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + if (err) + { + *err = HandleError_Version; + } return 0; } @@ -67,34 +82,44 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, isChild = true; if (parent & HANDLESYS_SUBTYPE_MASK) { + if (err) + { + *err = HandleError_NoInherit; + } return 0; } if (parent >= HANDLESYS_TYPEARRAY_SIZE - || m_Types[parent].dispatch == NULL - || (m_Types[parent].sec.access[HandleAccess_Inherit] == false - && m_Types[parent].sec.owner != ident)) + || m_Types[parent].dispatch == NULL) { + if (err) + { + *err = HandleError_Parameter; + } + return 0; + } + if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false + && (m_Types[parent].typeSec.ident != ident)) + { + if (err) + { + *err = HandleError_Access; + } return 0; } } - if (!security) + if (name && name[0] != '\0') { - if (isChild) + if (sm_trie_retrieve(m_TypeLookup, name, NULL)) { - security = &m_Types[parent].sec; - } else { - static HandleSecurity def_h; - security = &def_h; + if (err) + { + *err = HandleError_Parameter; + } + return 0; } } - if (security->access[HandleAccess_Create] - && sm_trie_retrieve(m_TypeLookup, name, NULL)) - { - return 0; - } - unsigned int index; if (isChild) @@ -102,6 +127,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, QHandleType *pParent = &m_Types[parent]; if (pParent->children >= HANDLESYS_MAX_SUBTYPES) { + if (err) + { + *err = HandleError_Limit; + } return 0; } index = 0; @@ -115,6 +144,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, } if (!index) { + if (err) + { + *err = HandleError_Limit; + } return 0; } pParent->children++; @@ -124,6 +157,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, /* Reserve another index */ if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE) { + if (err) + { + *err = HandleError_Limit; + } return 0; } else { m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1); @@ -145,9 +182,24 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, } else { pType->nameIdx = -1; } - pType->sec = *security; + pType->opened = 0; + if (typeAccess) + { + pType->typeSec = *typeAccess; + } else { + InitAccessDefaults(&pType->typeSec, NULL); + pType->typeSec.ident = ident; + } + + if (hndlAccess) + { + pType->hndlSec = *hndlAccess; + } else { + InitAccessDefaults(NULL, &pType->hndlSec); + } + if (!isChild) { pType->children = 0; @@ -264,33 +316,46 @@ void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pTok return; } - m_Types[type].sec.owner = pToken; + m_Types[type].typeSec.ident = pToken; } -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *source, IdentityToken_t *ident) +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) { if (!type || type >= HANDLESYS_TYPEARRAY_SIZE || m_Types[type].dispatch == NULL) { + if (err) + { + *err = HandleError_Parameter; + } return 0; } - /* Check the security of this handle */ + /* Check to see if we're allowed to create this handle type */ QHandleType *pType = &m_Types[type]; - if (!pType->sec.access[HandleAccess_Create] - && pType->sec.owner != ident) + if (!pType->typeSec.access[HTypeAccess_Create] + && (!pType->typeSec.ident + || pType->typeSec.ident != ident)) { + if (err) + { + *err = HandleError_Access; + } return 0; } unsigned int index; Handle_t handle; QHandle *pHandle; - HandleError err; + HandleError _err; - if ((err=MakePrimHandle(type, &pHandle, &index, &handle, source)) != HandleError_None) + if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner)) != HandleError_None) { + if (err) + { + *err = _err; + } return 0; } @@ -300,16 +365,6 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok return handle; } -Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, - void *object, - IPluginContext *pContext, - IdentityToken_t *ident) -{ - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); - - return CreateHandle(type, object, pPlugin->GetIdentity(), ident); -} - bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) { /* Check the type inheritance */ @@ -334,7 +389,6 @@ HandleError HandleSystem::GetHandle(Handle_t handle, IdentityToken_t *ident, QHandle **in_pHandle, unsigned int *in_index, - HandleAccessRight access, bool ignoreFree) { unsigned int serial = (handle >> 16); @@ -348,11 +402,6 @@ HandleError HandleSystem::GetHandle(Handle_t handle, QHandle *pHandle = &m_Handles[index]; QHandleType *pType = &m_Types[pHandle->type]; - if ((access != HandleAccess_TOTAL) - && (!pType->sec.access[access] && pType->sec.owner != ident)) - { - return HandleError_Access; - } if (!pHandle->set || (pHandle->set == HandleSet_Freed && !ignoreFree)) { @@ -374,13 +423,44 @@ HandleError HandleSystem::GetHandle(Handle_t handle, return HandleError_None; } -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t *source, IdentityToken_t *ident) +bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity) +{ + QHandleType *pType = &m_Types[pHandle->type]; + unsigned int access = pType->hndlSec.access[right]; + + /* Check if the type's identity matches */ + if (access & HANDLE_RESTRICT_IDENTITY) + { + IdentityToken_t *owner = pType->typeSec.ident; + if (!owner + || (!pSecurity || pSecurity->pIdentity != owner)) + { + return false; + } + } + + /* Check if the owner is allowed */ + if (access & HANDLE_RESTRICT_OWNER) + { + IdentityToken_t *owner = pHandle->owner; + if (owner + && (!pSecurity || pSecurity->pOwner != owner)) + { + return false; + } + } + + return true; +} + +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity) { HandleError err; QHandle *pHandle; unsigned int index; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Clone)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } @@ -391,49 +471,49 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return HandleError_Identity; } - QHandleType *pType = &m_Types[pHandle->type]; + /* Check if the handle can be cloned */ + if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity)) + { + return HandleError_Access; + } /* Get a new Handle ID */ unsigned int new_index; QHandle *pNewHandle; Handle_t new_handle; - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, source)) != HandleError_None) + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None) { return err; } - pNewHandle->clone = handle; + pNewHandle->clone = index; pHandle->refcount++; - if (out_newhandle) - { - *out_newhandle = new_handle; - } + *newhandle = new_handle; return HandleError_None; } -HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, IdentityToken_t *ident) +HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) { unsigned int index; QHandle *pHandle; HandleError err; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_IdentDelete)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } - QHandleType *pType = &m_Types[pHandle->type]; - - if (pType->sec.access[HandleAccess_OwnerDelete] == false - && pHandle->owner - && pHandle->owner != pOwner) + if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity)) { return HandleError_Access; } + QHandleType *pType = &m_Types[pHandle->type]; + bool dofree = false; if (pHandle->clone) { @@ -441,9 +521,10 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, I QHandle *pMaster; unsigned int master; - /* This call should not return an error, it'd be a corruption sign */ - err = GetHandle(pHandle->clone, ident, &pMaster, &master, HandleAccess_IdentDelete, true); - assert(err == HandleError_None); + /* Note that if we ever have per-handle security, we would need to re-check + * the access on this Handle. */ + master = pHandle->clone; + pMaster = &m_Handles[master]; /* Release the clone now */ ReleasePrimHandle(index); @@ -471,20 +552,23 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, I return HandleError_None; } -HandleError HandleSystem::ReadHandle(Handle_t handle, - HandleType_t type, - IdentityToken_t *ident, - void **object) +HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object) { unsigned int index; QHandle *pHandle; HandleError err; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Read)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } + if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity)) + { + return HandleError_Access; + } + /* Check the type inheritance */ if (pHandle->type & HANDLESYS_SUBTYPE_MASK) { @@ -505,8 +589,7 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, /* if we're a clone, the rules change - object is ONLY in our reference */ if (pHandle->clone) { - /* :TODO: optimize this */ - return ReadHandle(pHandle->clone, pHandle->type, ident, object); + pHandle = &m_Handles[pHandle->clone]; } *object = pHandle->object; } @@ -579,7 +662,8 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) QHandleType *pType = &m_Types[type]; - if (pType->sec.owner && pType->sec.owner != ident) + if (pType->typeSec.ident + && pType->typeSec.ident != ident) { return false; } @@ -598,7 +682,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) childType = &m_Types[type + i]; if (childType->dispatch) { - RemoveType(type + i, childType->sec.owner); + RemoveType(type + i, childType->typeSec.ident); } } /* Link us into the free chain */ @@ -658,10 +742,38 @@ void HandleSystem::MarkHandleAsIdentity(Handle_t handle) QHandle *pHandle; unsigned int index; - if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index, HandleAccess_Read) != HandleError_None) + if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index) != HandleError_None) { return; } pHandle->set = HandleSet_Identity; } + +bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) +{ + if (pTypeAccess) + { + if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + return false; + } + pTypeAccess->access[HTypeAccess_Create] = false; + pTypeAccess->access[HTypeAccess_Inherit] = false; + pTypeAccess->ident = NULL; + } + + if (pHandleAccess) + { + if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + return false; + } + + pHandleAccess->access[HandleAccess_Clone] = 0; + pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER; + pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY; + } + + return true; +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 5f23cdf1..55c65dc4 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -48,7 +48,7 @@ struct QHandle IdentityToken_t *owner; /* Identity of object which owns this */ unsigned int serial; /* Serial no. for sanity checking */ unsigned int refcount; /* Reference count for safe destruction */ - Handle_t clone; /* If non-zero, this is our cloned parent */ + unsigned int clone; /* If non-zero, this is our cloned parent index */ HandleSet set; /* Information about the handle's state */ /* The following variables are unrelated to the Handle array, and used * as an inlined chain of information */ @@ -64,7 +64,8 @@ struct QHandleType IHandleTypeDispatch *dispatch; unsigned int freeID; unsigned int children; - HandleSecurity sec; + TypeAccess typeSec; + HandleAccess hndlSec; unsigned int opened; int nameIdx; }; @@ -78,23 +79,38 @@ public: HandleSystem(); ~HandleSystem(); public: //IHandleSystem - HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch); - HandleType_t CreateTypeEx(const char *name, - IHandleTypeDispatch *dispatch, - HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident); - HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); + + HandleType_t CreateType(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err); + bool RemoveType(HandleType_t type, IdentityToken_t *ident); + bool FindHandleType(const char *name, HandleType_t *type); + Handle_t CreateHandle(HandleType_t type, - void *object, - IdentityToken_t *source, - IdentityToken_t *ident); - Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, IdentityToken_t *ident); - HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident); - HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); - HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); + void *object, + IdentityToken_t *owner, + IdentityToken_t *ident, + HandleError *err); + HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity); + + HandleError CloneHandle(Handle_t handle, + Handle_t *newhandle, + IdentityToken_t *newOwner, + const HandleSecurity *pSecurity); + + HandleError ReadHandle(Handle_t handle, + HandleType_t type, + const HandleSecurity *pSecurity, + void **object); + + bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess); + bool TypeCheck(HandleType_t intype, HandleType_t outtype); protected: /** @@ -104,7 +120,6 @@ protected: IdentityToken_t *ident, QHandle **pHandle, unsigned int *index, - HandleAccessRight access, bool ignoreFree=false); /** @@ -133,6 +148,8 @@ protected: * This prevents it from being tampered with by outside stuff */ void MarkHandleAsIdentity(Handle_t handle); + + bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 71d8f0d3..01a5db4a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -32,7 +32,7 @@ CPlugin::~CPlugin() { if (m_ctx.base) { - g_pSourcePawn->FreeBaseContext(m_ctx.base); + delete m_ctx.base; m_ctx.base = NULL; } if (m_ctx.ctx) @@ -74,7 +74,11 @@ CPlugin::~CPlugin() if (m_handle) { - g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); + HandleSecurity sec; + sec.pOwner = g_PluginSys.GetIdentity(); + sec.pIdentity = sec.pOwner; + + g_HandleSys.FreeHandle(m_handle, &sec); g_ShareSys.DestroyIdentity(m_ident); } } @@ -84,7 +88,8 @@ void CPlugin::InitIdentity() if (!m_handle) { m_ident = g_ShareSys.CreateIdentity(g_PluginIdent); - m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); + m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL); + m_ctx.base->SetIdentity(m_ident); } } @@ -188,7 +193,7 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) return false; } - m_ctx.base = g_pSourcePawn->CreateBaseContext(m_ctx.ctx); + m_ctx.base = new BaseContext(m_ctx.ctx); m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx); @@ -1113,15 +1118,13 @@ void CPluginManager::OnSourceModAllInitialized() { m_MyIdent = g_ShareSys.CreateCoreIdentity(); - HandleSecurity sec; + HandleAccess sec; + g_HandleSys.InitAccessDefaults(NULL, &sec); - sec.owner = m_MyIdent; /* :TODO: implement ShareSys */ - sec.access[HandleAccess_Create] = false; - sec.access[HandleAccess_IdentDelete] = false; - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_Clone] = false; - - g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec, NULL); + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY; + + g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL); g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); } @@ -1147,7 +1150,12 @@ IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) IPlugin *pPlugin; HandleError _err; - if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, m_MyIdent, (void **)&pPlugin)) != HandleError_None) + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = m_MyIdent; + + if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None) { pPlugin = NULL; } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 904cd127..4f682973 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -7,6 +7,7 @@ #include #include #include "sm_globals.h" +#include "vm/sp_vm_basecontext.h" #include "CFunction.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" @@ -67,7 +68,7 @@ struct ContextPair ContextPair() : base(NULL), ctx(NULL), co(NULL) { }; - IPluginContext *base; + BaseContext *base; sp_context_t *ctx; ICompilation *co; IVirtualMachine *vm; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 049ca6a2..784a69db 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -23,17 +23,16 @@ IdentityToken_t *ShareSystem::CreateCoreIdentity() void ShareSystem::OnSourceModStartup(bool late) { - HandleSecurity sec; + TypeAccess sec; - sec.owner = GetIdentRoot(); - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_IdentDelete] = false; - - m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL); - m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL); + g_HandleSys.InitAccessDefaults(&sec, NULL); + sec.ident = GetIdentRoot(); + + m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL); + m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL); /* Initialize our static identity handle */ - m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, NULL); + m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); } void ShareSystem::OnSourceModShutdown() @@ -69,7 +68,7 @@ IdentityType_t ShareSystem::CreateIdentType(const char *name) return 0; } - return g_HandleSys.CreateTypeEx(name, this, m_TypeRoot, NULL, GetIdentRoot()); + return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); } void ShareSystem::OnHandleDestroy(HandleType_t type, void *object) @@ -86,7 +85,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) /* :TODO: Cache? */ IdentityToken_t *pToken = new IdentityToken_t; - pToken->ident = g_HandleSys.CreateHandle(type, NULL, NULL, GetIdentRoot()); + pToken->ident = g_HandleSys.CreateHandle(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL); return pToken; } @@ -106,7 +105,7 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) if (token) { /* If we're an external object, we have to do this */ - info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot()); + info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot(), NULL); } else { info.handle = 0; } @@ -125,7 +124,12 @@ bool ShareSystem::RequestInterface(const char *iface_name, * HORRIBLE PERSON passed in a token that we don't recognize.... * Punish them. */ - if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, GetIdentRoot(), NULL)) + HandleSecurity sec; + + sec.pIdentity = GetIdentRoot(); + sec.pOwner = NULL; + + if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, &sec, NULL)) { return false; } @@ -162,7 +166,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, if (iface_owner) { Handle_t newhandle; - if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, GetIdentRoot()) + if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, &sec) != HandleError_None) { return false; @@ -184,7 +188,12 @@ void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *nati void ShareSystem::DestroyIdentity(IdentityToken_t *identity) { - g_HandleSys.FreeHandle(identity->ident, NULL, GetIdentRoot()); + HandleSecurity sec; + + sec.pOwner = GetIdentRoot(); + sec.pIdentity = GetIdentRoot(); + + g_HandleSys.FreeHandle(identity->ident, &sec); delete identity; } diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index d261292e..a1bf02f1 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -252,11 +252,9 @@ int BaseContext::HeapRelease(cell_t local_addr) int BaseContext::FindNativeByName(const char *name, uint32_t *index) { - int diff, high, low; - uint32_t mid; + int high; high = ctx->plugin->info.natives_num - 1; - low = 0; #if 0 while (low <= high) @@ -786,3 +784,15 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) return SP_ERROR_NONE; } + +#if defined SOURCEMOD_BUILD +SourceMod::IdentityToken_t *BaseContext::GetIdentity() +{ + return m_pToken; +} + +void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) +{ + m_pToken = token; +} +#endif diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 44f7e6af..5b495509 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -44,6 +44,10 @@ namespace SourcePawn virtual int Execute(funcid_t funcid, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); +#if defined SOURCEMOD_BUILD + virtual SourceMod::IdentityToken_t *GetIdentity(); + void SetIdentity(SourceMod::IdentityToken_t *token); +#endif public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); virtual int LookupFunction(ucell_t addr, const char **name); @@ -52,6 +56,9 @@ namespace SourcePawn void SetErrorMessage(const char *msg, va_list ap); private: sp_context_t *ctx; +#if defined SOURCEMOD_BUILD + SourceMod::IdentityToken_t *m_pToken; +#endif char m_MsgCache[1024]; bool m_CustomMsg; bool m_InExec; diff --git a/plugins/test.sma b/plugins/test.sma index 8143007f..30f93206 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -12,7 +12,7 @@ public Plugin:myinfo = native PrintStuff(const String:buffer[]); -public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) +DoItAll() { new String:buffer[PLATFORM_MAX_PATH]; new FileType:type; @@ -24,7 +24,14 @@ public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) Format(stuff, sizeof(stuff), "Type: %d Dir: %s", _:type, buffer) PrintStuff(stuff); } + new Handle:copy = CloneHandle(dir); + CloseHandle(copy); CloseHandle(dir); +} + +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) +{ + DoItAll(); return true; } diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 16d5d1ee..f1421743 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -6,6 +6,13 @@ #define SOURCEPAWN_VM_API_VERSION 1 +#if defined SOURCEMOD_BUILD +namespace SourceMod +{ + struct IdentityToken_t; +}; +#endif + namespace SourcePawn { class IVirtualMachine; @@ -331,6 +338,16 @@ namespace SourcePawn * @return 0 for convenience. */ virtual cell_t ThrowNativeError(const char *msg, ...) =0; + +#if defined SOURCEMOD_BUILD + /** + * @brief Returns the identity token for this context. + * Note: This is a helper function for native calls and the Handle System. + * + * @return Identity token. + */ + virtual SourceMod::IdentityToken_t *GetIdentity() =0; +#endif }; @@ -448,21 +465,6 @@ namespace SourcePawn */ virtual int FreeFromMemory(sp_plugin_t *plugin) =0; - /** - * @brief Creates a new IContext from a context handle. - * - * @param ctx Context to use as a basis for the IPluginContext. - * @return New IPluginContext handle. - */ - virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0; - - /** - * @brief Frees a base context. Does not free the sp_context_t it holds. - * - * @param ctx Context pointer to free. - */ - virtual void FreeBaseContext(IPluginContext *ctx) =0; - /** * @brief Allocates large blocks of temporary memory. * From 4508cea343704107c0efc397a6aaa288bfa6719e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 Jan 2007 20:43:28 +0000 Subject: [PATCH 0238/1664] fixed some doc problems --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40268 --- sourcepawn/include/sp_vm_api.h | 99 +++++++++++++++++----------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index f1421743..3a3e01a8 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -24,7 +24,7 @@ namespace SourcePawn { public: /** - * Given a code pointer, finds the file it is associated with. + * @brief Given a code pointer, finds the file it is associated with. * * @param addr Code address offset. * @param filename Pointer to store filename pointer in. @@ -32,7 +32,7 @@ namespace SourcePawn virtual int LookupFile(ucell_t addr, const char **filename) =0; /** - * Given a code pointer, finds the function it is associated with. + * @brief Given a code pointer, finds the function it is associated with. * * @param addr Code address offset. * @param name Pointer to store function name pointer in. @@ -40,7 +40,7 @@ namespace SourcePawn virtual int LookupFunction(ucell_t addr, const char **name) =0; /** - * Given a code pointer, finds the line it is associated with. + * @brief Given a code pointer, finds the line it is associated with. * * @param addr Code address offset. * @param line Pointer to store line number in. @@ -57,28 +57,28 @@ namespace SourcePawn virtual ~IPluginContext() { }; public: /** - * Returns the parent IVirtualMachine. + * @brief Returns the parent IVirtualMachine. * * @return Parent virtual machine pointer. */ virtual IVirtualMachine *GetVirtualMachine() =0; /** - * Returns the child sp_context_t structure. + * @brief Returns the child sp_context_t structure. * * @return Child sp_context_t structure. */ virtual sp_context_t *GetContext() =0; /** - * Returns true if the plugin is in debug mode. + * @brief Returns true if the plugin is in debug mode. * * @return True if in debug mode, false otherwise. */ virtual bool IsDebugging() =0; /** - * Installs a debug break and returns the old one, if any. + * @brief Installs a debug break and returns the old one, if any. * This will fail if the plugin is not debugging. * * @param newpfn New function pointer. @@ -87,24 +87,24 @@ namespace SourcePawn virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; /** - * Returns debug info. + * @brief Returns debug info. * * @return IPluginDebugInfo, or NULL if no debug info found. */ virtual IPluginDebugInfo *GetDebugInfo() =0; /** - * Allocs memory on the secondary stack of a plugin. + * @brief Allocs memory on the secondary stack of a plugin. * Note that although called a heap, it is in fact a stack. * * @param cells Number of cells to allocate. - * @param local_adddr Will be filled with data offset to heap. + * @param local_addr Will be filled with data offset to heap. * @param phys_addr Physical address to heap memory. */ virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; /** - * Pops a heap address off the heap stack. Use this to free memory allocated with + * @brief Pops a heap address off the heap stack. Use this to free memory allocated with * SP_HeapAlloc(). * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations * with this native should be performed in precisely the REVERSE order. @@ -114,7 +114,7 @@ namespace SourcePawn virtual int HeapPop(cell_t local_addr) =0; /** - * Releases a heap address using a different method than SP_HeapPop(). + * @brief Releases a heap address using a different method than SP_HeapPop(). * This allows you to release in any order. However, if you allocate N * objects, release only some of them, then begin allocating again, * you cannot go back and starting freeing the originals. @@ -127,7 +127,7 @@ namespace SourcePawn virtual int HeapRelease(cell_t local_addr) =0; /** - * Finds a native by name. + * @brief Finds a native by name. * * @param name Name of native. * @param index Optionally filled with native index number. @@ -135,7 +135,7 @@ namespace SourcePawn virtual int FindNativeByName(const char *name, uint32_t *index) =0; /** - * Gets native info by index. + * @brief Gets native info by index. * * @param index Index number of native. * @param native Optionally filled with pointer to native structure. @@ -143,14 +143,14 @@ namespace SourcePawn virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; /** - * Gets the number of natives. + * @brief Gets the number of natives. * * @return Filled with the number of natives. */ virtual uint32_t GetNativesNum() =0; /** - * Finds a public function by name. + * @brief Finds a public function by name. * * @param name Name of public * @param index Optionally filled with public index number. @@ -158,29 +158,30 @@ namespace SourcePawn virtual int FindPublicByName(const char *name, uint32_t *index) =0; /** - * Gets public function info by index. + * @brief Gets public function info by index. * * @param index Public function index number. - * @param public Optionally filled with pointer to public structure. + * @param publicptr Optionally filled with pointer to public structure. */ virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; /** - * Gets the number of public functions. + * @brief Gets the number of public functions. * * @return Filled with the number of public functions. */ virtual uint32_t GetPublicsNum() =0; /** - * Gets public variable info by index. + * @brief Gets public variable info by index. + * * @param index Public variable index number. * @param pubvar Optionally filled with pointer to pubvar structure. */ virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; /** - * Finds a public variable by name. + * @brief Finds a public variable by name. * * @param name Name of pubvar * @param index Optionally filled with pubvar index number. @@ -188,23 +189,23 @@ namespace SourcePawn virtual int FindPubvarByName(const char *name, uint32_t *index) =0; /** - * Gets the addresses of a public variable. - * - * @param index Index of public variable. - * @param local_addr Address to store local address in. - * @param phys_addr Address to store physically relocated in. - */ + * @brief Gets the addresses of a public variable. + * + * @param index Index of public variable. + * @param local_addr Address to store local address in. + * @param phys_addr Address to store physically relocated in. + */ virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; /** - * Returns the number of public variables. + * @brief Returns the number of public variables. * * @return Number of public variables. */ virtual uint32_t GetPubVarsNum() =0; /** - * Round-about method of converting a plugin reference to a physical address + * @brief Round-about method of converting a plugin reference to a physical address * * @param local_addr Local address in plugin. * @param phys_addr Optionally filled with relocated physical address. @@ -212,7 +213,7 @@ namespace SourcePawn virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; /** - * Converts a local address to a physical string. + * @brief Converts a local address to a physical string. * * @param local_addr Local address in plugin. * @param addr Destination output pointer. @@ -220,7 +221,7 @@ namespace SourcePawn virtual int LocalToString(cell_t local_addr, char **addr) =0; /** - * Converts a physical string to a local address. + * @brief Converts a physical string to a local address. * * @param local_addr Local address in plugin. * @param bytes Number of chars to write, including NULL terminator. @@ -229,29 +230,29 @@ namespace SourcePawn virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; /** - * Converts a physical UTF-8 string to a local address. - * This function is the same as the ANSI version, except it will copy the maximum number of characters possible - * without accidentally chopping a multi-byte character. - * - * @param local_addr Local address in plugin. - * @param maxbytes Number of bytes to write, including NULL terminator. - * @param source Source string to copy. - * @param wrtnbytes Optionally set to the number of actual bytes written. - */ + * @brief Converts a physical UTF-8 string to a local address. + * This function is the same as the ANSI version, except it will copy the maximum number of characters possible + * without accidentally chopping a multi-byte character. + * + * @param local_addr Local address in plugin. + * @param maxbytes Number of bytes to write, including NULL terminator. + * @param source Source string to copy. + * @param wrtnbytes Optionally set to the number of actual bytes written. + */ virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) =0; /** - * Pushes a cell onto the stack. Increases the parameter count by one. + * @brief Pushes a cell onto the stack. Increases the parameter count by one. * * @param value Cell value. */ virtual int PushCell(cell_t value) =0; /** - * Pushes an array of cells onto the stack. Increases the parameter count by one. + * @brief Pushes an array of cells onto the stack. Increases the parameter count by one. * If the function returns an error it will fail entirely, releasing anything allocated in the process. * Note that this does not release the heap, so you should release it after * calling Execute(). @@ -264,7 +265,7 @@ namespace SourcePawn virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; /** - * Pushes a string onto the stack (by reference) and increases the parameter count by one. + * @brief Pushes a string onto the stack (by reference) and increases the parameter count by one. * Note that this does not release the heap, so you should release it after * calling Execute(). * @@ -275,7 +276,7 @@ namespace SourcePawn virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; /** - * Individually pushes each cell of an array of cells onto the stack. Increases the + * @brief Individually pushes each cell of an array of cells onto the stack. Increases the * parameter count by the number of cells pushed. * If the function returns an error it will fail entirely, releasing anything allocated in the process. * @@ -285,7 +286,7 @@ namespace SourcePawn virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; /** - * Binds a list of native names and their function pointers to a context. + * @brief Binds a list of native names and their function pointers to a context. * If num is 0, the list is read until an entry with a NULL name is reached. * If overwrite is non-zero, already registered natives will be overwritten. * @@ -296,7 +297,7 @@ namespace SourcePawn virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; /** - * Binds a single native. Overwrites any existing bind. + * @brief Binds a single native. Overwrites any existing bind. * If the context does not contain the native that will be binded the function will return * with a SP_ERROR_NOT_FOUND error. * @@ -305,14 +306,14 @@ namespace SourcePawn virtual int BindNative(sp_nativeinfo_t *native) =0; /** - * Binds a single native to any non-registered native. + * @brief Binds a single native to any non-registered native. * * @param native Native to bind. */ virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; /** - * Executes a function ID located in this context. + * @brief Executes a function ID located in this context. * * @param funcid Function id to execute. * @param result Pointer to store the return value (required). @@ -504,7 +505,7 @@ namespace SourcePawn * @param listener Pointer to an IDebugListener. * @return Old IDebugListener, or NULL if none. */ - virtual IDebugListener *SetDebugListener(IDebugListener *pListener) =0; + virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0; /** * @brief Returns the number of plugins on the call stack. From 7bbe099cea4e003c72efbcdcdc15d95731812dcc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 Jan 2007 23:30:54 +0000 Subject: [PATCH 0239/1664] fixed a bug causing mapchanges to crash --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40269 --- core/systems/PluginInfoDatabase.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index 5b7d1ac6..3783bf4b 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -45,6 +45,9 @@ void CPluginInfoDatabase::ReadSMC_ParseStart() in_plugins = false; cur_plugin = -1; in_options = false; + m_infodb_size = 0; + m_infodb_count = 0; + m_infodb = -1; } SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...) From ab004f5ce584982c8933f51a116678b608aee0bc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 Jan 2007 23:32:46 +0000 Subject: [PATCH 0240/1664] cleaned up some handle code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40270 --- core/smn_handles.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 9d0105d9..d7e5f1a1 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -20,10 +20,6 @@ static cell_t sm_IsValidHandle(IPluginContext *pContext, const cell_t *params) static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - - /* :TODO: make this a little bit cleaner, eh? */ - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); - HandleSecurity sec; sec.pIdentity = NULL; @@ -45,22 +41,23 @@ static cell_t sm_CloneHandle(IPluginContext *pContext, const cell_t *params) { Handle_t new_hndl; Handle_t hndl = static_cast(params[1]); - IPlugin *pPlugin; HandleError err; + IdentityToken_t *pNewOwner; if (params[2] == 0) { - pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + pNewOwner = pContext->GetIdentity(); } else { Handle_t hPlugin = static_cast(params[2]); - pPlugin = g_PluginSys.PluginFromHandle(hPlugin, &err); + IPlugin *pPlugin = g_PluginSys.PluginFromHandle(hPlugin, &err); if (!pPlugin) { return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err); } + pNewOwner = pPlugin->GetIdentity(); } - err = g_HandleSys.CloneHandle(hndl, &new_hndl, pPlugin->GetIdentity(), NULL); + err = g_HandleSys.CloneHandle(hndl, &new_hndl, pNewOwner, NULL); if (err == HandleError_Access) { From 6a0ddf78d4e00e9d83b2c11a00de600b5e853793 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 4 Jan 2007 23:41:51 +0000 Subject: [PATCH 0241/1664] Initial import of the logger --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40271 --- core/CLogger.cpp | 287 +++++++++++++++++++++++++++++++++++++++++++++++ core/CLogger.h | 101 +++++++++++++++++ 2 files changed, 388 insertions(+) create mode 100644 core/CLogger.cpp create mode 100644 core/CLogger.h diff --git a/core/CLogger.cpp b/core/CLogger.cpp new file mode 100644 index 00000000..d7c9d2f1 --- /dev/null +++ b/core/CLogger.cpp @@ -0,0 +1,287 @@ +#include "CLogger.h" +#include "systems/Librarysys.h" + +CLogger g_Logger; + +void CLogger::_NewMapFile() +{ + if (!m_Active) + { + return; + } + + char _filename[256]; + int i = 0; + + time_t t; + time(&t); + tm *curtime = localtime(&t); + + while (true) + { + g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d%03d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, i); + FILE *fp = fopen(_filename, "r"); + if (!fp) + { + break; + } + fclose(fp); + i++; + } + m_NrmFileName.assign(_filename); + + FILE *fp = fopen(m_NrmFileName.c_str(), "w"); + if (!fp) + { + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + m_Active = false; + } else { + char date[32]; + strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); + fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); + fprintf(fp, "L %s: Info (map \"%s\")\n", date, m_CurMapName.c_str()); + fclose(fp); + } +} + +void CLogger::_CloseFile() +{ + if (!m_Active) + { + return; + } + + FILE *fp = NULL; + if (!m_NrmFileName.empty()) + { + fp = fopen(m_NrmFileName.c_str(), "r+"); + if (fp) + { + fseek(fp, 0, SEEK_END); + LogMessage("Log file closed."); + fclose(fp); + } + m_NrmFileName.clear(); + } + + if (!m_ErrMapStart) + { + return; + } + fp = fopen(m_ErrFileName.c_str(), "r+"); + if (fp) + { + fseek(fp, 0, SEEK_END); + LogMessageEx(LogType_Error, "Error log file session closed."); + fclose(fp); + } + m_ErrFileName.clear(); +} + +void CLogger::InitLogger(LoggingMode mode, bool startlogging) +{ + m_mode = mode; + m_Active = startlogging; + + time_t t; + time(&t); + tm *curtime = localtime(&t); + m_CurDay = curtime->tm_mday; + + char _filename[256]; + g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/errors_%02d%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + m_ErrFileName.assign(_filename); + + switch (m_mode) + { + case LoggingMode_PerMap: + { + if (!startlogging) + { + m_DelayedStart = true; + } + break; + } + case LoggingMode_Daily: + { + g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday); + m_NrmFileName.assign(_filename); + m_DailyPrintHdr = true; + break; + } + } +} + +void CLogger::CloseLogger() +{ + _CloseFile(); +} + +void CLogger::LogMessage(const char *vafmt, ...) +{ + if (!m_Active) + { + return; + } + + if (m_mode == LoggingMode_HL2) + { + _PrintToHL2Log(vafmt); + return; + } + + if (m_DelayedStart) + { + m_DelayedStart = false; + _NewMapFile(); + } + + static char msg[3072]; + va_list ap; + va_start(ap, vafmt); + vsnprintf(msg, sizeof(msg), vafmt, ap); + va_end(ap); + + char date[32]; + time_t t; + time(&t); + tm *curtime = localtime(&t); + strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); + + FILE *fp = NULL; + if (m_mode == LoggingMode_PerMap) + { + fp = fopen(m_NrmFileName.c_str(), "a+"); + if (!fp) + { + _NewMapFile(); + fp = fopen(m_NrmFileName.c_str(), "a+"); + if (!fp) + { + goto print_error; + } + } + } else { + if (m_CurDay != curtime->tm_mday) + { + char _filename[256]; + g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday); + m_NrmFileName.assign(_filename); + m_CurDay = curtime->tm_mday; + m_DailyPrintHdr = true; + } + fp = fopen(m_NrmFileName.c_str(), "a+"); + } + + if (fp) + { + if (m_DailyPrintHdr) + { + m_DailyPrintHdr = false; + fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); + } + fprintf(fp, "L %s: %s\n", date, msg); + fclose(fp); + } else { + goto print_error; + } + + g_SMAPI->ConPrintf("L %s: %s\n", date, msg); +print_error: + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + m_Active = false; +} + +void CLogger::LogMessageEx(LogType type, const char *vafmt, ...) +{ + if (!m_Active) + { + return; + } + + if (type == LogType_Normal) + { + LogMessage(vafmt); + return; + } + + time_t t; + time(&t); + tm *curtime = localtime(&t); + + char date[32]; + strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); + + if (curtime->tm_mday != m_CurDay) + { + char _filename[256]; + g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/errors_%02d%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + m_ErrFileName.assign(_filename); + m_CurDay = curtime->tm_mday; + m_ErrMapStart = false; + } + + static char msg[3072]; + va_list ap; + va_start(ap, vafmt); + vsnprintf(msg, sizeof(msg), vafmt, ap); + va_end(ap); + + FILE *fp = fopen(m_ErrFileName.c_str(), "a+"); + if (fp) + { + if (!m_ErrMapStart) + { + fprintf(fp, "L %s: SourceMod error session started\n", date); + fprintf(fp, "L %s: Info (map \"%s\") (log file \"errors_%02d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + m_ErrMapStart = true; + } + fprintf(fp, "L %s: %s\n", date, msg); + fclose(fp); + } else { + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + m_Active = false; + } + + g_SMAPI->ConPrintf("L %s: %s\n", date, msg); +} + +void CLogger::MapChange(const char *mapname) +{ + m_CurMapName.assign(mapname); + + switch (m_mode) + { + case LoggingMode_Daily: + { + LogMessage("-------- Mapchange to %s --------", mapname); + break; + } + case LoggingMode_PerMap: + { + _NewMapFile(); + break; + } + } + + if (m_ErrMapStart) + { + LogMessageEx(LogType_Error, "Error log file session closed."); + } + m_ErrMapStart = false; +} + +void CLogger::_PrintToHL2Log(const char *fmt, ...) +{ + static char msg[3072]; + size_t len; + + va_list ap; + va_start(ap, fmt); + len = vsnprintf(msg, sizeof(msg)-1, fmt, ap); + msg[len++] = '\n'; + msg[len] = '\0'; + va_end(ap); + + engine->LogPrint(msg); +} \ No newline at end of file diff --git a/core/CLogger.h b/core/CLogger.h new file mode 100644 index 00000000..3c23cfc9 --- /dev/null +++ b/core/CLogger.h @@ -0,0 +1,101 @@ +#ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_ +#define _INCLUDE_SOURCEMOD_CLOGGER_H_ + +#include +#include "sourcemm_api.h" +#include +#include "sourcemod.h" +#include "sm_version.h" + +using namespace SourceHook; + +enum LogType +{ + LogType_Normal, + LogType_Error +}; + +enum LoggingMode +{ + LoggingMode_Daily, + LoggingMode_PerMap, + LoggingMode_HL2 +}; + +class CLogger +{ +public: + CLogger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} +public: + void InitLogger(LoggingMode mode, bool startlogging); + void CloseLogger(); + void EnableLogging(); + void DisableLogging(); + void LogMessage(const char *msg, ...); + void LogMessageEx(LogType type, const char *msg, ...); + void MapChange(const char *mapname); + const char *GetLogFileName(LogType type); + LoggingMode GetLoggingMode(); +private: + void _CloseFile(); + void _NewMapFile(); + void _PrintToHL2Log(const char *fmt, ...); +private: + String m_NrmFileName; + String m_ErrFileName; + String m_CurMapName; + LoggingMode m_mode; + int m_CurDay; + bool m_ErrMapStart; + bool m_Active; + bool m_DelayedStart; + bool m_DailyPrintHdr; +}; + +extern CLogger g_Logger; + +inline const char *CLogger::GetLogFileName(LogType type) +{ + switch (type) + { + case LogType_Normal: + { + return m_NrmFileName.c_str(); + } + case LogType_Error: + { + return m_ErrFileName.c_str(); + } + default: + { + return ""; + } + } +} + +inline LoggingMode CLogger::GetLoggingMode() +{ + return m_mode; +} + +inline void CLogger::EnableLogging() +{ + if (m_Active) + { + return; + } + m_Active = true; + LogMessage("Logging enabled manually by user."); +} + +inline void CLogger::DisableLogging() +{ + if (!m_Active) + { + return; + } + LogMessage("Logging disabled manually by user."); + m_Active = false; +} + +#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_ \ No newline at end of file From 35896b6eb37e9ce61618836547b2c4dfce3f0c9c Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 4 Jan 2007 23:43:01 +0000 Subject: [PATCH 0242/1664] forgot this --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40272 --- core/msvc8/sourcemod_mm.vcproj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index ddef6937..db34d866 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -245,6 +249,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + From d899b7a32a7d6808cb9a37fe79bc09d19b8dff4f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 5 Jan 2007 00:42:22 +0000 Subject: [PATCH 0243/1664] Fixed CPlayer init, it was called too early. nothing important on the logger --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40273 --- core/CLogger.cpp | 7 ++++++- core/CLogger.h | 3 ++- core/CPlayerManager.cpp | 16 +++++++++++----- core/CPlayerManager.h | 2 ++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index d7c9d2f1..8fe96454 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -39,7 +39,11 @@ void CLogger::_NewMapFile() char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); - fprintf(fp, "L %s: Info (map \"%s\")\n", date, m_CurMapName.c_str()); + if (m_PrntMapname) + { + fprintf(fp, "L %s: Info (map \"%s\")\n", date, m_CurMapName.c_str()); + m_PrntMapname = false; + } fclose(fp); } } @@ -249,6 +253,7 @@ void CLogger::LogMessageEx(LogType type, const char *vafmt, ...) void CLogger::MapChange(const char *mapname) { m_CurMapName.assign(mapname); + m_PrntMapname = true; switch (m_mode) { diff --git a/core/CLogger.h b/core/CLogger.h index 3c23cfc9..ce587819 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -25,7 +25,7 @@ enum LoggingMode class CLogger { public: - CLogger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} + CLogger() : m_PrntMapname(false), m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} public: void InitLogger(LoggingMode mode, bool startlogging); void CloseLogger(); @@ -46,6 +46,7 @@ private: String m_CurMapName; LoggingMode m_mode; int m_CurDay; + bool m_PrntMapname; bool m_ErrMapStart; bool m_Active; bool m_DelayedStart; diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 2158648f..ea30b8c0 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -8,6 +8,7 @@ SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_ SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *); +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int); void CPlayerManager::OnSourceModAllInitialized() { @@ -17,6 +18,7 @@ void CPlayerManager::OnSourceModAllInitialized() SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true); /* Register OnClientConnect */ ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; @@ -40,11 +42,6 @@ void CPlayerManager::OnSourceModAllInitialized() /* Register OnClientAuthorized */ //:TODO: - - /* Initialize all players */ - m_maxClients = g_SMAPI->pGlobals()->maxClients; - m_PlayerCount = 0; - m_Players = new CPlayer[m_maxClients]; } void CPlayerManager::OnSourceModShutdown() @@ -55,6 +52,7 @@ void CPlayerManager::OnSourceModShutdown() SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true); /* Release forwards */ g_Forwards.ReleaseForward(m_clconnect); @@ -67,6 +65,14 @@ void CPlayerManager::OnSourceModShutdown() delete [] m_Players; } +void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +{ + /* Initialize all players */ + m_maxClients = clientMax; + m_PlayerCount = 0; + m_Players = new CPlayer[m_maxClients + 1]; +} + bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { cell_t res = 1; diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index ed482517..a3fd1630 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -26,6 +26,8 @@ public: void OnClientAuthorized(); //:TODO: any args needed? void OnClientCommand(edict_t *pEntity); void OnClientSettingsChanged(edict_t *pEntity); +private: + void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); private: IForward *m_clconnect; IForward *m_cldisconnect; From c4d8d30a39ff7b973c31fed532754f7c843c2673 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 5 Jan 2007 00:58:28 +0000 Subject: [PATCH 0244/1664] whoa this caused a memory LEEK --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40274 --- core/CPlayerManager.cpp | 12 ++++++++---- core/CPlayerManager.h | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index ea30b8c0..02952b24 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -67,10 +67,14 @@ void CPlayerManager::OnSourceModShutdown() void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { - /* Initialize all players */ - m_maxClients = clientMax; - m_PlayerCount = 0; - m_Players = new CPlayer[m_maxClients + 1]; + if (m_FirstPass) + { + /* Initialize all players */ + m_maxClients = clientMax; + m_PlayerCount = 0; + m_Players = new CPlayer[m_maxClients + 1]; + m_FirstPass = false; + } } bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index a3fd1630..042476bf 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -11,6 +11,8 @@ class CPlayer; class CPlayerManager : public SMGlobalClass { +public: + CPlayerManager() : m_FirstPass(true) {} public: //SMGlobalClass virtual void OnSourceModAllInitialized(); virtual void OnSourceModShutdown(); @@ -38,6 +40,7 @@ private: CPlayer *m_Players; int m_maxClients; int m_PlayerCount; + bool m_FirstPass; }; extern CPlayerManager g_PlayerManager; From ac50163647b630b3f98959b72dcfda39e99c06d5 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 5 Jan 2007 13:23:25 +0000 Subject: [PATCH 0245/1664] added console cmd list --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40275 --- core/CLogger.cpp | 9 ++------- core/CLogger.h | 3 +-- core/sm_srvcmds.cpp | 21 +++++++++++++++++++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 8fe96454..ea622002 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -39,11 +39,6 @@ void CLogger::_NewMapFile() char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); - if (m_PrntMapname) - { - fprintf(fp, "L %s: Info (map \"%s\")\n", date, m_CurMapName.c_str()); - m_PrntMapname = false; - } fclose(fp); } } @@ -182,7 +177,7 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_DailyPrintHdr) { m_DailyPrintHdr = false; - fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); + fprintf(fp, "L %s: SourceMod log file session started (file \"L%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); } fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); @@ -191,6 +186,7 @@ void CLogger::LogMessage(const char *vafmt, ...) } g_SMAPI->ConPrintf("L %s: %s\n", date, msg); + return; print_error: g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; @@ -253,7 +249,6 @@ void CLogger::LogMessageEx(LogType type, const char *vafmt, ...) void CLogger::MapChange(const char *mapname) { m_CurMapName.assign(mapname); - m_PrntMapname = true; switch (m_mode) { diff --git a/core/CLogger.h b/core/CLogger.h index ce587819..3c23cfc9 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -25,7 +25,7 @@ enum LoggingMode class CLogger { public: - CLogger() : m_PrntMapname(false), m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} + CLogger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} public: void InitLogger(LoggingMode mode, bool startlogging); void CloseLogger(); @@ -46,7 +46,6 @@ private: String m_CurMapName; LoggingMode m_mode; int m_CurDay; - bool m_PrntMapname; bool m_ErrMapStart; bool m_Active; bool m_DelayedStart; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 6d8f8ed0..e0ccd463 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -1,4 +1,5 @@ #include "sm_srvcmds.h" +#include "sm_version.h" ConVarAccessor g_ConCmdAccessor; @@ -183,8 +184,24 @@ CON_COMMAND(sm, "SourceMod Menu") return; } } - //:TODO: print plugins cmd list + + META_CONPRINT(" SourceMod Plugin Menu:\n"); + META_CONPRINT(" list - Show loaded plugins\n"); + META_CONPRINT(" load - Load a plugin\n"); + META_CONPRINT(" unload - Unload a plugin\n"); + META_CONPRINT(" info - Information about a plugin\n"); + return; + } else if (!strcmp("version", cmd)) { + META_CONPRINT(" SourceMod Version Information:\n"); + META_CONPRINTF(" SourceMod Version: \"%s\"\n", SOURCEMOD_VERSION); + META_CONPRINTF(" JIT Version: %s (%s)\n", g_pVM->GetVMName(), g_pVM->GetVersionString()); + META_CONPRINTF(" JIT Settings: %s\n", g_pVM->GetCPUOptimizations()); + META_CONPRINTF(" http://www.sourcemod.net/\n"); + return; } } - //:TODO: print cmd list or something + META_CONPRINT(" SourceMod Menu:\n"); + META_CONPRINT(" Usage: sm [arguments]\n"); + META_CONPRINT(" plugins - Plugins menu\n"); + META_CONPRINT(" version - Display version information\n"); } \ No newline at end of file From 814007df49a132e4455b93fd366360b9d99d184d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 6 Jan 2007 07:53:34 +0000 Subject: [PATCH 0246/1664] since these two functions are implemented separately, API calls are now divided got rid of ARRAYSIZE warning --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40276 --- core/CLogger.cpp | 12 +++--------- core/CLogger.h | 3 ++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index ea622002..1f98f247 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -71,7 +71,7 @@ void CLogger::_CloseFile() if (fp) { fseek(fp, 0, SEEK_END); - LogMessageEx(LogType_Error, "Error log file session closed."); + LogError("Error log file session closed."); fclose(fp); } m_ErrFileName.clear(); @@ -192,19 +192,13 @@ print_error: m_Active = false; } -void CLogger::LogMessageEx(LogType type, const char *vafmt, ...) +void CLogger::LogError(const char *vafmt, ...) { if (!m_Active) { return; } - if (type == LogType_Normal) - { - LogMessage(vafmt); - return; - } - time_t t; time(&t); tm *curtime = localtime(&t); @@ -266,7 +260,7 @@ void CLogger::MapChange(const char *mapname) if (m_ErrMapStart) { - LogMessageEx(LogType_Error, "Error log file session closed."); + LogError("Error log file session closed."); } m_ErrMapStart = false; } diff --git a/core/CLogger.h b/core/CLogger.h index 3c23cfc9..5d3aa3c6 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -1,6 +1,7 @@ #ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_ #define _INCLUDE_SOURCEMOD_CLOGGER_H_ +#include "sm_globals.h" #include #include "sourcemm_api.h" #include @@ -32,7 +33,7 @@ public: void EnableLogging(); void DisableLogging(); void LogMessage(const char *msg, ...); - void LogMessageEx(LogType type, const char *msg, ...); + void LogError(const char *msg, ...); void MapChange(const char *mapname); const char *GetLogFileName(LogType type); LoggingMode GetLoggingMode(); From 43005abc2fc88014f1221009714f9e57e3c75700 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 6 Jan 2007 07:53:56 +0000 Subject: [PATCH 0247/1664] added API for getting error messages --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40277 --- core/CTextParsers.cpp | 27 ++++++++++++++++++++++++++- core/CTextParsers.h | 10 ++++++---- core/interfaces/ITextParsers.h | 11 ++++++++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index b0720bad..c653601e 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -6,7 +6,7 @@ #include #include "CTextParsers.h" -CTextParsers g_TextParse; +CTextParsers g_TextParser; static int g_ini_chartable1[255] = {0}; static int g_ws_chartable[255] = {0}; @@ -898,3 +898,28 @@ event_failed: return false; } + +const char *CTextParsers::GetSMCErrorString(SMCParseError err) +{ + static const char *s_errors[] = + { + NULL, + "Stream failed to open", + "Stream returned read error", + NULL, + "Un-quoted section has invalid tokens", + "Section declared without header", + "Section declared with unknown tokens", + "Section ending without a matching section beginning", + "Line contained too many invalid tokens", + "Token buffer overflowed", + "A property was declared outside of a section", + }; + + if (err < SMCParse_Okay || err > SMCParse_InvalidProperty1) + { + return NULL; + } + + return s_errors[err]; +} diff --git a/core/CTextParsers.h b/core/CTextParsers.h index 0c0f48d0..aeaf40da 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -37,17 +37,19 @@ class CTextParsers : public ITextParsers public: CTextParsers(); public: - virtual bool ParseFile_INI(const char *file, + bool ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col); - virtual SMCParseError ParseFile_SMC(const char *file, + SMCParseError ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col); - virtual unsigned int GetUTF8CharBytes(const char *stream); + unsigned int GetUTF8CharBytes(const char *stream); + + const char *GetSMCErrorString(SMCParseError err); private: SMCParseError ParseString_SMC(const char *stream, ITextListener_SMC *smc, @@ -61,6 +63,6 @@ private: }; -extern CTextParsers g_TextParse; +extern CTextParsers g_TextParser; #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ diff --git a/core/interfaces/ITextParsers.h b/core/interfaces/ITextParsers.h index 0812cdfc..8a583a82 100644 --- a/core/interfaces/ITextParsers.h +++ b/core/interfaces/ITextParsers.h @@ -149,7 +149,7 @@ namespace SourceMod enum SMCParseError { - SMCParse_Okay, //no error + SMCParse_Okay = 0, //no error SMCParse_StreamOpen, //stream failed to open SMCParse_StreamError, //the stream died... somehow SMCParse_Custom, //a custom handler threw an error @@ -292,6 +292,15 @@ namespace SourceMod ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col) =0; + + /** + * @brief Converts an SMCParseError to a stirng. + * + * @param err SMCParseError. + * @return String error message, or NULL if none. + */ + virtual const char *GetSMCErrorString(SMCParseError err) =0; + public: /** * @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream. From 7bb52e67f31f1b98a15ad651b961880f713242ea Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 6 Jan 2007 19:35:25 +0000 Subject: [PATCH 0248/1664] compiles again --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40278 --- core/systems/PluginSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 01a5db4a..7432baaa 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -535,7 +535,7 @@ void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) SMCParseError err; unsigned int line, col; m_AllPluginsLoaded = false; - if ((err=g_TextParse.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) + if ((err=g_TextParser.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) { /* :TODO: log the error, don't bail out though */ } From 45baab94a6e979f44de113122166f41c76399855 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 7 Jan 2007 01:30:28 +0000 Subject: [PATCH 0249/1664] Added a bunch of new file natives. Fixed possible corruption in snprintf when input buffer was bigger than output buffer and relaying on its retval. Fixed all cases when the above situation happened. Fixed _PrintToHL2Log not taking va_list in. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40279 --- core/CLogger.cpp | 22 ++- core/CLogger.h | 2 +- core/sm_srvcmds.cpp | 9 +- core/sm_stringutil.cpp | 11 ++ core/sm_stringutil.h | 1 + core/smn_filesystem.cpp | 338 +++++++++++++++++++++++++++++++++++- core/smn_string.cpp | 6 +- core/systems/LibrarySys.cpp | 2 + plugins/include/files.inc | 112 ++++++++++++ 9 files changed, 484 insertions(+), 19 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 1f98f247..3e56a65c 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -35,6 +35,7 @@ void CLogger::_NewMapFile() { g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; + return; } else { char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); @@ -125,7 +126,10 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_mode == LoggingMode_HL2) { - _PrintToHL2Log(vafmt); + va_list ap; + va_start(ap, vafmt); + _PrintToHL2Log(vafmt, ap); + va_end(ap); return; } @@ -135,7 +139,7 @@ void CLogger::LogMessage(const char *vafmt, ...) _NewMapFile(); } - static char msg[3072]; + char msg[3072]; va_list ap; va_start(ap, vafmt); vsnprintf(msg, sizeof(msg), vafmt, ap); @@ -215,7 +219,7 @@ void CLogger::LogError(const char *vafmt, ...) m_ErrMapStart = false; } - static char msg[3072]; + char msg[3072]; va_list ap; va_start(ap, vafmt); vsnprintf(msg, sizeof(msg), vafmt, ap); @@ -235,6 +239,7 @@ void CLogger::LogError(const char *vafmt, ...) } else { g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; + return; } g_SMAPI->ConPrintf("L %s: %s\n", date, msg); @@ -265,17 +270,16 @@ void CLogger::MapChange(const char *mapname) m_ErrMapStart = false; } -void CLogger::_PrintToHL2Log(const char *fmt, ...) +void CLogger::_PrintToHL2Log(const char *fmt, va_list ap) { - static char msg[3072]; + char msg[3072]; size_t len; - va_list ap; - va_start(ap, fmt); - len = vsnprintf(msg, sizeof(msg)-1, fmt, ap); + len = vsnprintf(msg, sizeof(msg)-2, fmt, ap); + len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len; + msg[len++] = '\n'; msg[len] = '\0'; - va_end(ap); engine->LogPrint(msg); } \ No newline at end of file diff --git a/core/CLogger.h b/core/CLogger.h index 5d3aa3c6..9eed457d 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -40,7 +40,7 @@ public: private: void _CloseFile(); void _NewMapFile(); - void _PrintToHL2Log(const char *fmt, ...); + void _PrintToHL2Log(const char *fmt, va_list ap); private: String m_NrmFileName; String m_ErrFileName; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index e0ccd463..ae3a54c5 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -1,5 +1,6 @@ #include "sm_srvcmds.h" #include "sm_version.h" +#include "sm_stringutil.h" ConVarAccessor g_ConCmdAccessor; @@ -70,15 +71,15 @@ CON_COMMAND(sm, "SourceMod Menu") int len = 0; const sm_plugininfo_t *info = pl->GetPublicInfo(); - len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, StatusToStr(pl->GetStatus())); + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); if (IS_STR_FILLED(info->version)) { - len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); } if (IS_STR_FILLED(info->author)) { - snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); + UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author); } META_CONPRINTF("%s\n", buffer); } diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 25a37ba0..ff89a123 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "sm_stringutil.h" #define ALT 0x00000001 /* alternate form */ @@ -471,3 +472,13 @@ unsigned int strncopy(char *dest, const char *src, size_t count) return (dest - start); } + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + return (len >= maxlength) ? (maxlength - 1) : len; +} \ No newline at end of file diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 5dce299f..49facef6 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -10,5 +10,6 @@ using namespace SourcePawn; size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 75db63f2..949f153c 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -1,6 +1,8 @@ +#include #include "sm_globals.h" #include "HandleSys.h" #include "LibrarySys.h" +#include "sm_stringutil.h" HandleType_t g_FileType; HandleType_t g_DirType; @@ -36,7 +38,7 @@ public: }; -cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) +static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) { char *path; int err; @@ -58,7 +60,7 @@ cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); } -cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) +static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); IDirectory *pDir; @@ -109,6 +111,324 @@ cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) return true; } +static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) +{ + char *name, *mode; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + FILE *pFile = fopen(realpath, mode); + if (!pFile) + { + return 0; + } + + return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + return (unlink(realpath)) ? 0 : 1; +} + +static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + int err; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *buf; + if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + fgets(buf, params[3], pFile); + + return 1; +} + +static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + return (feof(pFile)) ? 1 : 0; +} + +static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + fseek(pFile, params[2], params[3]); + + return 1; +} + +static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + return ftell(pFile); +} + +static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return 0; + } + if (s.st_mode & S_IFREG) + { + return 1; + } + return 0; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return 0; + } + if (S_ISREG(s.st_mode)) + { + return 1; + } + return 0; +#endif +} + +static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) +{ + char *newpath, *oldpath; + int err; + if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char new_realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(new_realpath, sizeof(new_realpath), "%s/%s", g_SourceMod.GetBaseDir(), newpath); + char old_realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(old_realpath, sizeof(old_realpath), "%s/%s", g_SourceMod.GetBaseDir(), oldpath); + +#ifdef PLATFORM_WINDOWS + return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; +#elif PLATFORM_LINUX + return (rename(old_realpath, new_realpath)) ? 0 : 1; +#endif +} + +static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return 0; + } + if (s.st_mode & S_IFDIR) + { + return 1; + } + return 0; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return 0; + } + if (S_ISDIR(s.st_mode)) + { + return 1; + } + return 0; +#endif +} + +static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return -1; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return -1; + } + if (s.st_mode & S_IFREG) + { + return static_cast(s.st_size); + } + return -1; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return -1; + } + if (S_ISREG(s.st_mode)) + { + return static_cast(s.st_size); + } + return -1; +#endif +} + +static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + return (rmdir(realpath)) ? 0 : 1; +} + +static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *fmt; + int err; + if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char buffer[2048]; + int arg = 3; + atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); + fprintf(pFile, "%s\n", buffer); + + return 1; +} + +//:TODO: DEBUG CODE HERE cell_t PrintStuff(IPluginContext *pContext, const cell_t *params) { char *stuff; @@ -127,6 +447,18 @@ REGISTER_NATIVES(filesystem) { {"OpenDirectory", sm_OpenDirectory}, {"ReadDirEntry", sm_ReadDirEntry}, - {"PrintStuff", PrintStuff}, + {"PrintStuff", PrintStuff},//:TODO: remove this when no longer needed + {"OpenFile", sm_OpenFile}, + {"DeleteFile", sm_DeleteFile}, + {"ReadFileLine", sm_ReadFileLine}, + {"IsEndOfFile", sm_IsEndOfFile}, + {"FileSeek", sm_FileSeek}, + {"FilePosition", sm_FilePosition}, + {"FileExists", sm_FileExists}, + {"RenameFile", sm_RenameFile}, + {"DirExists", sm_DirExists}, + {"FileSize", sm_FileSize}, + {"RemoveDir", sm_RemoveDir}, + {"WriteFileLine", sm_WriteFileLine}, {NULL, NULL}, }; diff --git a/core/smn_string.cpp b/core/smn_string.cpp index d8b7436c..2fbfca82 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -84,8 +84,9 @@ static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) { char *str; pCtx->LocalToString(params[2], &str); + size_t res = UTIL_Format(str, params[3], "%d", params[1]); - return snprintf(str, params[3], "%d", params[1]); + return static_cast(res); } static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params) @@ -102,8 +103,9 @@ static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) { char *str; pCtx->LocalToString(params[2], &str); + size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1])); - return snprintf(str, params[3], "%f", sp_ctof(params[1])); + return static_cast(res); } static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params) diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 6fc467b1..2bc57460 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -289,6 +289,8 @@ void LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) size_t mylen = vsnprintf(buffer, len, fmt, ap); va_end(ap); + mylen = (mylen >= len) ? (len - 1) : mylen; + for (size_t i=0; i Date: Sun, 7 Jan 2007 01:32:08 +0000 Subject: [PATCH 0250/1664] i have a hat --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40280 --- plugins/include/files.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 861e9b6a..18052e96 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -152,4 +152,4 @@ native bool:RemoveDir(const String:path[]); * @param ... Variable number of format parameters. * @return True on success, false otherwise. */ -native bool:WriteFileLine(Handle:hndl, const String:format[], ...); +native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,_}:...); From 95368e57cd3915f6b98e1acbd75ca42ad2b9d655 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 7 Jan 2007 08:47:38 +0000 Subject: [PATCH 0251/1664] initial import of translator code (tested) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40281 --- core/CTranslator.cpp | 748 +++++++++++++++++++++++++++++++++ core/CTranslator.h | 101 +++++ core/msvc8/sourcemod_mm.vcproj | 10 +- core/sm_stringutil.cpp | 182 +++++++- core/sm_stringutil.h | 1 + core/sourcemod.cpp | 6 - 6 files changed, 1033 insertions(+), 15 deletions(-) create mode 100644 core/CTranslator.cpp create mode 100644 core/CTranslator.h diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp new file mode 100644 index 00000000..723a984a --- /dev/null +++ b/core/CTranslator.cpp @@ -0,0 +1,748 @@ +#include +#include "CTranslator.h" +#include "CLogger.h" +#include "CTextParsers.h" +#include "LibrarySys.h" +#include "sm_stringutil.h" + +CTranslator g_Translator; + +struct trans_t +{ + int stridx; + int fmt_order; +}; + +struct phrase_t +{ + int fmt_list; + unsigned int fmt_count; + unsigned int fmt_bytes; + int trans_tbl; + unsigned int translations; +}; + +CPhraseFile::CPhraseFile(CTranslator *pTranslator, const char *file) +{ + m_pStringTab = pTranslator->GetStringTable(); + m_pMemory = m_pStringTab->GetMemTable(); + m_LangCount = pTranslator->GetLanguageCount(); + m_File.assign(file); + m_pTranslator = pTranslator; + m_pPhraseLookup = NULL; +} + +CPhraseFile::~CPhraseFile() +{ + if (m_pPhraseLookup) + { + sm_trie_destroy(m_pPhraseLookup); + } +} + +void CPhraseFile::ParseError(const char *message, ...) +{ + char buffer[1024]; + va_list ap; + va_start(ap, message); + vsnprintf(buffer, sizeof(buffer), message, ap); + va_end(ap); + + m_ParseError.assign(buffer); +} + +void CPhraseFile::ParseWarning(const char *message, ...) +{ + char buffer[1024]; + va_list ap; + va_start(ap, message); + vsnprintf(buffer, sizeof(buffer), message, ap); + va_end(ap); + + if (!m_FileLogged) + { + g_Logger.LogError("[SOURCEMOD] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); + m_FileLogged; + } + + g_Logger.LogError("[SOURCEMOD] %s", message); +} + +void CPhraseFile::ReparseFile() +{ + if (m_pPhraseLookup) + { + sm_trie_destroy(m_pPhraseLookup); + } + m_pPhraseLookup = sm_trie_create(); + + m_LangCount = m_pTranslator->GetLanguageCount(); + + if (!m_LangCount) + { + return; + } + + SMCParseError err; + char path[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/translations/%s", g_SourceMod.GetSMBaseDir(), m_File.c_str()); + unsigned int line=0, col=0; + + if ((err=g_TextParser.ParseFile_SMC(path, this, &line, &col)) != SMCParse_Okay) + { + const char *msg = g_TextParser.GetSMCErrorString(err); + if (!msg) + { + msg = m_ParseError.c_str(); + } + + g_Logger.LogError("[SOURCEMOD] Fatal error encountered parsing translation file \"%s\"", m_File.c_str()); + g_Logger.LogError("[SOURCEMOD] Error (line %d, column %d): %s", line, col, msg); + } +} + +void CPhraseFile::ReadSMC_ParseStart() +{ + m_CurPhrase = -1; + m_ParseState = PPS_None; + m_CurLine = 0; + m_FileLogged = false; + m_LastPhraseString.clear(); +} + +SMCParseResult CPhraseFile::ReadSMC_RawLine(const char *line, unsigned int curline) +{ + m_CurLine = curline; + + return SMCParse_Continue; +} + +SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes) +{ + bool recognized = false; + if (m_ParseState == PPS_None) + { + if (strcmp(name, "Phrases") == 0) + { + m_ParseState = PPS_Phrases; + recognized = true; + } + } else if (m_ParseState == PPS_Phrases) { + m_ParseState = PPS_InPhrase; + recognized = true; + + phrase_t *pPhrase; + m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase); + + /* Create the reverse lookup */ + if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast(m_CurPhrase))) + { + ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, m_CurLine); + /* :IDEA: prevent memory waste by seeking backwards in memtable? */ + m_CurPhrase = -1; + } else { + /* Initialize new phrase */ + trans_t *pTrans; + + pPhrase->fmt_count = 0; + pPhrase->fmt_list = -1; + pPhrase->trans_tbl = m_pMemory->CreateMem(sizeof(trans_t) * m_LangCount, (void **)&pTrans); + pPhrase->translations = 0; + pPhrase->fmt_bytes = 0; + + for (unsigned int i=0; iGetAddress(m_CurPhrase); + + if (key[0] == '#' && strcmp(key, "#format") == 0) + { + if (pPhrase->fmt_list != -1) + { + ParseWarning("Ignoring duplicated #format property on line %d", m_CurLine); + return SMCParse_Continue; + } + + if (pPhrase->translations > 0) + { + ParseWarning("#format property should come before translations on line %d, ignoring", m_CurLine); + return SMCParse_Continue; + } + + /* Do an initial browsing for error checking and what not */ + enum ParseStates + { + Parse_None, + Parse_Index, + Parse_Format, + }; + + ParseStates state = Parse_None; + + const char *old_value = value; + while (*value != '\0') + { + if (state == Parse_None) + { + if (*value == '{') + { + pPhrase->fmt_count++; + state = Parse_Index; + } else if (*value == ',') { + /* Do nothing */ + } else { + unsigned int bytes = g_TextParser.GetUTF8CharBytes(value); + if (bytes != 1 || !isalpha(*value)) + { + ParseWarning("Invalid token '%c' in #format property on line %d.", *value, m_CurLine); + } + } + } else if (state == Parse_Index) { + if (*value == ':') + { + state = Parse_Format; + if (value - old_value >= 15) + { + ParseWarning("Too many digits in format index on line %d, phrase will be ignored.", m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + } else { + unsigned int bytes = g_TextParser.GetUTF8CharBytes(value); + if (bytes != 1 || !isdigit(*value)) + { + ParseWarning("Token '%c' in #format property on line %d is not a digit, phrase will be ignored.", + *value, + m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + } + } else if (state == Parse_Format) { + if (*value == '}') + { + state = Parse_None; + } + } + value++; + } + + if (state != Parse_None) + { + /* Moose clam cow. */ + ParseWarning("Unterminated format string on line %d, phrase will be ignored.", m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + value = old_value; + + /* Allocate the format table */ + char fmt_buf[16]; + int *fmt_list; + pPhrase->fmt_list = m_pMemory->CreateMem(sizeof(int) * pPhrase->fmt_count, (void **)&fmt_list); + + /* Initialize */ + for (size_t i=0; ifmt_count; i++) + { + fmt_list[i] = -1; + } + + /* Now we need to read again... this time into the format buffer */ + const char *in_ptr = value; + const char *idx_ptr = NULL; + char *out_ptr = NULL; + unsigned int cur_idx = 0; + state = Parse_None; + while (*in_ptr != '\0') + { + if (state == Parse_None) + { + if (*in_ptr == '{') + { + state = Parse_Index; + idx_ptr = NULL; + } + } else if (state == Parse_Index) { + if (*in_ptr == ':') + { + /* Check the number! */ + if (!idx_ptr) + { + ParseWarning("Format property contains unindexed format string on line %d, phrase will be ignored.", m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + long idx = strtol(idx_ptr, NULL, 10); + if (idx < 1 || idx > (long)pPhrase->fmt_count) + { + ParseWarning("Format property contains invalid index '%d' on line %d, phrase will be ignored.", idx, m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } else if (fmt_list[idx - 1] != -1) { + ParseWarning("Format property contains duplicated index '%d' on line %d, phrase will be ignored.", idx, m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + cur_idx = (unsigned int)idx; + state = Parse_Format; + out_ptr = NULL; + } else if (!idx_ptr) { + idx_ptr = in_ptr; + } + } else if (state == Parse_Format) { + if (*in_ptr == '}') + { + if (!out_ptr) + { + ParseWarning("Format property contains empty format string on line %d, phrase will be ignored.", m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + *out_ptr = '\0'; + state = Parse_None; + /* Now, add this to our table */ + fmt_list[cur_idx - 1] = m_pStringTab->AddString(fmt_buf); + pPhrase->fmt_bytes += strlen(fmt_buf); + } else { + if (!out_ptr) + { + out_ptr = fmt_buf; + *out_ptr++ = '%'; + } + /* Check length ... */ + if (out_ptr - fmt_buf >= sizeof(fmt_buf) - 1) + { + ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.", + m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + *out_ptr++ = *in_ptr; + } + } + in_ptr++; + } + + /* If we've gotten here, we only accepted unique indexes in a range. + * Therefore, the list has to be completely filled. Double check anyway. + */ + for (size_t i=0; ifmt_count; i++) + { + if (fmt_list[i] == -1) + { + ParseWarning("Format property contains no string for index %d on line %d, phrase will be ignored.", + i + 1, + m_CurLine); + m_CurPhrase = -1; + return SMCParse_Continue; + } + } + } else { + size_t len = strlen(key); + if (len != 2) + { + ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, m_CurLine); + return SMCParse_Continue; + } + + unsigned int lang; + if (!m_pTranslator->GetLanguageByCode(key, &lang)) + { + /* Ignore if we don't have a language. + * :IDEA: issue a one-time alert? + */ + return SMCParse_Continue; + } + + /* See how many bytes we need for this string, then allocate. + * NOTE: THIS SHOULD GUARANTEE THAT WE DO NOT NEED TO NEED TO SIZE CHECK + */ + len = strlen(value) + pPhrase->fmt_bytes + 1; + char *out_buf; + int out_idx; + + out_idx = m_pMemory->CreateMem(len, (void **)&out_buf); + + int *fmt_order; + int *fmt_list = (int *)m_pMemory->GetAddress(pPhrase->fmt_list); + trans_t *pTrans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); + + pTrans = &pTrans[lang]; + pTrans->stridx = out_idx; + + bool params[MAX_TRANSLATE_PARAMS]; + + /* Build the format order list, if necessary */ + if (fmt_list) + { + pTrans->fmt_order = m_pMemory->CreateMem(pPhrase->fmt_count * sizeof(int), (void **)&fmt_order); + + for (unsigned int i=0; ifmt_count; i++) + { + fmt_order[i] = -1; + } + memset(¶ms[0], 0, sizeof(params)); + } + + const char *in_ptr = value; + char *out_ptr = out_buf; + unsigned int order_idx = 0; + while (*in_ptr != '\0') + { + if (*in_ptr == '\\') + { + switch (*(in_ptr + 1)) + { + case '\n': + *out_ptr++ = '\n'; + break; + case '\t': + *out_ptr++ = '\t'; + break; + case '\r': + *out_ptr++ = '\r'; + break; + case '{': + *out_ptr++ = '{'; + break; + default: + /* Copy both bytes since we don't know what's going on */ + *out_ptr++ = *in_ptr++; + *out_ptr++ = *in_ptr; + break; + } + /* Skip past the last byte read */ + in_ptr++; + } else if (*in_ptr == '{' && fmt_list != NULL) { + /* Search for parameters if this is a formatted string */ + const char *scrap_in_point = in_ptr; + const char *digit_start = ++in_ptr; + unsigned int bytes; + while (*in_ptr != '\0') + { + bytes = g_TextParser.GetUTF8CharBytes(in_ptr); + if (bytes != 1) + { + goto scrap_point; + } + if (*in_ptr == '}') + { + /* Did we get an index? */ + if (in_ptr == digit_start) + { + goto scrap_point; + } + /* Is it valid? */ + long idx = strtol(digit_start, NULL, 10); + if (idx < 1 || idx > (int)pPhrase->fmt_count) + { + goto scrap_point; + } + if (params[idx-1]) + { + goto scrap_point; + } + + /* We're safe to insert the string. First mark order. */ + fmt_order[order_idx++] = (int)idx - 1; + /* Now concatenate */ + out_ptr += sprintf(out_ptr, "%s", m_pStringTab->GetString(fmt_list[idx-1])); + /* Mark as used */ + params[idx-1] = true; + + goto cont_loop; + } + in_ptr++; + } +scrap_point: + /* Pretend none of this ever happened. Move along now! */ + in_ptr = scrap_in_point; + *out_ptr++ = *in_ptr; + } else { + *out_ptr++ = *in_ptr; + } +cont_loop: + in_ptr++; + } + *out_ptr = '\0'; + pPhrase->translations++; + } + + return SMCParse_Continue; +} + +SMCParseResult CPhraseFile::ReadSMC_LeavingSection() +{ + if (m_ParseState == PPS_InPhrase) + { + if (m_CurPhrase == -1 && m_LastPhraseString.size()) + { + sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str()); + } + m_CurPhrase = -1; + m_ParseState = PPS_Phrases; + m_LastPhraseString.assign(""); + } else if (m_ParseState == PPS_Phrases) { + m_ParseState = PPS_None; + } + + return SMCParse_Continue; +} + +void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed) +{ + /* Check to see if we have any dangling phrases that weren't completed, and scrap them */ + if ((halted || failed) && m_LastPhraseString.size()) + { + sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str()); + } +} + +const char *CPhraseFile::GetTranslation(const Translation *pTrans, int **fmt_order, unsigned int *fmt_count) +{ + if (pTrans->lang_id >= m_LangCount) + { + return NULL; + } + + void *object; + if (!sm_trie_retrieve(m_pPhraseLookup, pTrans->szPhrase, &object)) + { + return NULL; + } + + phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(reinterpret_cast(object)); + trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); + + trans = &trans[pTrans->lang_id]; + + if (trans->stridx == -1) + { + return NULL; + } + + *fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order); + *fmt_count = pPhrase->fmt_count; + + return m_pStringTab->GetString(trans->stridx); +} + +const char *CPhraseFile::GetFilename() +{ + return m_File.c_str(); +} + +CTranslator::CTranslator() +{ + m_pStringTab = new BaseStringTable(2048); + m_pLCodeLookup = sm_trie_create(); +} + +CTranslator::~CTranslator() +{ + for (size_t i=0; i(_index); + } + + return true; +} + +unsigned int CTranslator::GetLanguageCount() +{ + return (unsigned int)m_Languages.size(); +} + +BaseStringTable *CTranslator::GetStringTable() +{ + return m_pStringTab; +} + +unsigned int CTranslator::FindOrAddPhraseFile(const char *phrase_file) +{ + for (size_t i=0; iGetFilename(), phrase_file) == 0) + { + return (unsigned int)i; + } + } + + CPhraseFile *pFile = new CPhraseFile(this, phrase_file); + unsigned int idx = (unsigned int)m_Files.size(); + + m_Files.push_back(pFile); + + pFile->ReparseFile(); + + return idx; +} + +void CTranslator::RebuildLanguageDatabase(const char *lang_header_file) +{ + /* Erase everything we have */ + sm_trie_destroy(m_pLCodeLookup); + m_pLCodeLookup = sm_trie_create(); + m_pStringTab->Reset(); + + for (size_t i=0; iReparseFile(); + } +} + +void CTranslator::ReadSMC_ParseStart() +{ + m_InLanguageSection = false; + m_CustomError.clear(); +} + +SMCParseResult CTranslator::ReadSMC_NewSection(const char *name, bool opt_quotes) +{ + if (!m_InLanguageSection) + { + if (strcmp(name, "Languages") == 0) + { + m_InLanguageSection = true; + } + } + + if (!m_InLanguageSection) + { + g_Logger.LogError("[SOURCEMOD] Warning: Unrecognized section \"%s\" in languages.cfg"); + } + + return SMCParse_Continue; +} + +SMCParseResult CTranslator::ReadSMC_LeavingSection() +{ + m_InLanguageSection = false; + + return SMCParse_Continue; +} + +SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) +{ + size_t len = strlen(key); + + if (len != 2) + { + g_Logger.LogError("[SOURCEMOD] Warning encountered parsing languages.cfg file."); + g_Logger.LogError("[SOURCEMOD] Invalid language code \"%s\" is being ignored."); + } + + Language *pLanguage = new Language; + unsigned int idx = m_Languages.size(); + + strcpy(pLanguage->m_code2, key); + pLanguage->m_FullName = m_pStringTab->AddString(value); + + sm_trie_insert(m_pLCodeLookup, key, reinterpret_cast(idx)); + + m_Languages.push_back(pLanguage); + + return SMCParse_Continue; +} + +size_t CTranslator::Translate(char *buffer, size_t maxlength, const Translation *pTrans) +{ + if (pTrans->file_id >= m_Files.size()) + { + return 0; + } + + CPhraseFile *pFile = m_Files[pTrans->file_id]; + unsigned int count; + int *order_table; + const char *str; + + if ((str=pFile->GetTranslation(pTrans, &order_table, &count)) == NULL) + { + return 0; + } + + void *params[MAX_TRANSLATE_PARAMS]; + + /* Rewrite the parameter order */ + for (unsigned int i=0; iparams[order_table[i]]; + } + + return gnprintf(buffer, maxlength, str, params); +} diff --git a/core/CTranslator.h b/core/CTranslator.h new file mode 100644 index 00000000..cb0da51f --- /dev/null +++ b/core/CTranslator.h @@ -0,0 +1,101 @@ +#ifndef _INCLUDE_SOURCEMOD_TRANSLATOR_H_ +#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_ + +#include "sm_trie.h" +#include +#include +#include "sm_globals.h" +#include "sm_memtable.h" +#include "ITextParsers.h" + +#define MAX_TRANSLATE_PARAMS 32 + +/* :TODO: write a templatized version of tries? */ + +using namespace SourceHook; +class CTranslator; + +enum PhraseParseState +{ + PPS_None = 0, + PPS_Phrases, + PPS_InPhrase, +}; + +struct Language +{ + char m_code2[3]; + int m_FullName; +}; + +struct Translation +{ + const char *szPhrase; + unsigned int lang_id; + unsigned int file_id; + void **params; +}; + +class CPhraseFile : public ITextListener_SMC +{ +public: + CPhraseFile(CTranslator *pTranslator, const char *file); + ~CPhraseFile(); +public: + void ReparseFile(); + const char *GetFilename(); + const char *GetTranslation(const Translation *pTrans, int **fmt_order, unsigned int *fmt_count); +public: //ITextListener_SMC + void ReadSMC_ParseStart(); + void ReadSMC_ParseEnd(bool halted, bool failed); + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); + SMCParseResult ReadSMC_LeavingSection(); + SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline); +private: + void ParseError(const char *message, ...); + void ParseWarning(const char *message, ...); +private: + Trie *m_pPhraseLookup; + String m_File; + CTranslator *m_pTranslator; + PhraseParseState m_ParseState; + int m_CurPhrase; + BaseMemTable *m_pMemory; + BaseStringTable *m_pStringTab; + unsigned int m_LangCount; + String m_ParseError; + String m_LastPhraseString; + unsigned int m_CurLine; + bool m_FileLogged; +}; + +class CTranslator : public ITextListener_SMC +{ +public: + CTranslator(); + ~CTranslator(); +public: //ITextListener_SMC + void ReadSMC_ParseStart(); + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); + SMCParseResult ReadSMC_LeavingSection(); +public: + void RebuildLanguageDatabase(const char *lang_header_file); + unsigned int FindOrAddPhraseFile(const char *phrase_file); + BaseStringTable *GetStringTable(); + unsigned int GetLanguageCount(); + bool GetLanguageByCode(const char *code, unsigned int *index); + size_t Translate(char *buffer, size_t maxlength, const Translation *pTrans); +private: + CVector m_Languages; + CVector m_Files; + BaseStringTable *m_pStringTab; + Trie *m_pLCodeLookup; + bool m_InLanguageSection; + String m_CustomError; +}; + +extern CTranslator g_Translator; + +#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index db34d866..79ada0a9 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -265,6 +269,10 @@ RelativePath="..\CTextParsers.h" > + + diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index ff89a123..47d85685 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -3,18 +3,10 @@ #include #include "sm_stringutil.h" -#define ALT 0x00000001 /* alternate form */ -#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ #define LADJUST 0x00000004 /* left adjustment */ -#define LONGDBL 0x00000008 /* long double */ -#define LONGINT 0x00000010 /* long integer */ -#define QUADINT 0x00000020 /* quad integer */ -#define SHORTINT 0x00000040 /* short integer */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define FPT 0x00000100 /* floating point number */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') //:TODO: fix this macro when we have a debugger @@ -25,6 +17,8 @@ } */ +//:TODO: review this code before we choose a license + void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) { int size = 0; @@ -252,8 +246,180 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags) *buf_p = buf; } +size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args) +{ + if (!buffer || !maxlen) + { + return 0; + } + + int arg = 0; + char *buf_p; + char ch; + int flags; + int width; + int prec; + int n; + char sign; + const char *fmt; + size_t llen = maxlen - 1; + + buf_p = buffer; + fmt = format; + + while (true) + { + // run through the format string until we hit a '%' or '\0' + for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++) + { + *buf_p++ = ch; + llen--; + } + if ((ch == '\0') || (llen <= 0)) + { + goto done; + } + + // skip over the '%' + fmt++; + + // reset formatting state + flags = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: + ch = *fmt++; +reswitch: + switch(ch) + { + case '-': + { + flags |= LADJUST; + goto rflag; + } + case '.': + { + n = 0; + while(is_digit((ch = *fmt++))) + { + n = 10 * n + (ch - '0'); + } + prec = (n < 0) ? -1 : n; + goto reswitch; + } + case '0': + { + flags |= ZEROPAD; + goto rflag; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + n = 0; + do + { + n = 10 * n + (ch - '0'); + ch = *fmt++; + } while(is_digit(ch)); + width = n; + goto reswitch; + } + case 'c': + { + if (!llen) + { + goto done; + } + char *c = (char *)args[arg]; + *buf_p++ = *c; + llen--; + arg++; + break; + } + case 'd': + case 'i': + { + int *value = (int *)args[arg]; + AddInt(&buf_p, llen, *value, width, flags); + arg++; + break; + } + case 'u': + { + unsigned int *value = (unsigned int *)args[arg]; + AddUInt(&buf_p, llen, *value, width, flags); + arg++; + break; + } + case 'f': + { + float *value = (float *)args[arg]; + AddFloat(&buf_p, llen, *value, width, prec); + arg++; + break; + } + case 's': + { + const char *str = (const char *)args[arg]; + AddString(&buf_p, llen, str, width, prec); + arg++; + break; + } + case '%': + { + if (!llen) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + case '\0': + { + if (!llen) + { + goto done; + } + *buf_p++ = '%'; + llen--; + goto done; + } + default: + { + if (!llen) + { + goto done; + } + *buf_p++ = ch; + llen--; + break; + } + } + } + +done: + *buf_p = '\0'; + + return (maxlen - llen - 1); +} + size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param) { + if (!buffer || !maxlen) + { + return 0; + } + int arg; //int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count // either way this is only used when the above macro is fixed, until then not needed diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 49facef6..8ef7336f 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -10,6 +10,7 @@ using namespace SourcePawn; size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); +size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 150b68d2..52d1fee9 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -150,12 +150,6 @@ void SourceModBase::StartSourceMod(bool late) pBase->OnSourceModAllInitialized(); pBase = pBase->m_pGlobalClassNext; } - - /* If we're late, automatically load plugins now */ - if (late) - { - DoGlobalPluginLoads(); - } } bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) From 0849820a3adc57135c627207c576735d95c457c5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 7 Jan 2007 08:48:54 +0000 Subject: [PATCH 0252/1664] initial import of languages file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40282 --- configs/languages.cfg | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 configs/languages.cfg diff --git a/configs/languages.cfg b/configs/languages.cfg new file mode 100644 index 00000000..6bbce279 --- /dev/null +++ b/configs/languages.cfg @@ -0,0 +1,6 @@ +"Languages" +{ + "en" "English" + "es" "Español" +} + From 07729d669e4c153bc797c7b4c30f55d6367e53f5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 7 Jan 2007 08:51:18 +0000 Subject: [PATCH 0253/1664] initial import of core translation strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40283 --- translations/core.cfg | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 translations/core.cfg diff --git a/translations/core.cfg b/translations/core.cfg new file mode 100644 index 00000000..9bfadc53 --- /dev/null +++ b/translations/core.cfg @@ -0,0 +1,8 @@ +"Phrases" +{ + "No Access" + { + "en" "You do not have access to this command" + } + +} From 951e942ed667b2851292ba9e5cb426d048392e4d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 7 Jan 2007 08:55:02 +0000 Subject: [PATCH 0254/1664] PLATFORM_LINUX -> PLATFORM_POSIX --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40284 --- core/smn_filesystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 949f153c..7a135c69 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -265,7 +265,7 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) return 1; } return 0; -#elif PLATFORM_LINUX +#else if defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { @@ -301,7 +301,7 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) #ifdef PLATFORM_WINDOWS return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; -#elif PLATFORM_LINUX +#else if defined PLATFORM_POSIX return (rename(old_realpath, new_realpath)) ? 0 : 1; #endif } @@ -329,7 +329,7 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) return 1; } return 0; -#elif PLATFORM_LINUX +#else if defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { @@ -366,7 +366,7 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) return static_cast(s.st_size); } return -1; -#elif PLATFORM_LINUX +#else if defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { From 8ec61eecbff730be2298773bd06d616e9306a8de Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 10 Jan 2007 23:49:22 +0000 Subject: [PATCH 0255/1664] added some console natives more consts here and there in the logger --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40285 --- core/CLogger.h | 8 ++--- core/msvc8/sourcemod_mm.vcproj | 4 +++ core/smn_player.cpp | 59 +++++++++++++++++++++++++++++++++- plugins/include/sourcemod.inc | 23 ++++++++++++- 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/core/CLogger.h b/core/CLogger.h index 9eed457d..c28136f1 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -35,8 +35,8 @@ public: void LogMessage(const char *msg, ...); void LogError(const char *msg, ...); void MapChange(const char *mapname); - const char *GetLogFileName(LogType type); - LoggingMode GetLoggingMode(); + const char *GetLogFileName(LogType type) const; + LoggingMode GetLoggingMode() const; private: void _CloseFile(); void _NewMapFile(); @@ -55,7 +55,7 @@ private: extern CLogger g_Logger; -inline const char *CLogger::GetLogFileName(LogType type) +inline const char *CLogger::GetLogFileName(LogType type) const { switch (type) { @@ -74,7 +74,7 @@ inline const char *CLogger::GetLogFileName(LogType type) } } -inline LoggingMode CLogger::GetLoggingMode() +inline LoggingMode CLogger::GetLoggingMode() const { return m_mode; } diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 79ada0a9..e66833ad 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -203,6 +203,10 @@ RelativePath="..\sm_autonatives.cpp" > + + diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 441d0ec4..62f22cae 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1,4 +1,5 @@ #include "CPlayerManager.h" +#include "sm_stringutil.h" static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) { @@ -58,7 +59,15 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Client %d is not connected.", index); } - pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->PlayerIP()); + char buf[64], *ptr; + strcpy(buf, pPlayer->PlayerIP()); + + if (params[4] && (ptr = strchr(buf, ':'))) + { + *ptr = '\0'; + } + + pCtx->StringToLocal(params[2], static_cast(params[3]), buf); return 1; } @@ -130,6 +139,52 @@ static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) return (pPlayer->IsPlayerFakeClient()) ? 1 : 0; } +static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) +{ + char buffer[1024]; + char *fmt; + int arg = 2; + + pCtx->LocalToString(params[1], &fmt); + size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); + + buffer[res++] = '\n'; + buffer[res] = '\0'; + + META_CONPRINT(buffer); + + return 1; +} + +static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + { + return pCtx->ThrowNativeError("Invalid client index %d.", index); + } + + CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + if (!pPlayer->IsPlayerInGame()) + { + return pCtx->ThrowNativeError("Client %d is not in game.", index); + } + + char buffer[1024]; + char *fmt; + int arg = 3; + + pCtx->LocalToString(params[2], &fmt); + size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); + + buffer[res++] = '\n'; + buffer[res] = '\0'; + + engine->ClientPrintf(pPlayer->GetPlayerEdict(), buffer); + + return 1; +} + REGISTER_NATIVES(playernatives) { {"GetMaxClients", sm_GetMaxClients}, @@ -141,5 +196,7 @@ REGISTER_NATIVES(playernatives) {"IsPlayerInGame", sm_IsPlayerIngame}, {"IsPlayerAuthorized", sm_IsPlayerAuthorized}, {"IsPlayerFakeClient", sm_IsPlayerFakeClient}, + {"PrintToServer", sm_PrintToServer}, + {"PrintToConsole", sm_PrintToConsole}, {NULL, NULL} }; \ No newline at end of file diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index deef6f13..efd9686b 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -155,10 +155,11 @@ native bool:GetClientName(client, String:name[], maxlen); * @param client Player index. * @param name Buffer to store the client's ip address. * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param remport Remove client's port from the ip string (true by default). * @return True on success, false otherwise. * @error If the client is not connected an error will be thrown. */ -native bool:GetClientIP(client, String:ip[], maxlen); +native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); /** * Retrieves a client's authentication string (SteamID). @@ -202,3 +203,23 @@ native bool:IsPlayerAuthorized(client); * @return True if player is a fake client, false otherwise. */ native bool:IsPlayerFakeClient(client); + +/** + * Sends a message to the server console. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native PrintToServer(const String:format[], {Handle,Float,String,_}:...); + +/** + * Sends a message to a client's console. + * + * @param client Player index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error If the client is not connected an error will be thrown. + */ +native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); From f30dfedeeb5895dd2b95ffbb03a47647972a4287 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 11 Jan 2007 01:11:24 +0000 Subject: [PATCH 0256/1664] logger gets initialized now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40286 --- core/CLogger.cpp | 11 +++++++++++ core/CLogger.h | 5 ++++- core/sm_globals.h | 7 +++++++ core/sourcemod.cpp | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 3e56a65c..d458c02c 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -3,6 +3,17 @@ CLogger g_Logger; +void CLogger::OnSourceModStartup(bool late) +{ + //:TODO: read these options from a file, dont hardcode them + InitLogger(LoggingMode_PerMap, true); +} + +void CLogger::OnSourceModAllShutdown() +{ + CloseLogger(); +} + void CLogger::_NewMapFile() { if (!m_Active) diff --git a/core/CLogger.h b/core/CLogger.h index c28136f1..e08a8cb8 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -23,10 +23,13 @@ enum LoggingMode LoggingMode_HL2 }; -class CLogger +class CLogger : public SMGlobalClass { public: CLogger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} +public: //SMGlobalClass + void OnSourceModStartup(bool late); + void OnSourceModAllShutdown(); public: void InitLogger(LoggingMode mode, bool startlogging); void CloseLogger(); diff --git a/core/sm_globals.h b/core/sm_globals.h index 226ef801..90114c35 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -42,6 +42,13 @@ public: virtual void OnSourceModShutdown() { } + + /** + * @brief Called after SourceMod is completely shutted down + */ + virtual void OnSourceModAllShutdown() + { + } private: SMGlobalClass *m_pGlobalClassNext; static SMGlobalClass *head; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 52d1fee9..b0cf9650 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -6,6 +6,7 @@ #include #include "PluginSys.h" #include "ShareSys.h" +#include "CLogger.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -157,6 +158,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_IsMapLoading = true; m_IsLateLoadInMap = false; + g_Logger.MapChange(pMapName); + DoGlobalPluginLoads(); m_IsMapLoading = false; From 09b01f7950d05df1eb09e60d4060a1b20b84621a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Jan 2007 01:13:34 +0000 Subject: [PATCH 0257/1664] removed a few TODOs and filled out some PluginSys stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40287 --- core/interfaces/IPluginSys.h | 3 +- core/sm_srvcmds.cpp | 13 +++++- core/smn_handles.cpp | 2 +- core/systems/ForwardSys.cpp | 19 +------- core/systems/PluginSys.cpp | 85 ++++++++++++++++++++++++++---------- core/systems/PluginSys.h | 37 ++++++++++------ 6 files changed, 104 insertions(+), 55 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index dca8e2db..3f728536 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -36,9 +36,10 @@ namespace SourceMod Plugin_Running=0, /* Plugin is running */ /* All states below are unexecutable */ Plugin_Paused, /* Plugin is loaded but paused */ + Plugin_Error, /* Plugin is loaded but errored/locked */ /* All states below do not have all natives */ Plugin_Loaded, /* Plugin has passed loading and can be finalized */ - Plugin_Error, /* Plugin has a blocking error */ + Plugin_Failed, /* Plugin has a fatal failure */ Plugin_Created, /* Plugin is created but not initialized */ Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */ Plugin_BadLoad, /* Plugin failed to load */ diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index ae3a54c5..3c7d756a 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -192,6 +192,16 @@ CON_COMMAND(sm, "SourceMod Menu") META_CONPRINT(" unload - Unload a plugin\n"); META_CONPRINT(" info - Information about a plugin\n"); return; + } else if (!strcmp("credits", cmd)) { + META_CONPRINTF(" SourceMod was developed by AlliedModders, LLC.\n"); + META_CONPRINTF(" Development would not have been possible without the following people:\n"); + META_CONPRINTF(" David \"BAILOPAN\" Anderson, lead developer\n"); + META_CONPRINTF(" Borja \"faluco\" Ferrer, Core developer\n"); + META_CONPRINTF(" Scott \"Damaged Soul\" Ehlert, SourceMM developer\n"); + META_CONPRINTF(" Pavol \"PM OnoTo\" Marko, SourceHook developer\n"); + META_CONPRINTF(" Special thanks to Viper of GameConnect, and Mani\n"); + META_CONPRINTF(" http://www.sourcemod.net/\n"); + return; } else if (!strcmp("version", cmd)) { META_CONPRINT(" SourceMod Version Information:\n"); META_CONPRINTF(" SourceMod Version: \"%s\"\n", SOURCEMOD_VERSION); @@ -203,6 +213,7 @@ CON_COMMAND(sm, "SourceMod Menu") } META_CONPRINT(" SourceMod Menu:\n"); META_CONPRINT(" Usage: sm [arguments]\n"); + META_CONPRINT(" credits - Credits listing\n"); META_CONPRINT(" plugins - Plugins menu\n"); META_CONPRINT(" version - Display version information\n"); -} \ No newline at end of file +} diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index d7e5f1a1..875f8e4e 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -65,7 +65,7 @@ static cell_t sm_CloneHandle(IPluginContext *pContext, const cell_t *params) } else if (err == HandleError_None) { return new_hndl; } else { - return pContext->ThrowNativeError("Handle to clone %x is invalid (error %d)", hndl, err); + return pContext->ThrowNativeError("Handle %x cannot be cloned because it is invalid (error %d)", hndl, err); } } diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 76acd0ab..e4c2ca18 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -8,24 +8,9 @@ CForwardManager g_Forwards; * Gensis turns to its source, reduction occurs stepwise although the essence is all one. * End of line. FTL system check. * - * :TODO: Implement the manager. ho ho ho - * - * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO) - * NORMAL FUNCTIONS: - * X Push cells - * X Push cells byref (copyback tested = yes) - * X Push floats - * X Push floats byref (copyback tested = yes) - * X Push arrays (copyback tested = yes) - * X Push strings (copyback tested = yes) + * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST * VARARG FUNCTIONS: * - Pushing no varargs - * X Push vararg cells (copyback should be verified to not happen = didnt happen) - * X Push vararg cells byref (copyback tested = yes) - * X Push vararg floats (copyback should be verified to not happen = didnt happen) - * X Push vararg floats byref (copyback tested = yes) - * X Push vararg arrays (copyback tested = yes) - * X Push vararg strings (copyback tested = :TODO:) */ // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails @@ -646,7 +631,7 @@ bool CForward::AddFunction(IPluginFunction *func) return false; } - //:TODO: eventually we will tell the plugin we're using it [?] + //:IDEA: eventually we will tell the plugin we're using it [?] m_functions.push_back(func); return true; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 7432baaa..50fb4238 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -6,6 +6,7 @@ #include "sourcemm_api.h" #include "sourcemod.h" #include "CTextParsers.h" +#include "CLogger.h" CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; @@ -186,7 +187,7 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) memset(&m_ctx, 0, sizeof(m_ctx)); if (!error) { - SetErrorState(Plugin_Error, "Failed to compile (error %d)", err); + SetErrorState(Plugin_Failed, "Failed to compile (error %d)", err); } else { snprintf(error, maxlength, "Failed to compile (error %d)", err); } @@ -341,7 +342,6 @@ void CPlugin::Call_OnPluginInit() m_status = Plugin_Running; - int err; cell_t result; IPluginFunction *pFunction = GetFunctionByName("OnPluginInit"); if (!pFunction) @@ -349,13 +349,25 @@ void CPlugin::Call_OnPluginInit() return; } - /* :TODO: push our own handle */ pFunction->PushCell(m_handle); - if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) + pFunction->Execute(&result); +} + +void CPlugin::Call_OnPluginUnload() +{ + if (m_status < Plugin_Paused) { - /* :TODO: log into debugger instead */ - SetErrorState(Plugin_Error, "Runtime error %d", err); + return; } + + cell_t result; + IPluginFunction *pFunction = GetFunctionByName("OnPluginUnload"); + if (!pFunction) + { + return; + } + + pFunction->Execute(&result); } bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) @@ -388,15 +400,13 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) pFunction->PushCell(maxlength); if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) { - /* :TODO: debugging system */ - snprintf(error, maxlength, "Plugin load returned run time error %d", err); - m_status = Plugin_Error; + m_status = Plugin_Failed; return false; } - if (!result) + if (!result || m_status != Plugin_Loaded) { - m_status = Plugin_Error; + m_status = Plugin_Failed; return false; } @@ -461,8 +471,14 @@ bool CPlugin::SetPauseState(bool paused) } else if (!paused && GetStatus() != Plugin_Running) { return false; } - - /* :TODO: execute some forwards or some crap */ + + IPluginFunction *pFunction = GetFunctionByName("OnPluginPauseChange"); + if (pFunction) + { + cell_t result; + pFunction->PushCell(paused ? 1 : 0); + pFunction->Execute(&result); + } return true; } @@ -524,7 +540,11 @@ CPluginManager::CPluginManager() CPluginManager::~CPluginManager() { - //:TODO: we need a good way to free what we're holding + /* :NOTICE: + * Ignore the fact that there might be plugins in the cache. + * This usually means that Core is not being unloaded properly, and everything + * will crash anyway. YAY + */ sm_trie_destroy(m_LoadLookup); } @@ -537,7 +557,12 @@ void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) m_AllPluginsLoaded = false; if ((err=g_TextParser.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) { - /* :TODO: log the error, don't bail out though */ + g_Logger.LogError("[SOURCEMOD] Encountered fatal error parsing file \"%s\"", config); + const char *err_msg = g_TextParser.GetSMCErrorString(err); + if (err_msg) + { + g_Logger.LogError("[SOURCEMOD] Parse error encountered: \"%s\"", err_msg); + } } LoadPluginsFromDir(basedir, NULL); @@ -559,8 +584,10 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa if (!dir) { - //:TODO: write a logger and LOG THIS UP, BABY - //g_LibSys.GetPlatformError(error, err_max); + char error[256]; + g_LibSys.GetPlatformError(error, sizeof(error)); + g_Logger.LogError("[SOURCEMOD] Failure reading from plugins path: %s", localpath); + g_Logger.LogError("[SOURCEMOD] Platform returned error: %s", error); return; } @@ -622,7 +649,8 @@ void CPluginManager::LoadAutoPlugin(const char *file) } /* Check to see if we should try reloading it */ if (pPlugin->GetStatus() == Plugin_BadLoad - || pPlugin->GetStatus() == Plugin_Error) + || pPlugin->GetStatus() == Plugin_Error + || pPlugin->GetStatus() == Plugin_Failed) { UnloadPlugin(pPlugin); } @@ -663,7 +691,7 @@ void CPluginManager::LoadAutoPlugin(const char *file) } if (!g_pVM->SetCompilationOption(co, key, val)) { - pPlugin->SetErrorState(Plugin_Error, "Unable to set option (key \"%s\") (value \"%s\")", key, val); + pPlugin->SetErrorState(Plugin_Failed, "Unable to set option (key \"%s\") (value \"%s\")", key, val); pPlugin->CancelMyCompile(); co = NULL; break; @@ -819,20 +847,33 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) bool CPluginManager::UnloadPlugin(IPlugin *plugin) { CPlugin *pPlugin = (CPlugin *)plugin; - - /* :TODO: More */ - List::iterator iter; IPluginsListener *pListener; + + if (pPlugin->GetStatus() >= Plugin_Error) + { + /* Notify listeners of unloading */ + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) + { + pListener = (*iter); + pListener->OnPluginUnloaded(pPlugin); + } + /* Notify plugin */ + pPlugin->Call_OnPluginUnload(); + } + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) { + /* Notify listeners of destruction */ pListener = (*iter); pListener->OnPluginDestroyed(pPlugin); } + /* Remove us from the lookup table and linked list */ m_plugins.remove(pPlugin); sm_trie_delete(m_LoadLookup, pPlugin->m_filename); + /* Tell the plugin to delete itself */ delete pPlugin; return true; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 4f682973..7ac3d980 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -129,7 +129,7 @@ public: /** * Calls the OnPluginLoad function, and sets any failed states if necessary. * NOTE: Valid pre-states are: Plugin_Created - * If validated, plugin state is changed to Plugin_Loaded + * NOTE: If validated, plugin state is changed to Plugin_Loaded * * If the error buffer is NULL, the error message is cached locally. */ @@ -138,11 +138,21 @@ public: /** * Calls the OnPluginInit function. * NOTE: Valid pre-states are: Plugin_Created - * NOTE: Pre-state will be changed to Plugin_Running + * NOTE: Post-state will be Plugin_Running */ void Call_OnPluginInit(); + + /** + * Calls the OnPluginUnload function. + */ + void Call_OnPluginUnload(); public: time_t HasUpdatedFile(); + + /** + * Returns true if the plugin was running, but is now invalid. + */ + bool WasRunning(); protected: void UpdateInfo(); private: @@ -160,6 +170,7 @@ private: time_t m_LastAccess; IdentityToken_t *m_ident; Handle_t m_handle; + bool m_WasRunning; }; class CPluginManager : @@ -181,7 +192,7 @@ public: virtual bool MorePlugins(); virtual IPlugin *GetPlugin(); virtual void NextPlugin(); - virtual void Release(); + void Release(); public: void Reset(); private: @@ -190,22 +201,22 @@ public: }; friend class CPluginManager::CPluginIterator; public: //IPluginManager - virtual IPlugin *LoadPlugin(const char *path, + IPlugin *LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max); - virtual bool UnloadPlugin(IPlugin *plugin); - virtual IPlugin *FindPluginByContext(const sp_context_t *ctx); - virtual unsigned int GetPluginCount(); - virtual IPluginIterator *GetPluginIterator(); - virtual void AddPluginsListener(IPluginsListener *listener); - virtual void RemovePluginsListener(IPluginsListener *listener); + bool UnloadPlugin(IPlugin *plugin); + IPlugin *FindPluginByContext(const sp_context_t *ctx); + unsigned int GetPluginCount(); + IPluginIterator *GetPluginIterator(); + void AddPluginsListener(IPluginsListener *listener); + void RemovePluginsListener(IPluginsListener *listener); public: //SMGlobalClass - virtual void OnSourceModAllInitialized(); - virtual void OnSourceModShutdown(); + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); public: //IHandleTypeDispatch - virtual void OnHandleDestroy(HandleType_t type, void *object); + void OnHandleDestroy(HandleType_t type, void *object); public: /** * Loads all plugins not yet loaded From efd3a8ab5fa7e03f5431598e66498b2552f81641 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Jan 2007 07:29:09 +0000 Subject: [PATCH 0258/1664] Handle system can now unload identities safely. when an identity is removed, all handles owned by it are removed in a chain. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40288 --- core/msvc8/sourcemod_mm.vcproj | 12 +- core/sm_srvcmds.cpp | 2 + core/smn_filesystem.cpp | 14 -- core/systems/HandleSys.cpp | 280 +++++++++++++++++++-------------- core/systems/HandleSys.h | 26 +-- core/systems/ShareSys.cpp | 4 +- 6 files changed, 188 insertions(+), 150 deletions(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index e66833ad..11b7fc16 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -203,10 +203,6 @@ RelativePath="..\sm_autonatives.cpp" > - - @@ -396,6 +392,10 @@ + + @@ -408,10 +408,6 @@ RelativePath="..\interfaces\ILibrarySys.h" > - - diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 3c7d756a..0b88e3ee 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -30,6 +30,8 @@ inline const char *StatusToStr(PluginStatus st) return "Uncompiled"; case Plugin_BadLoad: return "Bad Load"; + case Plugin_Failed: + return "Failed"; default: assert(false); return "-"; diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 7a135c69..bc777175 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -428,26 +428,12 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) return 1; } -//:TODO: DEBUG CODE HERE -cell_t PrintStuff(IPluginContext *pContext, const cell_t *params) -{ - char *stuff; - pContext->LocalToString(params[1], &stuff); - - FILE *fp = fopen("c:\\debug.txt", "at"); - fprintf(fp, "%s\n", stuff); - fclose(fp); - - return 0; -} - static FileNatives s_FileNatives; REGISTER_NATIVES(filesystem) { {"OpenDirectory", sm_OpenDirectory}, {"ReadDirEntry", sm_ReadDirEntry}, - {"PrintStuff", PrintStuff},//:TODO: remove this when no longer needed {"OpenFile", sm_OpenFile}, {"DeleteFile", sm_DeleteFile}, {"ReadFileLine", sm_ReadFileLine}, diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 4c25ca7b..36ee9a57 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -231,7 +231,8 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, QHandle **in_pHandle, unsigned int *in_index, Handle_t *in_handle, - IdentityToken_t *owner) + IdentityToken_t *owner, + bool identity) { unsigned int owner_index = 0; @@ -262,7 +263,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, } /* Set essential information */ - pHandle->set = HandleSet_Used;; + pHandle->set = identity ? HandleSet_Identity : HandleSet_Used; pHandle->refcount = 1; pHandle->type = type; pHandle->serial = m_HSerial; @@ -282,8 +283,10 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, *in_index = handle; *in_handle = hash; - /* Decode the identity token */ - if (owner) + /* Decode the identity token + * For now, we don't allow nested ownership + */ + if (owner && !identity) { QHandle *pIdentity = &m_Handles[owner_index]; if (pIdentity->ch_prev == 0) @@ -319,7 +322,7 @@ void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pTok m_Types[type].typeSec.ident = pToken; } -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) +Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity) { if (!type || type >= HANDLESYS_TYPEARRAY_SIZE @@ -335,8 +338,8 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok /* Check to see if we're allowed to create this handle type */ QHandleType *pType = &m_Types[type]; if (!pType->typeSec.access[HTypeAccess_Create] - && (!pType->typeSec.ident - || pType->typeSec.ident != ident)) + && (!pType->typeSec.ident + || pType->typeSec.ident != ident)) { if (err) { @@ -350,7 +353,7 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok QHandle *pHandle; HandleError _err; - if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner)) != HandleError_None) + if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None) { if (err) { @@ -365,6 +368,11 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok return handle; } +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) +{ + return CreateHandleEx(type, object, owner, ident, err, false); +} + bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) { /* Check the type inheritance */ @@ -453,6 +461,27 @@ bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const return true; } +HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner) +{ + /* Get a new Handle ID */ + unsigned int new_index; + QHandle *pNewHandle; + Handle_t new_handle; + HandleError err; + + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None) + { + return err; + } + + pNewHandle->clone = index; + pHandle->refcount++; + + *newhandle = new_handle; + + return HandleError_None; +} + HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity) { HandleError err; @@ -477,20 +506,63 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden return HandleError_Access; } - /* Get a new Handle ID */ - unsigned int new_index; - QHandle *pNewHandle; - Handle_t new_handle; - - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None) + /* Make sure we're not cloning a clone */ + if (pHandle->clone) { - return err; + QHandle *pParent = &m_Handles[pHandle->clone]; + return CloneHandle(pParent, pHandle->clone, newhandle, newOwner); } - pNewHandle->clone = index; - pHandle->refcount++; + return CloneHandle(pHandle, index, newhandle, newOwner); +} - *newhandle = new_handle; +HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) +{ + QHandleType *pType = &m_Types[pHandle->type]; + + if (pHandle->clone) + { + /* If we're a clone, decrease the parent reference count */ + QHandle *pMaster; + unsigned int master; + + /* Note that if we ever have per-handle security, we would need to re-check + * the access on this Handle. */ + master = pHandle->clone; + pMaster = &m_Handles[master]; + + /* Release the clone now */ + ReleasePrimHandle(index); + + /* Decrement the master's reference count */ + if (--pMaster->refcount == 0) + { + /* Type should be the same but do this anyway... */ + pType = &m_Types[pMaster->type]; + pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); + ReleasePrimHandle(master); + } + } else if (pHandle->set == HandleSet_Identity) { + /* If we're an identity, skip all this stuff! + * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR + */ + ReleasePrimHandle(index); + } else { + /* Decrement, free if necessary */ + if (--pHandle->refcount == 0) + { + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + ReleasePrimHandle(index); + } else { + /* We must be cloned, so mark ourselves as freed */ + pHandle->set = HandleSet_Freed; + /* Now, unlink us, so we're not being tracked by the owner */ + if (pHandle->owner) + { + UnlinkHandleFromOwner(pHandle, index); + } + } + } return HandleError_None; } @@ -512,44 +584,7 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec return HandleError_Access; } - QHandleType *pType = &m_Types[pHandle->type]; - - bool dofree = false; - if (pHandle->clone) - { - /* If we're a clone, decrease the parent reference count */ - QHandle *pMaster; - unsigned int master; - - /* Note that if we ever have per-handle security, we would need to re-check - * the access on this Handle. */ - master = pHandle->clone; - pMaster = &m_Handles[master]; - - /* Release the clone now */ - ReleasePrimHandle(index); - - /* Decrement the master's reference count */ - if (--pMaster->refcount == 0) - { - /* Type should be the same but do this anyway... */ - pType = &m_Types[pMaster->type]; - pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); - ReleasePrimHandle(master); - } - } else { - /* Decrement, free if necessary */ - if (--pHandle->refcount == 0) - { - pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); - ReleasePrimHandle(index); - } else { - /* We must be cloned, so mark ourselves as freed */ - pHandle->set = HandleSet_Freed; - } - } - - return HandleError_None; + return FreeHandle(pHandle, index); } HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object) @@ -597,60 +632,84 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const H return HandleError_None; } +void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index) +{ + /* Unlink us if necessary */ + unsigned int ident_index; + if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None) + { + /* Uh-oh! */ + assert(pHandle->owner == 0); + return; + } + /* Note that since 0 is an invalid handle, if any of these links are 0, + * the data can still be set. + */ + QHandle *pIdentity = &m_Handles[ident_index]; + + /* Unlink case: We're the head AND tail node */ + if (index == pIdentity->ch_prev && index == pIdentity->ch_next) + { + pIdentity->ch_prev = 0; + pIdentity->ch_next = 0; + } + /* Unlink case: We're the head node */ + else if (index == pIdentity->ch_prev) { + /* Link us to the next in the chain */ + pIdentity->ch_prev = pHandle->ch_next; + /* Patch up the previous link */ + m_Handles[pHandle->ch_next].ch_prev = 0; + } + /* Unlink case: We're the tail node */ + else if (index == pIdentity->ch_next) { + /* Link us to the previous in the chain */ + pIdentity->ch_next = pHandle->ch_prev; + /* Patch up the next link */ + m_Handles[pHandle->ch_prev].ch_next = 0; + } + /* Unlink case: We're in the middle! */ + else { + /* Patch the forward reference */ + m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev; + /* Patch the backward reference */ + m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next; + } + + /* Lastly, decrease the reference count */ + pIdentity->refcount--; +} + void HandleSystem::ReleasePrimHandle(unsigned int index) { QHandle *pHandle = &m_Handles[index]; - + HandleSet set = pHandle->set; + + if (pHandle->owner && (set != HandleSet_Identity)) + { + UnlinkHandleFromOwner(pHandle, index); + } + + /* Were we an identity ourself? */ + QHandle *pLocal; + if (set == HandleSet_Identity) + { + /* Extra work to do. We need to find everything connected to this identity and release it. */ + unsigned int ch_index, old_index = 0; + while ((ch_index = pHandle->ch_next) != 0) + { + pLocal = &m_Handles[ch_index]; +#if defined _DEBUG + assert(old_index != ch_index); + assert(pLocal->set == HandleSet_Used); + old_index = ch_index; +#endif + FreeHandle(pLocal, ch_index); + } + } + pHandle->set = HandleSet_None; m_Types[pHandle->type].opened--; m_Handles[++m_FreeHandles].freeID = index; - - /* Unlink us if necessary */ - if (pHandle->owner) - { - unsigned int ident_index; - if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None) - { - /* Uh-oh! */ - assert(pHandle->owner == 0); - return; - } - /* Note that since 0 is an invalid handle, if any of these links are 0, - * the data can still be set. - */ - QHandle *pIdentity = &m_Handles[ident_index]; - - /* Unlink case: We're the head AND tail node */ - if (index == pIdentity->ch_prev && index == pIdentity->ch_next) - { - pIdentity->ch_prev = 0; - pIdentity->ch_next = 0; - } - /* Unlink case: We're the head node */ - else if (index == pIdentity->ch_prev) { - /* Link us to the next in the chain */ - pIdentity->ch_prev = pHandle->ch_next; - /* Patch up the previous link */ - m_Handles[pHandle->ch_next].ch_prev = 0; - } - /* Unlink case: We're the tail node */ - else if (index == pIdentity->ch_next) { - /* Link us to the previous in the chain */ - pIdentity->ch_next = pHandle->ch_prev; - /* Patch up the next link */ - m_Handles[pHandle->ch_prev].ch_next = 0; - } - /* Unlink case: We're in the middle! */ - else { - /* Patch the forward reference */ - m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev; - /* Patch the backward reference */ - m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next; - } - - /* Lastly, decrease the reference count */ - pIdentity->refcount--; - } } bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) @@ -737,19 +796,6 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) return true; } -void HandleSystem::MarkHandleAsIdentity(Handle_t handle) -{ - QHandle *pHandle; - unsigned int index; - - if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index) != HandleError_None) - { - return; - } - - pHandle->set = HandleSet_Identity; -} - bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) { if (pTypeAccess) diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 55c65dc4..1b651ba8 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -55,8 +55,8 @@ struct QHandle unsigned int freeID; /* ID of a free handle in the free handle chain */ /* Indexes into the handle array for owner membership. * For identity roots, these are treated as the head/tail. */ - unsigned int ch_prev; /* chained previous handle or HEAD */ - unsigned int ch_next; /* chained next handle or TAIL */ + unsigned int ch_prev; /* chained previous handle */ + unsigned int ch_next; /* chained next handle */ }; struct QHandleType @@ -97,6 +97,7 @@ public: //IHandleSystem IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err); + HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity); HandleError CloneHandle(Handle_t handle, @@ -130,26 +131,33 @@ protected: QHandle **pHandle, unsigned int *index, HandleType_t *handle, - IdentityToken_t *owner); + IdentityToken_t *owner, + bool identity=false); /** * Frees a primitive handle. Does no object freeing, only reference count, bookkeepping, * and linked list maintenance. + * If used on an Identity handle, destroys all Handles under that identity. */ void ReleasePrimHandle(unsigned int index); /** - * Sets the security owner of a type + * Sets the security owner of a type. */ void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken); - /** - * Marks a handle as an identity. - * This prevents it from being tampered with by outside stuff + /** + * Helper function to check access rights. */ - void MarkHandleAsIdentity(Handle_t handle); - bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity); + + /** + * Some wrappers for internal functions, so we can pass indexes instead of encoded handles. + */ + HandleError FreeHandle(QHandle *pHandle, unsigned int index); + void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index); + HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner); + Handle_t CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 784a69db..ef10e505 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -73,7 +73,7 @@ IdentityType_t ShareSystem::CreateIdentType(const char *name) void ShareSystem::OnHandleDestroy(HandleType_t type, void *object) { - /* We don't care here */ + /* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */ } IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) @@ -85,7 +85,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) /* :TODO: Cache? */ IdentityToken_t *pToken = new IdentityToken_t; - pToken->ident = g_HandleSys.CreateHandle(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL); + pToken->ident = g_HandleSys.CreateHandleEx(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL, true); return pToken; } From 3250194a8793b5c7d89f810567ae9c3f44e1030e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Jan 2007 08:45:38 +0000 Subject: [PATCH 0259/1664] added todo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40289 --- TODO.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 TODO.txt diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 00000000..780cedc2 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,11 @@ +things to do for a release, in priority + X finish plugin unloading + - URGENT: fix compiler's sizeof(), add countof + - do module api + - finish plugin pausing/unpausing, forwards must block execution + - do admin api + - add debugging output to logger + - finish ML api, expose through interface + - add error messages to format routine + - finish global unloading + - add hex format specifier From 8d27faa359577a6157cc7a4ebd6d68eaa2101c0f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Jan 2007 08:46:41 +0000 Subject: [PATCH 0260/1664] filled out info about pausing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40290 --- plugins/include/sourcemod.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index efd9686b..70877e73 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -69,6 +69,7 @@ forward OnPluginUnload(); /** * Called when the plugin's pause status is changing. * + * @param pause True if the plugin is being paused, false otherwise. * @noreturn */ forward OnPluginPauseChange(bool:pause); From 7ccf3a17874ae15bdf104880f89bd86f90129b57 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 12 Jan 2007 04:11:39 +0000 Subject: [PATCH 0261/1664] sizeof() now returns character array sizes correctly added untested cellsof() opreator --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40291 --- sourcepawn/compiler/sc.h | 119 ++++++++++++++++++++------------------ sourcepawn/compiler/sc1.c | 46 ++++++++++----- sourcepawn/compiler/sc2.c | 12 +++- sourcepawn/compiler/sc3.c | 63 ++++++++++++++++++-- 4 files changed, 163 insertions(+), 77 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 43d0ae15..d89b282f 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -138,6 +138,7 @@ typedef struct s_symbol { constvalue *enumlist;/* list of names for the "root" of an enumeration */ struct { cell length; /* arrays: length (size) */ + cell slength; /* if a string index, this will be set to the original size */ short level; /* number of dimensions below this level */ } array; } dim; /* for 'dimension', both functions and arrays */ @@ -223,6 +224,7 @@ typedef struct s_symbol { #define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */ +#define uCOUNTOF 0x20 /* set in the "hasdefault" field of the arginfo struct */ #define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */ #define uSIZEOF 0x80 /* set in the "hasdefault" field of the arginfo struct */ @@ -286,7 +288,7 @@ typedef struct s_stringpair { */ #define tFIRST 256 /* value of first multi-character operator */ #define tMIDDLE 280 /* value of last multi-character operator */ -#define tLAST 331 /* value of last multi-character match-able token */ +#define tLAST 332 /* value of last multi-character match-able token */ /* multi-character operators */ #define taMULT 256 /* *= */ #define taDIV 257 /* /= */ @@ -318,65 +320,66 @@ typedef struct s_stringpair { #define tBEGIN 282 #define tBREAK 283 #define tCASE 284 -#define tCHAR 285 -#define tCONST 286 -#define tCONTINUE 287 -#define tDEFAULT 288 -#define tDEFINED 289 -#define tDO 290 -#define tELSE 291 -#define tEND 292 -#define tENUM 293 -#define tEXIT 294 -#define tFOR 295 -#define tFORWARD 296 -#define tFUNCENUM 297 -#define tGOTO 298 -#define tIF 299 -#define tNATIVE 300 -#define tNEW 301 -#define tDECL 302 -#define tOPERATOR 303 -#define tPUBLIC 304 -#define tRETURN 305 -#define tSIZEOF 306 -#define tSLEEP 307 -#define tSTATE 308 -#define tSTATIC 309 -#define tSTOCK 310 -#define tSTRUCT 311 -#define tSWITCH 312 -#define tTAGOF 313 -#define tTHEN 314 -#define tWHILE 315 +#define tCELLSOF 285 +#define tCHAR 286 +#define tCONST 287 +#define tCONTINUE 288 +#define tDEFAULT 289 +#define tDEFINED 290 +#define tDO 291 +#define tELSE 292 +#define tEND 293 +#define tENUM 294 +#define tEXIT 295 +#define tFOR 296 +#define tFORWARD 297 +#define tFUNCENUM 298 +#define tGOTO 299 +#define tIF 300 +#define tNATIVE 301 +#define tNEW 302 +#define tDECL 303 +#define tOPERATOR 304 +#define tPUBLIC 305 +#define tRETURN 306 +#define tSIZEOF 307 +#define tSLEEP 308 +#define tSTATE 309 +#define tSTATIC 310 +#define tSTOCK 311 +#define tSTRUCT 312 +#define tSWITCH 313 +#define tTAGOF 314 +#define tTHEN 315 +#define tWHILE 316 /* compiler directives */ -#define tpASSERT 316 /* #assert */ -#define tpDEFINE 317 -#define tpELSE 318 /* #else */ -#define tpELSEIF 319 /* #elseif */ -#define tpEMIT 320 -#define tpENDIF 321 -#define tpENDINPUT 322 -#define tpENDSCRPT 323 -#define tpERROR 324 -#define tpFILE 325 -#define tpIF 326 /* #if */ -#define tINCLUDE 327 -#define tpLINE 328 -#define tpPRAGMA 329 -#define tpTRYINCLUDE 330 -#define tpUNDEF 331 +#define tpASSERT 317 /* #assert */ +#define tpDEFINE 318 +#define tpELSE 319 /* #else */ +#define tpELSEIF 320 /* #elseif */ +#define tpEMIT 321 +#define tpENDIF 322 +#define tpENDINPUT 323 +#define tpENDSCRPT 324 +#define tpERROR 325 +#define tpFILE 326 +#define tpIF 327 /* #if */ +#define tINCLUDE 328 +#define tpLINE 329 +#define tpPRAGMA 330 +#define tpTRYINCLUDE 331 +#define tpUNDEF 332 /* semicolon is a special case, because it can be optional */ -#define tTERM 332 /* semicolon or newline */ -#define tENDEXPR 333 /* forced end of expression */ +#define tTERM 333 /* semicolon or newline */ +#define tENDEXPR 334 /* forced end of expression */ /* other recognized tokens */ -#define tNUMBER 334 /* integer number */ -#define tRATIONAL 335 /* rational number */ -#define tSYMBOL 336 -#define tLABEL 337 -#define tSTRING 338 -#define tEXPR 339 /* for assigment to "lastst" only (see SC1.C) */ -#define tENDLESS 340 /* endless loop, for assigment to "lastst" only */ +#define tNUMBER 335 /* integer number */ +#define tRATIONAL 336 /* rational number */ +#define tSYMBOL 337 +#define tLABEL 338 +#define tSTRING 339 +#define tEXPR 340 /* for assigment to "lastst" only (see SC1.C) */ +#define tENDLESS 341 /* endless loop, for assigment to "lastst" only */ /* (reversed) evaluation of staging buffer */ #define sSTARTREORDER 0x01 @@ -562,6 +565,8 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag, int usage); SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag, int dim[],int numdim,int idxtag[]); +SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag, + int dim[],int numdim,int idxtag[],int slength); SC_FUNC int getlabel(void); SC_FUNC char *itoh(ucell val); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 91a49386..784c6138 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1930,6 +1930,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst char *str; int dim[sDIMEN_MAX]; int numdim; + int slength=0; short filenum; symbol *sym; constvalue *enumroot; @@ -1978,8 +1979,10 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst #endif dim[numdim++]=(int)size; } /* while */ - if (ident == iARRAY && tag == pc_tag_string && dim[numdim-1]) + if (ident == iARRAY && tag == pc_tag_string && dim[numdim-1]) { + slength=dim[numdim-1]; dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); + } assert(sc_curstates==0); sc_curstates=getstates(name); if (sc_curstates<0) { @@ -2142,7 +2145,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst } /* if */ litidx=0; if (sym==NULL) { /* define only if not yet defined */ - sym=addvariable(name,address,ident,sGLOBAL,tag,dim,numdim,idxtag); + sym=addvariable2(name,address,ident,sGLOBAL,tag,dim,numdim,idxtag,slength); if (sc_curstates>0) attachstatelist(sym,sc_curstates); } else { /* if declared but not yet defined, adjust the variable's address */ @@ -2198,6 +2201,7 @@ static int declloc(int fstatic) int numdim; int fconst; int staging_start; + int slength = 0; fconst=matchtoken(tCONST); do { @@ -2270,8 +2274,10 @@ static int declloc(int fstatic) } while (matchtoken('[')); if (all_constant) { /* Change the last dimension to be based on chars instead if we have a string */ - if (tag == pc_tag_string && numdim && dim[numdim-1]) + if (tag == pc_tag_string && numdim && dim[numdim-1]) { + slength = dim[numdim-1]; dim[numdim-1] = (dim[numdim-1] + sizeof(cell)-1) / sizeof(cell); + } /* Scrap the code generated */ ident = iARRAY; stgdel(_index, _code); @@ -2307,12 +2313,12 @@ static int declloc(int fstatic) /* write zeros for uninitialized fields */ while (litidxx.tags.field=fieldtag; sym->dim.array.length=size; sym->dim.array.level=0; + sym->dim.array.slength=0; sym->parent=enumsym; /* add the constant to a separate list as well */ if (enumroot!=NULL) { @@ -4082,7 +4089,7 @@ static int argcompare(arginfo *a1,arginfo *a2) * Pawn currently does not forbid them) */ } else { if (result) { - if ((a1->hasdefault & uSIZEOF)!=0 || (a1->hasdefault & uTAGOF)!=0) + if ((a1->hasdefault & uSIZEOF)!=0 || (a1->hasdefault & uTAGOF)!=0 || (a1->hasdefault & uCOUNTOF)!=0) result= a1->hasdefault==a2->hasdefault && strcmp(a1->defvalue.size.symname,a2->defvalue.size.symname)==0 && a1->defvalue.size.level==a2->defvalue.size.level; @@ -4198,7 +4205,7 @@ static int declargs(symbol *sym,int chkshadow) if (arg.ident==iREFARRAY && arg.hasdefault) free(arg.defvalue.array.data); else if (arg.ident==iVARIABLE - && ((arg.hasdefault & uSIZEOF)!=0 || (arg.hasdefault & uTAGOF)!=0)) + && ((arg.hasdefault & uSIZEOF)!=0 || (arg.hasdefault & uTAGOF)!=0) || (arg.hasdefault & uCOUNTOF)!=0) free(arg.defvalue.size.symname); free(arg.tags); } /* if */ @@ -4245,7 +4252,9 @@ static int declargs(symbol *sym,int chkshadow) assert(sym->dim.arglist!=NULL); arglist=sym->dim.arglist; for (idx=0; idxname,name); arg->hasdefault=FALSE; /* preset (most common case) */ @@ -4321,8 +4333,10 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, arg->numdim+=1; } while (matchtoken('[')); ident=iREFARRAY; /* "reference to array" (is a pointer) */ - if (checktag(tags, numtags, pc_tag_string)) + if (checktag(tags, numtags, pc_tag_string)) { + slength = arg->dim[arg->numdim - 1]; arg->dim[arg->numdim - 1] = (size + sizeof(cell) - 1) / sizeof(cell); + } if (matchtoken('=')) { lexpush(); /* initials() needs the "=" token again */ assert(litidx==0); /* at the start of a function, this is reset */ @@ -4354,6 +4368,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, size_tag_token=(unsigned char)(matchtoken(tSIZEOF) ? uSIZEOF : 0); if (size_tag_token==0) size_tag_token=(unsigned char)(matchtoken(tTAGOF) ? uTAGOF : 0); + if (size_tag_token==0) + size_tag_token=(unsigned char)(matchtoken(tCELLSOF) ? uCOUNTOF : 0); if (size_tag_token!=0) { int paranthese; if (ident==iREFERENCE) @@ -4369,7 +4385,7 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, if ((arg->defvalue.size.symname=duplicatestring(name)) == NULL) error(103); /* insufficient memory */ arg->defvalue.size.level=0; - if (size_tag_token==uSIZEOF) { + if (size_tag_token==uSIZEOF || size_tag_token==uCOUNTOF) { while (matchtoken('[')) { arg->defvalue.size.level+=(short)1; needtoken(']'); @@ -4403,8 +4419,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, error(219,name); /* variable shadows another symbol */ /* add details of type and address */ assert(numtags>0); - argsym=addvariable(name,offset,ident,sLOCAL,tags[0], - arg->dim,arg->numdim,arg->idxtag); + argsym=addvariable2(name,offset,ident,sLOCAL,tags[0], + arg->dim,arg->numdim,arg->idxtag,slength); argsym->compound=0; if (ident==iREFERENCE) argsym->usage|=uREAD; /* because references are passed back */ diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index a1efb2aa..77365892 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1877,7 +1877,7 @@ char *sc_tokens[] = { "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=", "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", - "assert", "*begin", "break", "case", "chars", "const", "continue", "default", + "assert", "*begin", "break", "case", "cellsof", "chars", "const", "continue", "default", "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", "sleep", "state", "static", "stock", "struct", "switch", "tagof", "*then", "while", @@ -2793,6 +2793,12 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag, int dim[],int numdim,int idxtag[]) +{ + return addvariable2(name,addr,ident,vclass,tag,dim,numdim,idxtag,0); +} + +SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag, + int dim[],int numdim,int idxtag[],int slength) { symbol *sym; @@ -2814,6 +2820,10 @@ SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int for (level=0; leveldim.array.length=dim[level]; + if (tag == pc_tag_string && level == numdim - 1) + top->dim.array.slength=slength; + else + top->dim.array.slength=0; top->dim.array.level=(short)(numdim-level-1); top->x.tags.index=idxtag[level]; top->parent=parent; diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index e31e195c..f7fde4c9 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -992,7 +992,7 @@ static cell array_levelsize(symbol *sym,int level) sym=finddepend(sym); assert(sym!=NULL); } /* if */ - return sym->dim.array.length; + return (sym->dim.array.slength ? sym->dim.array.slength : sym->dim.array.length); } /* hier14 @@ -1559,12 +1559,67 @@ static int hier2(value *lval) if (subsym!=NULL) subsym=finddepend(subsym); } /* for */ - if (level>sym->dim.array.level+1) + if (level>sym->dim.array.level+1) { error(28,sym->name); /* invalid subscript */ - else if (level==sym->dim.array.level+1) + } else if (level==sym->dim.array.level+1) { lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1; - else + } else { lval->constval=array_levelsize(sym,level); + } + if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL) + error(224,st); /* indeterminate array size in "sizeof" expression */ + } /* if */ + ldconst(lval->constval,sPRI); + while (paranthese--) + needtoken(')'); + return FALSE; + case tCELLSOF: + paranthese=0; + while (matchtoken('(')) + paranthese++; + tok=lex(&val,&st); + if (tok!=tSYMBOL) + return error(20,st); /* illegal symbol name */ + sym=findloc(st); + if (sym==NULL) + sym=findglb(st,sSTATEVAR); + if (sym==NULL) + return error(17,st); /* undefined symbol */ + if (sym->ident==iCONSTEXPR) + error(39); /* constant symbol has no size */ + else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) + error(72); /* "function" symbol has no size */ + else if ((sym->usage & uDEFINE)==0) + return error(17,st); /* undefined symbol (symbol is in the table, but it is "used" only) */ + clear_value(lval); + lval->ident=iCONSTEXPR; + lval->constval=1; /* preset */ + if (sym->ident==iARRAY || sym->ident==iREFARRAY) { + int level; + symbol *idxsym=NULL; + symbol *subsym=sym; + for (level=0; matchtoken('['); level++) { + idxsym=NULL; + if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) { + char *idxname; + int cmptag=subsym->x.tags.index; + tokeninfo(&val,&idxname); + if ((idxsym=findconst(idxname,&cmptag))==NULL) + error(80,idxname); /* unknown symbol, or non-constant */ + else if (cmptag>1) + error(91,idxname); /* ambiguous constant */ + } /* if */ + needtoken(']'); + if (subsym!=NULL) + subsym=finddepend(subsym); + } /* for */ + if (level>sym->dim.array.level+1) { + error(28,sym->name); /* invalid subscript */ + } else if (level==sym->dim.array.level+1) { + lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1; + } else { + lval->constval=array_levelsize(sym,level); + } if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL) error(224,st); /* indeterminate array size in "sizeof" expression */ } /* if */ From b50bb2bdcadc04ba2f1a27a8923b526ee31db61e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 12 Jan 2007 05:23:39 +0000 Subject: [PATCH 0262/1664] whoa done --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40292 --- TODO.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.txt b/TODO.txt index 780cedc2..f1885ed6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,6 +1,6 @@ things to do for a release, in priority X finish plugin unloading - - URGENT: fix compiler's sizeof(), add countof + X URGENT: fix compiler's sizeof(), add cellsof - do module api - finish plugin pausing/unpausing, forwards must block execution - do admin api From eea576cb52345c78b4ec25625ea478561c033e2d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 12 Jan 2007 23:56:02 +0000 Subject: [PATCH 0263/1664] Added new debugger logger Added format errors Paused plugins now have their forwards blocked Fixed bug where pausing a plugin wouldnt make any effect --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40293 --- TODO.txt | 6 +-- core/CDbgReporter.cpp | 73 ++++++++++++++++++++++++++++++++++ core/CDbgReporter.h | 19 +++++++++ core/msvc8/sourcemod_mm.vcproj | 10 ++++- core/sm_stringutil.cpp | 15 +++---- core/systems/ForwardSys.cpp | 4 ++ core/systems/PluginSys.cpp | 2 + 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 core/CDbgReporter.cpp create mode 100644 core/CDbgReporter.h diff --git a/TODO.txt b/TODO.txt index f1885ed6..e1049ca0 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,10 +2,10 @@ things to do for a release, in priority X finish plugin unloading X URGENT: fix compiler's sizeof(), add cellsof - do module api - - finish plugin pausing/unpausing, forwards must block execution + X finish plugin pausing/unpausing, forwards must block execution - do admin api - - add debugging output to logger + X add debugging output to logger - finish ML api, expose through interface - - add error messages to format routine + X add error messages to format routine - finish global unloading - add hex format specifier diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp new file mode 100644 index 00000000..7a02fb10 --- /dev/null +++ b/core/CDbgReporter.cpp @@ -0,0 +1,73 @@ +#include "CDbgReporter.h" +#include "CLogger.h" +#include "PluginSys.h" + +void CDbgReporter::OnSourceModAllInitialized() +{ + g_pSourcePawn->SetDebugListener(this); +} + +void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) +{ + const char *lastname; + const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename(); + int n_err = error->GetErrorCode(); + + if (n_err != SP_ERROR_NATIVE) + { + g_Logger.LogError("[SOURCEMOD] Plugin \"%s\" encountered error %d: %s", + plname, + n_err, + error->GetErrorString()); + } + + if ((lastname=error->GetLastNative(NULL)) != NULL) + { + const char *custerr; + if ((custerr=error->GetCustomErrorString()) != NULL) + { + g_Logger.LogError("[SOURCEMOD] Native \"%s\" reported: \"%s\"", lastname, custerr); + } else { + g_Logger.LogError("[SOURCEMOD] Native \"%s\" encountered a generic error.", lastname); + } + } + + if (!error->DebugInfoAvailable()) + { + g_Logger.LogError("[SOURCEMOD] Debug mode is not enabled for this plugin."); + g_Logger.LogError("[SOURCEMOD] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on", + _GetPluginIndex(ctx)); + return; + } + + CallStackInfo stk_info; + int i = 0; + g_Logger.LogError("[SOURCEMOD] Displaying call stack trace:"); + while (error->GetTraceInfo(&stk_info)) + { + g_Logger.LogError("[SOURCEMOD] [%d] Line %d, %s::%s()", + i++, + stk_info.line, + stk_info.filename, + stk_info.function); + } +} + +int CDbgReporter::_GetPluginIndex(IPluginContext *ctx) +{ + int id = 1; + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + + for (; iter->MorePlugins(); iter->NextPlugin(), id++) + { + IPlugin *pl = iter->GetPlugin(); + if (pl->GetBaseContext() == ctx) + { + iter->Release(); + return id; + } + } + + iter->Release(); + return -1; +} \ No newline at end of file diff --git a/core/CDbgReporter.h b/core/CDbgReporter.h new file mode 100644 index 00000000..7d296a46 --- /dev/null +++ b/core/CDbgReporter.h @@ -0,0 +1,19 @@ +#ifndef _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ +#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ + +#include "sp_vm_api.h" +#include "sm_globals.h" + +class CDbgReporter : + public SMGlobalClass, + public IDebugListener +{ +public: // SMGlobalClass + void OnSourceModAllInitialized(); +public: // IDebugListener + void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error); +private: + int _GetPluginIndex(IPluginContext *ctx); +}; + +#endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ \ No newline at end of file diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 11b7fc16..e7575631 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -253,6 +257,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 47d85685..c6798224 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -2,20 +2,18 @@ #include #include #include "sm_stringutil.h" +#include "CLogger.h" #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) -//:TODO: fix this macro when we have a debugger - -#define CHECK_ARGS(n)/* \ - if ((arg+n) > args) { \ - LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ - return 0; \ +#define CHECK_ARGS(x) \ + if ((arg+x) > args) { \ + g_Logger.LogError("String formatted incorrectly - parameter %d (total %d)", arg, args); \ + return 0; \ } -*/ //:TODO: review this code before we choose a license @@ -421,8 +419,7 @@ size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext } int arg; - //int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count - // either way this is only used when the above macro is fixed, until then not needed + int args = params[0]; char *buf_p; char ch; int flags; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index e4c2ca18..0622cb6a 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -255,6 +255,10 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); + if (func->GetParentPlugin()->GetStatus() == Plugin_Paused) + { + continue; + } for (unsigned int i=0; i Date: Sat, 13 Jan 2007 04:28:13 +0000 Subject: [PATCH 0264/1664] SMGlobalClass unloads now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40294 --- TODO.txt | 2 +- core/sourcemm_api.cpp | 1 + core/sourcemod.cpp | 22 ++++++++++++++++++++++ core/sourcemod.h | 5 +++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/TODO.txt b/TODO.txt index e1049ca0..73923ed6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -7,5 +7,5 @@ things to do for a release, in priority X add debugging output to logger - finish ML api, expose through interface X add error messages to format routine - - finish global unloading + X finish global unloading - add hex format specifier diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 1b593456..bf2f884c 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -23,6 +23,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen bool SourceMod_Core::Unload(char *error, size_t maxlen) { + g_SourceMod.CloseSourceMod(); return true; } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index b0cf9650..11ea03d1 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -187,6 +187,28 @@ void SourceModBase::DoGlobalPluginLoads() g_PluginSys.LoadAll_SecondPass(); } +void SourceModBase::CloseSourceMod() +{ + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModShutdown(); + pBase = pBase->m_pGlobalClassNext; + } + + /* Notify! */ + pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModAllShutdown(); + pBase = pBase->m_pGlobalClassNext; + } + + /* Rest In Peace */ + ShutdownJIT(); +} + bool SourceModBase::IsLateLoadInMap() { return m_IsLateLoadInMap; diff --git a/core/sourcemod.h b/core/sourcemod.h index 1dcec7c3..38a3d217 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -22,6 +22,11 @@ public: */ void StartSourceMod(bool late); + /** + * @brief Shuts down all SourceMod components + */ + void CloseSourceMod(); + /** * @brief Map change hook */ From 89350a178502eb46c37dd786666cb08952b2cfea Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 15 Jan 2007 00:56:39 +0000 Subject: [PATCH 0265/1664] Added capability to toggle debug state in plugins at runtime --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40295 --- core/interfaces/IPluginSys.h | 2 +- core/sm_srvcmds.cpp | 67 ++++++++++++++++++++++++++++++----- core/systems/PluginSys.cpp | 65 +++++++++++++++++++++++++++++++-- core/systems/PluginSys.h | 19 ++++++++-- core/vm/sp_vm_basecontext.cpp | 9 +++++ core/vm/sp_vm_basecontext.h | 2 ++ 6 files changed, 150 insertions(+), 14 deletions(-) diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 3f728536..45f27065 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -148,7 +148,7 @@ namespace SourceMod /** * @brief Returns a plugin's identity token. */ - virtual IdentityToken_t *GetIdentity() =0; + virtual IdentityToken_t *GetIdentity() const =0; }; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 0b88e3ee..016c46fe 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -185,6 +185,54 @@ CON_COMMAND(sm, "SourceMod Menu") iter->Release(); return; + } else if (!strcmp("debug", cmd2)) { + if (argnum < 5) + { + META_CONPRINT("Usage: sm plugins debug <#> [on|off]\n"); + return; + } + + int num = atoi(engine->Cmd_Argv(3)); + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + META_CONPRINT("Plugin index not found.\n"); + return; + } + + int res; + char *mode = engine->Cmd_Argv(4); + if ((res=strcmp("on", mode)) && strcmp("off", mode)) + { + META_CONPRINT("The only possible options are on and off.\n"); + return; + } + + bool debug; + if (!res) + { + debug = true; + } else { + debug = false; + } + + CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + if (debug && pl->IsDebugging()) + { + META_CONPRINT("This plugin is already in debug mode.\n"); + return; + } else if (!debug && !pl->IsDebugging()) { + META_CONPRINT("Debug mode is already disabled in this plugin.\n"); + return; + } + + if (pl->ToggleDebugMode(debug)) + { + META_CONPRINTF("Toggled debug mode on plugin %s successfully.\n", pl->GetFilename()); + return; + } else { + META_CONPRINTF("Could not toggle debug mode in plugin %s.\n", pl->GetFilename()); + return; + } } } @@ -193,23 +241,24 @@ CON_COMMAND(sm, "SourceMod Menu") META_CONPRINT(" load - Load a plugin\n"); META_CONPRINT(" unload - Unload a plugin\n"); META_CONPRINT(" info - Information about a plugin\n"); + META_CONPRINT(" debug - Toggles debug mode in a plugin\n"); return; } else if (!strcmp("credits", cmd)) { - META_CONPRINTF(" SourceMod was developed by AlliedModders, LLC.\n"); - META_CONPRINTF(" Development would not have been possible without the following people:\n"); - META_CONPRINTF(" David \"BAILOPAN\" Anderson, lead developer\n"); - META_CONPRINTF(" Borja \"faluco\" Ferrer, Core developer\n"); - META_CONPRINTF(" Scott \"Damaged Soul\" Ehlert, SourceMM developer\n"); - META_CONPRINTF(" Pavol \"PM OnoTo\" Marko, SourceHook developer\n"); - META_CONPRINTF(" Special thanks to Viper of GameConnect, and Mani\n"); - META_CONPRINTF(" http://www.sourcemod.net/\n"); + META_CONPRINT(" SourceMod was developed by AlliedModders, LLC.\n"); + META_CONPRINT(" Development would not have been possible without the following people:\n"); + META_CONPRINT(" David \"BAILOPAN\" Anderson, lead developer\n"); + META_CONPRINT(" Borja \"faluco\" Ferrer, Core developer\n"); + META_CONPRINT(" Scott \"Damaged Soul\" Ehlert, SourceMM developer\n"); + META_CONPRINT(" Pavol \"PM OnoTo\" Marko, SourceHook developer\n"); + META_CONPRINT(" Special thanks to Viper of GameConnect, and Mani\n"); + META_CONPRINT(" http://www.sourcemod.net/\n"); return; } else if (!strcmp("version", cmd)) { META_CONPRINT(" SourceMod Version Information:\n"); META_CONPRINTF(" SourceMod Version: \"%s\"\n", SOURCEMOD_VERSION); META_CONPRINTF(" JIT Version: %s (%s)\n", g_pVM->GetVMName(), g_pVM->GetVersionString()); META_CONPRINTF(" JIT Settings: %s\n", g_pVM->GetCPUOptimizations()); - META_CONPRINTF(" http://www.sourcemod.net/\n"); + META_CONPRINT(" http://www.sourcemod.net/\n"); return; } } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 1d1551b6..d7f3bb07 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -485,11 +485,53 @@ bool CPlugin::SetPauseState(bool paused) return true; } -IdentityToken_t *CPlugin::GetIdentity() +IdentityToken_t *CPlugin::GetIdentity() const { return m_ident; } +bool CPlugin::ToggleDebugMode(bool debug) +{ + int err; + + if (!IsRunnable()) + { + return false; + } + + if ((debug && IsDebugging()) || (!debug && !IsDebugging())) + { + return false; + } + ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin); + if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0")) + { + return false; + } + sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err); + + memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size); + new_ctx->hp = m_ctx.ctx->hp; + new_ctx->sp = m_ctx.ctx->sp; + new_ctx->frm = m_ctx.ctx->frm; + new_ctx->dbreak = m_ctx.ctx->dbreak; + new_ctx->context = m_ctx.ctx->context; + memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user)); + + g_pVM->FreeContext(m_ctx.ctx); + m_ctx.ctx = new_ctx; + m_ctx.base->SetContext(new_ctx); + + UpdateInfo(); + + return true; +} + +bool CPlugin::IsRunnable() const +{ + return (m_status <= Plugin_Paused) ? true : false; +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -1152,7 +1194,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) return true; } -bool CPluginManager::IsLateLoadTime() +bool CPluginManager::IsLateLoadTime() const { return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap()); } @@ -1210,3 +1252,22 @@ IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) return pPlugin; } + +CPlugin *CPluginManager::GetPluginByOrder(int num) +{ + if (num < 1 || num > (int)GetPluginCount()) + { + return NULL; + } + + CPlugin *pl; + int id = 1; + + IPluginIterator *iter = GetPluginIterator(); + for (; iter->MorePlugins() && idNextPlugin(), id++) {} + + pl = (CPlugin *)(iter->GetPlugin()); + iter->Release(); + + return pl; +} \ No newline at end of file diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 7ac3d980..5a585655 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -94,7 +94,7 @@ public: virtual const sp_plugin_t *GetPluginStructure() const; virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); - virtual IdentityToken_t *GetIdentity(); + virtual IdentityToken_t *GetIdentity() const; public: /** * Creates a plugin object with default values. @@ -146,6 +146,16 @@ public: * Calls the OnPluginUnload function. */ void Call_OnPluginUnload(); + + /** + * Toggles debug mode in the plugin + */ + bool ToggleDebugMode(bool debug); + + /** + * Returns true if a plugin is usable. + */ + bool IsRunnable() const; public: time_t HasUpdatedFile(); @@ -242,7 +252,7 @@ public: /** * Returns whether anything loaded will be a late load. */ - bool IsLateLoadTime(); + bool IsLateLoadTime() const; /** * Adds natives from core into the native pool. @@ -253,6 +263,11 @@ public: * Converts a Handle to an IPlugin if possible. */ IPlugin *PluginFromHandle(Handle_t handle, HandleError *err); + + /** + * Finds a plugin based on its index. (starts on index 1) + */ + CPlugin *GetPluginByOrder(int num); private: /** * Recursively loads all plugins in the given directory. diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index a1bf02f1..6b63ae53 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -29,6 +29,15 @@ BaseContext::BaseContext(sp_context_t *_ctx) m_CustomMsg = false; } +void BaseContext::SetContext(sp_context_t *_ctx) +{ + if (!_ctx) + { + return; + } + ctx = _ctx; +} + IVirtualMachine *BaseContext::GetVirtualMachine() { return (IVirtualMachine *)ctx->vmbase; diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 5b495509..7ba4d0f6 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -52,6 +52,8 @@ namespace SourcePawn virtual int LookupFile(ucell_t addr, const char **filename); virtual int LookupFunction(ucell_t addr, const char **name); virtual int LookupLine(ucell_t addr, uint32_t *line); + public: + void SetContext(sp_context_t *_ctx); private: void SetErrorMessage(const char *msg, va_list ap); private: From 9f2c0e370e2292ed93547c3bab7a93ec6d6a1f3d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 15 Jan 2007 03:28:55 +0000 Subject: [PATCH 0266/1664] forwards are now really unregistered --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40296 --- core/systems/ForwardSys.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 0622cb6a..6011cdcc 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -144,6 +144,7 @@ void CForwardManager::ReleaseForward(IForward *forward) void CForwardManager::ForwardFree(CForward *fwd) { m_FreeForwards.push(fwd); + m_managed.remove(fwd); } CForward *CForwardManager::ForwardMake() From d74e35f1d55aa5759d6bf02945340cfece344118 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 Jan 2007 22:08:43 +0000 Subject: [PATCH 0267/1664] changed default logging method --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40297 --- core/CLogger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index d458c02c..c6a6bb71 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -6,7 +6,7 @@ CLogger g_Logger; void CLogger::OnSourceModStartup(bool late) { //:TODO: read these options from a file, dont hardcode them - InitLogger(LoggingMode_PerMap, true); + InitLogger(LoggingMode_Daily, true); } void CLogger::OnSourceModAllShutdown() From f4cd98191e8365d157a021b8ba86bcb1290dce44 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 Jan 2007 22:09:11 +0000 Subject: [PATCH 0268/1664] small optimization, fixed a corruption bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40298 --- core/sm_memtable.cpp | 4 ++-- core/sm_memtable.h | 5 ++++- core/systems/PluginInfoDatabase.cpp | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/sm_memtable.cpp b/core/sm_memtable.cpp index f2f4ad63..dc15dff2 100644 --- a/core/sm_memtable.cpp +++ b/core/sm_memtable.cpp @@ -70,10 +70,10 @@ int BaseStringTable::AddString(const char *string) return idx; } -const char *BaseStringTable::GetString(int str) +/*const char *BaseStringTable::GetString(int str) { return (const char *)m_table.GetAddress(str); -} +}*/ void BaseStringTable::Reset() { diff --git a/core/sm_memtable.h b/core/sm_memtable.h index 0fe631a9..35066982 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -46,7 +46,10 @@ public: /** * Given an index into the string table, returns the associated string. */ - const char *GetString(int str); + inline const char *GetString(int str) + { + return (const char *)m_table.GetAddress(str); + } /** * Scraps the string table. For caching purposes, the memory diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index 3783bf4b..47d04d8e 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -168,6 +168,8 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, plugin->opts_size *= 2; } int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table); + /* in case it resized */ + plugin = (PluginSettings *)memtab->GetAddress(cur_plugin); if (plugin->optarray != -1) { void *oldtable = memtab->GetAddress(plugin->optarray); From 9331fe2a5c99e56e90b1b4b219aa3ea62fc617e1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 Jan 2007 22:33:50 +0000 Subject: [PATCH 0269/1664] small notice to srvcommands preparation for extension system import --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40299 --- core/interfaces/IExtensionSys.h | 165 ++++++++++++++++++++++++++++++++ core/interfaces/IModuleSys.h | 93 ------------------ core/msvc8/sourcemod_mm.vcproj | 118 ++++++++++++----------- core/sm_platform.h | 2 + core/sm_srvcmds.cpp | 5 +- 5 files changed, 233 insertions(+), 150 deletions(-) create mode 100644 core/interfaces/IExtensionSys.h delete mode 100644 core/interfaces/IModuleSys.h diff --git a/core/interfaces/IExtensionSys.h b/core/interfaces/IExtensionSys.h new file mode 100644 index 00000000..7dd23455 --- /dev/null +++ b/core/interfaces/IExtensionSys.h @@ -0,0 +1,165 @@ +#ifndef _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ + +#include +#include + +namespace SourceMod +{ + class IExtensionInterface; + + /** + * @brief Encapsulates an IExtension. + */ + class IExtension + { + public: + /** + * @brief Returns the extension's API interface + * + * @return An IExtensionInterface pointer. + */ + virtual IExtensionInterface *GetAPI() =0; + + /** + * @brief Returns the filename of the extension, relative to the + * extension folder. + * + * @return A string containing the extension file name. + */ + virtual const char *GetFilename() =0; + + /** + * @brief Returns the extension's identity token. + * + * @return An IdentityToken_t pointer. + */ + virtual IdentityToken_t *GetIdentity() =0; + }; + + #define SMINTERFACE_EXTENSIONAPI_VERSION 1 + + /** + * @brief The interface an extension must expose. + */ + class IExtensionInterface + { + public: + /** + * @brief Called when the extension is loaded. + * + * @param me Pointer back to extension. + * @param sys Pointer to interface sharing system of SourceMod. + * @param error Error buffer to print back to, if any. + * @param err_max Maximum size of error buffer. + * @param late If this extension was loaded "late" (i.e. manually). + * @return True if load should continue, false otherwise. + */ + virtual bool OnExtensionLoad(IExtension *me, + IShareSys *sys, + char *error, + size_t err_max, + bool late) =0; + + /** + * @brief Called when the extension is about to be unloaded. + */ + virtual void OnExtensionUnload() =0; + + /** + * @brief Called when all extensions are loaded (loading cycle is done). + * If loaded late, this will be called right after OnExtensionLoad(). + */ + virtual void OnExtensionsAllLoaded() =0; + + /** + * @brief Called when your pause state is about to change. + * + * @param pause True if pausing, false if unpausing. + */ + virtual void OnExtensionPauseChange(bool pause) =0; + + virtual unsigned int GetExtensionVersion() + { + return SMINTERFACE_EXTENSIONAPI_VERSION; + } + + /** + * @brief Returns true if the extension is Metamod-dependent. + */ + virtual bool IsMetamodExtension() =0; + public: + virtual const char *GetExtensionName() =0; + virtual const char *GetExtensionURL() =0; + virtual const char *GetExtensionTag() =0; + virtual const char *GetExtensionAuthor() =0; + virtual const char *GetExtensionVerString() =0; + virtual const char *GetExtensionDescription() =0; + virtual const char *GetExtensionDateString() =0; + }; + + #define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager" + #define SMINTERFACE_EXTENSIONMANAGER_VERSION 1 + + enum ExtensionLifetime + { + ExtLifetime_Forever, //Extension will never be unloaded automatically + ExtLifetime_Map, //Extension will be unloaded at the end of the map + }; + + class IExtensionManager : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_EXTENSIONMANAGER_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_EXTENSIONMANAGER_VERSION; + } + public: + /** + * @brief Loads a extension into the extension system. + * + * @param path Path to extension file, relative to the extensions folder. + * @param lifetime Lifetime of the extension. + * @param error Error buffer. + * @param err_max Maximum error buffer length. + * @return New IExtension on success, NULL on failure. + */ + virtual IExtension *LoadModule(const char *path, + ExtensionLifetime lifetime, + char *error, + size_t err_max) =0; + + /** + * @brief Returns the number of plugins that will be unloaded when this + * module is unloaded. + * + * @param pExt IExtension pointer. + * @param optional Optional pointer to be filled with # of plugins that + * are dependent, but will continue safely. NOT YET USED. + * @return Total number of dependent plugins. + */ + virtual unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional) =0; + + /** + * @brief Returns whether or not the extension can be unloaded. + * + * @param pExt IExtension pointer. + * @return True if unloading is possible, false otherwise. + */ + virtual bool IsExtensionUnloadable(IExtension *pExtension) =0; + + /** + * @brief Attempts to unload a module. + * + * @param pExt IExtension pointer. + * @return True if successful, false otherwise. + */ + virtual bool UnloadModule(IExtension *pExt) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ diff --git a/core/interfaces/IModuleSys.h b/core/interfaces/IModuleSys.h deleted file mode 100644 index fa13f3ba..00000000 --- a/core/interfaces/IModuleSys.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ -#define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ - -#include -#include - -namespace SourceMod -{ - class IModuleInterface; - - class IModule - { - public: - virtual IModuleInterface *GetModuleInfo() =0; - virtual const char *GetFilename() =0; - virtual IdentityToken_t GetIdentityToken() =0; - }; - - class IModuleInterface - { - public: - /** - * @brief Called when the module is loaded. - * - * @param me Pointer back to module. - * @param token Identity token handle. - * @param sys Pointer to interface sharing system of SourceMod. - * @param error Error buffer to print back to, if any. - * @param err_max Maximum size of error buffer. - * @param late If this module was loaded "late" (i.e. manually). - * @return True if load should continue, false otherwise. - */ - virtual bool OnModuleLoad(IModule *me, - IdentityToken_t token, - IShareSys *sys, - char *error, - size_t err_max, - bool late) =0; - - /** - * @brief Called when the module is unloaded. - * - * @param force True if this unload will be forced. - * @param error Error message buffer. - * @param err_max Maximum siez of error buffer. - * @return True on success, false to request no unload. - */ - virtual bool OnModuleUnload(bool force, char *error, size_t err_max) =0; - - /** - * @brief Called when your pause state is about to change. - * - * @param pause True if pausing, false if unpausing. - */ - virtual void OnPauseChange(bool pause) =0; - public: - virtual const char *GetModuleName() =0; - virtual const char *GetModuleVersion() =0; - virtual const char *GetModuleURL() =0; - virtual const char *GetModuleTags() =0; - virtual const char *GetModuleAuthor() =0; - }; - - #define SMINTERFACE_MODULEMANAGER_NAME "IModuleManager" - #define SMINTERFACE_MODULEMANAGER_VERSION 1 - - enum ModuleLifetime - { - ModuleLifetime_Forever, //Module will never be unloaded automatically - ModuleLifetime_Map, //Module will be unloaded at the end of the map - ModuleLifetime_Dependent, //Module will be unloaded once its dependencies are gone - }; - - class IModuleManager : public SMInterface - { - public: - /** - * @brief Loads a module into the module system. - * - * @param path Path to module file, relative to the modules folder. - * @param lifetime Lifetime of the module. - * @param error Error buffer. - * @param err_max Maximum error buffer length. - * @return New IModule on success, NULL on failure. - */ - virtual IModule *LoadModule(const char *path, - ModuleLifetime lifetime, - char *error, - size_t err_max); - }; -}; - -#endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index e7575631..ac77eff7 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -372,6 +376,10 @@ RelativePath="..\systems\CFunction.cpp" > + + @@ -430,6 +438,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -530,58 +590,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/sm_platform.h b/core/sm_platform.h index 2487611f..05171cd8 100644 --- a/core/sm_platform.h +++ b/core/sm_platform.h @@ -23,6 +23,7 @@ #define PLATFORM_MAX_PATH MAX_PATH #define PLATFORM_SEP_CHAR '\\' #define PLATFORM_SEP_ALTCHAR '/' +#define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) #else if defined __linux__ #define PLATFORM_LINUX #define PLATFORM_POSIX @@ -32,6 +33,7 @@ #define PLATFORM_LIB_EXT "so" #define PLATFORM_SEP_CHAR '/' #define PLATFORM_SEP_ALTCHAR '\\' +#define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) #endif #endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 016c46fe..9f0a49bf 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -227,10 +227,11 @@ CON_COMMAND(sm, "SourceMod Menu") if (pl->ToggleDebugMode(debug)) { - META_CONPRINTF("Toggled debug mode on plugin %s successfully.\n", pl->GetFilename()); + META_CONPRINTF("Successfully toggled debug mode on plugin %s.\n", pl->GetFilename()); return; } else { - META_CONPRINTF("Could not toggle debug mode in plugin %s.\n", pl->GetFilename()); + /* :TODO: ... we should be getting an actual error message here */ + META_CONPRINTF("Could not toggle debug mode on plugin %s.\n", pl->GetFilename()); return; } } From c97d129c4d9549f5296d7975f43b2942ef820be2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 Jan 2007 23:10:59 +0000 Subject: [PATCH 0270/1664] temporarily removed optimization that is breaking zlib somehow --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40300 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 9 +++++++++ sourcepawn/compiler/pawncc.c | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index 34f0e739..bc6dacc2 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -116,6 +116,7 @@ /> + + + base + header_size; /* get initial size estimate */ - pHdr->disksize = (uint32_t)compressBound(pHdr->imagesize); + pHdr->disksize = (uint32_t)compressBound(pHdr->imagesize) * 2; zcmp = (Bytef *)malloc(pHdr->disksize); if ((err=compress2(zcmp, @@ -451,7 +451,7 @@ int main(int argc, char *argv[]) != Z_OK) { free(zcmp); - pc_printf("Unable to compress (Z): error %d", err); + pc_printf("Unable to compress (Z): error %d\n", err); pc_printf("Falling back to no compression."); memfile_write(bin_file, proper, From 5366d05ce266ec7db1b34981bca692c44571f228 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 19:03:29 +0000 Subject: [PATCH 0271/1664] Fixed a serious potential corruption bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40301 --- core/systems/CFunction.cpp | 8 ++++---- core/systems/CFunction.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 1d6bf769..6f123518 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -90,7 +90,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr info->flags = inarray ? copyback : 0; info->marked = true; - info->size = cells; + info->size = cells * sizeof(cell_t); m_params[m_curparam] = info->local_addr; m_curparam++; @@ -162,7 +162,7 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ skip_localtostr: info->flags = cp_flags; info->orig_addr = (cell_t *)string; - info->size = cells; + info->size = len; return SP_ERROR_NONE; } @@ -229,13 +229,13 @@ int CFunction::Execute(cell_t *result) { if (temp_info[numparams].orig_addr) { - if (temp_info[numparams].size == 1) + if (temp_info[numparams].size == sizeof(cell_t)) { *temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr; } else { memcpy(temp_info[numparams].orig_addr, temp_info[numparams].phys_addr, - temp_info[numparams].size * sizeof(cell_t)); + temp_info[numparams].size); } } } diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h index d68d837d..f0f05897 100644 --- a/core/systems/CFunction.h +++ b/core/systems/CFunction.h @@ -11,7 +11,7 @@ struct ParamInfo cell_t local_addr; /* Local address to free */ cell_t *phys_addr; /* Physical address of our copy */ cell_t *orig_addr; /* Original address to copy back to */ - ucell_t size; /* Size of array in cells */ + ucell_t size; /* Size of array in bytes */ }; class CPlugin; From f7545a848f2edbf2604a3ce0a2d76e4554cc9ede Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 19:34:32 +0000 Subject: [PATCH 0272/1664] Fixed an off-by-one bug in the handle system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40302 --- core/systems/HandleSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 36ee9a57..f42ba3c3 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -756,7 +756,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) if (pType->opened) { QHandle *pHandle; - for (unsigned int i=1; iset || pHandle->type != type) From 03277707b56f463bd8f017116511e41ea361b4f5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 19:41:21 +0000 Subject: [PATCH 0273/1664] initial import of extension API and SDK as well as auto-loading --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40303 --- core/interfaces/IExtensionSys.h | 9 +- core/systems/ExtensionSys.cpp | 222 +++++++++++++++++++ core/systems/ExtensionSys.h | 58 +++++ core/systems/PluginSys.cpp | 242 ++++++++++++--------- core/systems/PluginSys.h | 12 +- extensions/sdk/extension.cpp | 5 + extensions/sdk/extension.h | 49 +++++ extensions/sdk/sdk.sln | 26 +++ extensions/sdk/sdk.vcproj | 364 ++++++++++++++++++++++++++++++++ plugins/include/core.inc | 27 +++ plugins/include/sourcemod.inc | 2 +- 11 files changed, 905 insertions(+), 111 deletions(-) create mode 100644 core/systems/ExtensionSys.cpp create mode 100644 core/systems/ExtensionSys.h create mode 100644 extensions/sdk/extension.cpp create mode 100644 extensions/sdk/extension.h create mode 100644 extensions/sdk/sdk.sln create mode 100644 extensions/sdk/sdk.vcproj create mode 100644 plugins/include/core.inc diff --git a/core/interfaces/IExtensionSys.h b/core/interfaces/IExtensionSys.h index 7dd23455..16f25474 100644 --- a/core/interfaces/IExtensionSys.h +++ b/core/interfaces/IExtensionSys.h @@ -14,6 +14,11 @@ namespace SourceMod class IExtension { public: + /** + * @brief Returns whether or not the extension is properly loaded. + */ + virtual bool IsLoaded() =0; + /** * @brief Returns the extension's API interface * @@ -128,7 +133,7 @@ namespace SourceMod * @param err_max Maximum error buffer length. * @return New IExtension on success, NULL on failure. */ - virtual IExtension *LoadModule(const char *path, + virtual IExtension *LoadExtension(const char *path, ExtensionLifetime lifetime, char *error, size_t err_max) =0; @@ -158,7 +163,7 @@ namespace SourceMod * @param pExt IExtension pointer. * @return True if successful, false otherwise. */ - virtual bool UnloadModule(IExtension *pExt) =0; + virtual bool UnloadExtension(IExtension *pExt) =0; }; }; diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp new file mode 100644 index 00000000..f7287315 --- /dev/null +++ b/core/systems/ExtensionSys.cpp @@ -0,0 +1,222 @@ +#include "ExtensionSys.h" +#include "LibrarySys.h" +#include "ShareSys.h" +#include "CLogger.h" + +CExtensionManager g_Extensions; +IdentityType_t g_ExtType; + +CExtension::CExtension(const char *filename, char *error, size_t err_max) +{ + m_File.assign(filename); + m_pAPI = NULL; + m_pIdentToken = NULL; + + char path[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); + + m_pLib = g_LibSys.OpenLibrary(path, error, err_max); + + if (m_pLib == NULL) + { + return; + } + + typedef IExtensionInterface *(*GETAPI)(); + GETAPI pfnGetAPI = NULL; + + if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL) + { + m_pLib->CloseLibrary(); + m_pLib = NULL; + snprintf(error, err_max, "Unable to find extension entry point"); + return; + } + + m_pAPI = pfnGetAPI(); + if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION) + { + m_pLib->CloseLibrary(); + m_pLib = NULL; + snprintf(error, err_max, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION); + return; + } + + if (m_pAPI->IsMetamodExtension()) + { + /* :TODO: STUFF */ + } + + m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType); + + if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, g_SourceMod.IsLateLoadInMap())) + { + if (m_pAPI->IsMetamodExtension()) + { + /* :TODO: stuff */ + } + m_pAPI = NULL; + m_pLib->CloseLibrary(); + m_pLib = NULL; + g_ShareSys.DestroyIdentity(m_pIdentToken); + m_pIdentToken = NULL; + return; + } +} + +CExtension::~CExtension() +{ + if (m_pAPI) + { + m_pAPI->OnExtensionUnload(); + } + + if (m_pIdentToken) + { + g_ShareSys.DestroyIdentity(m_pIdentToken); + } + + if (m_pLib) + { + m_pLib->CloseLibrary(); + } +} + +void CExtension::SetError(const char *error) +{ + m_Error.assign(error); +} + +IExtensionInterface *CExtension::GetAPI() +{ + return m_pAPI; +} + +const char *CExtension::GetFilename() +{ + return m_File.c_str(); +} + +IdentityToken_t *CExtension::GetIdentity() +{ + return m_pIdentToken; +} + +bool CExtension::IsLoaded() +{ + return (m_pLib != NULL); +} + +void CExtensionManager::OnSourceModAllInitialized() +{ + g_ExtType = g_ShareSys.CreateIdentType("EXTENSION"); +} + +void CExtensionManager::OnSourceModShutdown() +{ + g_ShareSys.DestroyIdentType(g_ExtType); +} + +IExtension *CExtensionManager::LoadAutoExtension(const char *path) +{ + char error[256]; + CExtension *p = new CExtension(path, error, sizeof(error)); + + if (!p->IsLoaded()) + { + g_Logger.LogError("[SOURCEMOD] Unable to load extension \"%s\": %s", path, error); + p->SetError(error); + } + + m_Libs.push_back(p); + + return p; +} + +IExtension *CExtensionManager::FindExtensionByFile(const char *file) +{ + List::iterator iter; + CExtension *pExt; + + /* Make sure the file direction is right */ + char path[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); + + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + pExt = (*iter); + if (strcmp(pExt->GetFilename(), path) == 0) + { + return pExt; + } + } + + return NULL; +} + +IExtension *CExtensionManager::FindExtensionByName(const char *ext) +{ + List::iterator iter; + CExtension *pExt; + IExtensionInterface *pAPI; + const char *name; + + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + pExt = (*iter); + if (!pExt->IsLoaded()) + { + continue; + } + if ((pAPI = pExt->GetAPI()) == NULL) + { + continue; + } + name = pAPI->GetExtensionName(); + if (!name) + { + continue; + } + if (strcmp(name, ext) == 0) + { + return pExt; + } + } + + return NULL; +} + +IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max) +{ + CExtension *pExt = new CExtension(file, error, err_max); + + /* :NOTE: lifetime is currently ignored */ + + if (!pExt->IsLoaded()) + { + delete pExt; + return NULL; + } + + m_Libs.push_back(pExt); + + return pExt; +} + +bool CExtensionManager::UnloadExtension(IExtension *pExt) +{ + /* :TODO: implement */ + return true; +} + +unsigned int CExtensionManager::NumberOfPluginDependents(IExtension *pExt, unsigned int *optional) +{ + /* :TODO: implement */ + return 0; +} + +bool CExtensionManager::IsExtensionUnloadable(IExtension *pExtension) +{ + /* :TODO: implement */ + return true; +} diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h new file mode 100644 index 00000000..8d7a69cf --- /dev/null +++ b/core/systems/ExtensionSys.h @@ -0,0 +1,58 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_ + +#include +#include +#include +#include +#include "sm_globals.h" + +using namespace SourceMod; +using namespace SourceHook; + +class CExtension : public IExtension +{ +public: + CExtension(const char *filename, char *error, size_t maxlen); + ~CExtension(); +public: //IExtension + IExtensionInterface *GetAPI(); + const char *GetFilename(); + IdentityToken_t *GetIdentity(); + bool IsLoaded(); +public: + void SetError(const char *error); +private: + IdentityToken_t *m_pIdentToken; + IExtensionInterface *m_pAPI; + String m_File; + ILibrary *m_pLib; + String m_Error; +}; + +class CExtensionManager : + public IExtensionManager, + public SMGlobalClass +{ +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: //IExtensionManager + IExtension *LoadExtension(const char *path, + ExtensionLifetime lifetime, + char *error, + size_t err_max); + unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional); + bool IsExtensionUnloadable(IExtension *pExtension); + bool UnloadExtension(IExtension *pExt); + IExtension *FindExtensionByFile(const char *file); + IExtension *FindExtensionByName(const char *ext); +public: + IExtension *LoadAutoExtension(const char *path); +private: + List m_Libs; +}; + +extern CExtensionManager g_Extensions; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_ diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index d7f3bb07..627c4f9a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -7,6 +7,7 @@ #include "sourcemod.h" #include "CTextParsers.h" #include "CLogger.h" +#include "ExtensionSys.h" CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; @@ -31,6 +32,16 @@ CPlugin::CPlugin(const char *file) CPlugin::~CPlugin() { + if (m_handle) + { + HandleSecurity sec; + sec.pOwner = g_PluginSys.GetIdentity(); + sec.pIdentity = sec.pOwner; + + g_HandleSys.FreeHandle(m_handle, &sec); + g_ShareSys.DestroyIdentity(m_ident); + } + if (m_ctx.base) { delete m_ctx.base; @@ -72,16 +83,6 @@ CPlugin::~CPlugin() g_pSourcePawn->FreeFromMemory(m_plugin); m_plugin = NULL; } - - if (m_handle) - { - HandleSecurity sec; - sec.pOwner = g_PluginSys.GetIdentity(); - sec.pIdentity = sec.pOwner; - - g_HandleSys.FreeHandle(m_handle, &sec); - g_ShareSys.DestroyIdentity(m_ident); - } } void CPlugin::InitIdentity() @@ -100,18 +101,16 @@ CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) g_LibSys.PathFormat(fullpath, sizeof(fullpath), "%s/plugins/%s", g_SourceMod.GetSMBaseDir(), file); FILE *fp = fopen(fullpath, "rb"); + CPlugin *pPlugin = new CPlugin(file); + if (!fp) { if (error) { snprintf(error, maxlength, "Unable to open file"); - return NULL; - } else { - CPlugin *pPlugin = new CPlugin(file); - snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Unable to open file"); - pPlugin->m_status = Plugin_BadLoad; - return pPlugin; } + pPlugin->m_status = Plugin_BadLoad; + return pPlugin; } int err; @@ -122,19 +121,15 @@ CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) if (error) { snprintf(error, maxlength, "Error %d while parsing plugin", err); - return NULL; - } else { - CPlugin *pPlugin = new CPlugin(file); - snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Error %d while parsing plugin", err); - pPlugin->m_status = Plugin_BadLoad; - return pPlugin; } + pPlugin->m_status = Plugin_BadLoad; + return pPlugin; } fclose(fp); - CPlugin *pPlugin = new CPlugin(file); pPlugin->m_plugin = pl; + return pPlugin; } @@ -185,10 +180,8 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) if (!m_ctx.ctx) { memset(&m_ctx, 0, sizeof(m_ctx)); - if (!error) + if (error) { - SetErrorState(Plugin_Failed, "Failed to compile (error %d)", err); - } else { snprintf(error, maxlength, "Failed to compile (error %d)", err); } return false; @@ -377,12 +370,6 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) return false; } - if (!error) - { - error = m_errormsg; - maxlength = sizeof(m_errormsg); - } - m_status = Plugin_Loaded; int err; @@ -676,20 +663,20 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa //well i have discovered that gabe newell is very fat, so i wrote this comment now //:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin() -void CPluginManager::LoadAutoPlugin(const char *file) +bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max) { /** * Does this plugin already exist? */ CPlugin *pPlugin; - if (sm_trie_retrieve(m_LoadLookup, file, (void **)&pPlugin)) + if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin)) { /* First check the type */ PluginType type = pPlugin->GetType(); if (type == PluginType_Private || type == PluginType_Global) { - return; + return true; } /* Check to see if we should try reloading it */ if (pPlugin->GetStatus() == Plugin_BadLoad @@ -700,7 +687,7 @@ void CPluginManager::LoadAutoPlugin(const char *file) } } - pPlugin = CPlugin::CreatePlugin(file, NULL, 0); + pPlugin = CPlugin::CreatePlugin(path, error, err_max); assert(pPlugin != NULL); @@ -717,8 +704,7 @@ void CPluginManager::LoadAutoPlugin(const char *file) unsigned int setcount = m_PluginInfo.GetSettingsNum(); for (unsigned int i=0; iSetCompilationOption(co, key, val)) { - pPlugin->SetErrorState(Plugin_Failed, "Unable to set option (key \"%s\") (value \"%s\")", key, val); + if (error) + { + snprintf(error, err_max, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); + } pPlugin->CancelMyCompile(); + pPlugin->m_status = Plugin_Failed; co = NULL; break; } @@ -744,100 +734,71 @@ void CPluginManager::LoadAutoPlugin(const char *file) } } + /* Do the actual compiling */ if (co) { pPlugin->FinishMyCompile(NULL, 0); co = NULL; } - /* We don't care about the return value */ + /* Get the status */ if (pPlugin->GetStatus() == Plugin_Created) { AddCoreNativesToPlugin(pPlugin); pPlugin->InitIdentity(); - pPlugin->Call_AskPluginLoad(NULL, 0); + pPlugin->Call_AskPluginLoad(error, err_max); } - AddPlugin(pPlugin); + if (_plugin) + { + *_plugin = pPlugin; + } + + return (pPlugin->GetStatus() == Plugin_Loaded); } IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) { - /* See if this plugin is already loaded... reformat to get sep chars right */ - char checkpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(checkpath, sizeof(checkpath), "%s", path); + CPlugin *pl; - /** - * In manually loading a plugin, any sort of load error causes a deletion. - * This is because it's assumed manually loaded plugins will not be managed. - * For managed plugins, we need the UI to report them properly. - */ - - CPlugin *pPlugin; - if (sm_trie_retrieve(m_LoadLookup, checkpath, (void **)&pPlugin)) + if (!_LoadPlugin(&pl, path, debug, type, error, err_max)) { - snprintf(error, err_max, "Plugin file is already loaded"); + delete pl; return NULL; } - pPlugin = CPlugin::CreatePlugin(path, error, err_max); + AddPlugin(pl); - if (!pPlugin) + return pl; +} + +void CPluginManager::LoadAutoPlugin(const char *plugin) +{ + CPlugin *pl; + char error[255] = "Unknown error"; + + if (!_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) { - return NULL; + g_Logger.LogError("[SOURCEMOD] Failed to load plugin \"%s\": %s", plugin, error); + pl->SetErrorState(Plugin_Failed, "%s", error); } - ICompilation *co = pPlugin->StartMyCompile(g_pVM); - if (!co || (debug && !g_pVM->SetCompilationOption(co, "debug", "1"))) - { - snprintf(error, err_max, "Unable to start%s compilation", debug ? " debug" : ""); - pPlugin->CancelMyCompile(); - delete pPlugin; - return NULL; - } - - if (!pPlugin->FinishMyCompile(error, err_max)) - { - delete pPlugin; - return NULL; - } - - pPlugin->m_type = type; - - AddCoreNativesToPlugin(pPlugin); - - pPlugin->InitIdentity(); - - /* Finally, ask the plugin if it wants to be loaded */ - if (!pPlugin->Call_AskPluginLoad(error, err_max)) - { - delete pPlugin; - return NULL; - } - - AddPlugin(pPlugin); - - return pPlugin; + AddPlugin(pl); } void CPluginManager::AddPlugin(CPlugin *pPlugin) { - m_plugins.push_back(pPlugin); - sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin); - List::iterator iter; IPluginsListener *pListener; + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) { pListener = (*iter); pListener->OnPluginCreated(pPlugin); } - /* If the second pass was already completed, we have to run the pass on this plugin */ - if (m_AllPluginsLoaded && pPlugin->GetStatus() == Plugin_Loaded) - { - RunSecondPass(pPlugin); - } + m_plugins.push_back(pPlugin); + sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin); } void CPluginManager::LoadAll_SecondPass() @@ -850,16 +811,77 @@ void CPluginManager::LoadAll_SecondPass() pPlugin = (*iter); if (pPlugin->GetStatus() == Plugin_Loaded) { - RunSecondPass(pPlugin); + /* :TODO: fix */ + RunSecondPass(pPlugin, NULL, 0); } } + m_AllPluginsLoaded = true; } -void CPluginManager::RunSecondPass(CPlugin *pPlugin) +bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength) { - /* Tell this plugin to finish initializing itself */ - pPlugin->Call_OnPluginInit(); + /* Find any extensions this plugin needs */ + struct _ext + { + cell_t name; + cell_t file; + cell_t autoload; + cell_t required; + } *ext; + + IPluginContext *pBase = pPlugin->GetBaseContext(); + uint32_t num = pBase->GetPubVarsNum(); + sp_pubvar_t *pubvar; + IExtension *pExt; + char path[PLATFORM_MAX_PATH+1]; + char *file, *name; + for (uint32_t i=0; iGetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE) + { + continue; + } + if (strncmp(pubvar->name, "__ext_", 6) == 0) + { + ext = (_ext *)pubvar->offs; + if (!ext->required && !ext->autoload) + { + continue; + } + if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE) + { + continue; + } + if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE) + { + continue; + } + snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT); + pExt = NULL; + /* Attempt to auto-load if necessary */ + if (ext->autoload) + { + pExt = g_Extensions.LoadAutoExtension(path); + } + if (ext->required && !pExt) + { + if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL) + { + pExt = g_Extensions.FindExtensionByName(name); + } + } + if (ext->required && (!pExt || !pExt->IsLoaded())) + { + if (error) + { + snprintf(error, maxlength, "Required extension \"%s\" (file \"%s\") not found", name, file); + } + pPlugin->m_status = Plugin_Failed; + return false; + } + } + } /* Finish by telling all listeners */ List::iterator iter; @@ -869,6 +891,11 @@ void CPluginManager::RunSecondPass(CPlugin *pPlugin) pListener = (*iter); pListener->OnPluginLoaded(pPlugin); } + + /* Tell this plugin to finish initializing itself */ + pPlugin->Call_OnPluginInit(); + + return true; } void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) @@ -891,6 +918,13 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) bool CPluginManager::UnloadPlugin(IPlugin *plugin) { CPlugin *pPlugin = (CPlugin *)plugin; + + /* This prevents removal during insertion or anything else weird */ + if (m_plugins.find(pPlugin) == m_plugins.end()) + { + return false; + } + List::iterator iter; IPluginsListener *pListener; @@ -1215,6 +1249,12 @@ void CPluginManager::OnSourceModAllInitialized() void CPluginManager::OnSourceModShutdown() { + List::iterator iter; + while ( (iter = m_plugins.begin()) != m_plugins.end() ) + { + UnloadPlugin((*iter)); + } + g_HandleSys.RemoveType(g_PluginType, m_MyIdent); g_ShareSys.DestroyIdentType(g_PluginIdent); g_ShareSys.DestroyIdentity(m_MyIdent); @@ -1270,4 +1310,4 @@ CPlugin *CPluginManager::GetPluginByOrder(int num) iter->Release(); return pl; -} \ No newline at end of file +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 5a585655..83c11f7a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -269,17 +269,15 @@ public: */ CPlugin *GetPluginByOrder(int num); private: + bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); + + void LoadAutoPlugin(const char *plugin); + /** * Recursively loads all plugins in the given directory. */ void LoadPluginsFromDir(const char *basedir, const char *localdir); - /** - * Loads a plugin using automatic information. - * The file must be relative to the plugins folder. - */ - void LoadAutoPlugin(const char *file); - /** * Adds a plugin object. This is wrapped by LoadPlugin functions. */ @@ -288,7 +286,7 @@ private: /** * Runs the second loading pass on a plugin. */ - void RunSecondPass(CPlugin *pPlugin); + bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength); /** * Adds any globally registered natives to a plugin diff --git a/extensions/sdk/extension.cpp b/extensions/sdk/extension.cpp new file mode 100644 index 00000000..9065e47d --- /dev/null +++ b/extensions/sdk/extension.cpp @@ -0,0 +1,5 @@ +#include "extension.h" + +Sample g_Sample; + +SMEXT_LINK(&g_Sample); diff --git a/extensions/sdk/extension.h b/extensions/sdk/extension.h new file mode 100644 index 00000000..d93261e1 --- /dev/null +++ b/extensions/sdk/extension.h @@ -0,0 +1,49 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +#include "smsdk_ext.h" + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class Sample : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + //virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + //virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); +public: +#if defined SMEXT_CONF_METAMOD + /** + * Read smext_base.h for documentation on these. + */ + + //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif +}; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/sdk/sdk.sln b/extensions/sdk/sdk.sln new file mode 100644 index 00000000..99656471 --- /dev/null +++ b/extensions/sdk/sdk.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug - Metamod|Win32 = Debug - Metamod|Win32 + Debug|Win32 = Debug|Win32 + Release - Metamod|Win32 = Release - Metamod|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.ActiveCfg = Debug - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.Build.0 = Debug - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.ActiveCfg = Release - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.Build.0 = Release - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/sdk/sdk.vcproj b/extensions/sdk/sdk.vcproj new file mode 100644 index 00000000..d4ccdd57 --- /dev/null +++ b/extensions/sdk/sdk.vcproj @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/include/core.inc b/plugins/include/core.inc new file mode 100644 index 00000000..03678840 --- /dev/null +++ b/plugins/include/core.inc @@ -0,0 +1,27 @@ +#if defined _core_included + #endinput +#endif +#define _core_included + +#define SOURCEMOD_PLUGINAPI_VERSION 1 +struct PlVers +{ + version, +}; + +public PlVers:__version = +{ + version = SOURCEMOD_PLUGINAPI_VERSION, +}; + +struct Extension +{ + const String:name[], /* Short name */ + const String:file[], /* Default file name */ + bool:autoload, /* Whether or not to auto-load */ + bool:required, /* Whether or not to require */ +}; + +#define AUTOLOAD_EXTENSIONS +#define REQUIRE_EXTENSIONS + diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 70877e73..b942d78f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -16,10 +16,10 @@ struct Plugin const String:url[], /* Plugin URL */ }; +#include #include #include #include -#include /** * Declare this as a struct in your plugin to expose its information. From e4602813e82a0bf75c48954f635e11c24bd4ff03 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 19:42:05 +0000 Subject: [PATCH 0274/1664] initial import of SDK proper --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40304 --- extensions/sdk/smsdk_config.h | 27 ++++ extensions/sdk/smsdk_ext.cpp | 263 ++++++++++++++++++++++++++++++++++ extensions/sdk/smsdk_ext.h | 139 ++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 extensions/sdk/smsdk_config.h create mode 100644 extensions/sdk/smsdk_ext.cpp create mode 100644 extensions/sdk/smsdk_ext.h diff --git a/extensions/sdk/smsdk_config.h b/extensions/sdk/smsdk_config.h new file mode 100644 index 00000000..488dedf1 --- /dev/null +++ b/extensions/sdk/smsdk_config.h @@ -0,0 +1,27 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "Sample Extension" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SAMPLE" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +//#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/sdk/smsdk_ext.cpp b/extensions/sdk/smsdk_ext.cpp new file mode 100644 index 00000000..4b2ad1dd --- /dev/null +++ b/extensions/sdk/smsdk_ext.cpp @@ -0,0 +1,263 @@ +#include +#include "smsdk_ext.h" + +IShareSys *g_pShareSys = NULL; +IdentityToken_t *myself = NULL; +IHandleSys *g_pHandleSys = NULL; + +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me->GetIdentity(); + +#if defined SMEXT_CONF_METAMOD + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + + return SDK_OnLoad(error, err_max, late); +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ + m_WeGotPauseChange = true; + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ + m_WeAreUnloaded = true; + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; +ISmmPlugin *g_PLAPI = NULL; +SourceHook::ISourceHook *g_SHPtr = NULL; +ISmmAPI *g_SMAPI = NULL; + +IVEngineServer *engine = NULL; +IServerGameDLL *gamedll = NULL; + +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif diff --git a/extensions/sdk/smsdk_ext.h b/extensions/sdk/smsdk_ext.h new file mode 100644 index 00000000..420e7e93 --- /dev/null +++ b/extensions/sdk/smsdk_ext.h @@ -0,0 +1,139 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +#include "smsdk_config.h" +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + virtual bool IsMetamodExtension(); + virtual void OnExtensionPauseChange(bool state); + virtual const char *GetExtensionName(); + virtual const char *GetExtensionURL(); + virtual const char *GetExtensionTag(); + virtual const char *GetExtensionAuthor(); + virtual const char *GetExtensionVerString(); + virtual const char *GetExtensionDescription(); + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual const char *GetAuthor(); + virtual const char *GetName(); + virtual const char *GetDescription(); + virtual const char *GetURL(); + virtual const char *GetLicense(); + virtual const char *GetVersion(); + virtual const char *GetDate(); + virtual const char *GetLogTag(); + virtual bool Unload(char *error, size_t maxlen); + virtual bool Pause(char *error, size_t maxlen); + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IdentityToken_t *myself; +extern IHandleSys *g_pHandleSys; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ From 4a1c111350bf461a64da76833bdca6026c66b705 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 20:36:09 +0000 Subject: [PATCH 0275/1664] fixed up bad includes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40305 --- core/CLogger.cpp | 50 +++++++++++++++++++++++++++++++++++++++++- core/CLogger.h | 52 ++------------------------------------------ core/CTranslator.cpp | 2 ++ 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index c6a6bb71..1c2bb2bb 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -1,5 +1,9 @@ +#include +#include "sourcemod.h" +#include "sourcemm_api.h" #include "CLogger.h" #include "systems/Librarysys.h" +#include "sm_version.h" CLogger g_Logger; @@ -293,4 +297,48 @@ void CLogger::_PrintToHL2Log(const char *fmt, va_list ap) msg[len] = '\0'; engine->LogPrint(msg); -} \ No newline at end of file +} + +const char *CLogger::GetLogFileName(LogType type) const +{ + switch (type) + { + case LogType_Normal: + { + return m_NrmFileName.c_str(); + } + case LogType_Error: + { + return m_ErrFileName.c_str(); + } + default: + { + return ""; + } + } +} + +LoggingMode CLogger::GetLoggingMode() const +{ + return m_mode; +} + +void CLogger::EnableLogging() +{ + if (m_Active) + { + return; + } + m_Active = true; + LogMessage("Logging enabled manually by user."); +} + +void CLogger::DisableLogging() +{ + if (!m_Active) + { + return; + } + LogMessage("Logging disabled manually by user."); + m_Active = false; +} diff --git a/core/CLogger.h b/core/CLogger.h index e08a8cb8..89ad0175 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -1,12 +1,8 @@ #ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_ #define _INCLUDE_SOURCEMOD_CLOGGER_H_ -#include "sm_globals.h" -#include -#include "sourcemm_api.h" #include -#include "sourcemod.h" -#include "sm_version.h" +#include "sm_globals.h" using namespace SourceHook; @@ -58,48 +54,4 @@ private: extern CLogger g_Logger; -inline const char *CLogger::GetLogFileName(LogType type) const -{ - switch (type) - { - case LogType_Normal: - { - return m_NrmFileName.c_str(); - } - case LogType_Error: - { - return m_ErrFileName.c_str(); - } - default: - { - return ""; - } - } -} - -inline LoggingMode CLogger::GetLoggingMode() const -{ - return m_mode; -} - -inline void CLogger::EnableLogging() -{ - if (m_Active) - { - return; - } - m_Active = true; - LogMessage("Logging enabled manually by user."); -} - -inline void CLogger::DisableLogging() -{ - if (!m_Active) - { - return; - } - LogMessage("Logging disabled manually by user."); - m_Active = false; -} - -#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_ \ No newline at end of file +#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_ diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 723a984a..80caa037 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -1,9 +1,11 @@ #include +#include #include "CTranslator.h" #include "CLogger.h" #include "CTextParsers.h" #include "LibrarySys.h" #include "sm_stringutil.h" +#include "sourcemod.h" CTranslator g_Translator; From 0182ef0d5fa534702d422451096521b9403a2cf5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 20:38:22 +0000 Subject: [PATCH 0276/1664] fixed log tag --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40306 --- core/CLogger.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 1c2bb2bb..fe96469d 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -48,7 +48,7 @@ void CLogger::_NewMapFile() FILE *fp = fopen(m_NrmFileName.c_str(), "w"); if (!fp) { - g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; return; } else { @@ -207,7 +207,7 @@ void CLogger::LogMessage(const char *vafmt, ...) g_SMAPI->ConPrintf("L %s: %s\n", date, msg); return; print_error: - g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; } @@ -252,7 +252,7 @@ void CLogger::LogError(const char *vafmt, ...) fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); } else { - g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; return; } From aec325b19ccffbd60985757889f5551d4823d853 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 Jan 2007 20:40:00 +0000 Subject: [PATCH 0277/1664] test of svn rev id --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40307 --- core/sm_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sm_version.h b/core/sm_version.h index 1aaaa6d4..c22253af 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -5,10 +5,10 @@ * @file Contains SourceMod version information. */ -#define SOURCEMOD_VERSION "0.0.0.0" -#define SOURCEMOD_V_MAJOR 0 +#define SOURCEMOD_VERSION "1.0.0.$Id$" +#define SOURCEMOD_V_MAJOR 1 #define SOURCEMOD_V_MINOR 0 #define SOURCEMOD_V_REV 0 -#define SOURCEMOD_V_BUILD 0 +#define SOURCEMOD_V_BUILD $Id$ #endif //_INCLUDE_SOURCEMOD_VERSION_H_ From 1857f29efc92d2c2f72538f1ba50286fc4bac382 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 17 Jan 2007 03:01:38 +0000 Subject: [PATCH 0279/1664] Added extension loading/unloading Extended SDK for interface sharing Completed Metamod extension support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40309 --- core/interfaces/IExtensionSys.h | 72 +++++++++---- core/interfaces/IShareSys.h | 9 +- core/sourcemm_api.cpp | 10 ++ core/sourcemm_api.h | 1 + core/systems/ExtensionSys.cpp | 179 ++++++++++++++++++++++++++++++-- core/systems/ExtensionSys.h | 15 ++- core/systems/ShareSys.cpp | 71 ++++++------- core/systems/ShareSys.h | 8 +- extensions/sdk/sdk.vcproj | 12 ++- extensions/sdk/smsdk_ext.cpp | 18 +++- extensions/sdk/smsdk_ext.h | 2 +- 11 files changed, 305 insertions(+), 92 deletions(-) diff --git a/core/interfaces/IExtensionSys.h b/core/interfaces/IExtensionSys.h index 16f25474..9982832e 100644 --- a/core/interfaces/IExtensionSys.h +++ b/core/interfaces/IExtensionSys.h @@ -7,6 +7,7 @@ namespace SourceMod { class IExtensionInterface; + typedef void * ITERATOR; /** * @brief Encapsulates an IExtension. @@ -40,6 +41,32 @@ namespace SourceMod * @return An IdentityToken_t pointer. */ virtual IdentityToken_t *GetIdentity() =0; + + /** + * @brief Retrieves the extension dependency list for this extension. + * + * @param pOwner Optional pointer to store the first interface's owner. + * @param pInterface Optional pointer to store the first interface. + * @return An ITERATOR pointer for the results, or NULL if no results at all. + */ + virtual ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) =0; + + /** + * @brief Finds the next dependency in the dependency list. + * + * @param iter Pointer to iterator from FindFirstDependency. + * @param pOwner Optional pointer to store the interface's owner. + * @param pInterface Optional pointer to store the interface. + * @return True if there are more results after this, false otherwise. + */ + virtual bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) =0; + + /** + * @brief Frees an ITERATOR handle from FindFirstDependency. + * + * @param iter Pointer to iterator to free. + */ + virtual void FreeDependencyIterator(ITERATOR *iter) =0; }; #define SMINTERFACE_EXTENSIONAPI_VERSION 1 @@ -49,6 +76,11 @@ namespace SourceMod */ class IExtensionInterface { + public: + virtual unsigned int GetExtensionVersion() + { + return SMINTERFACE_EXTENSIONAPI_VERSION; + } public: /** * @brief Called when the extension is loaded. @@ -84,16 +116,29 @@ namespace SourceMod */ virtual void OnExtensionPauseChange(bool pause) =0; - virtual unsigned int GetExtensionVersion() + /** + * @brief Asks the extension whether it's safe to remove an external interface it's using. + * If it's not safe, return false, and the extension will be unloaded afterwards. + * NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources. + * + * @param pInterface Pointer to interface being dropped. + * @return True to continue, false to unload this extension afterwards. + */ + virtual bool QueryInterfaceDrop(SMInterface *pInterface) { - return SMINTERFACE_EXTENSIONAPI_VERSION; + return true; } /** - * @brief Returns true if the extension is Metamod-dependent. + * @brief Notifies the extension that an external interface it uses is being removed. + * + * @param pInterface Pointer to interface being dropped. */ - virtual bool IsMetamodExtension() =0; + virtual void NotifyInterfaceDrop(SMInterface *pInterface) + { + } public: + virtual bool IsMetamodExtension() =0; virtual const char *GetExtensionName() =0; virtual const char *GetExtensionURL() =0; virtual const char *GetExtensionTag() =0; @@ -138,25 +183,6 @@ namespace SourceMod char *error, size_t err_max) =0; - /** - * @brief Returns the number of plugins that will be unloaded when this - * module is unloaded. - * - * @param pExt IExtension pointer. - * @param optional Optional pointer to be filled with # of plugins that - * are dependent, but will continue safely. NOT YET USED. - * @return Total number of dependent plugins. - */ - virtual unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional) =0; - - /** - * @brief Returns whether or not the extension can be unloaded. - * - * @param pExt IExtension pointer. - * @return True if unloading is possible, false otherwise. - */ - virtual bool IsExtensionUnloadable(IExtension *pExtension) =0; - /** * @brief Attempts to unload a module. * diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index d4f6db0f..9569eb5c 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -7,6 +7,7 @@ namespace SourceMod { + class IExtension; struct IdentityToken_t; typedef unsigned int HandleType_t; typedef HandleType_t IdentityType_t; @@ -53,11 +54,11 @@ namespace SourceMod /** * @brief Adds an interface to the global interface system. * + * @param myself Object adding this interface, in order to track dependencies. * @param iface Interface pointer (must be unique). - * @param token Parent token of the module/interface. * @return True on success, false otherwise. */ - virtual bool AddInterface(SMInterface *iface, IdentityToken_t *token) =0; + virtual bool AddInterface(IExtension *myself, SMInterface *iface) =0; /** * @brief Requests an interface from the global interface system. @@ -65,12 +66,12 @@ namespace SourceMod * * @param iface_name Interface name. * @param iface_vers Interface version to attempt to match. - * @param token Object requesting this interface, in order to track dependencies. + * @param myself Object requesting this interface, in order to track dependencies. * @param pIface Pointer to store the return value in. */ virtual bool RequestInterface(const char *iface_name, unsigned int iface_vers, - IdentityToken_t *token, + IExtension *myself, SMInterface **pIface) =0; /** diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index bf2f884c..e81cf40f 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -7,6 +7,7 @@ SourceMod_Core g_SourceMod_Core; IVEngineServer *engine = NULL; IServerGameDLL *gamedll = NULL; IServerGameClients *serverClients = NULL; +ISmmPluginManager *g_pMMPlugins = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -18,6 +19,15 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); + if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL) + { + if (error) + { + snprintf(error, maxlen, "Unable to find interface %s", MMIFACE_PLMANAGER); + } + return false; + } + return g_SourceMod.InitializeSourceMod(error, maxlen, late); } diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 8dea8b0b..7e753363 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -31,6 +31,7 @@ extern SourceMod_Core g_SourceMod_Core; extern IVEngineServer *engine; extern IServerGameDLL *gamedll; extern IServerGameClients *serverClients; +extern ISmmPluginManager *g_pMMPlugins; PLUGIN_GLOBALVARS(); diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index f7287315..3d9375ce 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -2,6 +2,7 @@ #include "LibrarySys.h" #include "ShareSys.h" #include "CLogger.h" +#include "sourcemm_api.h" CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -11,6 +12,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_File.assign(filename); m_pAPI = NULL; m_pIdentToken = NULL; + m_PlId = 0; char path[PLATFORM_MAX_PATH+1]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); @@ -44,7 +46,8 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) if (m_pAPI->IsMetamodExtension()) { - /* :TODO: STUFF */ + bool already; + m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, err_max); } m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType); @@ -53,7 +56,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) { if (m_pAPI->IsMetamodExtension()) { - /* :TODO: stuff */ + if (m_PlId) + { + char dummy[255]; + g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy)); + m_PlId = 0; + } } m_pAPI = NULL; m_pLib->CloseLibrary(); @@ -69,6 +77,10 @@ CExtension::~CExtension() if (m_pAPI) { m_pAPI->OnExtensionUnload(); + if (m_PlId) + { + g_pMMPlugins->Unload(m_PlId, true, NULL, 0); + } } if (m_pIdentToken) @@ -107,6 +119,81 @@ bool CExtension::IsLoaded() return (m_pLib != NULL); } +void CExtension::AddDependency(IfaceInfo *pInfo) +{ + m_Deps.push_back(*pInfo); +} + +ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) +{ + List::iterator iter = m_Deps.begin(); + + if (iter == m_Deps.end()) + { + return NULL; + } + + if (pOwner) + { + *pOwner = (*iter).owner; + } + if (pInterface) + { + *pInterface = (*iter).iface; + } + + List::iterator *pIter = new List::iterator(iter); + + return (ITERATOR *)pIter; +} + +bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) +{ + List::iterator *pIter = (List::iterator *)iter; + List::iterator _iter; + + if (_iter == m_Deps.end()) + { + return false; + } + + _iter++; + + if (pOwner) + { + *pOwner = (*_iter).owner; + } + if (pInterface) + { + *pInterface = (*_iter).iface; + } + + *pIter = _iter; + + if (_iter == m_Deps.end()) + { + return false; + } + + return true; +} + +void CExtension::FreeDependencyIterator(ITERATOR *iter) +{ + List::iterator *pIter = (List::iterator *)iter; + + delete pIter; +} + +void CExtension::AddInterface(SMInterface *pInterface) +{ + m_Interfaces.push_back(pInterface); +} + +/********************* + * EXTENSION MANAGER * + *********************/ + void CExtensionManager::OnSourceModAllInitialized() { g_ExtType = g_ShareSys.CreateIdentType("EXTENSION"); @@ -119,6 +206,12 @@ void CExtensionManager::OnSourceModShutdown() IExtension *CExtensionManager::LoadAutoExtension(const char *path) { + IExtension *pAlready; + if ((pAlready=FindExtensionByFile(path)) != NULL) + { + return pAlready; + } + char error[256]; CExtension *p = new CExtension(path, error, sizeof(error)); @@ -188,6 +281,12 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext) IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max) { + IExtension *pAlready; + if ((pAlready=FindExtensionByFile(file)) != NULL) + { + return pAlready; + } + CExtension *pExt = new CExtension(file, error, err_max); /* :NOTE: lifetime is currently ignored */ @@ -203,20 +302,80 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime return pExt; } -bool CExtensionManager::UnloadExtension(IExtension *pExt) +void CExtensionManager::BindDependency(IExtension *pOwner, IfaceInfo *pInfo) { - /* :TODO: implement */ - return true; + CExtension *pExt = (CExtension *)pOwner; + + pExt->AddDependency(pInfo); } -unsigned int CExtensionManager::NumberOfPluginDependents(IExtension *pExt, unsigned int *optional) +void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface) { - /* :TODO: implement */ - return 0; + CExtension *pExt = (CExtension *)pOwner; + + pExt->AddInterface(pInterface); } -bool CExtensionManager::IsExtensionUnloadable(IExtension *pExtension) +bool CExtensionManager::UnloadExtension(IExtension *_pExt) { - /* :TODO: implement */ + if (!_pExt) + { + return false; + } + + CExtension *pExt = (CExtension *)_pExt; + + if (m_Libs.find(pExt) == m_Libs.end()) + { + return false; + } + + /* First remove us from internal lists */ + g_ShareSys.RemoveInterfaces(_pExt); + m_Libs.remove(pExt); + + List UnloadQueue; + + /* Handle dependencies */ + if (pExt->IsLoaded()) + { + /* Notify and/or unload all dependencies */ + List::iterator c_iter; + CExtension *pDep; + IExtensionInterface *pAPI; + for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++) + { + pDep = (*c_iter); + if ((pAPI=pDep->GetAPI()) == NULL) + { + continue; + } + /* Now, get its dependency list */ + bool dropped = false; + List::iterator i_iter = pDep->m_Deps.begin(); + while (i_iter != pDep->m_Deps.end()) + { + if ((*i_iter).owner == _pExt) + { + if (!dropped && !pAPI->QueryInterfaceDrop((*i_iter).iface)) + { + dropped = true; + } + pAPI->NotifyInterfaceDrop((*i_iter).iface); + i_iter = pDep->m_Deps.erase(i_iter); + } else { + i_iter++; + } + } + } + } + + List::iterator iter; + for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++) + { + /* NOTE: This is safe because the unload function backs out of anything not present */ + UnloadExtension((*iter)); + } + return true; } diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index 8d7a69cf..7bf05f1c 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -6,12 +6,15 @@ #include #include #include "sm_globals.h" +#include "ShareSys.h" +#include using namespace SourceMod; using namespace SourceHook; class CExtension : public IExtension { + friend class CExtensionManager; public: CExtension(const char *filename, char *error, size_t maxlen); ~CExtension(); @@ -20,14 +23,22 @@ public: //IExtension const char *GetFilename(); IdentityToken_t *GetIdentity(); bool IsLoaded(); + ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface); + bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface); + void FreeDependencyIterator(ITERATOR *iter); public: void SetError(const char *error); + void AddDependency(IfaceInfo *pInfo); + void AddInterface(SMInterface *pInterface); private: IdentityToken_t *m_pIdentToken; IExtensionInterface *m_pAPI; String m_File; ILibrary *m_pLib; String m_Error; + List m_Deps; + List m_Interfaces; + PluginId m_PlId; }; class CExtensionManager : @@ -42,13 +53,13 @@ public: //IExtensionManager ExtensionLifetime lifetime, char *error, size_t err_max); - unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional); - bool IsExtensionUnloadable(IExtension *pExtension); bool UnloadExtension(IExtension *pExt); IExtension *FindExtensionByFile(const char *file); IExtension *FindExtensionByName(const char *ext); public: IExtension *LoadAutoExtension(const char *path); + void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); + void AddInterface(IExtension *pOwner, SMInterface *pInterface); private: List m_Libs; }; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index ef10e505..bf91c851 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -1,5 +1,6 @@ #include "ShareSys.h" #include "HandleSys.h" +#include "ExtensionSys.h" ShareSystem g_ShareSys; @@ -90,7 +91,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) return pToken; } -bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) +bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface) { if (!iface) { @@ -99,17 +100,9 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) IfaceInfo info; + info.owner = myself; info.iface = iface; - info.token = token; - if (token) - { - /* If we're an external object, we have to do this */ - info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot(), NULL); - } else { - info.handle = 0; - } - m_Interfaces.push_back(info); return true; @@ -117,28 +110,13 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) bool ShareSystem::RequestInterface(const char *iface_name, unsigned int iface_vers, - IdentityToken_t *token, + IExtension *mysql, SMInterface **pIface) { - /* If Some yahoo.... SOME HOOLIGAN... some NO GOOD DIRTY - * HORRIBLE PERSON passed in a token that we don't recognize.... - * Punish them. - */ - HandleSecurity sec; - - sec.pIdentity = GetIdentRoot(); - sec.pOwner = NULL; - - if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, &sec, NULL)) - { - return false; - } - /* See if the interface exists */ List::iterator iter; SMInterface *iface; - IdentityToken_t *iface_owner; - Handle_t iface_handle; + IExtension *iface_owner; bool found = false; for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++) { @@ -149,8 +127,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, if (iface->GetInterfaceVersion() == iface_vers || iface->IsVersionCompatible(iface_vers)) { - iface_owner = info.token; - iface_handle = info.handle; + iface_owner = info.owner; found = true; break; } @@ -162,23 +139,21 @@ bool ShareSystem::RequestInterface(const char *iface_name, return false; } - /* If something external owns this, we need to track it. */ + /* Add a dependency node */ if (iface_owner) { - Handle_t newhandle; - if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, &sec) - != HandleError_None) - { - return false; - } - /** - * Now we can deny module loads based on dependencies. - */ + IfaceInfo info; + info.iface = iface; + info.owner = iface_owner; + g_Extensions.BindDependency(iface_owner, &info); } - /* :TODO: finish */ + if (pIface) + { + *pIface = iface; + } - return NULL; + return true; } void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) @@ -202,3 +177,17 @@ void ShareSystem::DestroyIdentType(IdentityType_t type) g_HandleSys.RemoveType(type, GetIdentRoot()); } +void ShareSystem::RemoveInterfaces(IExtension *pExtension) +{ + List::iterator iter = m_Interfaces.begin(); + + while (iter != m_Interfaces.end()) + { + if ((*iter).owner == pExtension) + { + iter = m_Interfaces.erase(iter); + } else { + iter++; + } + } +} diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index c8b8aecf..2aa86f82 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -20,8 +20,7 @@ namespace SourceMod struct IfaceInfo { SMInterface *iface; - IdentityToken_t *token; - Handle_t handle; + IExtension *owner; }; class ShareSystem : @@ -32,10 +31,10 @@ class ShareSystem : public: ShareSystem(); public: //IShareSys - bool AddInterface(SMInterface *iface, IdentityToken_t *token); + bool AddInterface(IExtension *myself, SMInterface *pIface); bool RequestInterface(const char *iface_name, unsigned int iface_vers, - IdentityToken_t *token, + IExtension *mysql, SMInterface **pIface); void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]); IdentityType_t CreateIdentType(const char *name); @@ -51,6 +50,7 @@ public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); public: IdentityToken_t *CreateCoreIdentity(); + void RemoveInterfaces(IExtension *pExtension); public: inline IdentityToken_t *GetIdentRoot() { diff --git a/extensions/sdk/sdk.vcproj b/extensions/sdk/sdk.vcproj index d4ccdd57..fb4199c5 100644 --- a/extensions/sdk/sdk.vcproj +++ b/extensions/sdk/sdk.vcproj @@ -43,7 +43,7 @@ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" - RuntimeLibrary="3" + RuntimeLibrary="1" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" @@ -60,6 +60,7 @@ /> GetIdentity(); + myself = me; + + m_WeAreUnloaded = true; #if defined SMEXT_CONF_METAMOD if (!m_SourceMMLoaded) @@ -37,7 +39,13 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); - return SDK_OnLoad(error, err_max, late); + if (SDK_OnLoad(error, err_max, late)) + { + m_WeAreUnloaded = true; + return true; + } + + return false; } bool SDKExtension::IsMetamodExtension() @@ -51,7 +59,9 @@ bool SDKExtension::IsMetamodExtension() void SDKExtension::OnExtensionPauseChange(bool state) { +#if defined SMEXT_CONF_METAMOD m_WeGotPauseChange = true; +#endif SDK_OnPauseChange(state); } @@ -62,7 +72,9 @@ void SDKExtension::OnExtensionsAllLoaded() void SDKExtension::OnExtensionUnload() { +#if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; +#endif SDK_OnUnload(); } diff --git a/extensions/sdk/smsdk_ext.h b/extensions/sdk/smsdk_ext.h index 420e7e93..7060cb1c 100644 --- a/extensions/sdk/smsdk_ext.h +++ b/extensions/sdk/smsdk_ext.h @@ -118,7 +118,7 @@ private: extern SDKExtension *g_pExtensionIface; extern IShareSys *g_pShareSys; -extern IdentityToken_t *myself; +extern IExtension *myself; extern IHandleSys *g_pHandleSys; #if defined SMEXT_CONF_METAMOD From 7b8c36cb79800eda60cb7e3580407316ed53e57a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 17 Jan 2007 06:48:11 +0000 Subject: [PATCH 0280/1664] Added plugin dependencies to extensions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40310 --- core/systems/ExtensionSys.cpp | 41 ++++++++++++++++++++++++++++++++++- core/systems/ExtensionSys.h | 10 ++++++++- core/systems/PluginSys.cpp | 17 ++++++++++----- core/systems/ShareSys.cpp | 3 +++ 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 3d9375ce..ae223b57 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -3,6 +3,7 @@ #include "ShareSys.h" #include "CLogger.h" #include "sourcemm_api.h" +#include "PluginSys.h" CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -94,6 +95,16 @@ CExtension::~CExtension() } } +void CExtension::AddPlugin(IPlugin *pPlugin) +{ + m_Plugins.push_back(pPlugin); +} + +void CExtension::RemovePlugin(IPlugin *pPlugin) +{ + m_Plugins.remove(pPlugin); +} + void CExtension::SetError(const char *error) { m_Error.assign(error); @@ -197,10 +208,12 @@ void CExtension::AddInterface(SMInterface *pInterface) void CExtensionManager::OnSourceModAllInitialized() { g_ExtType = g_ShareSys.CreateIdentType("EXTENSION"); + g_PluginSys.AddPluginsListener(this); } void CExtensionManager::OnSourceModShutdown() { + g_PluginSys.RemovePluginsListener(this); g_ShareSys.DestroyIdentType(g_ExtType); } @@ -217,7 +230,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path) if (!p->IsLoaded()) { - g_Logger.LogError("[SOURCEMOD] Unable to load extension \"%s\": %s", path, error); + g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error); p->SetError(error); } @@ -316,6 +329,23 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface pExt->AddInterface(pInterface); } +void CExtensionManager::BindChildPlugin(IExtension *pParent, IPlugin *pPlugin) +{ + CExtension *pExt = (CExtension *)pParent; + + pExt->AddPlugin(pPlugin); +} + +void CExtensionManager::OnPluginDestroyed(IPlugin *plugin) +{ + List::iterator iter; + + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + (*iter)->RemovePlugin(plugin); + } +} + bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -339,6 +369,15 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) /* Handle dependencies */ if (pExt->IsLoaded()) { + /* Unload any dependent plugins */ + List::iterator p_iter = pExt->m_Plugins.begin(); + while (p_iter != pExt->m_Plugins.end()) + { + g_PluginSys.UnloadPlugin((*p_iter)); + /* It should already have been removed! */ + assert(pExt->m_Plugins.find((*p_iter)) != pExt->m_Plugins.end()); + } + /* Notify and/or unload all dependencies */ List::iterator c_iter; CExtension *pDep; diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index 7bf05f1c..2e946406 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -8,6 +8,7 @@ #include "sm_globals.h" #include "ShareSys.h" #include +#include using namespace SourceMod; using namespace SourceHook; @@ -30,6 +31,8 @@ public: void SetError(const char *error); void AddDependency(IfaceInfo *pInfo); void AddInterface(SMInterface *pInterface); + void AddPlugin(IPlugin *pPlugin); + void RemovePlugin(IPlugin *pPlugin); private: IdentityToken_t *m_pIdentToken; IExtensionInterface *m_pAPI; @@ -38,12 +41,14 @@ private: String m_Error; List m_Deps; List m_Interfaces; + List m_Plugins; PluginId m_PlId; }; class CExtensionManager : public IExtensionManager, - public SMGlobalClass + public SMGlobalClass, + IPluginsListener { public: //SMGlobalClass void OnSourceModAllInitialized(); @@ -56,10 +61,13 @@ public: //IExtensionManager bool UnloadExtension(IExtension *pExt); IExtension *FindExtensionByFile(const char *file); IExtension *FindExtensionByName(const char *ext); +public: //IPluginsListener + void OnPluginDestroyed(IPlugin *plugin); public: IExtension *LoadAutoExtension(const char *path); void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); + void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); private: List m_Libs; }; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 627c4f9a..9e83688b 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -588,11 +588,11 @@ void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) m_AllPluginsLoaded = false; if ((err=g_TextParser.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay) { - g_Logger.LogError("[SOURCEMOD] Encountered fatal error parsing file \"%s\"", config); + g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config); const char *err_msg = g_TextParser.GetSMCErrorString(err); if (err_msg) { - g_Logger.LogError("[SOURCEMOD] Parse error encountered: \"%s\"", err_msg); + g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg); } } @@ -617,8 +617,8 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa { char error[256]; g_LibSys.GetPlatformError(error, sizeof(error)); - g_Logger.LogError("[SOURCEMOD] Failure reading from plugins path: %s", localpath); - g_Logger.LogError("[SOURCEMOD] Platform returned error: %s", error); + g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath); + g_Logger.LogError("[SM] Platform returned error: %s", error); return; } @@ -779,7 +779,7 @@ void CPluginManager::LoadAutoPlugin(const char *plugin) if (!_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) { - g_Logger.LogError("[SOURCEMOD] Failed to load plugin \"%s\": %s", plugin, error); + g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error); pl->SetErrorState(Plugin_Failed, "%s", error); } @@ -864,6 +864,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng { pExt = g_Extensions.LoadAutoExtension(path); } + /* See if we can find a similar extension */ if (ext->required && !pExt) { if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL) @@ -871,6 +872,12 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng pExt = g_Extensions.FindExtensionByName(name); } } + /* If we're requiring and got an extension and it's loaded, bind it */ + if (ext->required && pExt && pExt->IsLoaded()) + { + g_Extensions.BindChildPlugin(pExt, pPlugin); + } + /* If we're requiring and we didn't get an extension or it's not loaded, error */ if (ext->required && (!pExt || !pExt->IsLoaded())) { if (error) diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index bf91c851..4d96b3f8 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -34,6 +34,9 @@ void ShareSystem::OnSourceModStartup(bool late) /* Initialize our static identity handle */ m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); + + /* Add the Handle System... it's too innocent and pure to do it itself */ + AddInterface(NULL, &g_HandleSys); } void ShareSystem::OnSourceModShutdown() From 2bbcd57b9e83c3272178ba9c1e85232df14fb0f2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 17 Jan 2007 06:48:52 +0000 Subject: [PATCH 0281/1664] Changed [SOURCEMOD] to [SM] --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40311 --- core/CTranslator.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 80caa037..8fb074b8 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -63,11 +63,11 @@ void CPhraseFile::ParseWarning(const char *message, ...) if (!m_FileLogged) { - g_Logger.LogError("[SOURCEMOD] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); + g_Logger.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); m_FileLogged; } - g_Logger.LogError("[SOURCEMOD] %s", message); + g_Logger.LogError("[SM] %s", message); } void CPhraseFile::ReparseFile() @@ -98,8 +98,8 @@ void CPhraseFile::ReparseFile() msg = m_ParseError.c_str(); } - g_Logger.LogError("[SOURCEMOD] Fatal error encountered parsing translation file \"%s\"", m_File.c_str()); - g_Logger.LogError("[SOURCEMOD] Error (line %d, column %d): %s", line, col, msg); + g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str()); + g_Logger.LogError("[SM] Error (line %d, column %d): %s", line, col, msg); } } @@ -652,13 +652,13 @@ void CTranslator::RebuildLanguageDatabase(const char *lang_header_file) str_err = m_CustomError.c_str(); } - g_Logger.LogError("[SOURCEMOD] Failed to parse language header file: \"%s\"", lang_header_file); - g_Logger.LogError("[SOURCEMOD] Parse error (line %d, column %d): %s", line, col, str_err); + g_Logger.LogError("[SM] Failed to parse language header file: \"%s\"", lang_header_file); + g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", line, col, str_err); } if (!m_Languages.size()) { - g_Logger.LogError("[SOURCEMOD] Fatal error, no languages found! Translation will not work."); + g_Logger.LogError("[SM] Fatal error, no languages found! Translation will not work."); } for (size_t i=0; i Date: Wed, 17 Jan 2007 06:49:40 +0000 Subject: [PATCH 0282/1664] Changed [SOURCEMOD] to [SM] --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40312 --- core/CDbgReporter.cpp | 14 +++++++------- core/CLogger.cpp | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp index 7a02fb10..0a0d1dcf 100644 --- a/core/CDbgReporter.cpp +++ b/core/CDbgReporter.cpp @@ -15,7 +15,7 @@ void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *err if (n_err != SP_ERROR_NATIVE) { - g_Logger.LogError("[SOURCEMOD] Plugin \"%s\" encountered error %d: %s", + g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, n_err, error->GetErrorString()); @@ -26,26 +26,26 @@ void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *err const char *custerr; if ((custerr=error->GetCustomErrorString()) != NULL) { - g_Logger.LogError("[SOURCEMOD] Native \"%s\" reported: \"%s\"", lastname, custerr); + g_Logger.LogError("[SM] Native \"%s\" reported: \"%s\"", lastname, custerr); } else { - g_Logger.LogError("[SOURCEMOD] Native \"%s\" encountered a generic error.", lastname); + g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname); } } if (!error->DebugInfoAvailable()) { - g_Logger.LogError("[SOURCEMOD] Debug mode is not enabled for this plugin."); - g_Logger.LogError("[SOURCEMOD] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on", + g_Logger.LogError("[SM] Debug mode is not enabled for this plugin."); + g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on", _GetPluginIndex(ctx)); return; } CallStackInfo stk_info; int i = 0; - g_Logger.LogError("[SOURCEMOD] Displaying call stack trace:"); + g_Logger.LogError("[SM] Displaying call stack trace:"); while (error->GetTraceInfo(&stk_info)) { - g_Logger.LogError("[SOURCEMOD] [%d] Line %d, %s::%s()", + g_Logger.LogError("[SM] [%d] Line %d, %s::%s()", i++, stk_info.line, stk_info.filename, diff --git a/core/CLogger.cpp b/core/CLogger.cpp index fe96469d..1c2bb2bb 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -48,7 +48,7 @@ void CLogger::_NewMapFile() FILE *fp = fopen(m_NrmFileName.c_str(), "w"); if (!fp) { - g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; return; } else { @@ -207,7 +207,7 @@ void CLogger::LogMessage(const char *vafmt, ...) g_SMAPI->ConPrintf("L %s: %s\n", date, msg); return; print_error: - g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; } @@ -252,7 +252,7 @@ void CLogger::LogError(const char *vafmt, ...) fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); } else { - g_SMAPI->ConPrint("[SOURCEMOD] Unexpected fatal logging error. SourceMod logging disabled.\n"); + g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; return; } From 35d0c555fa474f0d5287181c61c03c347f334e90 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 17 Jan 2007 06:49:59 +0000 Subject: [PATCH 0283/1664] Redesigned how server commands work. The "plugins" command will be back soon. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40313 --- core/interfaces/IRootConsoleMenu.h | 77 ++++++ core/msvc8/sourcemod_mm.vcproj | 4 + core/sm_srvcmds.cpp | 419 +++++++++++++---------------- core/sm_srvcmds.h | 47 +++- core/sm_version.h | 5 +- 5 files changed, 317 insertions(+), 235 deletions(-) create mode 100644 core/interfaces/IRootConsoleMenu.h diff --git a/core/interfaces/IRootConsoleMenu.h b/core/interfaces/IRootConsoleMenu.h new file mode 100644 index 00000000..22629771 --- /dev/null +++ b/core/interfaces/IRootConsoleMenu.h @@ -0,0 +1,77 @@ +#ifndef _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ +#define _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ + +/** + * @brief Note: This interface is not exposed. + * The reason should be obvious: we do not want users touching the "root" console menu. + */ + +namespace SourceMod +{ + /** + * @brief Handles a root console menu action. + */ + class IRootConsoleCommand + { + public: + virtual void OnRootConsoleCommand(const char *command, unsigned int argcount) =0; + }; + + /** + * @brief Manages the root console menu. + */ + class IRootConsole + { + public: + /** + * @brief Adds a root console command handler. The command must be unique. + * + * @param cmd String containing the console command. + * @param text Description text. + * @param pHandler An IRootConsoleCommand pointer to handle the command. + * @return True on success, false on too many commands or duplicate command. + */ + virtual bool AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler) =0; + + /** + * @brief Removes a root console command handler. + * + * @param cmd String containing the console command. + * @param pHandler An IRootConsoleCommand pointer for verification. + * @return True on success, false otherwise. + */ + virtual bool RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler) =0; + + /** + * @brief Prints text back to the console. + * + * @param fmt Format of string. + * @param ... Format arguments. + */ + virtual void ConsolePrint(const char *fmt, ...) =0; + + /** + * @brief Returns the string of an argument. + * + * @param argno The index of the argument. + * @return A string containing the argument, or nothing if invalid. + */ + virtual const char *GetArgument(unsigned int argno) =0; + + /** + * @brief Returns the number of arguments. + * + * @return Number of arguments. + */ + virtual unsigned int GetArgumentCount() =0; + + /** + * @brief Returns the entire argument string. + * + * @return String containing all arguments. + */ + virtual const char *GetArguments() =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index ac77eff7..e1ba5db7 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -325,6 +325,10 @@ + + diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 9f0a49bf..f3ee50f4 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -2,14 +2,39 @@ #include "sm_version.h" #include "sm_stringutil.h" -ConVarAccessor g_ConCmdAccessor; +RootConsoleMenu g_RootMenu; -void ConVarAccessor::OnSourceModStartup(bool late) +RootConsoleMenu::RootConsoleMenu() { - ConCommandBaseMgr::OneTimeInit(&g_ConCmdAccessor); + m_pCommands = sm_trie_create(); } -bool ConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand) +RootConsoleMenu::~RootConsoleMenu() +{ + sm_trie_destroy(m_pCommands); + + List::iterator iter; + for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++) + { + delete (*iter); + } + m_Menu.clear(); +} + +void RootConsoleMenu::OnSourceModStartup(bool late) +{ + ConCommandBaseMgr::OneTimeInit(this); + AddRootConsoleCommand("version", "Display version information", this); + AddRootConsoleCommand("credits", "Display credits listing", this); +} + +void RootConsoleMenu::OnSourceModShutdown() +{ + RemoveRootConsoleCommand("credits", this); + RemoveRootConsoleCommand("version", this); +} + +bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand) { META_REGCVAR(pCommand); @@ -38,234 +63,176 @@ inline const char *StatusToStr(PluginStatus st) } } -#define IS_STR_FILLED(var) (var[0] != '\0') -CON_COMMAND(sm, "SourceMod Menu") +void RootConsoleMenu::ConsolePrint(const char *fmt, ...) { - int argnum = engine->Cmd_Argc(); + char buffer[512]; + + va_list ap; + va_start(ap, fmt); + size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + if (len >= sizeof(buffer)) + { + buffer[510] = '\n'; + buffer[511] = '\0'; + } else { + buffer[len++] = '\n'; + buffer[len] = '\0'; + } + + META_CONPRINT(buffer); +} + +bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler) +{ + if (sm_trie_retrieve(m_pCommands, cmd, NULL)) + { + return false; + } + + sm_trie_insert(m_pCommands, cmd, pHandler); + + /* Sort this into the menu */ + List::iterator iter = m_Menu.begin(); + ConsoleEntry *pEntry; + bool inserted = false; + while (iter != m_Menu.end()) + { + pEntry = (*iter); + if (strcmp(cmd, pEntry->command.c_str()) < 0) + { + ConsoleEntry *pNew = new ConsoleEntry; + pNew->command.assign(cmd); + pNew->description.assign(text); + m_Menu.insert(iter, pNew); + inserted = true; + break; + } + iter++; + } + + if (!inserted) + { + ConsoleEntry *pNew = new ConsoleEntry; + pNew->command.assign(cmd); + pNew->description.assign(text); + m_Menu.push_back(pNew); + } + + return true; +} + +bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler) +{ + /* Sanity tests */ + IRootConsoleCommand *object; + if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object)) + { + if (object != pHandler) + { + return false; + } + } else { + return false; + } + + sm_trie_delete(m_pCommands, cmd); + + List::iterator iter; + ConsoleEntry *pEntry; + for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++) + { + pEntry = (*iter); + if (pEntry->command.compare(cmd) == 0) + { + delete pEntry; + m_Menu.erase(iter); + break; + } + } + + return true; +} + +void RootConsoleMenu::GotRootCmd() +{ + unsigned int argnum = GetArgumentCount(); if (argnum >= 2) { - const char *cmd = engine->Cmd_Argv(1); - if (!strcmp("plugins", cmd)) + const char *cmd = GetArgument(1); + IRootConsoleCommand *pHandler; + if (sm_trie_retrieve(m_pCommands, cmd, (void **)&pHandler)) { - if (argnum >= 3) - { - const char *cmd2 = engine->Cmd_Argv(2); - if (!strcmp("list", cmd2)) - { - char buffer[256]; - unsigned int id = 1; - int plnum = g_PluginSys.GetPluginCount(); - - if (!plnum) - { - META_CONPRINT("[SM] No plugins loaded\n"); - return; - } else { - META_CONPRINTF("[SM] Displaying %d plugin%s:\n", g_PluginSys.GetPluginCount(), (plnum > 1) ? "s" : ""); - } - - IPluginIterator *iter = g_PluginSys.GetPluginIterator(); - for (; iter->MorePlugins(); iter->NextPlugin(), id++) - { - IPlugin *pl = iter->GetPlugin(); - assert(pl->GetStatus() != Plugin_Created); - int len = 0; - const sm_plugininfo_t *info = pl->GetPublicInfo(); - - len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); - if (IS_STR_FILLED(info->version)) - { - len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); - } - if (IS_STR_FILLED(info->author)) - { - UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author); - } - META_CONPRINTF("%s\n", buffer); - } - - iter->Release(); - return; - } else if (!strcmp("load", cmd2)) { - if (argnum < 4) - { - META_CONPRINT("Usage: sm plugins load \n"); - return; - } - - char error[128]; - const char *filename = engine->Cmd_Argv(3); - IPlugin *pl = g_PluginSys.LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error)); - - if (pl) - { - META_CONPRINTF("Loaded plugin %s successfully.\n", filename); - } else { - META_CONPRINTF("Plugin %s failed to load: %s.\n", filename, error); - } - - return; - } else if (!strcmp("unload", cmd2)) { - if (argnum < 4) - { - META_CONPRINT("Usage: sm plugins unload <#>\n"); - return; - } - - int id = 1; - int num = atoi(engine->Cmd_Argv(3)); - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) - { - META_CONPRINT("Plugin index not found.\n"); - return; - } - - IPluginIterator *iter = g_PluginSys.GetPluginIterator(); - for (; iter->MorePlugins() && idNextPlugin(), id++) {} - IPlugin *pl = iter->GetPlugin(); - - char name[64]; - const sm_plugininfo_t *info = pl->GetPublicInfo(); - strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); - - if (g_PluginSys.UnloadPlugin(pl)) - { - META_CONPRINTF("Plugin %s unloaded successfully.\n", name); - } else { - META_CONPRINTF("Failed to unload plugin %s.\n", name); - } - - iter->Release(); - return; - } else if (!strcmp("info", cmd2)) { - if (argnum < 4) - { - META_CONPRINT("Usage: sm plugins info <#>\n"); - return; - } - - int id = 1; - int num = atoi(engine->Cmd_Argv(3)); - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) - { - META_CONPRINT("Plugin index not found.\n"); - return; - } - - IPluginIterator *iter = g_PluginSys.GetPluginIterator(); - for (; iter->MorePlugins() && idNextPlugin(), id++) {} - - IPlugin *pl = iter->GetPlugin(); - const sm_plugininfo_t *info = pl->GetPublicInfo(); - - META_CONPRINTF(" Filename: %s\n", pl->GetFilename()); - if (IS_STR_FILLED(info->name)) - { - META_CONPRINTF(" Title: %s\n", info->name); - } - if (IS_STR_FILLED(info->author)) - { - META_CONPRINTF(" Author: %s\n", info->author); - } - if (IS_STR_FILLED(info->version)) - { - META_CONPRINTF(" Version: %s\n", info->version); - } - if (IS_STR_FILLED(info->description)) - { - META_CONPRINTF(" Description: %s\n", info->description); - } - if (IS_STR_FILLED(info->url)) - { - META_CONPRINTF(" URL: %s\n", info->url); - } - //:TODO: write if it's in debug mode, or do it inside LIST ? - - iter->Release(); - return; - } else if (!strcmp("debug", cmd2)) { - if (argnum < 5) - { - META_CONPRINT("Usage: sm plugins debug <#> [on|off]\n"); - return; - } - - int num = atoi(engine->Cmd_Argv(3)); - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) - { - META_CONPRINT("Plugin index not found.\n"); - return; - } - - int res; - char *mode = engine->Cmd_Argv(4); - if ((res=strcmp("on", mode)) && strcmp("off", mode)) - { - META_CONPRINT("The only possible options are on and off.\n"); - return; - } - - bool debug; - if (!res) - { - debug = true; - } else { - debug = false; - } - - CPlugin *pl = g_PluginSys.GetPluginByOrder(num); - if (debug && pl->IsDebugging()) - { - META_CONPRINT("This plugin is already in debug mode.\n"); - return; - } else if (!debug && !pl->IsDebugging()) { - META_CONPRINT("Debug mode is already disabled in this plugin.\n"); - return; - } - - if (pl->ToggleDebugMode(debug)) - { - META_CONPRINTF("Successfully toggled debug mode on plugin %s.\n", pl->GetFilename()); - return; - } else { - /* :TODO: ... we should be getting an actual error message here */ - META_CONPRINTF("Could not toggle debug mode on plugin %s.\n", pl->GetFilename()); - return; - } - } - } - - META_CONPRINT(" SourceMod Plugin Menu:\n"); - META_CONPRINT(" list - Show loaded plugins\n"); - META_CONPRINT(" load - Load a plugin\n"); - META_CONPRINT(" unload - Unload a plugin\n"); - META_CONPRINT(" info - Information about a plugin\n"); - META_CONPRINT(" debug - Toggles debug mode in a plugin\n"); - return; - } else if (!strcmp("credits", cmd)) { - META_CONPRINT(" SourceMod was developed by AlliedModders, LLC.\n"); - META_CONPRINT(" Development would not have been possible without the following people:\n"); - META_CONPRINT(" David \"BAILOPAN\" Anderson, lead developer\n"); - META_CONPRINT(" Borja \"faluco\" Ferrer, Core developer\n"); - META_CONPRINT(" Scott \"Damaged Soul\" Ehlert, SourceMM developer\n"); - META_CONPRINT(" Pavol \"PM OnoTo\" Marko, SourceHook developer\n"); - META_CONPRINT(" Special thanks to Viper of GameConnect, and Mani\n"); - META_CONPRINT(" http://www.sourcemod.net/\n"); - return; - } else if (!strcmp("version", cmd)) { - META_CONPRINT(" SourceMod Version Information:\n"); - META_CONPRINTF(" SourceMod Version: \"%s\"\n", SOURCEMOD_VERSION); - META_CONPRINTF(" JIT Version: %s (%s)\n", g_pVM->GetVMName(), g_pVM->GetVersionString()); - META_CONPRINTF(" JIT Settings: %s\n", g_pVM->GetCPUOptimizations()); - META_CONPRINT(" http://www.sourcemod.net/\n"); + pHandler->OnRootConsoleCommand(cmd, argnum); return; } } - META_CONPRINT(" SourceMod Menu:\n"); - META_CONPRINT(" Usage: sm [arguments]\n"); - META_CONPRINT(" credits - Credits listing\n"); - META_CONPRINT(" plugins - Plugins menu\n"); - META_CONPRINT(" version - Display version information\n"); + + ConsolePrint("SourceMod Menu:"); + ConsolePrint("Usage: sm [arguments]"); + + List::iterator iter; + ConsoleEntry *pEntry; + char buffer[255]; + size_t len; + for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++) + { + pEntry = (*iter); + len = snprintf(buffer, sizeof(buffer), " %s", pEntry->command.c_str()); + if (pEntry->command.size() < 16) + { + size_t num = 16 - pEntry->command.size(); + for (size_t i = 0; i < num; i++) + { + buffer[len++] = ' '; + } + } + len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", pEntry->description.c_str()); + ConsolePrint("%s", buffer); + } +} + +const char *RootConsoleMenu::GetArgument(unsigned int argno) +{ + return engine->Cmd_Argv(argno); +} + +const char *RootConsoleMenu::GetArguments() +{ + return engine->Cmd_Args(); +} + +unsigned int RootConsoleMenu::GetArgumentCount() +{ + return engine->Cmd_Argc(); +} + +void RootConsoleMenu::OnRootConsoleCommand(const char *cmd, unsigned int argcount) +{ + if (strcmp(cmd, "credits") == 0) + { + ConsolePrint(" SourceMod was developed by AlliedModders, LLC."); + ConsolePrint(" Development would not have been possible without the following people:"); + ConsolePrint(" David \"BAILOPAN\" Anderson, lead developer"); + ConsolePrint(" Borja \"faluco\" Ferrer, Core developer"); + ConsolePrint(" Scott \"Damaged Soul\" Ehlert, SourceMM developer"); + ConsolePrint(" Pavol \"PM OnoTo\" Marko, SourceHook developer"); + ConsolePrint(" Special thanks to Viper of GameConnect"); + ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin"); + ConsolePrint(" http://www.sourcemod.net/"); + } else if (strcmp(cmd, "version") == 0) { + ConsolePrint(" SourceMod Version Information:"); + ConsolePrint(" SourceMod Version: %s", SOURCEMOD_VERSION); + ConsolePrint(" JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString()); + ConsolePrint(" JIT Settings: %s", g_pVM->GetCPUOptimizations()); + ConsolePrint(" http://www.sourcemod.net/"); + } +} + +#define IS_STR_FILLED(var) (var[0] != '\0') +CON_COMMAND(sm, "SourceMod Menu") +{ + g_RootMenu.GotRootCmd(); } diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index aa4ac340..1d6ba02c 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -2,20 +2,53 @@ #define _INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ #include "sourcemod.h" +#include #include "PluginSys.h" #include "sourcemm_api.h" #include +#include +#include +#include "sm_trie.h" using namespace SourceMod; +using namespace SourceHook; -class ConVarAccessor : - public IConCommandBaseAccessor, - public SMGlobalClass +struct ConsoleEntry { -public: // IConCommandBaseAccessor - virtual bool RegisterConCommandBase(ConCommandBase *pCommand); -public: // SMGlobalClass - virtual void OnSourceModStartup(bool late); + String command; + String description; }; +class RootConsoleMenu : + public IConCommandBaseAccessor, + public SMGlobalClass, + public IRootConsoleCommand, + public IRootConsole +{ +public: + RootConsoleMenu(); + ~RootConsoleMenu(); +public: //IConCommandBaseAccessor + bool RegisterConCommandBase(ConCommandBase *pCommand); +public: //SMGlobalClass + void OnSourceModStartup(bool late); + void OnSourceModShutdown(); +public: //IRootConsoleCommand + void OnRootConsoleCommand(const char *cmd, unsigned int argcount); +public: //IRootConsole + bool AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler); + bool RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler); + void ConsolePrint(const char *fmt, ...); + const char *GetArgument(unsigned int argno); + unsigned int GetArgumentCount(); + const char *GetArguments(); +public: + void GotRootCmd(); +private: + Trie *m_pCommands; + List m_Menu; +}; + +extern RootConsoleMenu g_RootMenu; + #endif //_INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ diff --git a/core/sm_version.h b/core/sm_version.h index c22253af..6caa84d4 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -5,10 +5,11 @@ * @file Contains SourceMod version information. */ -#define SOURCEMOD_VERSION "1.0.0.$Id$" #define SOURCEMOD_V_MAJOR 1 #define SOURCEMOD_V_MINOR 0 #define SOURCEMOD_V_REV 0 -#define SOURCEMOD_V_BUILD $Id$ +#define SOURCEMOD_V_BUILD 308 + +#define SOURCEMOD_VERSION "1.0.0.308" #endif //_INCLUDE_SOURCEMOD_VERSION_H_ From 3597a8b1fec1a988205f45ff337a1daa308b6ae8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 17 Jan 2007 18:22:00 +0000 Subject: [PATCH 0284/1664] Finished porting the "plugins" command to the new menu system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40314 --- core/interfaces/IRootConsoleMenu.h | 11 ++ core/sm_srvcmds.cpp | 55 ++---- core/sm_srvcmds.h | 1 + core/systems/PluginSys.cpp | 290 +++++++++++++++++++++++++++-- core/systems/PluginSys.h | 17 +- 5 files changed, 321 insertions(+), 53 deletions(-) diff --git a/core/interfaces/IRootConsoleMenu.h b/core/interfaces/IRootConsoleMenu.h index 22629771..2344ae0e 100644 --- a/core/interfaces/IRootConsoleMenu.h +++ b/core/interfaces/IRootConsoleMenu.h @@ -71,6 +71,17 @@ namespace SourceMod * @return String containing all arguments. */ virtual const char *GetArguments() =0; + + /** + * @brief Draws a generic command/description pair. + * NOTE: The pair is currently four spaces indented and 16-N spaces of separation, + * N being the length of the command name. This is subject to change in case we + * account for Valve's font choices. + * + * @param option String containing the command option. + * @param description String containing the command description. + */ + virtual void DrawGenericOption(const char *cmd, const char *text) =0; }; }; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index f3ee50f4..507801e7 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -41,28 +41,6 @@ bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand) return true; } -inline const char *StatusToStr(PluginStatus st) -{ - switch (st) - { - case Plugin_Running: - return "Running"; - case Plugin_Paused: - return "Paused"; - case Plugin_Error: - return "Error"; - case Plugin_Uncompiled: - return "Uncompiled"; - case Plugin_BadLoad: - return "Bad Load"; - case Plugin_Failed: - return "Failed"; - default: - assert(false); - return "-"; - } -} - void RootConsoleMenu::ConsolePrint(const char *fmt, ...) { char buffer[512]; @@ -155,6 +133,24 @@ bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleComm return true; } +void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text) +{ + char buffer[255]; + size_t len, cmdlen = strlen(cmd); + + len = snprintf(buffer, sizeof(buffer), " %s", cmd); + if (cmdlen < 16) + { + size_t num = 16 - cmdlen; + for (size_t i = 0; i < num; i++) + { + buffer[len++] = ' '; + } + len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text); + ConsolePrint("%s", buffer); + } +} + void RootConsoleMenu::GotRootCmd() { unsigned int argnum = GetArgumentCount(); @@ -175,22 +171,10 @@ void RootConsoleMenu::GotRootCmd() List::iterator iter; ConsoleEntry *pEntry; - char buffer[255]; - size_t len; for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++) { pEntry = (*iter); - len = snprintf(buffer, sizeof(buffer), " %s", pEntry->command.c_str()); - if (pEntry->command.size() < 16) - { - size_t num = 16 - pEntry->command.size(); - for (size_t i = 0; i < num; i++) - { - buffer[len++] = ' '; - } - } - len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", pEntry->description.c_str()); - ConsolePrint("%s", buffer); + DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str()); } } @@ -231,7 +215,6 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmd, unsigned int argcoun } } -#define IS_STR_FILLED(var) (var[0] != '\0') CON_COMMAND(sm, "SourceMod Menu") { g_RootMenu.GotRootCmd(); diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 1d6ba02c..f381fc26 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -42,6 +42,7 @@ public: //IRootConsole const char *GetArgument(unsigned int argno); unsigned int GetArgumentCount(); const char *GetArguments(); + void DrawGenericOption(const char *cmd, const char *text); public: void GotRootCmd(); private: diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 9e83688b..c5db626e 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -8,6 +8,8 @@ #include "CTextParsers.h" #include "CLogger.h" #include "ExtensionSys.h" +#include "sm_srvcmds.h" +#include "sm_stringutil.h" CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; @@ -477,39 +479,68 @@ IdentityToken_t *CPlugin::GetIdentity() const return m_ident; } -bool CPlugin::ToggleDebugMode(bool debug) +bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) { int err; if (!IsRunnable()) { + if (error) + { + snprintf(error, maxlength, "Plugin is not runnable."); + } return false; } - if ((debug && IsDebugging()) || (!debug && !IsDebugging())) + if (debug && IsDebugging()) { + if (error) + { + snprintf(error, maxlength, "Plugin is already in debug mode."); + } + return false; + } else if (!debug && !IsDebugging()) { + if (error) + { + snprintf(error, maxlength, "Plugins is already in production mode."); + } return false; } + ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin); if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0")) { + if (error) + { + snprintf(error, maxlength, "Failed to change plugin mode (JIT failure)."); + } return false; } + sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err); - memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size); - new_ctx->hp = m_ctx.ctx->hp; - new_ctx->sp = m_ctx.ctx->sp; - new_ctx->frm = m_ctx.ctx->frm; - new_ctx->dbreak = m_ctx.ctx->dbreak; - new_ctx->context = m_ctx.ctx->context; - memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user)); + if (new_ctx) + { + memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size); + new_ctx->hp = m_ctx.ctx->hp; + new_ctx->sp = m_ctx.ctx->sp; + new_ctx->frm = m_ctx.ctx->frm; + new_ctx->dbreak = m_ctx.ctx->dbreak; + new_ctx->context = m_ctx.ctx->context; + memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user)); - g_pVM->FreeContext(m_ctx.ctx); - m_ctx.ctx = new_ctx; - m_ctx.base->SetContext(new_ctx); + g_pVM->FreeContext(m_ctx.ctx); + m_ctx.ctx = new_ctx; + m_ctx.base->SetContext(new_ctx); - UpdateInfo(); + UpdateInfo(); + } else { + if (error) + { + snprintf(error, maxlength, "Failed to recompile plugin (JIT error %d).", err); + } + return false; + } return true; } @@ -1252,10 +1283,14 @@ void CPluginManager::OnSourceModAllInitialized() g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL); g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); + + g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this); } void CPluginManager::OnSourceModShutdown() { + g_RootMenu.RemoveRootConsoleCommand("plugins", this); + List::iterator iter; while ( (iter = m_plugins.begin()) != m_plugins.end() ) { @@ -1318,3 +1353,232 @@ CPlugin *CPluginManager::GetPluginByOrder(int num) return pl; } + +const char *CPluginManager::GetStatusText(PluginStatus st) +{ + switch (st) + { + case Plugin_Running: + return "Running"; + case Plugin_Paused: + return "Paused"; + case Plugin_Error: + return "Error"; + case Plugin_Uncompiled: + return "Uncompiled"; + case Plugin_BadLoad: + return "Bad Load"; + case Plugin_Failed: + return "Failed"; + default: + assert(false); + return "-"; + } +} + +#define IS_STR_FILLED(var) (var[0] != '\0') +void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ + if (argcount >= 3) + { + const char *cmd = g_RootMenu.GetArgument(2); + if (strcmp(cmd, "list") == 0) + { + char buffer[256]; + unsigned int id = 1; + int plnum = GetPluginCount(); + + if (!plnum) + { + g_RootMenu.ConsolePrint("[SM] No plugins loaded"); + return; + } else { + g_RootMenu.ConsolePrint("[SM] Displaying %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : ""); + } + + IPluginIterator *iter = GetPluginIterator(); + for (; iter->MorePlugins(); iter->NextPlugin(), id++) + { + IPlugin *pl = iter->GetPlugin(); + assert(pl->GetStatus() != Plugin_Created); + int len = 0; + const sm_plugininfo_t *info = pl->GetPublicInfo(); + + len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus())); + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + if (IS_STR_FILLED(info->version)) + { + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); + } + if (IS_STR_FILLED(info->author)) + { + UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author); + } + g_RootMenu.ConsolePrint("%s", buffer); + } + + iter->Release(); + return; + } else if (strcmp(cmd, "load") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("Usage: sm plugins load "); + return; + } + + char error[128]; + const char *filename = g_RootMenu.GetArgument(3); + IPlugin *pl = LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error)); + + if (pl) + { + g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", filename); + } else { + g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", filename, error); + } + + return; + } else if (strcmp(cmd, "unload") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("Usage: sm plugins unload <#>"); + return; + } + + int id = 1; + int num = atoi(g_RootMenu.GetArgument(3)); + if (num < 1 || num > (int)GetPluginCount()) + { + g_RootMenu.ConsolePrint("Plugin index %d not found.", num); + return; + } + + IPluginIterator *iter = GetPluginIterator(); + for (; iter->MorePlugins() && idNextPlugin(), id++) + ; + IPlugin *pl = iter->GetPlugin(); + + char name[PLATFORM_MAX_PATH+1]; + const sm_plugininfo_t *info = pl->GetPublicInfo(); + strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + + if (UnloadPlugin(pl)) + { + g_RootMenu.ConsolePrint("Plugin %s unloaded successfully.", name); + } else { + g_RootMenu.ConsolePrint("Failed to unload plugin %s.", name); + } + + iter->Release(); + return; + } else if (strcmp(cmd, "info") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("Usage: sm plugins info <#>"); + return; + } + + int id = 1; + int num = atoi(g_RootMenu.GetArgument(3)); + if (num < 1 || num > (int)GetPluginCount()) + { + g_RootMenu.ConsolePrint("Plugin index not found."); + return; + } + + IPluginIterator *iter = GetPluginIterator(); + for (; iter->MorePlugins() && idNextPlugin(), id++) {} + + IPlugin *pl = iter->GetPlugin(); + const sm_plugininfo_t *info = pl->GetPublicInfo(); + + g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename()); + if (IS_STR_FILLED(info->name)) + { + g_RootMenu.ConsolePrint(" Title: %s", info->name); + } + if (IS_STR_FILLED(info->author)) + { + g_RootMenu.ConsolePrint(" Author: %s", info->author); + } + if (IS_STR_FILLED(info->version)) + { + g_RootMenu.ConsolePrint(" Version: %s", info->version); + } + if (IS_STR_FILLED(info->description)) + { + g_RootMenu.ConsolePrint(" Description: %s", info->description); + } + if (IS_STR_FILLED(info->url)) + { + g_RootMenu.ConsolePrint(" URL: %s", info->url); + } + if (pl->GetStatus() >= Plugin_Error) + { + g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no"); + } + + iter->Release(); + + return; + } else if (strcmp(cmd, "debug") == 0) { + if (argcount < 5) + { + g_RootMenu.ConsolePrint("Usage: sm plugins debug <#> [on|off]"); + return; + } + + int num = atoi(g_RootMenu.GetArgument(3)); + if (num < 1 || num > (int)GetPluginCount()) + { + g_RootMenu.ConsolePrint("Plugin index not found."); + return; + } + + int res; + const char *mode = g_RootMenu.GetArgument(4); + if ((res=strcmp("on", mode)) && strcmp("off", mode)) + { + g_RootMenu.ConsolePrint("The only possible options are \"on\" and \"off.\""); + return; + } + + bool debug; + if (!res) + { + debug = true; + } else { + debug = false; + } + + CPlugin *pl = GetPluginByOrder(num); + if (debug && pl->IsDebugging()) + { + g_RootMenu.ConsolePrint("[SM] This plugin is already in debug mode."); + return; + } else if (!debug && !pl->IsDebugging()) { + g_RootMenu.ConsolePrint("[SM] Debug mode is already disabled in this plugin."); + return; + } + + char error[256]; + if (pl->ToggleDebugMode(debug, error, sizeof(error))) + { + g_RootMenu.ConsolePrint("Successfully toggled debug mode on plugin %s.", pl->GetFilename()); + return; + } else { + g_RootMenu.ConsolePrint("[SM] Could not toggle debug mode on plugin %s.", pl->GetFilename()); + g_RootMenu.ConsolePrint("[SM] Plugin returned error: %s", error); + return; + } + } + } + + /* Draw the main menu */ + g_RootMenu.ConsolePrint("SourceMod Plugins Menu:"); + g_RootMenu.DrawGenericOption("list", "Show loaded plugins"); + g_RootMenu.DrawGenericOption("load", "Load a plugin"); + g_RootMenu.DrawGenericOption("unload", "Unload a plugin"); + g_RootMenu.DrawGenericOption("info", "Information about a plugin"); + g_RootMenu.DrawGenericOption("debug", "Toggle debug mode on a plugin"); +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 83c11f7a..2452dc7f 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -12,6 +12,7 @@ #include "PluginInfoDatabase.h" #include "sm_trie.h" #include "sourcemod.h" +#include using namespace SourceHook; @@ -150,7 +151,7 @@ public: /** * Toggles debug mode in the plugin */ - bool ToggleDebugMode(bool debug); + bool ToggleDebugMode(bool debug, char *error, size_t maxlength); /** * Returns true if a plugin is usable. @@ -186,7 +187,8 @@ private: class CPluginManager : public IPluginManager, public SMGlobalClass, - public IHandleTypeDispatch + public IHandleTypeDispatch, + public IRootConsoleCommand { friend class CPlugin; public: @@ -227,6 +229,8 @@ public: //SMGlobalClass void OnSourceModShutdown(); public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); +public: //IRootConsoleCommand + void OnRootConsoleCommand(const char *command, unsigned int argcount); public: /** * Loads all plugins not yet loaded @@ -265,9 +269,14 @@ public: IPlugin *PluginFromHandle(Handle_t handle, HandleError *err); /** - * Finds a plugin based on its index. (starts on index 1) - */ + * Finds a plugin based on its index. (starts on index 1) + */ CPlugin *GetPluginByOrder(int num); + + /** + * Gets status text for a status code + */ + const char *GetStatusText(PluginStatus status); private: bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); From 1efdacd69b66b495e789e30ce99d0c9c15fb6470 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 00:17:36 +0000 Subject: [PATCH 0285/1664] added [SM] to direct responses of menu cmds began adding the extension menu --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40315 --- core/interfaces/IRootConsoleMenu.h | 4 +- core/systems/ExtensionSys.cpp | 113 +++++++++++++++++++++++++++++ core/systems/ExtensionSys.h | 6 +- core/systems/PluginSys.cpp | 22 +++--- 4 files changed, 132 insertions(+), 13 deletions(-) diff --git a/core/interfaces/IRootConsoleMenu.h b/core/interfaces/IRootConsoleMenu.h index 2344ae0e..fc389b5a 100644 --- a/core/interfaces/IRootConsoleMenu.h +++ b/core/interfaces/IRootConsoleMenu.h @@ -4,6 +4,8 @@ /** * @brief Note: This interface is not exposed. * The reason should be obvious: we do not want users touching the "root" console menu. + * If we exposed this, every little plugin would be dropping down a silly set of user commands, + * whereas this menu is explicitly provided for stuff that only Core itself is capable of managing. */ namespace SourceMod @@ -18,7 +20,7 @@ namespace SourceMod }; /** - * @brief Manages the root console menu. + * @brief Manages the root console menu - the "sm" command for servers. */ class IRootConsole { diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index ae223b57..ccd33c69 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -4,6 +4,7 @@ #include "CLogger.h" #include "sourcemm_api.h" #include "PluginSys.h" +#include "sm_srvcmds.h" CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -209,10 +210,12 @@ void CExtensionManager::OnSourceModAllInitialized() { g_ExtType = g_ShareSys.CreateIdentType("EXTENSION"); g_PluginSys.AddPluginsListener(this); + g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this); } void CExtensionManager::OnSourceModShutdown() { + g_RootMenu.RemoveRootConsoleCommand("exts", this); g_PluginSys.RemovePluginsListener(this); g_ShareSys.DestroyIdentType(g_ExtType); } @@ -418,3 +421,113 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) return true; } + +void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount) +{ + if (argcount >= 3) + { + const char *cmd = g_RootMenu.GetArgument(2); + if (strcmp(cmd, "list") == 0) + { + List::iterator iter; + CExtension *pExt; + unsigned int num = 1; + switch (m_Libs.size()) + { + case 1: + { + g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:"); + break; + } + case 0: + { + g_RootMenu.ConsolePrint("[SM] No extensions are loaded."); + break; + } + default: + { + g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size()); + break; + } + } + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++) + { + pExt = (*iter); + if (pExt->IsLoaded()) + { + IExtensionInterface *pAPI = pExt->GetAPI(); + const char *name = pAPI->GetExtensionName(); + const char *version = pAPI->GetExtensionVerString(); + const char *descr = pAPI->GetExtensionDescription(); + g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr); + } else { + g_RootMenu.ConsolePrint("[%02d] file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str()); + } + } + return; + } else if (strcmp(cmd, "info") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>"); + return; + } + + const char *sId = g_RootMenu.GetArgument(3); + unsigned int id = atoi(sId); + if (id <= 0) + { + g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>"); + return; + } + + if (m_Libs.size() == 0) + { + g_RootMenu.ConsolePrint("[SM] No extensions are loaded."); + return; + } + + if (id > m_Libs.size()) + { + g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id); + return; + } + + List::iterator iter = m_Libs.begin(); + CExtension *pExt = NULL; + while (iter != m_Libs.end()) + { + if (--id == 0) + { + pExt = (*iter); + break; + } + iter++; + } + /* This should never happen */ + if (!pExt) + { + g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id); + return; + } + + if (!pExt->IsLoaded()) + { + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); + g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str()); + } else { + IExtensionInterface *pAPI = pExt->GetAPI(); + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); + g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString()); + g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription()); + g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL()); + g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString()); + g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); + } + return; + } + } + + g_RootMenu.ConsolePrint("SourceMod Extensions Menu:"); + g_RootMenu.DrawGenericOption("info", "Extra extension information"); + g_RootMenu.DrawGenericOption("list", "List extensions"); +} diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index 2e946406..b56da392 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -9,6 +9,7 @@ #include "ShareSys.h" #include #include +#include using namespace SourceMod; using namespace SourceHook; @@ -48,7 +49,8 @@ private: class CExtensionManager : public IExtensionManager, public SMGlobalClass, - IPluginsListener + public IPluginsListener, + public IRootConsoleCommand { public: //SMGlobalClass void OnSourceModAllInitialized(); @@ -63,6 +65,8 @@ public: //IExtensionManager IExtension *FindExtensionByName(const char *ext); public: //IPluginsListener void OnPluginDestroyed(IPlugin *plugin); +public: //IRootConsoleCommand + void OnRootConsoleCommand(const char *cmd, unsigned int argcount); public: IExtension *LoadAutoExtension(const char *path); void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index c5db626e..dc43ca22 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1422,7 +1422,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc } else if (strcmp(cmd, "load") == 0) { if (argcount < 4) { - g_RootMenu.ConsolePrint("Usage: sm plugins load "); + g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load "); return; } @@ -1441,7 +1441,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc } else if (strcmp(cmd, "unload") == 0) { if (argcount < 4) { - g_RootMenu.ConsolePrint("Usage: sm plugins unload <#>"); + g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#>"); return; } @@ -1449,7 +1449,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc int num = atoi(g_RootMenu.GetArgument(3)); if (num < 1 || num > (int)GetPluginCount()) { - g_RootMenu.ConsolePrint("Plugin index %d not found.", num); + g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", num); return; } @@ -1464,9 +1464,9 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc if (UnloadPlugin(pl)) { - g_RootMenu.ConsolePrint("Plugin %s unloaded successfully.", name); + g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name); } else { - g_RootMenu.ConsolePrint("Failed to unload plugin %s.", name); + g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name); } iter->Release(); @@ -1474,7 +1474,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc } else if (strcmp(cmd, "info") == 0) { if (argcount < 4) { - g_RootMenu.ConsolePrint("Usage: sm plugins info <#>"); + g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>"); return; } @@ -1482,7 +1482,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc int num = atoi(g_RootMenu.GetArgument(3)); if (num < 1 || num > (int)GetPluginCount()) { - g_RootMenu.ConsolePrint("Plugin index not found."); + g_RootMenu.ConsolePrint("[SM] Plugin index not found."); return; } @@ -1524,14 +1524,14 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc } else if (strcmp(cmd, "debug") == 0) { if (argcount < 5) { - g_RootMenu.ConsolePrint("Usage: sm plugins debug <#> [on|off]"); + g_RootMenu.ConsolePrint("[SM] Usage: sm plugins debug <#> [on|off]"); return; } int num = atoi(g_RootMenu.GetArgument(3)); if (num < 1 || num > (int)GetPluginCount()) { - g_RootMenu.ConsolePrint("Plugin index not found."); + g_RootMenu.ConsolePrint("[SM] Plugin index not found."); return; } @@ -1539,7 +1539,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc const char *mode = g_RootMenu.GetArgument(4); if ((res=strcmp("on", mode)) && strcmp("off", mode)) { - g_RootMenu.ConsolePrint("The only possible options are \"on\" and \"off.\""); + g_RootMenu.ConsolePrint("[SM] The only possible options are \"on\" and \"off.\""); return; } @@ -1564,7 +1564,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc char error[256]; if (pl->ToggleDebugMode(debug, error, sizeof(error))) { - g_RootMenu.ConsolePrint("Successfully toggled debug mode on plugin %s.", pl->GetFilename()); + g_RootMenu.ConsolePrint("[SM] Successfully toggled debug mode on plugin %s.", pl->GetFilename()); return; } else { g_RootMenu.ConsolePrint("[SM] Could not toggle debug mode on plugin %s.", pl->GetFilename()); From 4ac5297d116b4153d50c3583bb99a70ae89fb405 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 09:14:20 +0000 Subject: [PATCH 0286/1664] fixed a dep bug fixed a plugin unload iterator bug extension unloading now works --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40316 --- core/systems/ExtensionSys.cpp | 143 +++++++++++++++++++++++++++++++++- core/systems/ExtensionSys.h | 3 + core/systems/PluginSys.cpp | 2 +- core/systems/ShareSys.cpp | 4 +- 4 files changed, 147 insertions(+), 5 deletions(-) diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index ccd33c69..7cf0461b 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -5,6 +5,7 @@ #include "sourcemm_api.h" #include "PluginSys.h" #include "sm_srvcmds.h" +#include CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -15,6 +16,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_pAPI = NULL; m_pIdentToken = NULL; m_PlId = 0; + unload_code = 0; char path[PLATFORM_MAX_PATH+1]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); @@ -349,6 +351,27 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin) } } +CExtension *CExtensionManager::FindByOrder(unsigned int num) +{ + if (num < 1 || num > m_Libs.size()) + { + return NULL; + } + + List::iterator iter = m_Libs.begin(); + + while (iter != m_Libs.end()) + { + if (--num == 0) + { + return (*iter); + } + iter++; + } + + return NULL; +} + bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -376,9 +399,9 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) List::iterator p_iter = pExt->m_Plugins.begin(); while (p_iter != pExt->m_Plugins.end()) { + /* We have to manually unlink ourselves here, since we're no longer being managed */ g_PluginSys.UnloadPlugin((*p_iter)); - /* It should already have been removed! */ - assert(pExt->m_Plugins.find((*p_iter)) != pExt->m_Plugins.end()); + p_iter = pExt->m_Plugins.erase(p_iter); } /* Notify and/or unload all dependencies */ @@ -392,6 +415,10 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) { continue; } + if (pDep == pExt) + { + continue; + } /* Now, get its dependency list */ bool dropped = false; List::iterator i_iter = pDep->m_Deps.begin(); @@ -524,10 +551,122 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); } return; + } else if (strcmp(cmd, "unload") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]"); + return; + } + + const char *arg = g_RootMenu.GetArgument(3); + unsigned int num = atoi(arg); + CExtension *pExt = FindByOrder(num); + + if (!pExt) + { + g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num); + return; + } + + if (argcount > 4 && pExt->unload_code) + { + const char *unload = g_RootMenu.GetArgument(4); + if (pExt->unload_code == atoi(unload)) + { + char filename[PLATFORM_MAX_PATH+1]; + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); + UnloadExtension(pExt); + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); + } else { + g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code); + } + return; + } + + if (!pExt->IsLoaded() + || (!pExt->m_Deps.size() && !pExt->m_Plugins.size())) + { + char filename[PLATFORM_MAX_PATH+1]; + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); + UnloadExtension(pExt); + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); + return; + } else { + List plugins; + if (pExt->m_Deps.size()) + { + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename()); + List::iterator iter; + CExtension *pOther; + /* Get list of all extensions */ + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + List::iterator i_iter; + pOther = (*iter); + if (!pOther->IsLoaded() || pOther == pExt) + { + continue; + } + /* Get their dependencies */ + for (i_iter=pOther->m_Deps.begin(); + i_iter!=pOther->m_Deps.end(); + i_iter++) + { + /* Is this dependency to us? */ + if ((*i_iter).owner != pExt) + { + continue; + } + /* Will our dependent care? */ + if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface)) + { + g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename()); + /* Add to plugin unload list */ + List::iterator p_iter; + for (p_iter=pOther->m_Plugins.begin(); + p_iter!=pOther->m_Plugins.end(); + p_iter++) + { + if (plugins.find((*p_iter)) == plugins.end()) + { + plugins.push_back((*p_iter)); + } + } + } + } + } + } + if (pExt->m_Plugins.size()) + { + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename()); + List::iterator iter; + IPlugin *pPlugin; + for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++) + { + pPlugin = (*iter); + if (plugins.find(pPlugin) == plugins.end()) + { + plugins.push_back(pPlugin); + } + } + for (iter = plugins.begin(); iter != plugins.end(); iter++) + { + pPlugin = (*iter); + g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename()); + } + } + srand(static_cast(time(NULL))); + pExt->unload_code = (rand() % 877) + 123; //123 to 999 + g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename()); + g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code); + + return; + } } } g_RootMenu.ConsolePrint("SourceMod Extensions Menu:"); g_RootMenu.DrawGenericOption("info", "Extra extension information"); g_RootMenu.DrawGenericOption("list", "List extensions"); + g_RootMenu.DrawGenericOption("unload", "Unload an extension"); } diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index b56da392..ec3d9a05 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -44,6 +44,7 @@ private: List m_Interfaces; List m_Plugins; PluginId m_PlId; + unsigned int unload_code; }; class CExtensionManager : @@ -72,6 +73,8 @@ public: void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); +private: + CExtension *FindByOrder(unsigned int num); private: List m_Libs; }; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index dc43ca22..aaef6ef7 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -966,7 +966,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) List::iterator iter; IPluginsListener *pListener; - if (pPlugin->GetStatus() >= Plugin_Error) + if (pPlugin->GetStatus() <= Plugin_Error) { /* Notify listeners of unloading */ for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 4d96b3f8..54789628 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -113,7 +113,7 @@ bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface) bool ShareSystem::RequestInterface(const char *iface_name, unsigned int iface_vers, - IExtension *mysql, + IExtension *myself, SMInterface **pIface) { /* See if the interface exists */ @@ -148,7 +148,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, IfaceInfo info; info.iface = iface; info.owner = iface_owner; - g_Extensions.BindDependency(iface_owner, &info); + g_Extensions.BindDependency(myself, &info); } if (pIface) From 232e02713790e23eac842799fd680a14b5d05911 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 20:30:45 +0000 Subject: [PATCH 0287/1664] Quick commit of ShareSys API change --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40317 --- core/interfaces/IShareSys.h | 4 ++-- core/systems/ShareSys.cpp | 2 +- core/systems/ShareSys.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index 9569eb5c..ec4bd997 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -78,9 +78,9 @@ namespace SourceMod * @brief Adds a list of natives to the global native pool. * * @param token Identity token of parent object. - * @param natives Array of natives to add, NULL terminated. + * @param natives Array of natives to add. The last entry must have NULL members. */ - virtual void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) =0; + virtual void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0; /** * @brief Creates a new identity type. diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 54789628..d1c1ac92 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -159,7 +159,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, return true; } -void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) +void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) { /* :TODO: implement */ } diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index 2aa86f82..be249e5c 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -36,7 +36,7 @@ public: //IShareSys unsigned int iface_vers, IExtension *mysql, SMInterface **pIface); - void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]); + void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives); IdentityType_t CreateIdentType(const char *name); IdentityType_t FindIdentType(const char *name); IdentityToken_t *CreateIdentity(IdentityType_t type); From c6b77c8cc10b284163b138582efa40b443c4a8ac Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 20:56:41 +0000 Subject: [PATCH 0288/1664] This is now const --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40318 --- core/interfaces/IShareSys.h | 4 +++- core/systems/ShareSys.cpp | 2 +- core/vm/sp_vm_basecontext.cpp | 4 ++-- core/vm/sp_vm_basecontext.h | 4 ++-- sourcepawn/include/sp_vm_api.h | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index ec4bd997..997ff2d1 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -75,7 +75,9 @@ namespace SourceMod SMInterface **pIface) =0; /** - * @brief Adds a list of natives to the global native pool. + * @brief Adds a list of natives to the global native pool, to be bound on plugin load. + * NOTE: Adding natives currently does not bind them to any loaded plugins. + * You must manually bind late natives. * * @param token Identity token of parent object. * @param natives Array of natives to add. The last entry must have NULL members. diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index d1c1ac92..df8c719c 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -161,7 +161,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - /* :TODO: implement */ + } void ShareSystem::DestroyIdentity(IdentityToken_t *identity) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 6b63ae53..fecfe427 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -432,7 +432,7 @@ uint32_t BaseContext::GetPubVarsNum() return ctx->plugin->info.pubvars_num; } -int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) +int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) { uint32_t i, j, max; @@ -458,7 +458,7 @@ int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int ove return SP_ERROR_NONE; } -int BaseContext::BindNative(sp_nativeinfo_t *native) +int BaseContext::BindNative(const sp_nativeinfo_t *native) { uint32_t index; int err; diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 7ba4d0f6..f755335e 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -38,8 +38,8 @@ namespace SourcePawn virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string); virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); - virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); - virtual int BindNative(sp_nativeinfo_t *native); + virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite); + virtual int BindNative(const sp_nativeinfo_t *native); virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); virtual int Execute(funcid_t funcid, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 3a3e01a8..cb904105 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -294,7 +294,7 @@ namespace SourcePawn * @param num Number of natives in array. * @param overwrite Toggles overwrite. */ - virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; + virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; /** * @brief Binds a single native. Overwrites any existing bind. @@ -303,7 +303,7 @@ namespace SourcePawn * * @param native Pointer to native. */ - virtual int BindNative(sp_nativeinfo_t *native) =0; + virtual int BindNative(const sp_nativeinfo_t *native) =0; /** * @brief Binds a single native to any non-registered native. From 3bba8d6a2a9ea82b182d872dbac41c6a0da3eef6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 21:07:10 +0000 Subject: [PATCH 0289/1664] --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40319 --- core/interfaces/IExtensionSys.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/interfaces/IExtensionSys.h b/core/interfaces/IExtensionSys.h index 9982832e..fc1a68f6 100644 --- a/core/interfaces/IExtensionSys.h +++ b/core/interfaces/IExtensionSys.h @@ -137,6 +137,18 @@ namespace SourceMod virtual void NotifyInterfaceDrop(SMInterface *pInterface) { } + + /** + * @brief Return false to tell Core that your extension should be considered unsable. + * + * @param error Error buffer. + * @param maxlength Size of error buffer. + * @return True on success, false otherwise. + */ + virtual bool QueryRunning(char *error, size_t maxlength) + { + return true; + } public: virtual bool IsMetamodExtension() =0; virtual const char *GetExtensionName() =0; From c5d0848177f3dd80fd8bca999ad6492c632341b3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Jan 2007 23:28:14 +0000 Subject: [PATCH 0290/1664] finished most of the extension system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40320 --- TODO.txt | 3 +- core/interfaces/IExtensionSys.h | 9 ++ core/sourcemod.cpp | 23 ++-- core/sourcemod.h | 6 -- core/systems/ExtensionSys.cpp | 155 ++++++++++++++++++++++++--- core/systems/ExtensionSys.h | 7 ++ core/systems/PluginSys.cpp | 180 ++++++++++++++++++++++---------- core/systems/PluginSys.h | 14 ++- core/systems/ShareSys.cpp | 2 +- extensions/sdk/extension.h | 10 ++ extensions/sdk/smsdk_ext.cpp | 4 +- extensions/sdk/smsdk_ext.h | 1 + 12 files changed, 322 insertions(+), 92 deletions(-) diff --git a/TODO.txt b/TODO.txt index 73923ed6..2323d7f6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,9 +1,10 @@ things to do for a release, in priority X finish plugin unloading X URGENT: fix compiler's sizeof(), add cellsof - - do module api + X do module api X finish plugin pausing/unpausing, forwards must block execution - do admin api + - make "mapupdated" plugins work as intended (reload on mapchange if newer) X add debugging output to logger - finish ML api, expose through interface X add error messages to format routine diff --git a/core/interfaces/IExtensionSys.h b/core/interfaces/IExtensionSys.h index fc1a68f6..36c5430d 100644 --- a/core/interfaces/IExtensionSys.h +++ b/core/interfaces/IExtensionSys.h @@ -67,6 +67,15 @@ namespace SourceMod * @param iter Pointer to iterator to free. */ virtual void FreeDependencyIterator(ITERATOR *iter) =0; + + /** + * @brief Queries the extension to see its run state. + * + * @param error Error buffer (may be NULL). + * @param maxlength Maximum length of buffer. + * @return True if extension is okay, false if not okay. + */ + virtual bool IsRunning(char *error, size_t maxlength) =0; }; #define SMINTERFACE_EXTENSIONAPI_VERSION 1 diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 11ea03d1..2581a7f4 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -7,6 +7,7 @@ #include "PluginSys.h" #include "ShareSys.h" #include "CLogger.h" +#include "ExtensionSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -131,13 +132,11 @@ void SourceModBase::StartSourceMod(bool late) /* First initialize the global hooks we need */ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); - m_IsLateLoadInMap = late; - /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) { - pBase->OnSourceModStartup(m_IsLateLoadInMap); + pBase->OnSourceModStartup(false); pBase = pBase->m_pGlobalClassNext; } @@ -156,7 +155,6 @@ void SourceModBase::StartSourceMod(bool late) bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { m_IsMapLoading = true; - m_IsLateLoadInMap = false; g_Logger.MapChange(pMapName); @@ -167,6 +165,11 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch RETURN_META_VALUE(MRES_IGNORED, true); } +bool SourceModBase::IsMapLoading() +{ + return m_IsMapLoading; +} + void SourceModBase::DoGlobalPluginLoads() { char config_path[PLATFORM_MAX_PATH]; @@ -181,10 +184,17 @@ void SourceModBase::DoGlobalPluginLoads() "%s/plugins", GetSMBaseDir()); + /* Run the first pass */ g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); + /* Mark any extensions as loaded */ + g_Extensions.MarkAllLoaded(); + /* No modules yet, it's safe to call this from here */ g_PluginSys.LoadAll_SecondPass(); + + /* Re-mark any extensions as loaded */ + g_Extensions.MarkAllLoaded(); } void SourceModBase::CloseSourceMod() @@ -209,11 +219,6 @@ void SourceModBase::CloseSourceMod() ShutdownJIT(); } -bool SourceModBase::IsLateLoadInMap() -{ - return m_IsLateLoadInMap; -} - const char *SourceModBase::GetSMBaseDir() { return m_SMBaseDir; diff --git a/core/sourcemod.h b/core/sourcemod.h index 38a3d217..9b7aa24e 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -46,11 +46,6 @@ public: * @brief Returns the base folder for file natives. */ const char *GetBaseDir(); - - /** - * @brief Returns whether our load in this map is late. - */ - bool IsLateLoadInMap(); private: /** * @brief Loading plugins @@ -59,7 +54,6 @@ private: private: char m_SMBaseDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; - bool m_IsLateLoadInMap; }; extern SourceModBase g_SourceMod; diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 7cf0461b..a0f2407d 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -17,6 +17,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_pIdentToken = NULL; m_PlId = 0; unload_code = 0; + m_FullyLoaded = false; char path[PLATFORM_MAX_PATH+1]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); @@ -56,7 +57,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType); - if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, g_SourceMod.IsLateLoadInMap())) + if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, !g_SourceMod.IsMapLoading())) { if (m_pAPI->IsMetamodExtension()) { @@ -73,6 +74,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) g_ShareSys.DestroyIdentity(m_pIdentToken); m_pIdentToken = NULL; return; + } else { + /* Check if we're past load time */ + if (!g_SourceMod.IsMapLoading()) + { + m_pAPI->OnExtensionsAllLoaded(); + } } } @@ -98,6 +105,16 @@ CExtension::~CExtension() } } +void CExtension::MarkAllLoaded() +{ + assert(m_FullyLoaded == false); + if (!m_FullyLoaded) + { + m_FullyLoaded = true; + m_pAPI->OnExtensionsAllLoaded(); + } +} + void CExtension::AddPlugin(IPlugin *pPlugin) { m_Plugins.push_back(pPlugin); @@ -204,6 +221,20 @@ void CExtension::AddInterface(SMInterface *pInterface) m_Interfaces.push_back(pInterface); } +bool CExtension::IsRunning(char *error, size_t maxlength) +{ + if (!IsLoaded()) + { + if (error) + { + snprintf(error, maxlength, "%s", m_Error.c_str()); + } + return false; + } + + return m_pAPI->QueryRunning(error, maxlength); +} + /********************* * EXTENSION MANAGER * *********************/ @@ -224,6 +255,13 @@ void CExtensionManager::OnSourceModShutdown() IExtension *CExtensionManager::LoadAutoExtension(const char *path) { + if (!strstr(path, "." PLATFORM_LIB_EXT)) + { + char newpath[PLATFORM_MAX_PATH+1]; + snprintf(newpath, PLATFORM_MAX_PATH, "%s.%s", path, PLATFORM_LIB_EXT); + return LoadAutoExtension(newpath); + } + IExtension *pAlready; if ((pAlready=FindExtensionByFile(path)) != NULL) { @@ -249,6 +287,13 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file) List::iterator iter; CExtension *pExt; + if (!strstr(file, "." PLATFORM_LIB_EXT)) + { + char path[PLATFORM_MAX_PATH]; + snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT); + return FindExtensionByFile(path); + } + /* Make sure the file direction is right */ char path[PLATFORM_MAX_PATH+1]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); @@ -315,6 +360,8 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime return NULL; } + /* :TODO: do QueryRunning check if the map is loaded */ + m_Libs.push_back(pExt); return pExt; @@ -372,6 +419,47 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num) return NULL; } +void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin) +{ + List::iterator iter; + CExtension *pExt; + IPluginContext *pContext = pPlugin->GetBaseContext(); + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + pExt = (*iter); + if (!pExt->IsLoaded()) + { + continue; + } + if (!pExt->m_Natives.size()) + { + continue; + } + bool set = false; + List::iterator n_iter; + const sp_nativeinfo_t *natives; + for (n_iter = pExt->m_Natives.begin(); + n_iter != pExt->m_Natives.end(); + n_iter++) + { + natives = (*n_iter); + unsigned int i=0; + while (natives[i].func != NULL && natives[i].name != NULL) + { + if (pContext->BindNative(&natives[i++]) == SP_ERROR_NONE) + { + set = true; + } + } + } + if (set && (pExt->m_Plugins.find(pPlugin) == pExt->m_Plugins.end())) + { + /* For now, mark this plugin as a requirement. Later we'll introduce native filtering. */ + pExt->m_Plugins.push_back(pPlugin); + } + } +} + bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -449,6 +537,33 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) return true; } +void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives) +{ + CExtension *pExt = (CExtension *)pOwner; + + pExt->m_Natives.push_back(natives); +} + +void CExtensionManager::MarkAllLoaded() +{ + List::iterator iter; + CExtension *pExt; + + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + pExt = (*iter); + if (!pExt->IsLoaded()) + { + continue; + } + if (pExt->m_FullyLoaded) + { + continue; + } + pExt->MarkAllLoaded(); + } +} + void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount) { if (argcount >= 3) @@ -482,11 +597,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco pExt = (*iter); if (pExt->IsLoaded()) { - IExtensionInterface *pAPI = pExt->GetAPI(); - const char *name = pAPI->GetExtensionName(); - const char *version = pAPI->GetExtensionVerString(); - const char *descr = pAPI->GetExtensionDescription(); - g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr); + char error[255]; + if (!pExt->IsRunning(error, sizeof(error))) + { + g_RootMenu.ConsolePrint("[%02d] file \"%s\": %s", num, pExt->GetFilename(), error); + } else { + IExtensionInterface *pAPI = pExt->GetAPI(); + const char *name = pAPI->GetExtensionName(); + const char *version = pAPI->GetExtensionVerString(); + const char *descr = pAPI->GetExtensionDescription(); + g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr); + } } else { g_RootMenu.ConsolePrint("[%02d] file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str()); } @@ -542,13 +663,21 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str()); } else { - IExtensionInterface *pAPI = pExt->GetAPI(); - g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); - g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString()); - g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription()); - g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL()); - g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString()); - g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); + char error[255]; + if (!pExt->IsRunning(error, sizeof(error))) + { + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); + g_RootMenu.ConsolePrint(" Loaded: Yes"); + g_RootMenu.ConsolePrint(" Running: No (%s)", error); + } else { + IExtensionInterface *pAPI = pExt->GetAPI(); + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); + g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString()); + g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription()); + g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL()); + g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString()); + g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); + } } return; } else if (strcmp(cmd, "unload") == 0) { diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index ec3d9a05..f3afc978 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -28,12 +28,14 @@ public: //IExtension ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface); bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface); void FreeDependencyIterator(ITERATOR *iter); + bool IsRunning(char *error, size_t maxlength); public: void SetError(const char *error); void AddDependency(IfaceInfo *pInfo); void AddInterface(SMInterface *pInterface); void AddPlugin(IPlugin *pPlugin); void RemovePlugin(IPlugin *pPlugin); + void MarkAllLoaded(); private: IdentityToken_t *m_pIdentToken; IExtensionInterface *m_pAPI; @@ -43,8 +45,10 @@ private: List m_Deps; List m_Interfaces; List m_Plugins; + List m_Natives; PluginId m_PlId; unsigned int unload_code; + bool m_FullyLoaded; }; class CExtensionManager : @@ -73,6 +77,9 @@ public: void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); + void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives); + void BindAllNativesToPlugin(IPlugin *pPlugin); + void MarkAllLoaded(); private: CExtension *FindByOrder(unsigned int num); private: diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index aaef6ef7..bb168ffb 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -693,7 +693,6 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa } //well i have discovered that gabe newell is very fat, so i wrote this comment now -//:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin() bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max) { /** @@ -777,7 +776,11 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug { AddCoreNativesToPlugin(pPlugin); pPlugin->InitIdentity(); - pPlugin->Call_AskPluginLoad(error, err_max); + if (pPlugin->Call_AskPluginLoad(error, err_max)) + { + /* Autoload any modules */ + LoadOrRequireExtensions(pPlugin, 1, error, err_max); + } } if (_plugin) @@ -800,6 +803,16 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ AddPlugin(pl); + /* Run second pass if we need to */ + if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded) + { + if (!RunSecondPass(pl, error, err_max)) + { + UnloadPlugin(pl); + return NULL; + } + } + return pl; } @@ -837,20 +850,25 @@ void CPluginManager::LoadAll_SecondPass() List::iterator iter; CPlugin *pPlugin; + char error[256]; for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++) { pPlugin = (*iter); if (pPlugin->GetStatus() == Plugin_Loaded) { - /* :TODO: fix */ - RunSecondPass(pPlugin, NULL, 0); + error[0] = '\0'; + if (!RunSecondPass(pPlugin, error, sizeof(error))) + { + g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error); + pPlugin->SetErrorState(Plugin_Failed, "%s", error); + } } } m_AllPluginsLoaded = true; } -bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength) +bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength) { /* Find any extensions this plugin needs */ struct _ext @@ -888,36 +906,75 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng { continue; } - snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT); - pExt = NULL; - /* Attempt to auto-load if necessary */ - if (ext->autoload) + if (pass == 1) { - pExt = g_Extensions.LoadAutoExtension(path); - } - /* See if we can find a similar extension */ - if (ext->required && !pExt) - { - if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL) + /* Attempt to auto-load if necessary */ + if (ext->autoload) { - pExt = g_Extensions.FindExtensionByName(name); + g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); + g_Extensions.LoadAutoExtension(path); + } + } else if (pass == 2) { + /* Is this required? */ + if (ext->required) + { + g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); + if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL) + { + pExt = g_Extensions.FindExtensionByName(name); + } + /* :TODO: should we bind to unloaded extensions? + * Currently the extension manager will ignore this. + */ + if (!pExt || !pExt->IsRunning(NULL, 0)) + { + if (error) + { + snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file); + } + pPlugin->m_status = Plugin_Failed; + return false; + } else { + g_Extensions.BindChildPlugin(pExt, pPlugin); + } } } - /* If we're requiring and got an extension and it's loaded, bind it */ - if (ext->required && pExt && pExt->IsLoaded()) + } + } + + return true; +} + +bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength) +{ + /* Second pass for extension requirements */ + if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength)) + { + return false; + } + + /* Bind all extra natives */ + g_Extensions.BindAllNativesToPlugin(pPlugin); + + /* Find any unbound natives + * Right now, these are not allowed + */ + IPluginContext *pContext = pPlugin->GetBaseContext(); + uint32_t num = pContext->GetNativesNum(); + sp_native_t *native; + for (unsigned int i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + break; + } + if (native->status == SP_NATIVE_UNBOUND) + { + if (error) { - g_Extensions.BindChildPlugin(pExt, pPlugin); - } - /* If we're requiring and we didn't get an extension or it's not loaded, error */ - if (ext->required && (!pExt || !pExt->IsLoaded())) - { - if (error) - { - snprintf(error, maxlength, "Required extension \"%s\" (file \"%s\") not found", name, file); - } - pPlugin->m_status = Plugin_Failed; - return false; + snprintf(error, maxlength, "Native \"%s\" was not found.", native->name); } + return false; } } @@ -1268,7 +1325,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) bool CPluginManager::IsLateLoadTime() const { - return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap()); + return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading()); } void CPluginManager::OnSourceModAllInitialized() @@ -1486,40 +1543,49 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc return; } - IPluginIterator *iter = GetPluginIterator(); - for (; iter->MorePlugins() && idNextPlugin(), id++) {} - - IPlugin *pl = iter->GetPlugin(); + CPlugin *pl = GetPluginByOrder(num); const sm_plugininfo_t *info = pl->GetPublicInfo(); g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename()); - if (IS_STR_FILLED(info->name)) - { - g_RootMenu.ConsolePrint(" Title: %s", info->name); - } - if (IS_STR_FILLED(info->author)) - { - g_RootMenu.ConsolePrint(" Author: %s", info->author); - } - if (IS_STR_FILLED(info->version)) - { - g_RootMenu.ConsolePrint(" Version: %s", info->version); - } - if (IS_STR_FILLED(info->description)) - { - g_RootMenu.ConsolePrint(" Description: %s", info->description); - } - if (IS_STR_FILLED(info->url)) - { - g_RootMenu.ConsolePrint(" URL: %s", info->url); - } - if (pl->GetStatus() >= Plugin_Error) + if (pl->GetStatus() <= Plugin_Error) { + if (IS_STR_FILLED(info->name)) + { + g_RootMenu.ConsolePrint(" Title: %s", info->name); + } + if (IS_STR_FILLED(info->version)) + { + g_RootMenu.ConsolePrint(" Version: %s", info->version); + } + if (IS_STR_FILLED(info->url)) + { + g_RootMenu.ConsolePrint(" URL: %s", info->url); + } + if (IS_STR_FILLED(info->author)) + { + g_RootMenu.ConsolePrint(" Author: %s", info->author); + } + if (IS_STR_FILLED(info->version)) + { + g_RootMenu.ConsolePrint(" Version: %s", info->version); + } + if (IS_STR_FILLED(info->description)) + { + g_RootMenu.ConsolePrint(" Description: %s", info->description); + } g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no"); + g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "yes" : "no"); + } else { + g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg); + g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")", + info->name ? info->name : "", + info->version ? info->version : ""); + if (IS_STR_FILLED(info->url)) + { + g_RootMenu.ConsolePrint(" File URL: %s", info->url); + } } - iter->Release(); - return; } else if (strcmp(cmd, "debug") == 0) { if (argcount < 5) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 2452dc7f..5e804503 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -149,13 +149,13 @@ public: void Call_OnPluginUnload(); /** - * Toggles debug mode in the plugin - */ + * Toggles debug mode in the plugin + */ bool ToggleDebugMode(bool debug, char *error, size_t maxlength); /** - * Returns true if a plugin is usable. - */ + * Returns true if a plugin is usable. + */ bool IsRunnable() const; public: time_t HasUpdatedFile(); @@ -277,6 +277,7 @@ public: * Gets status text for a status code */ const char *GetStatusText(PluginStatus status); + private: bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); @@ -301,6 +302,11 @@ private: * Adds any globally registered natives to a plugin */ void AddCoreNativesToPlugin(CPlugin *pPlugin); + + /** + * Runs an extension pass on a plugin. + */ + bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength); protected: /** * Caching internal objects diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index df8c719c..5d7bb335 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -161,7 +161,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - + g_Extensions.AddNatives(myself, natives); } void ShareSystem::DestroyIdentity(IdentityToken_t *identity) diff --git a/extensions/sdk/extension.h b/extensions/sdk/extension.h index d93261e1..7d0fc767 100644 --- a/extensions/sdk/extension.h +++ b/extensions/sdk/extension.h @@ -27,6 +27,7 @@ public: /** * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. */ //virtual void SDK_OnAllLoaded(); @@ -34,6 +35,15 @@ public: * @brief Called when the pause state is changed. */ //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual void QueryRunning(char *error, size_t maxlength); public: #if defined SMEXT_CONF_METAMOD /** diff --git a/extensions/sdk/smsdk_ext.cpp b/extensions/sdk/smsdk_ext.cpp index b325a682..3bd1ffe2 100644 --- a/extensions/sdk/smsdk_ext.cpp +++ b/extensions/sdk/smsdk_ext.cpp @@ -24,9 +24,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, g_pShareSys = sys; myself = me; +#if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; -#if defined SMEXT_CONF_METAMOD if (!m_SourceMMLoaded) { if (error) @@ -41,7 +41,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, if (SDK_OnLoad(error, err_max, late)) { +#if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; +#endif return true; } diff --git a/extensions/sdk/smsdk_ext.h b/extensions/sdk/smsdk_ext.h index 7060cb1c..f4d30711 100644 --- a/extensions/sdk/smsdk_ext.h +++ b/extensions/sdk/smsdk_ext.h @@ -13,6 +13,7 @@ #endif using namespace SourceMod; +using namespace SourcePawn; class SDKExtension : #if defined SMEXT_CONF_METAMOD From 2ea877f14b8b27c79a38a404a1aefdd621ec2b12 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 19 Jan 2007 01:50:42 +0000 Subject: [PATCH 0291/1664] after some exam days its nice to code again --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40321 --- extensions/geoip/GeoIP.c | 969 ++++++++++++++++++++++++++++++++ extensions/geoip/GeoIP.dat | Bin 0 -> 682474 bytes extensions/geoip/GeoIP.h | 169 ++++++ extensions/geoip/extension.cpp | 83 +++ extensions/geoip/extension.h | 61 ++ extensions/geoip/geoip.sln | 26 + extensions/geoip/geoip.vcproj | 379 +++++++++++++ extensions/geoip/smsdk_config.h | 27 + extensions/geoip/smsdk_ext.cpp | 277 +++++++++ extensions/geoip/smsdk_ext.h | 140 +++++ 10 files changed, 2131 insertions(+) create mode 100644 extensions/geoip/GeoIP.c create mode 100644 extensions/geoip/GeoIP.dat create mode 100644 extensions/geoip/GeoIP.h create mode 100644 extensions/geoip/extension.cpp create mode 100644 extensions/geoip/extension.h create mode 100644 extensions/geoip/geoip.sln create mode 100644 extensions/geoip/geoip.vcproj create mode 100644 extensions/geoip/smsdk_config.h create mode 100644 extensions/geoip/smsdk_ext.cpp create mode 100644 extensions/geoip/smsdk_ext.h diff --git a/extensions/geoip/GeoIP.c b/extensions/geoip/GeoIP.c new file mode 100644 index 00000000..c5ee3217 --- /dev/null +++ b/extensions/geoip/GeoIP.c @@ -0,0 +1,969 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ +/* GeoIP.c + * + * Copyright (C) 2006 MaxMind LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "GeoIP.h" + +#ifndef _WIN32 +#include +#include +#include /* For ntohl */ +#include +#else +#include +#define snprintf _snprintf +#endif +#include +#include +#include +#include +#include +#include /* for fstat */ +#include /* for fstat */ + +#ifdef HAVE_STDINT_H +#include /* For uint32_t */ +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE -1 +#endif + +#define COUNTRY_BEGIN 16776960 +#define STATE_BEGIN_REV0 16700000 +#define STATE_BEGIN_REV1 16000000 +#define STRUCTURE_INFO_MAX_SIZE 20 +#define DATABASE_INFO_MAX_SIZE 100 +#define MAX_ORG_RECORD_LENGTH 300 +#define US_OFFSET 1 +#define CANADA_OFFSET 677 +#define WORLD_OFFSET 1353 +#define FIPS_RANGE 360 + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char GeoIP_country_code[251][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN", + "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB", + "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO", + "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD", + "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR", + "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO", + "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ", + "FK","FM","FO","FR","FX","GA","GB","GD","GE","GF", + "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT", + "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID", + "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO", + "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW", + "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT", + "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML", + "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV", + "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI", + "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF", + "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW", + "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD", + "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO", + "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH", + "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW", + "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE", + "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA", + "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"}; + +const char GeoIP_country_code3[251][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT", + "AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB", + "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL", + "BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD", + "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI", + "CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM", + "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI", + "FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF", + "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM", + "GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN", + "IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR", + "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT", + "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU", + "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI", + "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV", + "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC", + "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF", + "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW", + "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN", + "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM", + "SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA", + "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN", + "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN", + "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF", + "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"}; + +const char * GeoIP_country_name[251] = {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", + "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", + "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", + "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", + "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", + "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", + "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", + "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", + "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", + "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", + "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", + "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", + "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", + "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", + "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", + "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", + "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", + "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"}; + +const char GeoIP_country_continent[251][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA", + "AF","AN","SA","OC","EU","OC","SA","AS","EU","SA", + "AS","EU","AF","EU","AS","AF","AF","SA","AS","SA", + "SA","SA","AS","AF","AF","EU","SA","NA","AS","AF", + "AF","AF","EU","AF","OC","SA","AF","AS","SA","SA", + "SA","AF","AS","AS","EU","EU","AF","EU","SA","SA", + "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC", + "SA","OC","EU","EU","EU","AF","EU","SA","AS","SA", + "AF","EU","SA","AF","AF","SA","AF","EU","SA","SA", + "OC","AF","SA","AS","AF","SA","EU","SA","EU","AS", + "EU","AS","AS","AS","AS","AS","EU","EU","SA","AS", + "AS","AF","AS","AS","OC","AF","SA","AS","AS","AS", + "SA","AS","AS","AS","SA","EU","AS","AF","AF","EU", + "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF", + "AS","AS","AS","OC","SA","AF","SA","EU","AF","AS", + "AF","NA","AS","AF","AF","OC","AF","OC","AF","SA", + "EU","EU","AS","OC","OC","OC","AS","SA","SA","OC", + "OC","AS","AS","EU","SA","OC","SA","AS","EU","OC", + "SA","AS","AF","EU","AS","AF","AS","OC","AF","AF", + "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF", + "SA","AF","SA","AS","AF","SA","AF","AF","AF","AS", + "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS", + "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA", + "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF", + "AF","EU","AF","--","--","--","EU","EU","EU","EU"}; + +const char * GeoIPDBDescription[NUM_DB_TYPES] = {NULL, "GeoIP Country Edition", "GeoIP City Edition, Rev 1", "GeoIP Region Edition, Rev 1", "GeoIP ISP Edition", "GeoIP Organization Edition", "GeoIP City Edition, Rev 0", "GeoIP Region Edition, Rev 0","GeoIP Proxy Edition","GeoIP ASNum Edition","GeoIP Netspeed Edition","GeoIP Domain Name Edition"}; + +char * custom_directory = NULL; + +void GeoIP_setup_custom_directory (char * dir) { + custom_directory = dir; +} + +char *_GeoIP_full_path_to(const char *file_name) { + char *path = malloc(sizeof(char) * 1024); + + if (custom_directory == NULL){ +#ifndef _WIN32 + memset(path, 0, sizeof(char) * 1024); + snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name); +#else + char buf[MAX_PATH], *p, *q = NULL; + int len; + memset(buf, 0, sizeof(buf)); + len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1); + for (p = buf + len; p > buf; p--) + if (*p == '\\') + { + if (!q) + q = p; + else + *p = '/'; + } + *q = 0; + memset(path, 0, sizeof(char) * 1024); + snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name); +#endif + } else { + size_t l = strlen(custom_directory); + if (custom_directory[l-1] != '/') { + snprintf(path, sizeof(char) * 1024 - 1, "%s/%s",custom_directory, file_name); + } else { + snprintf(path, sizeof(char) * 1024 - 1, "%s%s", custom_directory, file_name); + } + } + return path; +} + +char ** GeoIPDBFileName = NULL; + +void _GeoIP_setup_dbfilename() { + if (NULL == GeoIPDBFileName) { + GeoIPDBFileName = malloc(sizeof(char *) * NUM_DB_TYPES); + memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES); + + GeoIPDBFileName[GEOIP_COUNTRY_EDITION] = _GeoIP_full_path_to("GeoIP.dat"); + GeoIPDBFileName[GEOIP_REGION_EDITION_REV0] = _GeoIP_full_path_to("GeoIPRegion.dat"); + GeoIPDBFileName[GEOIP_REGION_EDITION_REV1] = _GeoIP_full_path_to("GeoIPRegion.dat"); + GeoIPDBFileName[GEOIP_CITY_EDITION_REV0] = _GeoIP_full_path_to("GeoIPCity.dat"); + GeoIPDBFileName[GEOIP_CITY_EDITION_REV1] = _GeoIP_full_path_to("GeoIPCity.dat"); + GeoIPDBFileName[GEOIP_ISP_EDITION] = _GeoIP_full_path_to("GeoIPISP.dat"); + GeoIPDBFileName[GEOIP_ORG_EDITION] = _GeoIP_full_path_to("GeoIPOrg.dat"); + GeoIPDBFileName[GEOIP_PROXY_EDITION] = _GeoIP_full_path_to("GeoIPProxy.dat"); + GeoIPDBFileName[GEOIP_ASNUM_EDITION] = _GeoIP_full_path_to("GeoIPASNum.dat"); + GeoIPDBFileName[GEOIP_NETSPEED_EDITION] = _GeoIP_full_path_to("GeoIPNetSpeed.dat"); + GeoIPDBFileName[GEOIP_DOMAIN_EDITION] = _GeoIP_full_path_to("GeoIPDomain.dat"); + } +} + +static +int _file_exists(const char *file_name) { + struct stat file_stat; + return( (stat(file_name, &file_stat) == 0) ? 1:0); +} + +int GeoIP_db_avail(int type) { + const char * filePath; + if (type < 0 || type >= NUM_DB_TYPES) { + return 0; + } + filePath = GeoIPDBFileName[type]; + if (NULL == filePath) { + return 0; + } + return _file_exists(filePath); +} + +static +void _setup_segments(GeoIP * gi) { + int i, j; + unsigned char delim[3]; + unsigned char buf[SEGMENT_RECORD_LENGTH]; + + gi->databaseSegments = NULL; + + /* default to GeoIP Country Edition */ + gi->databaseType = GEOIP_COUNTRY_EDITION; + gi->record_length = STANDARD_RECORD_LENGTH; + fseek(gi->GeoIPDatabase, -3l, SEEK_END); + for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { + fread(delim, 1, 3, gi->GeoIPDatabase); + if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) { + fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase); + if (gi->databaseType >= 106) { + /* backwards compatibility with databases from April 2003 and earlier */ + gi->databaseType -= 105; + } + + if (gi->databaseType == GEOIP_REGION_EDITION_REV0) { + /* Region Edition, pre June 2003 */ + gi->databaseSegments = malloc(sizeof(int)); + gi->databaseSegments[0] = STATE_BEGIN_REV0; + } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) { + /* Region Edition, post June 2003 */ + gi->databaseSegments = malloc(sizeof(int)); + gi->databaseSegments[0] = STATE_BEGIN_REV1; + } else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 || + gi->databaseType == GEOIP_CITY_EDITION_REV1 || + gi->databaseType == GEOIP_ORG_EDITION || + gi->databaseType == GEOIP_ISP_EDITION || + gi->databaseType == GEOIP_ASNUM_EDITION) { + /* City/Org Editions have two segments, read offset of second segment */ + gi->databaseSegments = malloc(sizeof(int)); + gi->databaseSegments[0] = 0; + fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase); + for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) { + gi->databaseSegments[0] += (buf[j] << (j * 8)); + } + if (gi->databaseType == GEOIP_ORG_EDITION || + gi->databaseType == GEOIP_ISP_EDITION) + gi->record_length = ORG_RECORD_LENGTH; + } + break; + } else { + fseek(gi->GeoIPDatabase, -4l, SEEK_CUR); + } + } + if (gi->databaseType == GEOIP_COUNTRY_EDITION || + gi->databaseType == GEOIP_PROXY_EDITION || + gi->databaseType == GEOIP_NETSPEED_EDITION) { + gi->databaseSegments = malloc(sizeof(int)); + gi->databaseSegments[0] = COUNTRY_BEGIN; + } +} + +static +int _check_mtime(GeoIP *gi) { + struct stat buf; + if (gi->flags & GEOIP_CHECK_CACHE) { + if (stat(gi->file_path, &buf) != -1) { + if (buf.st_mtime != gi->mtime) { + /* GeoIP Database file updated */ + if (gi->flags & GEOIP_MEMORY_CACHE) { + /* reload database into memory cache */ + if ((gi->cache = (unsigned char*) realloc(gi->cache, buf.st_size)) == NULL) { + fprintf(stderr,"Out of memory when reloading %s\n",gi->file_path); + return -1; + } + } + /* refresh filehandle */ + fclose(gi->GeoIPDatabase); + gi->GeoIPDatabase = fopen(gi->file_path,"rb"); + if (gi->GeoIPDatabase == NULL) { + fprintf(stderr,"Error Opening file %s when reloading\n",gi->file_path); + return -1; + } + gi->mtime = buf.st_mtime; + if (gi->flags & GEOIP_MEMORY_CACHE) { + if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) { + fprintf(stderr,"Error reading file %s when reloading\n",gi->file_path); + return -1; + } + } + if (gi->databaseSegments != NULL) { + free(gi->databaseSegments); + gi->databaseSegments = NULL; + } + _setup_segments(gi); + if (gi->databaseSegments == NULL) { + fprintf(stderr, "Error reading file %s -- corrupt\n", gi->file_path); + return -1; + } + if (gi->flags & GEOIP_INDEX_CACHE) { + gi->index_cache = (unsigned char *) realloc(gi->index_cache, sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2))); + if (gi->index_cache != NULL) { + fseek(gi->GeoIPDatabase, 0, SEEK_SET); + if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) { + fprintf(stderr,"Error reading file %s where reloading\n",gi->file_path); + return -1; + } + } + } + } + } + } + return 0; +} + +unsigned int _GeoIP_seek_record (GeoIP *gi, unsigned long ipnum) { + int depth; + unsigned int x; + unsigned char stack_buffer[2 * MAX_RECORD_LENGTH]; + const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL; + unsigned int offset = 0; + + const unsigned char * p; + int j; + + _check_mtime(gi); + for (depth = 31; depth >= 0; depth--) { + if (gi->cache == NULL && gi->index_cache == NULL) { + /* read from disk */ + fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET); + fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase); + } else if (gi->index_cache == NULL) { + /* simply point to record in memory */ + buf = gi->cache + (long)gi->record_length * 2 *offset; + } else { + buf = gi->index_cache + (long)gi->record_length * 2 * offset; + } + + if (ipnum & (1 << depth)) { + /* Take the right-hand branch */ + if ( gi->record_length == 3 ) { + /* Most common case is completely unrolled and uses constants. */ + x = (buf[3*1 + 0] << (0*8)) + + (buf[3*1 + 1] << (1*8)) + + (buf[3*1 + 2] << (2*8)); + + } else { + /* General case */ + j = gi->record_length; + p = &buf[2*j]; + x = 0; + do { + x <<= 8; + x += *(--p); + } while ( --j ); + } + + } else { + /* Take the left-hand branch */ + if ( gi->record_length == 3 ) { + /* Most common case is completely unrolled and uses constants. */ + x = (buf[3*0 + 0] << (0*8)) + + (buf[3*0 + 1] << (1*8)) + + (buf[3*0 + 2] << (2*8)); + } else { + /* General case */ + j = gi->record_length; + p = &buf[1*j]; + x = 0; + do { + x <<= 8; + x += *(--p); + } while ( --j ); + } + } + + if (x >= gi->databaseSegments[0]) { + return x; + } + offset = x; + } + + /* shouldn't reach here */ + fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum); + return 0; +} + +unsigned long _GeoIP_addr_to_num (const char *addr) { + int i; + char tok[4]; + int octet; + int j = 0, k = 0; + unsigned long ipnum = 0; + char c = 0; + + for (i=0; i<4; i++) { + for (;;) { + c = addr[k++]; + if (c == '.' || c == '\0') { + tok[j] = '\0'; + octet = atoi(tok); + if (octet > 255) + return 0; + ipnum += (octet << ((3-i)*8)); + j = 0; + break; + } else if (c >= '0' && c<= '9') { + if (j > 2) { + return 0; + } + tok[j++] = c; + } else { + return 0; + } + } + if(c == '\0' && i<3) { + return 0; + } + } + return ipnum; +} + +GeoIP* GeoIP_open_type (int type, int flags) { + GeoIP * gi; + const char * filePath; + if (type < 0 || type >= NUM_DB_TYPES) { + printf("Invalid database type %d\n", type); + return NULL; + } + _GeoIP_setup_dbfilename(); + filePath = GeoIPDBFileName[type]; + if (filePath == NULL) { + printf("Invalid database type %d\n", type); + return NULL; + } + gi = GeoIP_open (filePath, flags); + return gi; +} + +GeoIP* GeoIP_new (int flags) { + GeoIP * gi; + _GeoIP_setup_dbfilename(); + gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags); + return gi; +} + +GeoIP* GeoIP_open (const char * filename, int flags) { + struct stat buf; + GeoIP * gi; + size_t len; + +#ifdef _WIN32 + WSADATA wsa; + if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0) + return NULL; +#endif + + gi = (GeoIP *)malloc(sizeof(GeoIP)); + if (gi == NULL) + return NULL; + len = sizeof(char) * (strlen(filename)+1); + gi->file_path = malloc(len); + if (gi->file_path == NULL) { + free(gi); + return NULL; + } + strncpy(gi->file_path, filename, len); + gi->GeoIPDatabase = fopen(filename,"rb"); + if (gi->GeoIPDatabase == NULL) { + fprintf(stderr,"Error Opening file %s\n",filename); + free(gi->file_path); + free(gi); + return NULL; + } else { + if (flags & GEOIP_MEMORY_CACHE) { + if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) { + fprintf(stderr,"Error stating file %s\n",filename); + free(gi->file_path); + free(gi); + return NULL; + } + gi->mtime = buf.st_mtime; + gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * buf.st_size); + if (gi->cache != NULL) { + if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) { + fprintf(stderr,"Error reading file %s\n",filename); + free(gi->cache); + free(gi->file_path); + free(gi); + return NULL; + } + } + } else { + if (flags & GEOIP_CHECK_CACHE) { + if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) { + fprintf(stderr,"Error stating file %s\n",filename); + free(gi->file_path); + free(gi); + return NULL; + } + gi->mtime = buf.st_mtime; + } + gi->cache = NULL; + } + gi->flags = flags; + _setup_segments(gi); + if (flags & GEOIP_INDEX_CACHE) { + gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2))); + if (gi->index_cache != NULL) { + fseek(gi->GeoIPDatabase, 0, SEEK_SET); + if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) { + fprintf(stderr,"Error reading file %s\n",filename); + free(gi->databaseSegments); + free(gi->index_cache); + free(gi); + return NULL; + } + } + } else { + gi->index_cache = NULL; + } + return gi; + } +} + +void GeoIP_delete (GeoIP *gi) { + if (gi == NULL ) + return; + if (gi->GeoIPDatabase != NULL) + fclose(gi->GeoIPDatabase); + if (gi->cache != NULL) + free(gi->cache); + if (gi->index_cache != NULL) + free(gi->index_cache); + if (gi->file_path != NULL) + free(gi->file_path); + if (gi->databaseSegments != NULL) + free(gi->databaseSegments); + free(gi); +} + +const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) { + int country_id; + country_id = GeoIP_id_by_name(gi, name); + return (country_id > 0) ? GeoIP_country_code[country_id] : NULL; +} + +const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) { + int country_id; + country_id = GeoIP_id_by_name(gi, name); + return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL; +} + +const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) { + int country_id; + country_id = GeoIP_id_by_name(gi, name); + return (country_id > 0) ? GeoIP_country_name[country_id] : NULL; +} + +unsigned long _GeoIP_lookupaddress (const char *host) { + unsigned long addr = inet_addr(host); + struct hostent phe2; + struct hostent * phe = &phe2; + char *buf = NULL; + int buflength = 16384; + int herr = 0; + int result = 0; +#ifdef HAVE_GETHOSTBYNAME_R + buf = malloc(buflength); +#endif + if (addr == INADDR_NONE) { +#ifdef HAVE_GETHOSTBYNAME_R + while (1) { + /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */ +#ifdef GETHOSTBYNAME_R_RETURNS_INT + result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr); +#else + phe = gethostbyname_r(host,&phe2,buf,buflength,&herr); +#endif + if (herr != ERANGE) + break; + if (result == 0) + break; + /* double the buffer if the buffer is too small */ + buflength = buflength * 2; + buf = realloc(buf,buflength); + } +#endif +#ifndef HAVE_GETHOSTBYNAME_R + /* Some systems do not support gethostbyname_r, such as Mac OS X */ + phe = gethostbyname(host); +#endif + if (!phe || result != 0) { + free(buf); + return 0; + } + addr = *((unsigned long *) phe->h_addr_list[0]); + } +#ifdef HAVE_GETHOSTBYNAME_R + free(buf); +#endif + return ntohl(addr); +} + +int GeoIP_id_by_name (GeoIP* gi, const char *name) { + unsigned long ipnum; + int ret; + if (name == NULL) { + return 0; + } + if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) { + printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]); + return 0; + } + if (!(ipnum = _GeoIP_lookupaddress(name))) + return 0; + ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN; + return ret; + +} + +const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) { + int country_id; + country_id = GeoIP_id_by_addr(gi, addr); + return (country_id > 0) ? GeoIP_country_code[country_id] : NULL; +} + +const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) { + int country_id; + country_id = GeoIP_id_by_addr(gi, addr); + return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL; + return GeoIP_country_code3[country_id]; +} + +const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) { + int country_id; + country_id = GeoIP_id_by_addr(gi, addr); + return (country_id > 0) ? GeoIP_country_name[country_id] : NULL; + return GeoIP_country_name[country_id]; +} + +const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum) { + int country_id; + country_id = GeoIP_id_by_ipnum(gi, ipnum); + return (country_id > 0) ? GeoIP_country_name[country_id] : NULL; +} + +const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) { + int country_id; + country_id = GeoIP_id_by_ipnum(gi, ipnum); + return (country_id > 0) ? GeoIP_country_code[country_id] : NULL; +} + +const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum) { + int country_id; + country_id = GeoIP_id_by_ipnum(gi, ipnum); + return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL; +} + +int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) { + return GeoIP_id_by_addr(gi, addr); +} + +int GeoIP_country_id_by_name (GeoIP* gi, const char *host) { + return GeoIP_id_by_name(gi, host); +} + +int GeoIP_id_by_addr (GeoIP* gi, const char *addr) { + unsigned long ipnum; + int ret; + if (addr == NULL) { + return 0; + } + if (gi->databaseType != GEOIP_COUNTRY_EDITION && + gi->databaseType != GEOIP_PROXY_EDITION && + gi->databaseType != GEOIP_NETSPEED_EDITION) { + printf("Invalid database type %s, expected %s\n", + GeoIPDBDescription[(int)gi->databaseType], + GeoIPDBDescription[GEOIP_COUNTRY_EDITION]); + return 0; + } + ipnum = _GeoIP_addr_to_num(addr); + ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN; + return ret; +} + +int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) { + int ret; + if (ipnum == 0) { + return 0; + } + if (gi->databaseType != GEOIP_COUNTRY_EDITION && + gi->databaseType != GEOIP_PROXY_EDITION && + gi->databaseType != GEOIP_NETSPEED_EDITION) { + printf("Invalid database type %s, expected %s\n", + GeoIPDBDescription[(int)gi->databaseType], + GeoIPDBDescription[GEOIP_COUNTRY_EDITION]); + return 0; + } + ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN; + return ret; +} + +char *GeoIP_database_info (GeoIP* gi) { + int i; + unsigned char buf[3]; + char *retval; + int hasStructureInfo = 0; + + if(gi == NULL) + return NULL; + + _check_mtime(gi); + fseek(gi->GeoIPDatabase, -3l, SEEK_END); + + /* first get past the database structure information */ + for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { + fread(buf, 1, 3, gi->GeoIPDatabase); + if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) { + hasStructureInfo = 1; + break; + } + fseek(gi->GeoIPDatabase, -4l, SEEK_CUR); + } + if (hasStructureInfo == 1) { + fseek(gi->GeoIPDatabase, -3l, SEEK_CUR); + } else { + /* no structure info, must be pre Sep 2002 database, go back to end */ + fseek(gi->GeoIPDatabase, -3l, SEEK_END); + } + + for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) { + fread(buf, 1, 3, gi->GeoIPDatabase); + if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) { + retval = malloc(sizeof(char) * (i+1)); + if (retval == NULL) { + return NULL; + } + fread(retval, 1, i, gi->GeoIPDatabase); + retval[i] = '\0'; + return retval; + } + fseek(gi->GeoIPDatabase, -4l, SEEK_CUR); + } + return NULL; +} + +/* GeoIP Region Edition functions */ + +void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) { + unsigned int seek_region; + + /* This also writes in the terminating NULs (if you decide to + * keep them) and clear any fields that are not set. */ + memset(region, 0, sizeof(GeoIPRegion)); + + seek_region = _GeoIP_seek_record(gi, ntohl(inetaddr)); + + if (gi->databaseType == GEOIP_REGION_EDITION_REV0) { + /* Region Edition, pre June 2003 */ + seek_region -= STATE_BEGIN_REV0; + if (seek_region >= 1000) { + region->country_code[0] = 'U'; + region->country_code[1] = 'S'; + region->region[0] = (char) ((seek_region - 1000)/26 + 65); + region->region[1] = (char) ((seek_region - 1000)%26 + 65); + } else { + memcpy(region->country_code, GeoIP_country_code[seek_region], 2); + } + } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) { + /* Region Edition, post June 2003 */ + seek_region -= STATE_BEGIN_REV1; + if (seek_region < US_OFFSET) { + /* Unknown */ + /* we don't need to do anything here b/c we memset region to 0 */ + } else if (seek_region < CANADA_OFFSET) { + /* USA State */ + region->country_code[0] = 'U'; + region->country_code[1] = 'S'; + region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65); + region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65); + } else if (seek_region < WORLD_OFFSET) { + /* Canada Province */ + region->country_code[0] = 'C'; + region->country_code[1] = 'A'; + region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65); + region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65); + } else { + /* Not US or Canada */ + memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2); + } + } +} + +static +GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) { + GeoIPRegion * region; + + region = malloc(sizeof(GeoIPRegion)); + if (region) { + GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region); + } + return region; +} + +GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) { + unsigned long ipnum; + if (addr == NULL) { + return 0; + } + if (gi->databaseType != GEOIP_REGION_EDITION_REV0 && + gi->databaseType != GEOIP_REGION_EDITION_REV1) { + printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]); + return 0; + } + ipnum = _GeoIP_addr_to_num(addr); + return _get_region(gi, ipnum); +} + +GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) { + unsigned long ipnum; + if (name == NULL) { + return 0; + } + if (gi->databaseType != GEOIP_REGION_EDITION_REV0 && + gi->databaseType != GEOIP_REGION_EDITION_REV1) { + printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]); + return 0; + } + if (!(ipnum = _GeoIP_lookupaddress(name))) + return 0; + return _get_region(gi, ipnum); +} + +GeoIPRegion * GeoIP_region_by_ipnum (GeoIP* gi, unsigned long ipnum) { + if (gi->databaseType != GEOIP_REGION_EDITION_REV0 && + gi->databaseType != GEOIP_REGION_EDITION_REV1) { + printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]); + return 0; + } + return _get_region(gi, ipnum); +} + +void GeoIPRegion_delete (GeoIPRegion *gir) { + free(gir); +} + +/* GeoIP Organization, ISP and AS Number Edition private method */ +static +char *_get_name (GeoIP* gi, unsigned long ipnum) { + int seek_org; + char buf[MAX_ORG_RECORD_LENGTH]; + char * org_buf, * buf_pointer; + int record_pointer; + size_t len; + + if (gi->databaseType != GEOIP_ORG_EDITION && + gi->databaseType != GEOIP_ISP_EDITION && + gi->databaseType != GEOIP_ASNUM_EDITION) { + printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]); + return 0; + } + + seek_org = _GeoIP_seek_record(gi, ipnum); + if (seek_org == gi->databaseSegments[0]) + return NULL; + + record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0]; + + if (gi->cache == NULL) { + fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET); + fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase); + len = sizeof(char) * (strlen(buf)+1); + org_buf = malloc(len); + strncpy(org_buf, buf, len); + } else { + buf_pointer = gi->cache + (long)record_pointer; + len = sizeof(char) * (strlen(buf_pointer)+1); + org_buf = malloc(len); + strncpy(org_buf, buf_pointer, len); + } + return org_buf; +} + +char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum) { + return _get_name(gi,ipnum); +} + +char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) { + unsigned long ipnum; + if (addr == NULL) { + return 0; + } + ipnum = _GeoIP_addr_to_num(addr); + return _get_name(gi, ipnum); +} + +char *GeoIP_name_by_name (GeoIP* gi, const char *name) { + unsigned long ipnum; + if (name == NULL) { + return 0; + } + if (!(ipnum = _GeoIP_lookupaddress(name))) + return 0; + return _get_name(gi, ipnum); +} + +char *GeoIP_org_by_ipnum (GeoIP* gi, unsigned long ipnum) { + return GeoIP_name_by_ipnum(gi, ipnum); +} + +char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) { + return GeoIP_name_by_addr(gi, addr); +} + +char *GeoIP_org_by_name (GeoIP* gi, const char *name) { + return GeoIP_name_by_name(gi, name); +} + +unsigned char GeoIP_database_edition (GeoIP* gi) { + return gi->databaseType; +} diff --git a/extensions/geoip/GeoIP.dat b/extensions/geoip/GeoIP.dat new file mode 100644 index 0000000000000000000000000000000000000000..397d489fdab8a7a0568519927b5a693d3e58f923 GIT binary patch literal 682474 zcmYhD2Xs``^T$8C@4bC(ci)O2ARr>rEI=>(AQrFz zDi#zADxzWsDJs~&F3pMs_djpq{?G56J#*&H{od(!_GLFo1d1UFoxy-cU_vdhz=s$( zKss&1^YCRl?Scod!cJZ8gE$0`fFyhk2Nf^K6r2EmDoiwp#_kfg!vJM>TywW3Y-az;dD3^PJXNb?y(2z))r_*OaHk=J@p*6J0Xpmj8o25$ucS@(*K?i6LIVy~%)3u{ah|&={ z!4*;NkMd2FcMZD01n3F_As5bpZqO6DLl0S+{9-c4;`A83pf^m5Q4!;<7~jU|1O1^d z^n+hxp`V>?ifjgGV&~XgZZil*!eAH%LtrR8WYgKRT) zVGNw;GtuW;A2ZH47%zt63==+1ew>Lg875_lC`rhJsW3$)`AW;B+3KNE|+Yd#QP_4T3r^@Wj-u~D`5e=U6=ax7+Q~+^|%Ta!MFA3U!R@zDL9#{;WoGi zZiH*$dbkdjK+^`SXuyDmT-}hRa0C3@kdj6mYDCLZxCw5Bo8cA#pF-`%bZE@n#w^pM z-6pN9DY{*k%i#{VQ(ld^uQBU%_io*~2OfhJ@F1*&``}(!1%EeY->IxQ;63DO?$@#zd~Ms+i4HRlm{6y9vkloqUQ!Qhsxg$=L{o`Ci6IQ-I* z`&vB~w5uvwW`WNs+_HMO!u>FZKxWwyc_%DgEBg12CsE)TZmx7Ok9kk>mZIo_K0 zlzAVvEAs(-sElB&HtfjoAIZFG^WOy61-mo;?2#-f|B2F1GxEL4)M>+Ks^RmDo-b+` zrC-5*We#L^8@1sZ<-b+>ozm|!yFV!Nqtc(0HfzHnWezJnqVy>ICLN``MDdHv1m(}v zz<;5c*HM|4h$2LkZ`+1WddkqH8NrIs zQzb){+7XfwoCtmdH-Z;ojLIh~jYml6!Rc+dunqIt5JWg3LP~{;+OV_@wIZAt;Wouf z6f4?LM|V$(&`{>T4EzZ7BGgymYK5(9LjzrIYQwfRG>UL)gi|6kR^gsD?9XUxqLLqV z*)+oGx)dwTA~cWCQkN|v{GxzXncctJaAt(@5zdOxJ;K=$vLdwB-8LCa+XzP6uurlh zbc)a}LWcfvW0iJ`Fr_Us+R`J! z5Xo?aeu9b6CqnNC=R~Mf*ab?(Xx|8PmG2*6P=o;y21Z!emL+YuHG>%(VWsjzr6>`G zMHm@jc!Uw^(gxky)Rs{ZMn`x}mv3jzj#bRK2s=d5mI=C?sB}_h-VrKe>yU!u!Pm0qTFZiIQtT&`5CpOFx6$ztgxy>ZuM&eklii?Bo`*Z+_Fh6r~=xG};qJ#|xr zo0YjG!mSaqGah!x3U%HV;dVW{Jfop|7I#Ki5#g=~cdJl56mRdz_^>j<{SofftyK~3 zi-f~g05vW>kkRvC2EQi4OA#JY`NI*OittE;wYq#X!ee@TmF8hxgeM}bkMOwe_RgYz z76Y?*GQtLxh>0QU|I-nkkMK-{jVgaO!q`k)&t>dxitu8D7Zfldi-}qP`T25$cOq<# zutm3CQT(gQzos-Vi`OH(rTo?iZ$x-gS}}{MYNAl-Hr;(YW9!`rdm_9S;iCxeN7x?W zg9sl+n6BWO%t(rM=&9l?b}F+g!fqK~nmySq%i?2|3;#)kPnECE;*u=(DgRl7Zr75K+D6OSbFegU&P2;T-rF)cMZfu1=>fk{c1FeUuhaT1ROa zMI^1FoEhZ|#T=J}WN}uMvnA4O9#cbhHf?H5M9Iq7%8t@5ijy6>v{xd{CMQbQC>^4R zR~@5tiP9-bXI-A4uv*z+P+~Dx?RHa(a$FMIBg(iaJ);bX(kn_|-Rd3X97RfueWIM0 z9fs2{%AhFyRX!lfKtG@GE ziE=@di}lonN-t8d*p&>=QA3hv>6}ZWToz?+4JMtQ7v*xzj6^NSj@itQa$S@w^|-{f zK$(S6u8MNCcGM!Jit(;G=n7M)+o!h zPnJcwEwgod6zN#ee@B#+QSOX#w_@&6DuLV+WrZfWOLo|Df)rKvMp+f*J~h-eo9>#Q z2cqnV@?exLqBF{iQPxD+5appLk7*trj`B#9N2B!2rcX8lvKf@k+9;1lStkP_%HV89 zWrzJUI-4h=JQ-!YHqQhVJ{9HpC{N2+i1JL7XXVGy*@j<{v!D($|st!oifLi*{yVs(vOu&dLPf` z(SnUtZbFNT-iw zQz64&hK7ukcEsCpEXu!8{*3Z>l)v%xZ$_QFhYwPWJ$gr2l& zPfmLRgCLzA(VkW5^a%#_3~CwFF*wnnw!zr;p_Pg4kM8(88dl!NeS<SWN>ptF4VBZ=)mv_n`;2`$&4o8+(qK?lwh zSOLl8P4@ z%rMx|k+Gea)``bDQDQJtwUw&p;zpT4xxv~_JllyEI)x2TX>h(lmBG0N)dsT^xup|7 zbqd2g&tSH}ubue26BldyU0`sr!G#7F8T_jntj?jHIR=;L*@P}zcIGmJs}1HFEHId7 zaD}$<<#Zj~F~;@UX$Yt{m$crc`zxHF!+!crJ-tQn_Jb z*BLxvu-@Qtxwg5So*PCXZTzJA&?=Xe$a8f$`lEKT8y4>&%ibSG*#o!HtR}Hopyr$7D%jND|UN_ikusWAV za>KHU+BXf}mgo$&Nl>{wqdGU`hN*i;3@P)T!Eqz}$@G1L4`j?5d}#2w!FGc^(vt=| z4L(wUVBW}Om%(nqDBoxBnSrN#Eu~)=d?Tt1 z_8WYqI!{*l0fVn)B6TCX8(mcLt?qs&!(VQ?N(L$Y(cn+9V(^Q>L4zX(hYSuYcw{#w zD(0xc&vMJUah@*cb>mlq-wl3K*p1y-*^NI8j_LCLZakx~zjP^X|84M3hTqUXDEcXGN@N0%p=G%~4ca4+;$*0}r9o*?ZMe5ZB1I6v@yA=2fwA$H}qh653+q(Rp!l}e4w!LCX-Aim`qgp&Ypa%^2xe9s{9m5nn}LN43nuQ zg(lNX3QX$s3S+6;i)(r@-K0p5EbqnUUVPY#Vw0IBB_^dNhZOm@(lV2BMIP^k)f=Zb zl_s-Hs#I95RMe(=bFT8|nanoH=}qU}bn8vu-dtdEy~%|p^Gz-?xl~~n%eN{fmnc81 zcj#DoZ!R;r++?oFJjsj-&r^DZ!WQ*reQ&NbS)|JaCJUtjlz*W&@Asz1IV?80*5qoF zYfO5c6RPc_^g5FziX3nbL(XCHIV?33T|z-zsh^f1AnO zCbyg1p_t{FQ+Jx&W%AfLe6FxWAMTM-DrSY!R3Gj&StYlo4=wtHE}h+n`%T_7dBEfa zlLt*6H(4#sX|l%TVUvgSU`GW%qI|CMkD079S*wyhDp{|*=p5dMCrq9-dD7%56>d;E zq7P4-Jfr-iJ{0z0MjtksJa6)x3QPKgF3D??v~h-i(c~qQEhaCUyrQtpCRgh2t0u2y zVqc_^*A=kUdQAK2Ti^;`N8Bnlka6H^<_+7=Jw@=zWiwNlY$>rRqOk5 z$mEDh4lCWzm!l>>EB|a?HYw~^nK>4}nItTJH~Ck0|1deG%%3LznEYk(w=Uo4%lkEc zrqjpO`R#p4%gndJuXqhB3?ZU4YVlEDKJAOCOOad3^y!Cf;aNDkbmgEtZ}ekmzwoSY z5zpX<^&=_YX<7spjVw|YbuCV?sBKZp;zWz`e$4L2)&01yA9XBFvUs5%d;0NPKg|Br zvuI#Z-{NG6PMas*pW6Ltn9+Yye@?MzqRYlgPgUBeKc`vYb!%E9>>oPT%;IbjTAX3g zLgg(jS}D`IKkfQ6T486Z;w6(~xxTHS|`*WRw+bLL--=fPL zU3O4K7F{iRTjW~wu;^ydU3VYo&*uK@=uc0JUKU^V=V*VN0kjyv zITrma`dIW8HwMsa0AmL*YXJQ%23RZ@z%2uKd;l8u59{*Z0Zg>WvzTNtSt>Y?<^yRr zFvL%>$d_;iGH4*&hzl$( zvba#yc2c3pFV=Gj@t8$yFj<4i85|~dofOET(_p3y zrhG87RrrMJdD7zI!7LrjQx?xzJZ(o(A&2a z)_4eK4&hyk?H2Dz+o_zf@v}uF#xE9sS^R48hfGKr z{(5B2Q0A+WV-|l(s}JS+p{yUuuA%&G@vp@{7RMFo4GV4c9!6Sbxc*{EzhO)r#`IxC zV^}INVwlQQD>xRziD9ecdXY7~{BNM3NrHDKVPFXdL5I@pCxN z@Gzp}a88TSG)4nmo;{qb;WUdeC`R)bxiMPAXd9ztjI&gEE2U>BJyU7tnuE%>j?qS$ z3ssmEBS)9nG1@637TYT`cQ_qlbXLBj(oRYj45y1Sg6tY&(QvLEPPZ66V{}(}kIb&r zy;qEWF?y@y9Ho6?^o?=5S{Dr~mFXX2fbI@dx<-YAWBOhkV{(k4F~-Cgrn|#qjEXTL z#z+GnIa)XUj9l${5ebsEYAGjOrNI#+VgjZj5tdTomKH z80W{Btp`Qtk>OkrM$(T&es*J+&~#;uu#+;bLqZ!L||XAHg>xxH`r)F}_z!Fp|0>xh}?SF_y%* zL62V_W2rI?MuygJjB!hhn_}Fo!ZTFZdL*~TSSG!s%U()vk8w|o}e& z(HIZMctq~+NM2R&+e#nPD(oJ~x)_hgSg&VA&krMcBF2-tG)HMll|CgJVr-1@OpIsc z+KwW36g_oIPCcjiEu+{Z35@YVj8|0hqSBXQysYLn>r(LV=)qTGyjF8i>FY{A(ycd? ze^Y5qUu}!=NsPB+?27SDjQ4cw-3;LU7(12!AjXF=b|}9+#vax7kuJrqyw%od+nqVM zC&tGaUI3p8FSkG?`;>mB^mCBa{Oy$zL8lsipXfb)8+R{e^B~k zjKeX0QeN-}l{pl{9Zjv#9MR=b&DGB`{B>F5aP86jCKJ!*cNP8-;{=;yF=94<#z@Eb zOU7o5zhnF(!*(-t&AFqwa5Qs9 zGj}w$jjtHT#&?-7?7T%GA`cr%f-Lem1>r z`q-Rfhd#)b(7wt`?85iY91(t?=0W6xYzEs5(XE;YwfT8W_$ARVWB7FpOKh&U`E3lpkKqsX;Rc(VZEn=FH!1Cy z`Cd=-%j;H~Wj1$8lgRJ?*xas|d!i*>upXR8@eZ&pRjq-W`j-Bv7sS(ojErAazP9|WAm)^t$va(er~jR&gOab zO@yoT`>7XfKDBw#<{g`tY+ko{+2&Q7%{H${+mB`HSZ0moim|+Av&CllSRNe9OJmtF zmaR5#*}P%%rp@PLIXISo$Ks4*o6XxYL&ni$9R0^pIF5I1KC*ew=0ltJZ9b3|8pn0x zST&Aykns#2&xG;J9M8u#pV-V9&$Z*ZdpwVh zXRpoIHv6QbY(BI3LOhXfmtf^JKCFU7`jyRoX>YCa0SQpP=@`$B@qAmvA92y^fz4H5b(&NL#imF30OC1i|{H@)1#OA2YAJT6&zpCUH8+$_7sK3eZ z7qIg6l^#>TpEiHlG*QXfO8>Djo$za;<2L`wz;{SXZ#ZFbb0&m#MO)OtaFB0)B^G(f zmgV3$#GEiFS=tWWCNOpau0!0xbMT$;3nMu$U*(8~ghSFn`dq+IPM}QYzr)E6Cpgq` zsO4~?S`;^Gt4{ec=sx*M$f2J4R@Xt6qOHCYem5iuly9{fIGo|o(4nbABZpHRPH|}L z{MT<{^py!TaX8K4tqEZ`#qzV>1WtEo;n2*XxkHlV~!D zPLnui5*-~nIZT^GdI9%k=)uG5C*I}|`&tZr|cZtrSheL0No({bnUYW#} zNxU(MZKBGdkHfo@*foidC$V=D{Tv25^miEG@Wmv)oW$Wt{62|64uc*3n8dM3{5grg zCNb1ujKeU8kq*NhMmYREiR5HXn@sD;jB*$)b|*7*GI^7kIhnBz6CB1ljCZ(fGS^LJ z#bh3u%tVJt4$n+x>tyy#=KINEw(}gONPte*E%^>pl{qOdToyP?*JYs--i2;?Azo@X z!{I`QVuzUyB@U&E5kO5ll{r*9lsi;PGdM^yh$`8t(k78Ulxog$nC)<`!+DalJSOH* zn#VULNn~u{)1Fd0g#qy~8yQ*Ew9PhCa#T z+dP&?2GZ%nd2CFlmpa_!aD&5*+NBcIpX%Pt4!3BSa^Gc6N~W9dr!Z#<_c^R~xZmMp8U79r zO88T_VG3KO@cIbTsBy!nZ=dfOdk2^f6K0l#! z>y)re8>By#dD>yG^ohfZ4$nHg;IL71@|@D=m2Ofh)!8xSzZ$*duuXiBR6A^z=2t@k zkj8k`;WdXXqDRK*l#u>7g{^Y69o}$wQ+i3~j1*cLOsE`r+u7`F z`7F%mx_nmTvrp!p%V!RMI(+VMNbaM%A9B}x`VZXx@`8=7=%lW*L&({v$IJ}zA zYx!)+=ks-wo4tC^QW?SDmP8#{;AY;IoYM2 zOMRF1Q+a$UPfX>>sWfnD=(1rdPfg|URC-L~6qjZ$ja^Q2In||!_&JTC(-<+0l4&$` zIo)N}G-glZf@#d1Mst@|E-hSIs(TWeG`YlnhRd1qlJ5uQ8-MwWvuT{|GSH>9OB*-L zlH{dI+cGcA0F6@_9#m@Y1TT)MjS zcFA?=;nK~eyUWsP+%t`})7UbNo-VyyUZ2L+X}mFwHzg3Us}(UNr7rz4KFd2@f0qF+ zF}(tBO=FPDC+3j!sSK{ZNAHu5`xPDmqjiMU9OUHt2QaFfET-5 zE$Py(5Tnun*ScKqa-GW(X|O_u6f(Y${6dzx+#s(sR>-nKZgaWaWkn$?3;Cju?+UrYP_lUCHF^rr~#)o@n1 zJRm*ea=*)wLXH;lXCcQ6dC+CGi$9(Cbm~v%rz zWv!-Som@a^D#_S%PMsbyPe|KHcgaJY-izkbL;fjA=5(%<=YMtbS(oQsHo83L^3!yV zPsc36FJhC+3vz{vXjw#?BDxpxlFPf|w#!zR%`UIGyyEhz{8-%W;=qTz+@?)#W#>kxU!8-IBCFT>f%7CRanu z74dTsV`q>zgTH0?OXJPpjv3rJgS%$%uZ!i8c8Pl7-|%n9 z@Wc$Bn!(N);Uh=P!}f4IcF*9G8SI-ugJL|79v;3&Gmp5(=^hD>I$k(YlOBObEsvDP z2_B~ub80b7i)mNPi5|5*IutXym~q8SEaoJSMjmxNPWGthQQr&mCMA%NB`pm+8hYVv zm9&UloH@m#iAQ6PQ$6yEL-3Sh@{2jmqp8Q#VhW3yQA}xZcuLCG+#|=Mg~wSQEyX>L zRvu?~;rpE=S?+Sp59XrzY>(DnIK$;s8;@*{wjNm?^NYE@m|KgvS3>Y;@3E$sb;Ueg z%uB`LyFdqzjvn2`bC0ebokfYqTgB`uW?wM}ipllp=J8`OKNs^)F(;IS&o(kcdWypy zy*x&H^!6CyagN6zk3Js#J^Fg|lUhjNC3G&KO9=x!28xLia!cq|LiZ8|d;k3|Zq57t zP>*3ABRz(Dj1X=5)+X=N!bpIlq+}&bDPfGqc#p9j_Twg+o zN2$jnC9Eys*%F>Fq0FPwqg;yXh5avALq6Ylv4kp*YA?*s=8|wGh8$%vZ z#QOQ-hQ|dS7kca}VRs38O8B^hi#_Ied{V-vCG0I>UkR6bEbx#KdYQ*uk1IUpd0g)C zSqWd4@M8%_OPKF*rH55Yyp)Eev?vV+&O(o?Jg)XwJAB zZ(Yg~k4+xed))7Z$yw@ggU78NH%cDT>6<)mmK&jId`5nAK+MTcNu?~4tLJf>#~mKG zdo0)9lX#_466T#Acd0}a%1aV*kH@_pD?Ct6UvAS+6Fq?9+b`U0-W##FlQ{O3^1^hI4=p{u_W0G~8;>I% z-+CPK_)dm^$M+sTXzT(Lu-v1cJPvwc*GZer&>s&E>&2IPO-QGY>O~gV&w3w!(fk}N z6%Tet6y5l!X_trB64XR=RtJPqxpQ%Ae)a#^-FG*6M?d3-Lr~Tc0dHd@q)z zyhM3BpUyt*eLASQ96y|&9n0t_2jx{p=Q6sK(X}jmf9c}W)hE{vXSfu1qt?2+AHHSu z@EPpW)2ELg_FFHX-jWI*87b4tC@Kq&^z|9w)6b{BPemD(WmJ_>UB*E1*=JT6=az9^ z8MDh6;xk(O@fqPW%xAdI`DI*G#^q&PS;k18Q9cXHSX{<6W!zrI7@zSzV|~VHawN0~ zdP67ZQcT}j#w4GmK9hYe^~v)&*Jp}Pp-;X~fzMQ*X?_@^XGa

`6W&P5sCEoYAMmnc1mqkSO1Z#ik>pBRUHY(`#^p3Gr+YbzeXjPIRL+!grj}D!&b2<*`&{R< z#1G$s#SLjQQ6-G1y20mppBv>O_}t`ko6pTYw`jLZJKgHDOx>$_LwPlwzTIbq&vKu; zeD3hMQ?gf1X*uQPRF!kL&plFta?UU3-g53Q4`+qMa<9*NpH)5&$(8YW(C2=i2PEg^ zVgIZt=b>^|`>c_Y$;bZXJW|f1B^C}&GKZ&b zq!vZP%hCoun|)sK`JtRY$~jg}P6e;|Y>~@VL8l5jSJ1VBtv>Jiyy3IW=S`otG~4p1 zFhSmWWd8fSBdYXnif{GO>Gym-lwJ}yq{%D7$5ClBxmMeyog`QCz+Azc3NEQ&r_X0T zyL@)*5Rj1f__^Nac^A;>6`PWw$$A-C^7dH(nL%jcNSpFT$_I9kEa75q}c z-+uT}=dTs~RuN9x<66gmW&Vpi9zN?zEu^fHpJ*H-9*$7Ki!;Jlahk`&dm4*l$2lpE z6UUF^#_?1x;mA9b9FNBd;w0iElu>3AN+YiHGl- zA8V(Hxw>&0ibNf#ALnG%U#1_VG!S!@w5p_0oW^2Eeguezv523i#%UU-Nu1N-;gl8= z;!NL4PLIq5AwN59uDx1l1%YAPUkq6Rx+=W`IRiF zq-&hqIEyN|rjn(V+*}#vp}QngavrCr1QMrLoZfL(Rq{|J>nnMtl0Kp{&Wn}2R>`(X zc2$PX_m49`qY!?eGJ}*3Ryssdm)ZTSlHnPCM4XYzk5W2X>6py!SY^JcWPC<4L79n4 zCrP9kd0w0;8UB#^GgX(<;uORwR=!ZGkiirwGefDgnfP21r!=!WGfr8C|Gkn59^s^pZ6lZaqx>ezyj@GN9K^51;xh>AMac+!r zU7RIiUH=;Q`Z!DD;otB|uwwBBm7h|@O>u5kXGDIBGPlNAmN`{}zdg>1ILqVQ6X%XN zcgDj%MHl>CaqgD3uj2HoFdUKmKV2E;UTGV_t6Y4zPjxm|S09M;V4St$Pn<{NtcmlG z#w8jaR^}1;Ur+LJrN;P}CblLI;`zFG_{Y5K752F5d_pdZA~(c&C(cuGUXAl~oaf^_ zqY*u;;EhV3Q|H^N!{XJZI4{K6Ed8wVm*Tvvu$(G7sm@o_`v2$cwK!Yi;op+K9_Q^i zTjRW`_&3z6ZdJS$XPev|4YQwGsqy^XID6u}7iV{z_v7q{^MM}xP(9qPbVL=CtN2JQ z?o_%pUN0fC3|(bPx-PcK3C?8IA6-dtKyO>=Bq!Fz5Tj% zAkNouzK!#Z9$c(`ei!F^sh9E(R(@BHDe`y4{1NAv8hWaVXRCNY6Z==3zZLV3(&KT`3jSAWQN?Q#a)L;L ztqK;+?`RT?1ZILn0xJ>bB$mKUgypak;XQH^yj#V4Rd@;F3H(IZMekRI4I`Ku-;#PT zP?}0`LV{WecBt~5ReVxK?F8o}sFR>|f|C+7OHemK!vyuzkn~Lb1ScnGkOeLSE?MBZGNvfCm-%LHd8XqDiM1mDzD zq>9Vs|Gy^7vPaO>kZ&qE;$DKfw(N zE=X`qf(sK|Azmf8EWyRs5)wvQ(F1?#2YSYsPL$ zaI-Sf9=9a8RgudQ+?I(;Jd}gW6Rgs$I}+TfO72RqBEj7W?n%(Kn(k^>^0P9*y$O0& z)2o`^)%2_8z61|y!tYP;Kq7n_lKWWm|2Q#Do9%&HFi=g|ZoN`EGJ zDZ$zV&m>rv;K>B*6aW1V-s8$Vp;VsVHYoFy(x;WmBi5JlA7hl?m|&AK&nbOgsXU#& zpo}12RHnH+l_l7gU~_^k30~3OdsXRcN=2c>_p8QN9FTs4FTVE>uN@jdA)oKg9=GI{g?Shl`T@MD4>R4yeD z$xq4)BgYRV_$$HT1ivRZlHeEJI;!+%r4rh&%KWBOPDvjA$neLM`BSEcYW`asPKKrY zC&6*u`ZqyZ^CPw-$+8tmVke0vv62``%;bOBldYOG#*(4)vUF6HFm5tz9%1|>Lz2Xk zv`Ugla%z%flG+Lj1e2te@+T-2Z6{_J>7_bJ8YDR>N&O^slhjLwKLm-+8m~@Pq=Y7t zhDlD*Wus*H^GHpl8fR2BNzyFIX}WBxRF0gk%z4#e?9G*Lk))+Ea@Rz7Mv`2KD@jh0 zvyx;dIXg)k1+-Qw-nLDWrMwuGmz6{Fo@J0Ad2H!P< z?3Sc|lI}_RB9iYpBVkOC7_5B8H@tW0bF{>9`~ll8jeLO=c!0nUoCQ`o&z$ zPl$O*rYm4dlKdpol1$a503=HVNeXo-%0(is79}Z5G9yW8lHw#Kx+`;_roJ;ZMdGj^ z%XLeb3S}hfswDH1R42JO$*d&jCpkCCdAeKU@a)VHv2{U`3zJ-=5^=buMst$POL9q) z%aUBGTQzMg__>+o<;q;4ROE8-$|Q?*xgg0xWv)uHNb?}OH5#r?a($9(l3bSzKcc)= zsT`Nr5Ha%ZL! zL~~76?@n@0l9fqTD6GbxdzG)r>U~KbPIA9W9!Rn#$%9E&XYO*18xQHO=v^*>8%f^G+$^y!+O{Qm zC&}9ilWfTGcayyLKORbheURjnBp)W(on(8Gj}*Kkqi1K5U7499U{SkA0Us-spU_3} zsqjhmCiy(cz9gTipEVT`i(e?R=ImEVzD}|~$$^Z1IlfxvfMSG~9DXM$4fsCE@gzSa z`6bDZNsc7>Daj#)9n9qXaORZ6epHSAtW-W-5mmn?`9qh#CHY;Ek^w;;OY(P;Ka>2W z!kU8Cxc86NS786js1HahK>lm9Xp1NnW|e%D8sG+)0WlR?N+n)9zzP1F34#<`UO*zi z4~Q#9ZeNXW$$%jE@7Ic*gs2flx;G`h@yhzT9laedZTrc?V zy+-(xRda(N{Io}wjRH;$I7Nkxm6q$pY!Yx<5I*n-rfIt6BH*lm zmH}r3v*&zt$ zwgl2CU~E9=fF5E(ce^UhRoYEyccuTIuATwC0)_|l4j3qr2J{Q)BMvC6=4wl}`v(lj zJo(gz2;OT&8w68=`qkm(-b9zd2 zN;bsLO#$x&yb!Q8;6>efDd1IQUJlr-jGTQ%nF;CiYszd<`g&$pjJ~1#n@Wr2AA$wp zcTd}tzO7W0yc=*N;Jtvo3VT1`gMeKD9|r7D$@bvCC)+d_<6t=!G8~XqUS3W3bS7sIs0|MPXXV^zz_H~;JZxr z#GJIj4*@@_WVJ3ucu)@>3OKB{SbUJ2OYBEwTnGFd@OQv30e=Sk8t}V9Df|?X6n2Ve3M++?!c6Hiv!+GDiKYH4`YL(;*DW`N zm-;W0;-Q#}r%35mB1JMqkl7Wx%jN&SrKp{vR*Dl-$Wrj~lC3%^PRb}3xn#IriYY1T zr|6O5

M8Xpo|DiiWCOf@-A9DN4oksVSPLXp*9-N=_3uRL|)tnyDn5|7xy9iZfEQ zOwmf^HFNdCYR*h?R>lX>FW}ZGI;LooqJ4_CDY6xxmBF;rrIbeMD^cX=vV&4-q)sWi zD&JXY7YR^dxhcAnlb5itGzK>FQXzZs<4Sqn1VJQZt z7?NU8ioyT0RnxIURU%Og&p13H6~1fB@lh$psc^K?F-pf~VB_`RgcOsMnW$8fIXOjM zMyEI|G3KYZA;r`b7pIt(VrGhh6h$ct6(*SJ8J#myl&G*c6~3{`mb^-}H&)576{R>g zMR|&<6cs5dwRR$xmv~#9VwOteh=e22otNT*6th#D|3Cf+^1>7ssYJ3WuQ}DsNijdg zB`M~nxKy_;Q!1BEw9Qlg@)TDnQ4qu$&>ePQv$f892 zxi-a;6xXSenkrwPVrlBX30&jzjVT^ZaZ`%BQrw*4HU;03;?@+)q`NXX5%BFP?$F)k zsqp_lND{=#ol<3G?oM%kihEMrn_@+Zm8tOaSOLgO+*_66K1I&Z42bZ76suL+gG$BQ zH7Op-WPX(%d?dw&6pyA@pW-ovtxd5mga3b3kBdJko>X~F0!7KzL3GcsLV^!56Vd3qU4nnZ|L$>rLU#fqKs_4o?>f;7x0_Pzom3r zM*en+ca&dK9S$yey_e$s6o*rMkm57l`Y^@z6uVRGNU<};M>01QDXHG200~MC?n&`! zijPx#qC&~7yrgyarr4L6X>tYR?B^+dOz}mEuLYT6zv91AD)o5dZ2h21N!kL1{gmRMO615P?R?4hk^iIWETF9@yZ`?Y8;cWjIwr2&*p1y?*w}%= zr9|lt0qIWZmX;2?#lqGXTd`3w`G056o!|TZ*P6B0e)hBL*)?{%OFr2K*ayMlGp-&>|%h zjk#We?Gx;fsC#~no-=n!gi+nuppab*kx2anS0>mk!9fXjPv9ijBSFG;_cXYd!3G8u zv7{j>gK2}(CcBvgUV?0bVuGB}^9c%uoM{j6Vk;%67^Q4bN2?}q6aRfrrBM3`_Dv8Z z*xPt&{%3a|qsZ2N2@XiGe}ARaB*H(>E-T_3 zlwfFr!3l;KgR(E8&O0o@aHD9cOa6>ZFfPF;BaSvWCc#+CnpDXdL0#h$Oi1vU=+?p! zeNuwSCQ{FMG;O9PsF!3~g0~Y)Pp~$@j0B4l%uFyp!K?&x6Uj zrbKlpKNloeXquz4S!7KlH(|5T7nIU zx@RzLMV`Nr;LQYY8H0kRM99O93BF12PJ+)9yqn;o1n(vIz(1mCGz5`3TF2er99 z$4Y}T_)~(PEf?w+(Up!ZrtQ}Rzr|BdMD1?XsJE>@68xFqFTBVNis=t#*;P8I-vCAli_Ti_W;EtN=slhhbbU{JYGK=#&_MQq2z|VQIb>b)LM!`{+ynqUy?JD+#)}dT%6>rBSzRY|T%a&?l%7Ar|fo8Yxct~2Hz z?ck!^kfceH8)z~D?aPM}Z($J=(ke+C{r|5d51Op>s3aQeBY-W} z+S6d$Bt4R}OVTw-`y`!`bV$-MiTXwHk7~Yik}e9V#b0W5u5QWj^?rAQq6pX3GfA%` zk0j}xq))sx(e(5+i&5$JPx4HXN0ZD@@=A=v5bgEYDJu^fuCfGLZ?XDZADO9 z)050dhIfCRJv#5KB+HY`PO>n`oFtDYnVV#uMMHYTDVOFaSzzZ?c%wpHlw@g=#YvXL zxrppOkz|=UrWh(6`jE0hp-!^Wh^vyUHa{cH`tIM_Bu^$;mt?&)h3Ju+C)t?f z>m=_a`Oqlu8hkIw`$;}9T;Wo`OYoy4pC|b^$)+TqXv?}r;f>UOn&dOhD^kxr2^N)#3`JGR_I-~UYE zr^wkdpQ4naV0h7BWWAiiO;JfvP1Vf=(QnuMPldOGsQ7~v`=+RgrS>*tpVWV!!1puC z{wWSfaiHN*F-XI~DXvR#NQz@q94e^y|0#}4ak$}HHZ>+rnn@<8N^Qsirq_{doW97>jqPwa%uQe&nitAH!PjN$v+7vgYxF^L;DQ-*AB*iVpbF=v) zky|Ynk)GRA+?C>v6n7d?1rs?ew!2MAhiYoby(u0@abJr2Q{j(hG;C#5{LO4P@~3%< z_9^(WR%AA&Sg{DIQMIM*sZLPN9>^mIT|TXs1Zpxx}xtcSzACMMo3tl%jL0 z?u|{QVdVgGsS=uy;Af|(c8BAqZ8<8%7(+%YhUWR$6yua-d$5saArsUH@;}Ao6py8t zWc;FQS1FicOF5wGnwDZ_is>n47*Ualp4?`om~9bIE+nO(%}uc~#k>@Ytw#cCo#o z0b>5Vm10whw^O{AVxzIWWAI&r|EKf)6d$DcIK_u4KC&%+a(uuve4=GsZxQ9w6q{3g zmg1`vpBwWRDZaFMrK*-rMgHp)-`JMi_%=qg^<9deZ25hPA5#2ixExj^D4Rd0*plKG zBZ_&VzW=Y`Z%dhuDsXFxY??nbPtyEpTYsh4mf~;2|4H$$)Y@Z`q9G;vN4$dD8I%%* zefuuS-YmGpAHA0WOd2I-P7!qW{)&`nyRRlq)@vJ z(sffMnZ`+ny_QOoHnym*#gmD7a%m1plTQ<*DWoYITQN<^km!t+G+vr&8rO)C+fw4& zQi%MlNwZ&?y^XR@ntjuCpKYTe*+0!eX%0wppxKSWE5Uljf2%=bF@cVoq~@nhWf7@_C{K{Gv1$r|Tx3%0_xF zO>=dc%hFtt=5mwOR}+*2BOYr~a^`kh3XzgK(=@f^U1{!4bC3Bf_p~c`Z<_nl+-D5R zvMfsE0b2^MP18M1^E7SKv`F({nwGZJDoyKj_?u8l%2X4PRGTyprFr;&>QnmLrRkEU zeVUFY*uml~=1yrkr^846s1&2)bTyuC2IXFlH2u@`O!G*ZUPkPlrjH@g9EnI(U!(Mk zEBVnhgN!o3;6Q`YHaN|&G(*x1Rc6g+Jq9aB!_$n2y^=P$G%C&FG^5i@O*2MLrWu=N ze425w30c=QK|N*4g-dXf;gbzcF({%kGA+&HX{M){WyBe2W*Q`7!$iIRN%Mj&RrAqHyqDtLm*e1w z^Hn3hmS%$?uN#a;)0=5NOY@eEqqoz%Z^*_p?-=r~!S@WxoFec+norVv7*jq<^ReNn zX7=z9(>EFNsX<9e_H)C(Nb_Zy-_m@Q=7%(2r`eq5n>62AB$XYVTKwOo`QGYQctrd$ z%`a(wO7pXZmGKCwBetaZRqbZKJQd0Qp61^)Thsid`LE$`n$;KDm8!qf{G$gF!yJxqINYJ36HW;^7WsB$?5BcxwBg4%9PezQN%}!*vI&nrst?TO4jSVidYt4Oiv-sQK@3m%|-Kxzk{ji@P0~+VUQQQIzhr zd`Zdu4(*gphgJ^F99lTkIy5&<`L7`8TrF)G`Ow#ea(t) zLt@hb``d1G(g6-b9R@lKHsT=5nocpqmZ~=u)i8&V4#OQrSl`K5qY=@Z+v&^FUPFr$j zj>B9NRK&zD%HwMD4D%f}IxKK_+F_x?YKKJ*OO11}!6k~n{nqCb4l5j%IV@MHnA#`~ zD;-u@4NG&B4q05|u-0L{X;^2lvA+M~@RZ^D7#R8djKixA&pJHs@SJU_J0$*s!^;jY zI=p1W$dKH4#hj59&9v7X-n88f4zD}Bp$a$INVAl@cR_`u;qW2;(!)AxC9KJE0uMH~8-&zWU z$eHhyEQjwMelTKGnLp_Lzr)YQuNqdebc8Jq+Z=v%_{-rphpi63+Zd1Z{NeDYEu}L$ zuaLhT{&D!%^e9$8TJ4cx#|+zL*giwO%zu9hApRX}DIa#qu(RRn`du>YYIrnW>REh9hH#qe_m_bWDber8C1B8IH?vN`~Vz zoRr~&3@4frv8kb?^W@kKQ5t19EyJlsQIteE-SDVB&&+T^hO;u9o8jyX=frGsTg>NW zIA0OA-)@#C(OE9caFMY^zFm^xstlKAxXg%ZoXay@nc<2|_)0+s7t|%MuFi06hQ`LG z;)ja8y;Sr;}6L&Jj2io!!ksfir|P0BV)C4 zMh6^iB4aX)%P`h((UtV^879b39KC7sA;XLelQK-rFxfb##O74Y(+r;;Ymnxd86M9t zE5n=&vyC1lWp0Lf@lu9lZoVxSWLRj39zsM^Y8GdBD#MZtYcnj(uqwk78I~K*GJ_Id zkzu9fQOcv-t zhMzNhm*K|@-)H#2`dX&tfKKs~u|?7QCBttSwq*F#h_{=EitX>VR7s2ShZ-%*pBer! z;$H^;HYn@=8Y1P}Y>tVtT{fJ+^$c!rP()F7%#zNsQ59`QIRMY4Qv_R%C$_|G8L2zchUVijaLI2(Qzs4=*AmVM0IeX|^3l>M^oZxr$9m7d#Mkj5RrFFcef^3teLzaiKw9E2v zmbSJfLs5~mkC!skF-vD#b}|?Ryh}FxvpLFOw=BagV%-h)$kH=Q|17<-JYtmIS^Ah@ zl*hh?_cJKv>WfFS49YSfrVKPh9uCejG|LcMDhOiMH7s6^$g(EO$SgCnjLI@4%V?El zmN8kzXBnGiT&yQL{)8+OV~X@B;FD}Q*`P`^(m&Of)3Qv@GD9ZphNb$~?yM{eY$9^-rziZ%U*_!1K+mfud zq+iHiYDq)>$&$?RukmlovP%wfY@Z8*yq&>%xw=R39dhhslpPI50omDbWo_3Sd*!H~ zV|SzMW>Bu~kz-H8<#QCV2DVHXREw!TWh<2y5IvE%z~~fbVC>{y7fHaX^j(Z5g$R z8vkHhMm`*Bxbz&Bee>#>RF{j_YzkW_CZZ!NRgG~(HoZ}YLrjZg&mD|jR+YR1f@J@qw8I1hAC&%a^|gac_=?bKGaz z?$6OO#{)T<=V+FrHWrbT9B5%Yii4J|ay)3u*17Npk*b+CIUf4|`P=5`n4_JswKv$o z;8fGlDMwdZb~e~WsjN5vE=8Ixmqj0 zOv*7qC1Gq64XWv)aWpx{)ErY{qUOM~9Mj{BD^T)bW{x>IW*N_HgCa(4JJ*);a^cl5f>U(;piy zBy=^$XE`?I_|%A^L?h+%9A6kEiiX1eRgPowe4Qho=Nlb1&$l^#F`msizLQruzR&T4 zxhLfsYYNU!Ies=CRbZrQOO8Kt{F-BHj^A?pZZ)Z7McJ3&A90obmE)frf19}Is-=H( zY|Dk8<+apR*6`0$KTo|pJLcIwAKngh?T`<9N@3h7&n`yX*`Q9ht07U=cFU8@vwNPs z^6Zgk&wO|XiJk{Sm?x31`?wu>p30NSlg{JBN>uzhS2j;B)~}@;DCF5MPcctTo>Cq! zPdQK3cq#@JWY-WeM8s<4NACB}R?2OtvD$mjJ>7sZZn-A}6#~D06&nbCMh_#)V=cGI*+p?>vm4-%n z&dPIYp3{wfnn4xb8F|jkhfnM}mmJmsbxHF%dD`YVH_r`u&dYOUKK!I}ex3{RTw?fz zc`nLxvEh-F9J@5n6?rbpbGg*o&x~YR%A<_v+2E=?SLeAVA3i5EHW72lKSCEwM$eK5Vw6 zS>o;T%+Aw3&!9XV^7P8nF;AB~os6fmLAfgCu6cUo>6WLvB5X#ZDD^a+dPeD;r*ED< zMtQ_wOj8}^nUZHxp2@Z)W@*qLm6~cxiQKC1f99EK z%NhCbZ zyqf2QJTDpXMS}{(%Xwb0sTD~n0&xVL7d`q5R^K8xY zTb|#I9u=^*{>byEb&c>ShJWYTwZK0b?*;zNvt5C0D$7DR>PMKis3q$a>fRFUP++G5 zI~s#{R6IKu*rgEujWTgY9Z|o)UIlh5ut$O2jZ=XVv#vdD8JTWS2=54q0#c$jNfkJy zK)S#|1)KtIflPr?foy?7fn0%nA-wN&F+Jihnks$LQFlmlxj>~r)re6%rQ9p9ZvnqR zO@Y9+qVKotEmehZAj`4HxBUtnP+97QGrVe zoLb=1i}`BvQ%0|`t!oQhXL^){NV9luC~%|g z-c+E8<@8qjL7RebOM#UIZY?mlz-_S=s{*YpzhaI~(Wbz|1s*b;BIN1*R1kT41CRhZPuZ$OwZ9jv_Fsz=Q&$3ydu= z#^_41%6MFX@n%Q*67tBTC%vjtu$@LYix3p`)og;=K|ptQbJ z;AJH=9!>J|RSl~GuNBy!R#HpaD`hEsqrjUc+sIxnDOPV6_)PP^z=s9iDe!)QcMH51 z*VX@d@`1T3TOSE2@Nt1pVjn~l+ol4a8c!4@Y5u&xW=)R*Ul;hYz*n{_y4+B-zbWu- z9Jhox23`*2gJ5bk$S~&>WWjdU1hdIvF=lVmOB}~bCF$&VI@bW zla=~Kaz%D4k}R@&k-duSQDjf)G(CqIY)~Xo{O>n&WFl3>DUvpwQP*dRWQ*ZFBAP-% z@UDiyTnoz+(7&1X3H-*um!NAw>=?hVhTgDH^&Cx2=W-kBConRFM;l99`r%(|L@+ zW9=;R>iD9)|1n}?^Yf%4jf{A5ky8xW%PQg2BB$H(G=n4>m*81NZYpwik*kWF zQ{>_z=N7r3$azK1FV@W*rAeu|u*gN0BU#r_QrTZpxX86duCc9%ex2b`C{F}$C~~7wqB3Ywis5@a ziA&@M{aCHYopDU0L4tRihI@)MHM)F=YVW=xwMFhPhM&zJDALT>w5wZ;D7u;#X<{+CjQB)NwRE4omk-o+7zdt-;P>1bTq`v|Z|CmpQ8c<|pk%2{q6&X}y zh`BU4?vbIUFpA`Gb7Ms8jP&aoWy{e;#uOPFZ|UGV(fA@el$cQDts)bPtXAHO%qudf z$c!SBi%csrMdcmalG`#g-7Kn9_R{;GB6Et&Dl)qmeil$wNUfC5jgKk(@ghr$%rCO2 z$bupZ<1KOObc>5Du|kbpl8GmZtdO=M%hjRri*yBKWsy}T8?~GG*A#hHbyDO>qpvHn z-VkjmyiXbabdhHaQ6;OMm7wQ}yjtY>A}WNxhvtt?`f-s> zMLy9|&1<8u98p?z9{l_kuQ}dbM-6JApDymn~QvF^sDT9q~BSJwIw}2 z6xpgqDDsQuzlr>8P+K~}mLk8|*?)~AAmZ;D!sh26MYa|Bv&i2?{xT`~CWe2C{A=DS zT#+71)GOKh|5ErVCTDEhm+Icb?^t4=5<8Wsl-RjMs>CiO_9(GyiQP=9zCk_v?QX~n z6W_B$16%G@3hxCY_3&RJX}D@eOIc5s$d_Uy+b-1w|X7~{$ju_aD0;&CO8H$<{)P3lBjo+SOY zJf*~GMrma5)Y#(bCC)5yh7qG2omJxOQuu$CBTp34b4zqAabAf#OPpWg#u68lxU$5B zB`z_+i%MMlKN>DAak(uoGpJ&?!VoDGepQKUZFzNx#wD&XJUY1Gb+){|#0`e1z@n|2 zO59qai4mpeW4OFUX)fQdw{ zr^kswB?gJ@vWd@fU6q}e=mRN1eRR%>_Q)0d5Oo??i zc|_4AD^HeqN|kH_Tp3@lpZ}J4qr|f%UM}%mi5E*eU*ZMh5kqvheaV)Ry0#gwlz6Sg zt1*L!8`NC3R1g%giQBflS>nACZn{#^-8iZoF$t&BMs6_Z4lUXsP3TRN}J| zAKO7bDe+qXmg1l4FAsH_Xag6 zel$ePKgDz77tMzXT!9qe+zON;Fj_S0-I1Q^qNWw;l-!W(^mj2pn<|qZB%+Y0zDTh;C;?ZnBuFUb} z@UP8_UnMQ5>%=lA#a6UDrOfGN8X4u(GN&nYF=uq^Iinojk=1Kw8PC~et}k;=nXAg2 zTjr87=PB}K&M$L;Y&8o9uX;i7qB0kk!>3RMEy~NKWiGcgT_!1`Us2}Da(E|Imc{vS zGp;UkO_|2!x=PkzuQj`J^*TdDxuMK0Wp1>kLVZ)2CS`8^|4(|W?cQea_A+-EqEke1 zxU0<6GIy8hT;?9zYFehHye(5(=Dsq`%G|GPsxsqf$gVEAA=tc33(Iu_qqHj1u1xDP z4=Gk<+L)9a(o9=STK%!D$-%Zx2E zqRi+rBg>46bxyG3h;2+vk%n<)#+!!dq!SH)tjuIXCRt`9XQsq;HLc9EWu})|Qf5Y( z$IHwtGu!xQS*1y>t~q7qmYHXCm7je6QC(bSp%uo0xI7jagZLM#-Ar(4nH6Q8i0RA9 zERS(%SXpLWnN?-h7;$whwbmL(3{the%+qC_Ec2A{NNwbRww^JHoO!Oyhh?5G^G2B$ z%DhtMMcaC*%*%#!Y8G~lL|!ek!6>h(VvX{;Ew!a|yjkYmGH;dHSmy1x*wlCL#5|Fb z_sYCq<^u)FG(=AzAC>u{%*SOuHRewQ%WSeZM^abn`#-kzd8|zb{L=8R%6wbq>oVUM zztX2mQk%|o374MwAE$4c0Va%txZdsf(`!fq9I ztx(^1qQFXa_X>L$B}%3KCD~rKY)~O#8f0a(IhLwWsgSOaGX|$Zrb4#z-*-f^m9J2$ zP^eI>)MZm9q(N7?5>DE~G@L6072FEG>G7mC=21v%D(q8X@5l#x0^iqgX^{T?D_l|G zfC|S}I8dDW@@Iv^jNxGEk2w!DM7xJqII==RTOJYbiY{$ORXDoBG3J$)ilpFi70#@1 ze1(&Z`Gg85#!@GlIq{rQ;j{{kjDBjoJJG~XuW*J@A`@p-xTwO}70xr_IR?))7@0f2 z!UYvBjN>fjiof8+6)vf8nQ>kk^IvX=cBTAEg}1_06>hI^b%mQNG_G)Cg=;EYU*Xyc z*BP@oBSVt9p;Gtcd{eBai6P2}c5gBK)(W@9yGqI(6`EDJv%){A7F5x!9fNG8&pr}utO_MuQ05_xC+B7jIyl}21hCpaRf$J7*k9Hw*pp7 z##eZ(!USU$eWD?9V^W2w6((1h5^u?tj;U*!QS_N&Mui0xW>%P2VOE7X6=uicVw-EY z5NUfn#^=ZWEUd7k!lIbI*bw#9(hAEfJW*j;rS3l&NyBw!cSYRAt15g|VReN!E3B#T za)q@Oo~^L1!c!I2S9sFSC_$xCI-joaOk5|Ti2huK7tG@G2KCPB#R@OQJc@&OUa7F5 z!mGycn!zY#uNy8sZD)-mCDw`7^?nfx!NhTP+@b0?~Fmo()IoS zov6akM*m4YVzLtdC63as75=L5TZKO={9a+Jamq1WQPTf3$|B8wL;lh5H>827k~37< zt;%*)cCJ#d$_~}=cCdXld}ksJJ674L`rjup4c=XhVb?14WBRqGYWFI8Ny>JmVNXL| zR357&s&z9wStV8d?^CX#>QpIL$yCW2zd9mkNZw$vrR;k+3t+HodpZIxrITv+9}DyN#%@l{T!a&nauZ7J&~Rpa+RMrjn&6^+xX zoK@xYm~w_8XI8`i?kB;stDINmoOt(KL!z;Bew7PssQ`-eBEv7Pa%GiE48OF><%V3Q zxEYVwuBg`iEcL1?SI5~Dy|Hm#V{olnxXS%iuCH>dQEo7JW0jk#+-!IggYx7SL!?2m zx~}dF{#RwDwB<( zT#Goh%IqrBEZx%$&M-LB;4Fh**{@U0F)1ZTQuC^8uJU-5cdN{=@&Y zMOBtoSzKjFmG7Fdr5RhB@ozJpsIsie_O;ZnC0R?MmK9Z2S6NwQmHM=neQP5eoLkGqwXCo5OqD0AJQdHMr_CRY9r^QYmFKHGXB5p?QFN*5Uaay;m6xi# zTtzp>FLZaakKwOYdBgO)R%Jt#*Hz@TTwlu#wcJ?Cn^iVed8^9Xs^nUl)bgGwe8==R ztwko@GyHw!rOF4@@UiE^Dj!$*$mn{p5V`S5m4|A>39zZk*Hu0hXO+*Ye6Av_rF|_O zYw29emsP&fFfl7H8vMre)Yq>7#Psis^1ZZ?pKT z@yHWd|Gml|Rkj*MVG-p|!xaVnHoF59_m?}n4Vp35Vq zc?XvrjWW2F_iMu~T|2w%V#H64Qr~4ym)(rAyUQLfM>h{SuQ#}tOVXu*OTrj#YtH>f z7emTrc5~isj^k3}l5r`!WL*j_IhVZgAJl?7S}>&rMVFF``bC|k?)#$!6&KH?>f*}t zmK@rWrY%|D65l0o+0wGk+xo58+vOmaeO&f;+1F)1msG3p%K&vEjSLl5$w2idbt==KRNC%c^Ja+1rLZMdQh9oz6|8%}X))vCAiIskEbII~KI# zT9+GKu5-EG<=b{#*gkv$xurcfy4>V4w>^Ki51q+&;AWRQU2bu?&E-}%{LSKvI)onH zE?gDWA*ARM^Ia}YUG8?d$K~}7VSGOB5GuLXn2!?if-Y(4kzKN!+E@rM*jY z1=gj7OKX>wF0CwCH+KyE@6?e8UD~*;?8vr`;la=A#KTIWhQCWYmnEI}rxQVE?(Iwm zmu@Z{T{;^>CzlSLd8ad7T)L_tyU?TyZ+78=u5@?l<85Vba_;T;qrAinsujrce;0Hkjr2<{0Uv3?hNf726L#( z2$x|l!`*OzEbks_d$KztT}HXQ(w$A+`L;Vhc4v&sc$cxpHqM|zCy@y*lUydcJm&I8 z_fUzh?RqfTWr|w62W@+>xkspWn#+2Z=?aC*4421UX1dIAnWbiQ>;9X7B6)gG=DN(Y z$jt7^b3NJ6lld--To$-2blKQ5)TZlWLl(On(u;e0vD9Ui%M&guT$Z^km(E@x=cZnK z*^8ByEG@t4#cG$ewp`FM!C2T@0scMbrAJSAFk}fHGR0P4R;TxCD>a2LUz1@fJ4Bz#U zurGda`BgD-`NicYjRF_v5t=>{HpoVUTjW4rZtlx(O1;bPE?bq&zHI2rF8w&OAAh?1 zr9$n;_xm(_ULp;(Ru7~4M^vHPRys(S21}EzMk4M4dsR7~FjnpQBC69_1KHZhYuaAKPsCwaq z(e8SE|HorL58q>NkHDkG+$Y@@T(fS^o`2>rOFE@_5ogK;<$kv z~V=K z4q@C7mJQ*BAzbEhh3#H$S<}&U_A5QU9b!}0<7P#`<9d&4Jg&9KC`8wp{y&F=(YwLp zCRK}xpEERcNhxSzQEEJtTRiUYxYa|2ahu2O9!-XZIl6ynD0`>J-KOd;kC%sr*}2D3 z`PNW&9LBvK-97H}Xyb9eM@x?fJeqqn^QcvnhH=9%+6)UV%Iy|%)qZl($_uAxYmWz2 zLi+Q_!^jQi?%_P-(b3~!kMmw}Tz++2Oo8oK7BHY}wgk<8byE zL06A%QagejM{>YOt{F)Wk3k+iRlpv-Jo@O2`Vp`^97&szJmT?${fJGP`*}R-(cdDl zVr2NGngJdIEno8d)sfU6#bA#S9z#5adkpm$W?5FmZXd}_9(`9 zjP>}>D1I8nwoxeE%BEFQzUG0gLL+~d_TygnvO=zqqrz+ zHM_@pk0<5-SZ0o8?btBaPkTHgAI65&^6glD9LsYaFRHseUa)Df<2Vi)7jnL&qVo7i zpSi~I#JJGmS3TbLc+KMtj}0EL$2GrZ99N9zO^>%!>f>oTo`=RWd^{UH-t%}zgTiCN z_^`8-KKc2+#|H}OcwQOL+vC|ho{v2K(){=MUi07MOXbDmGmlLkpL%Q^AGW7lVgjFg zd|{DEObDHnS6`{!Jihk$M*Tj4#uI2Vf#ws~?D3sybwU^!4UJwC_`%~>j~_jLwhH;l z;G7Bk;;}^$)=yq0gvBi6H;+F&ewS&Fl}6OFmXh+PHKs;xy@~wov7667n(aRSYUcZF z)A0Ahz`7H|!^&f`!&e(36^$3hPkjlieIP9fR7 zefIHbGASGm^0VtC_VYQ^XMdlAd=BtA&=2p(LnpC$Qh0MY*yj+RU@`|z=A6l)!oz%y z@HyP4p-+#=^qtJ7lS9)-`W)ql?n&)-Q`lt+$M~Esiq9!N$N8M-bG*+9e%N|@P2r#^ zA@fN-CrjHDPM#8mQDJXnN>24T%}#X76n3zvp5b%8PT_No&sjca`^=oe$5TR=ex1U( zKIfUBlB*H@+Y~PFxyTPY@j@kQDu++yVxLRmY$_}|-DOIO&*eTh`&{93ozIm%jeV~2 zx!UKRso}YrPi5FtuJO6nXWZ1V7%J1k^0?mTMxPtZNwMuSjhhr$g=-oOjX}g)eD3zS z)#nbM+k9^K`FL6wRkcG{BtCap&1^M(QSR}%Pw|)ArnWSlV0w59zTcLi&(mq<)4`|K zr;Sf@pH@CCd|E2h64#fGriVVa_IWU_MwwHbAM$DE^RQ1_t8h_jr!#qaSSRgGxq{Zw zr@K!lpDq@q&OX0R4+GfMr<+AmQso&OH-jENy?uK6^zy@}h4q#=`QOLq5uZjgIA=x} zqAO?6&u7Pg{ys1JJnA#oXMoRmpMgFjdDs&1dbeKQ#5Gu*P-&-6^3 z!APGmKBIg_`^=ibmKpp#gT^x%tE4D#Gig4P-ZPm$lLb3%FpHOGvDjyc&u_Cr{aa_T+iafjSs@>MmaD&JhmTkdXVYjl zD}7d}_GX6>o-&(-vsvTwjL%x1Cw*jy44%WrIiV-7_-yuh)#pQ>*L*hmZ18#0=XIYqe7>H; zo^#2}4U6F|pSRUYbJ;YP#5{8Ic*o~`pLc!U)2Nxp@$)$Lac+7%bmIfbK2B;rANhQ) z+V((^;5(l`e7;vH`uyPYv(Jw{KdDL=Fm?gs7cg}JzxZrXQWo&yg0T3*me&OE`Q2x$ zP3bol@csh6T)>|`+Xeikf$#IThQD+!2#0ohA*U{6n-2l!E)1W^FI`B}h13he=xrac zLlCA(CmOOayru3Ga7Mt+0s92(5|9npHK0L2{eV3Jb_>`&V9G+?T*yv~!m8UdV6Pwy zh49@Lky%6{ARUklNCly}eHL-&qOks*fK0%niTtGD-A5aP?1QY|7EaJ08 zY+e)|wj59i!lCrDL`=UM5CnJueh@Moxj3{dRW$*78>fgTE)H$&8*o&>egTID>>qGY zzySdVDgukSdoi_(d2lfY2OMG^c3I58#Y|kxVF5=393Idx2q(E>GIcR8F6PJ}bojl+ zY+B6G0Vf3<6L7o&7;v1_>Z@OiDJWQv*&3XcX}Dk}&4t z*Ktk@INeV1*%BHp4O4Jtz|8??1zZtuwzdM!QDEh>u}Pu)IX~cnAS`BuMNqAAQNX1E z7YAGtaQo6QBO{lFRxS&;JP1P}TjQ3pWGPn$To-UvK;s}}yEeZWltHw4@m@ZhpA)E$=5ds!ImCQ9q_(A!%Ang!e%a8JN(0e8xJz#ZmlZaG&k z=Z59n6>ztBH2Rj)dU>e1X~6xew}ATsx-Jj>9JD-aHy!7JfIU}m`U+}gG@yAv%OGsD z76DhUVB`u~1+)&Bwt{sl@K%PhZ35Z`JQVP-vcEFa-)d!ePiYs>K46sbj9D3$P{)9o z0iA;IlW%8j1$0p<%7=j70o?+626PYT5%94hwvr!K^2bVg1>sAx{a1ysPe5N=K4S3H zRrJ&FSL9dG*ch6uVnDzU+Z`A%C}42FUAEQK;Lv~(0mA}@2Xrus)b?7%NE3N%6?0cH zI$&zRn1JyCV~sw};0oiP5HLwGQCb7uT*W)9*tCkzRxw#E8Sv#QephsHP`C8_eHY;W*c!%z*5zJ!2E!DMtR(zZ=4GP76&X0SQN1DY8tNQ{MEdzXBa*I zD^U8oQmc6)V1>E2%;0i^H>_r*N-JQMYF?>d9Wt*8SR2r4bx3KZbgX8*T&m&8fUWAa zfDhCi0j~!<6Yx^NvjHyzJQwi1xzuYleO8BWdtMAe*x&G%175Y|D+Y(I=Cyzg0i#zl z&KSn8<_&eOVioXqz+0wj(rTuzW@ErR0pG9Ym(^@p%|UB;&y+~{`-U8{h7SY24)`eG zb5%varhrehWxM;tFS0%j_)ODaP3To4gI^fKmjPcHa_$-~G5R+FKLva%qXC-(zEg{> z;m$RTT*LS^{GiYUyuT*=cFJd3uHol^Uju##*dk;Nf2`pj)AL)v@1}XzwKP~8+WkXg zxrRRj>ecX9z&6|cJK&#ye>L~k(r7JbujPuhP!sZRXYk6kT(y?%YuKrV9gMQ0!M1DZ zx|W@5*tLdTj3SXo)>1#l2d!oI8nQL)QA4_hJ!?qRuvZNYYC`A7m`hXElB^+B!-}=6 zUCa8l;g(|>GO?al){=|yd<_M|KQ!@D4QJL+uHlFpDmCn1L$!v$7~C4X8hpb)mxguh zvyK{>u3_(3+j;BQw}$;{Xu2*uZv%Vfct8z@)o@@92OHZ#23xG-kQxrHp{;R>x!*bt zkM%UHVW`oMtl`8Oj{1L0od=W@#n;7uMUWhp4J0u!-80i+c4vCVj0poKOc=q4sDJ?@ zh$5n*fFdRYMFkT^#2gTioHI*Ca!yOmu;1&4{hj|geeSt+>(#4Quc~W$d%9<1oD<_r z9p+gv&Q`O}$MW4+ejdxYT0Bot2K&!gn#H(Six1FaeHKWhmuRj(MHLgG476Wm-3d{%RMpf)#7#IxKow3 zF+PfMe~edSw2RRt#se`r#dt8rBQYM5DTvWNMhDT={?TzfspMhF`8fKF<56`eF+Ub# zkXAh&crnt0b|{Xi-S#7(b6=#5kUf(Ot!^;xk4!<X43(8Oo-4+4?Raii@#`4h#P~MGo#VM*6^UGozmG92 z#_$+Fs1s2h9?y@;pBhj1@%$WPLX2PJ6prz0j6b#Nw-~?2_#;LSb=6z(ugJp)jr;+* z{}W?uj8QTE(W=pk{l+s!4F-%4cY|>%j#oSp(nL8yVoZuLRmI6MrYMovJ{iw6<suIh6X#o;{dOWKYcPic%rF&4yFD1*|5GZdwEu{0bXeljkVO-2?; zj3SHWvYp2GH^#OYD`KpVu`G^ z%4N+=3LpQFpw1EomaFt$)b`)Ws5cPIa&?-)*xBo<*^RFHS7Zm%F=D=r@ITr%)1QX229O z7UxP}^8AlQ*5WLSoW+^i?1Zk~MVC9q7VRurTik7hPgbroB$KK0hgVz$NO7GGIBVez`flNK*o zJZ15m#nTpDES|CGY|&vV!=^H3Dl@0@tVLIgty4KNl`7LXcN))Ibhqec@q)#b(|Bka zkI5ll99#4dZ_0mDeA(hPE3A6OqNl~HvL>f<`E)u?55-;;&ao(XB|7s??1>o zvFK~@w(4(M^s{)&3ZMLcaXP)GhhMP1W6|H@U5ocDzL?H$)5G^r7EkAWivbqvrc*wh zq8TJ+@PWk;iw`Y6wismbk@^%@7ti3z8GK?fSf+Re_showG$X`gGZ=31 zqwE7SsWp=(GfB?mXN%t~ezEvfR@Y3fn#t`m=`fSuE&h;+n8^z>={=KyGx^J6jKv6x zQ5Jt&jI{W2CL?Eto~O)Yw45Loi)ON8CVOX6dlq9YCRmKK7;n*J7WOR8nZ?z!m}oIc zR^2Q*&f1?i>%`%G>qFDSZ`I*hb zvw3bdJ!Z4gVwJ@!v*|ONezO@kn>7}jE!N61mf5seFViubZ)fwvY(~#!qs1nR-LpA9 zo62*@o5L21?XpTOwppAuhr}Gtp2LlE*kMs736wjEb9itLkIZ401va~7>#*1(8=%Er zi+!>x=J4Vi-k!t9b2wmeP}aa4hRtEr9LCS#ux$7iM`ZJtw9H}g9M;UCY!1gQ%B5-! z)#g%vF3sm+Y^vH+u&HcQ(Wa8k6?17hm)3K+XD%n%RI%wWm#62_buK;ThEF6`v#D-V z!w>s=PgyT6TDj$n4ZsQpcvQl03yv=7zQTHc!|T*j!{&Xj5WSWOKSreVayNFSmef z8Y=l_Zdhz=bBfK$HceFgVJ^R^eyYuBHY1eJQar;ZY17okwu#wTYQJ_ao9D7?E^(WL z409eu^RVWHo*f(C#dS=Fw^%cg-VhbEZv3#XvD@le2kz9^L2h zhPFM+=3K2hTk#yl!SguJrkTz8T9i(|n#Tn;7iw|%JpRzO7u(!obBUzg4%c3D#Y=52 zv$@=6!aSzWW8pkD%%g?Pbv9SpTw`;U&DA#B=3(YjXFg}l=USVVHtG4{iFV<9uAa~J zHaFSaU~{81na{)Xd3HW8&8L;k%`$iM!&B*p`TRVeTW#*Qxy|NIo7-(#+u`1Ihs~e! znKGX?8t}jK*(A<06rZ&D#^x!T zzBW(WylC@`O*fm)HeGGH*gR{~sg&nR=~>F_LTsM5d8?Fxr3@}*Xlb|zU(f~F-DX%R zqf6;w^P0^|Ha%@#ws}QzUdq(caBrVm%Byxr7M8NKlwLM{Yjd&CM)#eYI-)w%DnUx!i3mLL7T)KbS{H3c`f|1q!lCT%3|PnK)^!TCS~vI9V;O)8gJGoEhhARnAhZx|DO`oExX^(s1}Ea&>;3%e1yx zoD1SKk8@$1i{o6RqS!QD$|cH+wbiAOezv^-8|S7tSH!tCPK!8K$GI}jRcer3`d_r- z;Tl!0SW3${*DJqHaqv=Zh;w6{&zFXO)r#fNrL>B3tJdBe=N2Wywcp#~+!5z?RYosm z!ctntX%lD0Qc9PyEE>^Waqf=uVw`(qTI1Xs=K*bUU!1l|?vK+h&f29^Tt6LH2ZqjVW-)tfkcD$b^e zKcj6s$2p+NvvIn`>8j#$ah_LlWEq9a|C^B);&fM0{K%s15vPBgm*Vt^^KzV5qBYPn z&TFy`)$+vJ?iHuE7SC8727l3VUXSy3oHye1i_=$@sLauFu3XNw%W0$Cy%nd2l6SP> zyK&xA(tkMvRewLukT?V4e5m?B#Sh|qrnQ6Od=lrQI3KJ2?Q;HH&bZ|a*5c&lEL_f~ zalRJ&IA6*v$N3`8zsuRMobBpiXq>O&98@mjt@$tC#Q84Hw>r#5|AsmFUcEi0{D(Nl zWlxARC(e&?M#cFl&Yy99j`LfbU(`~X{Hmn0Hu*iyA6oqX9pJAxBUJf2&PbUHHS6^+ z{r_dOoQ7KUPnmm+^5X{EsVfI4RD|IFn_=k259C)HuWbWwAOuX9d$` zajJdu72!ZyD$a^CJMwws3g*Vy5NBSTWpU=mSrn&KYZt^>sHCm7dSV5OwYVhCQYBqg zueFlpan?vy;`M5|BhIckWpQ?@c-uk|gY?R>S1dX-0QLCCHI3@Alrct(%y(>9QiV03n&@{mrQI)ifC9o14)mE$u zBabIYs;fkT9;!GA+yuRqi@}Gh@DrS$AeA7KpjeGXFG-M&_&=)%5}cVJ8!5R2lhwmn z3C>aRY{hA-I5)w031+Nf-YS-?V)-hXCAcEN1qm)qaAAUr6I`Um`&V&j6_+Gvo}gU4 z)mTmbYA%a-?7qxmoa=tp8xQ7ySOwc|-2d(P4n!eiV;RKJUGC+$TuI8}> z&m`!S;K>A!CwM|@2d(BaHFzq)(+R#>&G6OyrAp@n&#FzA1QS&0szr%e`h7mZYYDm~ zcqzdPs&`j>Q36vkZ#7G`)yrCZMX_gsSCxnd@v~+%y%M}FYbL>)3Hl^>Bf;xxuzxkj zwRztttNm1$R&PZf-bpYp!Mh3GPw-xX{<4_YgcB;qscRSz**9Io2g*N;lsDJ#ku0+W zA1C-B!6ylZCK#OHGc_2Z_-WMd=UV(C!IyIWM*cro!&eEu)2go%e3RhY1S7O|q~iBl zHB3?B8MB7r3I0y-V}d^t{FLC=1V1PEMGYhy@d-vH7?WUhf`1YmifY@eWo&|R+VHNmVL~2IoRDB*f=RMk*7C3_kF8}&f+Y#2 zCYY08T7sDgrbjW)&`6$K%Pdu9D|Xg~a}z8`Fi(~F2}+f8T}!#vF4W?p1dF4w)Ls{^ z)ujnGCRir536>{Vp=STembH$n*0D0dDmly6ao0NTSx1L;tVysw!P*4tWW}!gZ)Trf z#|CY9VhL?Zusy-%1X~kqQC-H{Z5`W`zqO8m>)4TCrz{nD1wh3?>)4fGcjRQSdfqF0 zNRoZB=_T1Odw7xqvS}wdnBchNHo=huhqcKU>-b|GM-v>=;_P)SQV->_?I$4_#<_eQ zYu8aBNyQ`^qsX_fqjHiONlr>qElHImRi#I*J+_XT>#447^VWwRY9^_z#ac<~ucy&^ z>LjU~v7i;tfyX*Q|Rg#dQRSeudPxia08capd`t;NzzHqN|H&EOA;i>Cb@9~tu}D$2JYCvnNcJU zZU|FxwieGx(qRLgHgH~&i<6w6%!8egQvuF9qDB}tmA(t87aH*i^! zCzD(*!%uRBbeg0^l9oxXOmelFU6tg`4ZOdBYm!`>Wbg()Q&-<^;5s$9KFJM9epc~M z#ha4cmZVjZTaw(YHWO99Rr%}_2C(C0=9#7Iq zmHHbwbz_*@C$t#f$WuxBBzZc?i%FhI@?4V6NuJf(F0ueNa@Iz=YO$F%d_KtwTI?nX z*~slGc9-}!^2kPdBzY~#OG$brc{#}|;&~(8Hquwkq~BMy?R#46m87>82Wj#3B>j`T zk)&UezN(A;n@K*?+P9Lto8;{z?`N$lKiSw zEjQ6xEq~YI6UzTg@^_NIl8jLCDHY$}#7HfEyD8jPM<}CB-4{jNit0>rzR=asuTO_j3l#EpDEkU7B1bwY%Pkbc3YU6 zWNVUnN&ZbTKgp6LrAZd5!2-oMx3DP5VoBzfuy;AW*uqk+S|(GVWat)t)Y=tE)+Jdf zqUx)Xj8uJ1lC`Rg(&E%DtWUBj$p+a}rN=Gd*kfCslO2j28amW>XyD*)Be#vS zwYHH%V~2B;i_hlUXyS0H!zoeBS83I0TD)c(XE>BNG<9$sVh(W!%fZ&#Hru#s8*R6d za7e21xVG)Q4c8&%;7Qjf{A}m8?cq!nYw@Y=;c(IpXF6mYvJQdj&u^!QaX*94>RX z++n0D)3!5jJ1w+H>2@}5=PHNm9Ike_*5Mk}52$5J<>lL{xP$8*ZgjXol^Q#!y@Q(^ zT4^!1gX9h}JGjN+E{9tkT07jPRku6bq2!_+VJcee2$Rr8l{*z%?ci>Q`yK9axXe3$s;>>S@re~pEz`Ic+;Vy!z&ICJ9Kt<#NjE2M;#t_c+8=b zL(d)b+Cl#v;Z5Kt9G-OeUGBAWtj{uPmC?nayTh{%&pUK=c+R0t z8F^*YD+|A*=;rW(c-F6|q*Xx~FFL&B&_kWb_YNY;@v;^hmxZ2tI=t%ey2EP@eH?l@ z^p-VN7IrO%7|1bHzW;T?yWf2k-7<1z^pg?E#lORQD!#2g-%)&5@tiXHI}CDo-(jG` z02MDT3&Z=s;X^rh^!GpSEaToXK2mQVD?U)hqh$B5oWEratAFt`%3-v_KicZuGTtlW z{W8Wn%yJm#FvVfK`j=J{940zUiW*MVgvb!Y=TwL34%0Mal7DeK!(pZtCFgQT^Vtri z4s#slIn3265yg1E`WGT*3zQ34sAQ4iV#OsgDP`ddE|YV?Wx4D{F8?|lby(rB-C?D} z28UG+Yh`UatZ^7p#y@3DEMrC)>m1gLSs91QI4&!2CmS8MIBas*EPLHf(mTV4lh5AC zR)=j4m+s{1o!qdKTX(X`TK zmP>(4ZI?WkIxclx%674T7e{tcVK?<$^2Nz+YVW3SHzy0aG;k?$sqb>eZqmCsb2pdl zrlCtCmlnIjhrL_wrj;1GoafR+LUlRC#d0}Snz)?ia=J^`-MqY;-n)5gH%(n)E+0wT z-F&s1A9iEABwgYz375ZiQ@R_ohq`-kTwIrv_s~@M9$M_dcgeb>T+%MZE+sBE?%{zw zJh6vo_mFW3Twd72D|_g-hyHuWxt#5CrpsB<;~u`=!|*-)zK3&M&UG2Jhw*!uwuiZU zIN#-Jmu4=Px?JFLvCD-n7r89n!_GbI-@}nTT;kGPW@iu8_foi*llO9&B*Eo!mn&SF z?j^AoZ!hV+TUvX>iVATHnT z<)^)D+)I^xv~s!CE!aL%VUyQeaFY%PhvlhyF8)xC2E}6&r>d)U7mJ%MpC_> zX8XBpKbP;Pi_5ca_-aPW{oJyjVf%T`rMJuTE-$-ub9qr_(51T@zCSX2KY#2GgYV(; zlB^B+i+exz0Wt@8#pN}Zo-VJRh~z+MCeij%=a(Je+5_})d0X=A@}|ohE`8O*%?HAf z-g$t2E^oQCI}pB_@!SEr9pD|8{x0vjyeDBC2nYE30p6FxWq`{U2l(;;Ll1<3ecC;BqMlE@OEUc+KgtR2@{`NYZupAF zjDum=;^$YF-!z_?2U(-yAJUP_pR(*lcNyt2!sTz5y$9KUFnrhSTB@*B=Vk!(2Jp<+*}G%y&88qg3`Hj|CE*%R-m+E{j}N z$oc59Os3dnsjg}XSPp5pTsD7IB$Gdvm!By=f8nymWtGcnS>f_8lMaRRF3DW$vQAEl zL*d(Y(r^1iY;f7`ve9LW%O;o2vUCs8`%svTK8M)qvQ5|6m)b4QP-okM;(u@N5ZtcbR;~j@;vH!;ThED2rZ6=nJMt_JPJLU zcoccm_rlXeoHX!g?9tGpk@hw4XgGJ`Uy^XLDua%4iihQKs>c}~r+J+2@ySsJ9}U;% zkfSv9hxWMC1j|)9odR*jjg~!DnmwH?xoqD`?jKRkkdW`Rnahb>E9zP%BuVaik#*|~U z@VMIJN|`2)S;r_n#=&FMKF&1~k4M3AnjR;4oRZ^Q=W&b2^&U5Q+~9GeM0lKQkJIWn ztpz=9_PFmj?T_=qae5x-R*yS8Zu7X^v6BR^4N5o{BjzVb9y=Vd$g0Bm&+E1qx^N-)#EuyEarC1{g{rJZXO?byx`H-qr1ne9xr;l?9s#H zCFw|-V7|kQz`Wwo(?i~!8iN@hK44{D^XTKz%cHl)63l+g0n8E1>mF~&31Un=V+xHq z&6qbm`g`>Ac*o-{kGEw(8q>y@r;X`i%)2thvJ8yrZp=%@yk^Y%9v{dUJqC(%WBMBN zwlNfC$cg!}6lJx0eCaXR<1>#Tveb2%jWTAeF%yjW+~W(6DaOn- zrfLOKtAZKo@r}n<9$(ApS-~`{V474gr&loFdVD9bRWKJ;Fc()amsK#sJbv}~!Q&^7 z;T}KAlBi(rtYGe{V7gQ=KYRQlDXkDj@=*mdvV!@|<4=#@J^t{RTEQ%?U{+Nyn=6>V zWWjjss9+9MFtsb13oDwD9=6XY*{nQ9dn}dHL>92jqsL^Au^tmV#(9jFS*U1M%VwfD z(PNTFw~FTFil$dZ^KC^l#bdhk?vgRw9_La=Dl}s-&^H?LvRQq9y>pV7itXH2usUlr(loh3Xvqzc7 z7LRSR|ESG4)wfI1WOR}J+)8Gr#~zPe9=lJ3SIO+CWXdX;y&n5StYi*XG8HO^<2oQ4 zug^gb<8#R4n8#sla>V1PlIoRB6SX|9#c~gPPOoe_s`yxCQ^BXIPeq@Td@A`=_QQNW zp|#H_R`Kboq?%7npXxp})TUcy^G;>+l~&dA`Kz+|;3QMWr;$%xpM0M@H4|_3e2$!C zj-O--eCqoY`V>izRl@k|DmL(G=u@D)NU^a5>2tErDLzdiKj&02r}~`cbFtc7rg(-= zObwd)+*-xRN)We}&)r%Z_i5vk@VUe%>67(wd{REHHt~FXpLSJD=PKs;DyCNzQ|y!R zDe+0G!ADih7gfyADkg|xm{P^$e9rSZ)8`zYvwY6>nInBwG3%?C&D!a?YD`sgzR!g| z&3rD9+*S?8TfM5OS=C%5L-47iN`1xVKG*wP>T{*fWjO;vNN&mBIu`P}Z) zwyJqV4SFcHRvXFZojyVHPg$dx6dbPIYjYwpErHp@ad~&pI0;AR5N3%nSMTR z`Ak)t8P&|}YUUlEl|JwKjPQBSXSh#)pCLZ)`+OjaM}7iSaiGuqYGze6^P$hjK7)Kd z^4V0)9H?fhRyU_tH=pn|G_5@2ZJA9~%EZHH=(|{pE*Op`XglAD`Ji zBYmdJ{_iuvXSB~)pMQMD_)M!|7S}NAYnZYcW}MG>Srs+S=`~Hdrn#i1ndmdcXOhok zS(Y_TyPBqRP4iw&GgTT&5^9>!HO+#WW^GL)z0dHOsR7JV6lHHsGskD4&s?8*GBk~6 zzE7$D-}RwX>uunC5lNLD^ts|Mxj8yN6yji_g||%u%0Xa$bv>c65IoQ|?nM1u0HSVNz5| zQ6WXe6ra~IL+cp%lSdlL-vyOZVXkBdRZ>(>Q8h)i6wB(E9d*p%I;MJEQzJ#q6b{wevz(jZ>VG3KMd2iY7{m@{ANuO@$ZylGP6K`)?_%RCorRq1ZG< zOo=GTJYy@5M@m9TF3&hA&XagjWK!XsUN428BAp_Y3h%)dr^35`C8_Yft{lzsOjy(- zNRd^WoVe1qXQntS72a#TAkW;JXTNO8OR7kja6tsdH>xKkr}NMmcCXYNjM zUy6I8{M@Ux9r8@u6zx*sy94*9=$L07%QF(^11UNwc_>ADwG_`CWCpeCj*1eS9FL@U zR5SmWnw`k`Q$}nl4rW*nO-S+NAdSb@lJ}@Q@p9UeM3{x zS3B*IXZq>9yp`hZ6fftQx;i?+cT)^Z@m`AeQ}kC?BBHmo2WYB$>iYR0#fK>dMFuh= zSrQ+o_%_8SDZWTCSfd)ED0%x-EkBdV>u>kFH;n!rkIvuhVto( z@{Y#L6thy?uf{*+nV<8_oD@q_%uTUCUCqWeR zYMEHdCZFP8?MRxeNU<`-D)si8E|L*yxhBQhRQQUA_*tj^N9Gxs+zlx<%4Vw*y-CSt z#Vv|k6}L%#)L5=ScBCki9%cVm+@-i%QN%q;_9~9cGy9bsh-wd}IHdfr;t|E8iWBp~ zORwX~g_KLb#bGaUm|`j@uNWznikYVNC#h0Jv8rM<#p;SR6l*GqpA(l=wY6BMn7Wak zS4=(S`HBURJ|oW*75|r+`o%O*-cYfTV&kax%@tBeY zvi~cID<%|^ijJaNjIYEiW}l`ar9~Nw6y*a*NIFt7#RST;k&;t#W-(_)%Hlk8PQ=eu za$Yg#D`^(#7Zh`0#FuN5FD~X1Rhk#mLdm7YTo&0}Ud$CIxEf1HS8DO9Vy;$ljp9!l zt<<*E;&sJbuSAp^in&qwO^UL&i+Hp0TOylVi@7c0w-<9qF`M*1xQS&O)$fdI?<(f* zh~J~+-eT^Hlnr_2{$d_0rkyGe6w{%Y2cz1Dl(birfICL|!^J$J{Lx6+nrAvi{Bb2u z6!WB#ry~7nB|GKQSxJ{je^yCX#pjB7UP(8_eR<|kp6RaqMa3S9FDbsP_==(oyk{}T zqny81Os`1qt)!3Q>&3jGq^~0N!m~_{e#N|{%G-+XD88%so??GRv8-Ir3{XBWQa(`f zq2i!oK2q{=R9juU7_7x1#e5p+pB3}D@-HIg%VO%N@mH#R9qHc`^KHbxE9U!%4=bi1 zihp=9KdSzd;?KqWUd%6%<*!P9E2g2^{}Jhb7V}pzBZ_HK&&d4RT063s@x_daY(^LJ zPsGO*GgkSyNO85v1T9WfoK(zYB~uiqDoWl;)N*<;Gm4p~;!MR^inA5x$iAT@r^fS@ zOWV?77ARk+xG2)kRkJ0NvBYWEehU-<#WgNla~4=aj? zd+M2^%8w}?S1gZeDZ!M4p8^#W+o}Ib%0;YP!buUYqNHjG)s$3Ml*?~1s~OqUDxr47 z>y%Jed0t8Q&$;R;c2NJ)q@aYt5*n9K6xr7=p+UqODrr+mzfM+1yb=YvpYs ztNk-t>>Sy2DdAb=T_fc=CC``ewc5WB>D`sQSV9jaFDbqp)qbiA zyJrcns`6T-_bQ=x#QT)+y7FP_xv%m!quPE--co#9@tqRhjcR|^CjGVeehCAV3{?D} zgpW%2Q28K58T%h<|FIT7QT$t#A<92h{7iCE!Z#&+A%iUm_oy#R7+S(t%KxcnCe$-i zb%PRz-27bz}Q6c0;ESQ>Hi!w>Z3TKrdWMF}gF ztWvD324b^Di)%|*r)0gN=o?DHOR0@o+*CsKd{ZmmY|-M@$Yz_8?TR~ezNDcXJ0&NP z&F&KRDBr8NPjSCup2l!c`5{GVdsxYl5{{Nou0D^Ia9qX0{P5FR4$@(4MzLYOshAEw z3o4~KNl9fzF%Yqe@~Ua7DG^1Q*NAvcCAAc5E7nO%B3az?(%kCcKmh02Q}rM{8| ziVYQQ9aLlGCo48dbBYq_{Zu8VDW0zA=9{KUVv3fcttj^KGzsO&NGVbOZW>P&UooXv z{Qov-(h-;2P4Wj$kS422PVvN_JmUW>EuNj`oXGxMCFi9%KT?`0$>p01(_Eb9qV#_^ zqEGy7D6X2Pxh&14|D%iN%e5#rV$edlWd5pjc!FP@4*z-*UGUm8*Qx)Oit_i%^-69~ z6hAjAxk<5=HW%?0^>FL|_(|z>-=Su$6;JpV6#KjW$MPPn74hExiBO97Yq6bLN>O5a zP%R%y(_X7ii(>Am#fQ^85_R;bDkoZXO7o-^A6I-rZN%GCS`;Twr+Frg5IH)h=@Rj0 zm7J^dEB4Q8!)}V=`2{826<P zG~cKBE=?z$An`UV%@1k%%hNJ)J5+Wa+5BaZq{AOO?J2ikRQV;%ui9j^+!WP@lHT9b zToZ9={#TkYX-1?OmFDj>Bh##uyB6|_rA9tF%|9|6jbW5VJ~qvSG~?2Y*RhCOv6Mkg z)b%4=x|p11UYaRsW~Z5&W=5K6X{M`ZiGP>c&rCB*qZQ{8vv`=J9_A{FD1PLaufF&;xo-|<+~Kceovac zvTvx*#)|u+b#g$-!8C`I99BFM)ymCqxf44~eg{u)0+**T8OVfpxyR@|I;pCVL9k+m zN*O9=C{#Yim`VOn6hhuKJf+ zF_wO%R_?xvF2w>hliuYh%1}QO{_u-fHptLWyA~ViTClNJiJ5q4lHn9>SXuV}45wu{ zU5gT`9Ae)z^WRT$#WX5QM@yz_sydOJrI@o-|i=W8~k$7Wh9ampQ-3p3$It%w(AXs$h8A~T{H z7E#74W|w8SJi`?_3Qg zo0YNLm!WNj`!igv%Juo?#(eWYhKDmen4!JeKa}BSt?iJZqx7P@wc;ZZQiey>>>gD* zWq4dV%{Ohe*fHNcskPGAQ%aszd`3}*JVroZ;0BuVm<%p-;YfGv5r%H%5NsDnqXfALW~& z`DVB(eKPdTAXTqtcteS-87aQ0Tu479vH;$e$;$9fhW;7ejcVUhB5}T-VSol8P2?CD z@eeb6tbCC4tHwWSzn^6IG{fKwLo)oN%7}b3KHq$%HWTvAr2O#vBbgUjjbEyVq0wrT zsTWbE_#0gh-|8BWd6y;hy(+TCr1l40HexCEC;a@B;b%4YMNz7LRq|Vg-y`J@B~$Xl z?_b2{hzx(rV$hX5GQ(&+vqojYFVv(~Iug%gGR(~|HWPl|H!j1J4C6CQl7{m9e};*f z@RqD_K{+Nz#iBFuVpI))Cj_F zdn*Q13c}1+4yYP%lJY8wB9`ZyYRaoCRxB_go~hql*9s^Is2zk~*UC{xN!@@vCG{db zU)&ZLF(?cu3c{(E80zSkxebEw2kILJGz!9hJs@Lj9E8tso~+nJ@f5}Rvj0cq#5enA z1mPp5O%-E`mZFHZlDJ|*v1WmB0zQ#}2eb?D0U$BT)^1@X9k=V&_rubFECbtIVa%UfMkIwR`IL?bAG@@0nLJNja?9M zp?Wy4z%(x~Eeg!V0hb0`B7p_8ih8-Lz+4t^dB7tDrn8FDwne}#0apfGC$0jnQ9oA) zyi{QNh)qDtfW8H0klKG$V6G3iDd2{H8`bi+0yDC}Of4|20&WgiP+U+tKU82SG*t^tn}9o2$tyHPh33>kb9caf0rv#ltGZiga)sv1LenP3BJRk5(z_S6J1G;GKz(O;)&Preu4@qFa`a-k0(CjTV2Mf(B0dEEL40t2p)qvgsuLbl9s8VF= z6q$NOreTrk6YzS#DMhAfk%XyfLBNM<)~U$6sI?yjd@L~(nYXl~Aw_0zz`}qb z0e{Om8}NgiI00V=d>-&+z!#c|6Cn)^_)5KftFC@1GT#JzAMkC!cLBet!;y-^)a)NM z8!lA=KL-2~@ROub9gZt9lZ(t;HTYGH7Z;h|1OC+7KcY_m3K*fa%hYmBkr^2JnF}2CnH?!32QYqFqa{}fE%ng_qaBF>YTYb}3%}QnQYpaLrhZEPezF8Eo zCtz{FhJYmjs{)n={2Q<=V7WT%Ro@KIwkrZw1`MrleyndstFk&^ZNM5eo21G*Sxy17 zl+RY&7_cp1Q^02JSBA4CU~9ysIKRHx9eVFU9;1LI`FcO2X-o<`M9F8muI<5#qS!JUmBPzvb50RuMNx}YIBtqW$agHx#k2{Y^ivi;-6}H zLzY%qZp?C%hJ9iZ8|aHRm&yH~Z1_gTtyyl%hL-{ISu6%Z?#OaymeyI?sH+pA;9Xhn z))gY3)c0t{?#{a4I8x&bS74UDS$@p&W|ptA^vm*5mbbF>&+>Mb zceA{c4X>%>7}X%WWO^^l7$xs#`5?=HECbbGu-XWIm}O9waShCb2IhqLahA`sd?M44 zWpI`uYColcnc2Y1QCFWu9=^yjRMwIfX`9}3`vwSBfh2BT{KFcr} zm)gjU4zZMDxSGkmpr5jg%<^-V-&OfV@mIy)vj5$E`XkE-RsK}`OHn%gTZ!DC5r?C) zOv*Ak%h)Xcs6Iw zr_Zb`vz5<@lqGs1%*!%A%gQXJS(ap3kY!Pph1u|LffWsm;9})#l`oZ{Wm%SGxr&=q z6z40nC`9a6Wm%VHwf3?m%i1hEBD4Js%=#>wvTVq*G0Oqb8=7Q8)4ZYCtoC;{G>f{_va-62(DT=2m{@XD8Q{r^x(sfg{ zm+fnUJp7;IoE*0HD`CWQByyDGNajf8aB{f0|31;Y9Dc-QXksi!aipYkWOHQHPoTI; z(~`?^R*o}OS*yy~%1?MWH^)U$o9DPx@~m83 zT^|ONp z?g3pA4=O&S*j}-NqD)!G91kns(a=co(HtM=cq~V^9G!AJnd9*&&L?u=9Wx2|sT|L0 zcTeYdCP(LJq+QfCg3(z|Nnol44I@-1)j( zy8F!Yd~OmUGG!JaRLDG*h>|EGGKZ2VLliQUsi;hajG3pRME;-sKCSPs|MQ&Z{k+zD zeb#5Kz4qGc>@(bZYM9sKY+kBzCC-s~6D~w`UV!3At<2$k9=M#Z1%+5xX#V~0BI;u5 z66%MASV|~$@18s)X1R1ECr(y1^T?gR3OTd=g`HO~=ajb3QM` zp+c-F#73D1eZJNa))(Rn!UpaCSwnqUh#v~^RUvj2VpAcu7h-cEzLv+mds_-|w}vX2 zq_!4f8wXG}NmWTwQnjNH-xlH|@Bfb@ zBma>@`l%2H2y!QUQ1+Q5^BOr^h$B2e*}G(i871%k6ymsSWra8<3x-EMgj?CKg*c%n z?Ich1sX|;U#A&(Q3UQ_o=L&JQ5WjJc%1lzZNva@8oiD_NLimzYEJ?+a%+q?Q5LXIu znPJV6RO=*jXS>Q`+az^e7H1)D6yjzfelNry?5GnP_DE8<3h^f$X(FlmC8^si{#}SW za)B__AO_3G|0%>hx#)QPiUxQ$F3%v+wwQqu28tWz^;?>2sia}<*pgG`q?BQ9@1>~% zWe8;rlp{PqEl(YsWM0b;8mMUCA!d^dlCzS5hYj;dp|XK0hWU<-JgO3^QL9r&B&kOX z)G|=RFt_L=YE7yXlMUW!%cp*HQVnDnNHb7}#oAPPQj^GZ1LJr$GYw=L$kG|)MCXvl zvo_B_Lj!dUb58Q90`&~kCl_d^0bxRtdQ>}w1`M)AJ93{R(+y+7hJO=y*yas#*CiA>ZPf|0JRKP&cz#NWhev(>}q{0TG1|poarAg`&Suo@^ zNoq@yDl*X2z+(m)i)r9-R(+eKb~EP_2AUYyo22$9sUPV)X`qFHW(JxYIGCi4C#iF? zc#_mpoQ>i&)q^$7#ox-n(*`;iXl6rny$z8+gV*xTb1cQ+2AT zdel@M4RkTk$v|fV{TMT(rW#vQbv4kT13e53FwoOLUzs`s zeGK$6(A&W0HP!Z->QGH}rlxwHhm%-){S3Tlpud3^3|y(H?$lIel2z4Y^%7&!l2vB1 zIr4!#kU=zGHc*(XLdj|fi$e{JHZaV<2m`|tnUl?98EIgYOklEVmaMuat3JtUjDc4S zjFrVBk;!UOvYMH!7A31!4U9LiDp{>fR-4&&f`O$5CK{M!;B^D<8kl6@Z8@g~rWkm` zz?%lPGjdn5`aW5`B~xMGaI!j@tWGAYi^*yl2Rz-tI|i;X@-B4-M>v!E9#xJ`Mk|lm z2HrQYK-P&|YjQ0xgZL$Csd)zG>tZ5)p@GG0zQ{n?TILijG4P>Wm9@-cmxnmZ3~V&8 z+`t;SR1K^&@G+aLFz^YXS}m2!_)iV2X8u(&x3!eLmikOinXK^tWRsk04XiV;UXSDp z0~=()*HU2)piwRLrGZ@rzA~`Qz$OD<8`x}Mi-A_PRCmVoX2Pxdz_%Ot#=s6H?8mBa z4eZqU6GySzzz+uY82Db+yn*j@+r&KVGq7KlTrD*yF$UTE8Ss;V13HgHj;y5)$wXPq zt>CbMBL=P-_}Rd327WPc!oX1j$GJxxlSNWXO{}GUWuCWcsds9rlLpQhIA!3pEQVSt zvA@kDoRw3?k)Jbg(ZG4Ol9699uz~@X=v>ptJ?|TTse^3_4OJ8Oksw!R0LG^MaTOmG@ODSn!a=+@&An zOiEQn3o2QVczPPhn~EwHRI{Ke17xPuJsFG@KijoPDsR&yTwIE_Kp9kf|k(e=dCq)^C zsN{Lfg2r+>EO?yb7c)`&gaxfFXkx)rY~Gamqy^0g%`IqQ!Mqf6Pmsrw6!X<+OAA^t z|I<`)xbo|A#6^ zB;4JCJ{CMHXWW7w^n3oNwimhgf1KyZeX0HadE`~q46;n}Obg!A zJj;UFLhUaiEVf`1m)3_CEVE!K*P&#PGq{{*QZP9HhYK_Hwk8691lHxiG zHdwIUf-fxCnWFZjsJ%Qd60p&NeT?~v@tdfdE!d*7{lrLF{2obb!EOt-Td>Q59eU6C z#)5A(?H!b+df+H3j z;9<(lA0!;I;4t9`PvXxOoVDN=3x1_})PiFc92ZSdCsWjw6m=&>ov`4P1t%GBf2t~% zs!m&Q#)5}aReGw*PgM<5)o-#7Sa8mQix!->;DQB?R25BC?Ne3vRCURM%W{FFs)4C$ zY^r)ARb92gfVT?)B{#jv!c8em93~?MMWzfwBjKvx~Hj^ z($vT_H7-q6Vv-4LQiWWVIyp_vNmJFWsKMgH)JLpXoTiqisU$0ESy9u9Wcn-Fe0`cq zVeu;#)2!yxO>HaeR@AW~-->iAvKWv-&7|%~Q`uJJT9Lz|9PjsOD$k0#R{WHvj-{zn zY3f{>swanOMSUw8T2Wv{11tVuFA`s@wtCcxLN+f|+nlins1|Xou*re5D1Not%3(#+ z3a1r5D_mB1*vf5{AGlYUwUw8}dJWz(|N**rdBkeBW)*3S}U5d_-<`An=vh{ zXlcb$G-b?kv9z+{X{-74B)dv$`faFfsqLtet-V!#eB2yW2P=kI(UHf}NlrJRv(|w>4=Z{zvZoc#S<#CDG5`r!TwC?AqAzQor;6E+u#_2Iuwnq? zU$o*S!iw5zV{J9iiosS4vf^c{{9?FyYNVm)5G#i2{5zOoxD_+37-7YmR*bY_f)%5z zc-4y0R*bV^j1^<8@>ApHXm?RxVe>?`@f^u(dSJV2tBF=jw&HaiGf7uT*Kg>4rR@|e z-m>CtE2jR(oMy#4R!nCTiQms*ziXABDL2PI(~3E)de4ekgxR|7`?{C8a+z51ffWnn zjL@8~t0aRw7Fw~0j<5`4iLU*Ssg_!Cq_#RHtC2hZM^>!1;$y4%CBqeRA#+FlgiTh; zl9RuRwPF=P_$(K|XDrHUS!2aIE7r<`Tds7so(oAfWMO%V*&vHt_J1qBBnW?H#U}D* z?QF5iPo*oV+G@plE4Imn$=;x-+b3MtCDxFeUC{H&+d{9={7ohAL= zlRe)C*r06Y&M&nRCR)sf;x;o_OmXCWGl7zfxu06fhSCJ_%Mi-iP)<9)*H-0ic$mcs z)CX;N$c8F5RMat*Y^bdHR&7<4T#Z_tdWT2%hz%($)}SWYP?I42CfiVp{40l-N=~EJ zrq;0`gOF~+J!X?unKt=#dvo68kUBucMOcD7OtE8$2|txv+YqoJXp^6$ zSB^R=P)9YbW4;Cn+Yn(ulp3?4h!CfCtfL;Yp^*)p>X^H6k2>n*I;yb^PuR>ia^(y* zv7xCAa%b3>ha)3zWQdI#y+hK_Wm@=MX3ZRjGaiSM!fI(=>EXOkZ{H~W$UTvkWDzvh}#E-Da?~SF2=oB8bgWgWFt+R|BO z!*ZIk9;E7H8&=z}LRN?kpV+X{CO`geJ{#_!u41GVCHONN*4ps74Qp)JSx0@xfFJ9q zbvCTG$2j{-KnEWq^nZtYPSu0cr4Og*>rQX-`TL=hVO0IC%X`xs?;BB_))eg za$@9+(lMwKe3E0Z zq^r|5T(IGc4ZqPjYm;9CH?y6y;k-?L7F-3=Rg9T0+Hl2&OEz4#$&Y%QBbP_xbamB+ zYc@Pdr&YRYldf*aWo5_jO!x=&rVY1kxW%#kX~SP~ZL*hc>8fYC`rC%PiCJQ>r2R*> zL>u~~tG-P80)v$u_u28F9mVV@V@Gj2?zf|a9VPAZ?mh9mypXIRItmhMgMyga=Z`OQPqx$c2u_WRR(o+x~jrf60kO1 zRnsg<9=4-~9go<}ElZZP>{m%-iA)sb+N@=VVMmG`^`xO4Id-Jkkzq$|IS{_~uVY8L z=5^^RlbofUY`gppwUWqO?c@>a+L2G#oUXPqpuQaibQB?e9 zSdPmM7k!%@c7j88+}@672#H{c?`TISI>HCos*4?6?Rbu6H#@rP+Gp+PVMk9{80<*m4>P`( z9lh=7Yeyd)`8+`mwx4$T6Qt7@?Redem+W{&R;e9B>=?+ZLDZLZ{9wEMc(*yXL+u!8 z$1wWCsUvjEv2-{zUwC3bvh$5IymW~;e!@v``l9V-YQQ<0%Qk;_?j zgA8?lhAN$5el2j79hdA_ZO7Mkd}habMt)9RLtRTW5*FYj@$9G9Y?Ot%TV47^{X8xS#`oLzu9fJJ!QvfxmwAMsAn1Qn;qu~=cr9H)CD^( zlAp{_%@}#v4&}fVJN~xgsvWoNxF#FE9oHEq$!`#vGx!fXZnD^l=jBiGU)0;wHVl(i zcUZhj{l|`bcEBM&;cbpq9-Rdoc))>T4&3iBx6tAalpqL~By`VEr5q^ZKxysEoR=k+ z(@u{JRo;Or4peZUq5}`oe~8*g_f^S($_{h;lFSLM>OeII9(JHQBL^|^5%N%S65}Pf zCLx(x%YhU^Dm9HdoTsJ^Io*ML2QtXgHq(JD2XY*4{wXnl{8FGd9)lp#wVh(fLl(f=yk;DATgmfg&iH#hX;K1V!^m3rF z1Dzds!hx0!G;yH015G)fPddi%&by+JQDax=EZ^ z325g)2M5~A;$h763^kYMsG|d&=q$-l%VpEZP+c78PNyri8?~jp|3i>eJsjxiz;h0) zVe$IK4!4!lIz%K;q7Py-zpLT8WzFFP=p zEVFc&`G-0%+<{>% z$h3=2bYQ6iuRHL*1Ctz>?!aURraJJ315?=QP3l!PdCMWc)2;4gsJCfOqaxGH_KpMZ zIq)u>84k>pYb{efz^aEb)hzlFHd`(+nsXeOPjfEy0|(~mm>QXC0ePVViyc@*PMq{5 z4t(g4U(Ggqlu5|SRLf*#IA2j!fmvRGY|~9oXV9KTVKq(M(m8skS<> z-GObguJ{^UF0LI8^B=;??*O5|`T^2lmQN!WenwE-!(e+1LBb*GVF!*7e%7_kGSyKBF0gpaf#VLGcHmcC zd%}T}E6@=I?i+j1#4tDD5=g9g=-aGRui5>qI%HxzWke8YLg{vZ}lj z6`bZCC8Mn__y10FhUHO_P|1nPgeugky0)6r{GYKB_OKI4PCVj74Q6i1JaUR_I#Jt+ zWX4P8T27=m&F2w$q&m$FGmR=mNg|r=M5YrNPV-H_#G1)+VvQbTjuUmA$aNx*3FV;V zA(8n`)DxdCt|#yUFK{B_L<6V!30*^{`CZmWo$xzR=!DY=!wH*AlqBI`p379dIe~U3 z9L(IG#UYu><%EZhn>t<=zY{*E{Cc=~7N+pJ2(T(h4LK2ZLM|4mO{k1eraIvQkH}ht(<7% zH17ePrncrXkYZaF+fk(`SJpF{I}keRNJ-V1=dOzrU1h;I(M`^R6WyJ7)+xVc&d)Na zJsGx;+>0ZTw!NKL#_>Gw#EVY!W%7QE>`#6{_ba=BjN~OJ2GAME41;u@m!0xE=H_t? zabmO+LwWXP=?>$p4tHV%LFRU(6Qjs0c^1YvA>V42B_zS)oaVbUukhr`l73ZYUhe;? zuQ@S+Fp(;?t1{Ijr@0-;V>00lC*IV~6er%&Jk=>br*6K>J=PG>nW--+4mOIE`Bteqp%LXbuBffMsI%Q{)Wz9f|#$RZ~ebLmQ+ zB~Eh}m4gz0DdU&%#JxhttYX8DsVk_TP*+kvbz+qap1d|w$>tzO@wpRgWqRep=K_=A zt>cWDqvE0+$K)HF*hpWx{?duB$eXB}o!IKc7AL+IUpD_twI|cO&ECe^AILknL48C0 zmb#Prt9(r3#BL|{vbe{Ij`A+Cy#K@E(aeAUBi}w2_dD@}%mDdE>QB@I)Pqj*_DtFy zX7LDB9O>d0vcOToG3xPz>BI?Ld(tUCH~(*sr-kXCrT(U4&JoU2FHl>vi%aCovJwc= z*HywbC$1B2P(NYtA5PqH;wGJ2)IX_zQEyZKrb-@Za+mxM^`7?OGXIT?qDojXm-!SR zkK!(rAeYq6{e)63lqQ_h$5@udaxOfeBg?x`LGy!zhg>+%_)6NZOsGPw>OwU_b?U=Z z8Nk{ zQzO(UHAcP3p%#%P&ton$()_p!jWs`^GdHF4r1qN;n!C_KJ5RaLQuE)L>S=OoY8z@> zUE7Y(-i2ofiPb1$=;%Tx7oMZp*@Z5It}Z-F=;lIqfqV}zUM%)@ zp%3ACYG0}ZJeZ~WlV6~|NPWqLmk9%?1F3_km9x}f!Vs!t80tcG_9Z;rg%R{eQb)Nk z(S^}2jCWy-3$M5^)`fAbI+nQH`0s08b(#BvG=GgCJb{purC!&)OmbneW(j!Hg?Ct- z;=)_npGtV!g=vK8+E3x|-gRMyc4oTp9(fjZHZ@%z#T*vry6^#E0LM1pg{3SmaA6@~ z5p^+D2ET;xp$khGFU~SL%c&o^@UaV@l2^#i;KE9BR+h45Dft+56^pB>_AC|1QlGo9 zk;OICwbXUg^)7rt*g$=UJ$~uJw=R6;!d9A_T-Z#Ik!*3{Yt2n~nA=#~PTk?cH@Y^F zYNrdk=$wH11=;ka2dlPmwC&2*o7m6pQ(d* zCw7$a$EX?i?j0vUKK#{rP7+R0PrD$kB;i?I`0pBCTZEpCAdY>D`2;vlXqXfCVUTOEU zSjvskgfco(mQXqJ18!7uqrCPj5FT{nAwos%Kf{ETS*+qlRYEmtbsf_wOFcraK~198 zbR(6JOsz#taihB)VVWDYY0CKP5PGsI!;MT9v#8nB95?E@k?TfXH}dF6tKN*ycbotJ zM~d~`Xy`_P8x0uHKg;~jD#NnWqb!cfQsWqJxM87V)p=}g*fl%caB3c(rQB{j;fBYJ zkQ-k5K3(f~BR~#nr-i)#<3BDN@wl#SOpqli2hzlirrLkf zjb`NL)E3l9%+u11jx4rv<7q-`nF=@BklRw9VZ!!g$@~nVgBz2Xp_3cE-RSJbvuS8TomFp9r&8Z`V;Ui`^SncrvAs)}L7ho`kD54y*>1eg;vDK+ zs8#lgnV>fxH8@qJ;Cs}Hb=DmbOkKenoPy71`KTuckpnh`W0E-88%po@p zlh-ofXE!dp@rxV3xpCBulWrW-k;fC@#tFhk#>-KhV)3*aX9#B#Vefw9@M-uOI7rsmIswQ zsOdpv52~}OiU(B*)pVpB+QZ~Ws5Pib)V+FclUYpcY$@ba57G!S{@NbYA*WMiGR4gF zAm4*5I@#15s#N6?@;sDu~)0%`*f8fyPh!jDZB&F zakmEn7Cjz#2{HyB!S6xh%!(8AAf#)Z&4ccAo~8ECwLK*dd+FuDOCI#rejmc~)V?0{^WX(?f9m-x^Gp6O zdT@pP4xl-ZDm@M&yzIeX!VqfWwnu7*c`#f@jv$QmU=(4r$9y?FM%N0D^O!gMuXykp z;Z+aD6B5}bkSBWZI-7_ok4ZG8BjGp5Z&Igt@D^bz^=;}j52kx?gNO4cRa(94!3@^U zq>A&N2eUNKCcICTUgi=$(6#eCm``5d!D0^*ovrqG@S_KNJ=o{LcOHE2G5;B$gvmp? z+wZ{-jI5BYDrTF%68IB~0tYxR7Bn#Ms!yX*-;D`smFyLqEE(RR+nExB|ee!V` zxd$icNJojjPI++NgVP@T=D`^c&dPSjz9e}~!Z~J>;0uI{a^Z6Z zKmpr|O2hJ!Q2u60U-b`q@sQVi(y2(TUxpyg*E%% zZ`ymaRediC7#7G@F{W+kh2h1cUKG-AM6+48vPeTO+OYUcw(3f-d*SfH=Y`V?j~6a4 z++IA(s@~aZP`2_i$xu3eFM?hK=*Y2*$yOmR!d|?}+PA4uT^sWvuDOWt7_|}gaqqwH zQ9Pkznt1>HN7It|Nt(^PXf7w(ixx6$);{G$OF5@rv|@2Odz97K+KZWb^|tk*9c$ZD z6Kk~txg)ic7oC}3s^rndi}%@9`t3%)yUc(NkaHw{PcNSHq8FP>Q69Z@!1G=V^P(@S z`gt+Pi~i&ns4sdkz>Al3!$gk*S)7}#UM7e+*oz^WhZ5#-NW;k^s3WPPsH3T4s4|#w zUcBYSD_%^Hb3t=F^)(%k=yxKEuTv*^G1-eZy?BE~37DU)rs#u`oKwA+;l{6Prc@jD#=&V`HcEGbq#eHldSXNOE1=Yv4Q3nUh}^M z%Mop4Q9v?$Mczc+%!ArO{o0FdUTh_=K|Sd^Wml!cfGjf#cePC^x`is4rQwg+2%(le`Kq_y}08wU*E~6F!B)i zNA`Rl?#ZNyW}E+|K_2CD)O|kl^Wus*rc>O9vObjXp_C6LeYl@hsW~cxwWWP1Luamh z9-3qBmgRh?;KKtxl=s2Sm`ILlmZKi@;UOQ|%5Bt!-hev!!_o0RlwS4B@mE=QBMkZ6`KqQYmQhZ4Dp*GDlYJVB0y#K>iiI@x@ zGJUA)LzWM@K4kll!^nX-=FP?s#^>qyd>`ujP>%spJ1j>P=qgFu&-# zs)af_N7;OEknPkl?8V6@lELjmkq;gpLOytX2>9Uh!Oz-PbJXiO>TQlE$hIm~ z^&r>fsP4MqrX1D7hh9GP^x-)MY{^ky>kPep*g<~YhnHB}m)eio--j1`c#$mK?aWbo za?}7HM)@$%hhaVp@?nS%FZ(dqhy6L~V2(P>qmZK>ss}LKhY^}b5{|OR(LRjxVGNT? z{8-(~D}-0I|7(tV&4)LAn4q1BKD2H z-qn#ae3_%%L$3oC;G7uD}7ku!zVu6W_+UR)Bl96_F*lHpHV;e zVGSWMo^|B)K5QU-;RABb3v;6nU;0oi_uu>cMA}V^+3dp>IrTn#t@CUpY@=?M`C+SX zSp3$9J%pV;?DAo^Y+0-=Pu_xe%Ci!O{eqohlOUqTqd^qF7aUV{K>B9-xVHlQ2J>|n`9}37uu5#t7vp$@c z^X0=ix!7}6gjJ8_ste57oW)Bzzs$)MAFi=@l`774AO0lYkn_kDE3XRw@R@gdH>tO% zGQ7X!l*w%C9WpV)cXXbA2=}NG48OS{E9!mJV$|Z)XL40Zf+V@0ARBLKg0w0_C`&Ep z#{-1&)C$x@*An@V-yCN}KPvf==0{~eYWh*dkLnDo>PIy~XU@aJe$?>e5jxN2sy?|Y zi7a^r$HEozD%sf0nfYFMrsldEd`k?%(xKXUy@_an=X3_mjcc#WAQ!{l6*?MDt< zP0LlYwVy|)E_Gh6s^>=oa(zDv2+J7RkSuu~C9I}t_+jzGDt+O`(;?MGY2w4t8ORqgy} z@5iNFbu(A}m8JD4RXtC2XYpA-ddLFE zGk1WLJXM?U9IJX!ds7pO=Xr8p?ezC!IQa!XUi9N-@=JaUAPl5R+ChHgF|F`mKZa<3 zC}EfkSYI6@=!~R}@?$h%40SA3G9=0SKYq;i<5fT2^kcjqlVr8aN5Iqx)QNt)P7uF- zo)VobD@We{p~`!1Q~a3e$6J29>&H|-rup%<-~9OXj2_8!Ki<(jiZ5+vu&wZWe$0}E zEuY)cm*nsJvDl9}ek|}~E~`G!0rQx4K2-)Utrq&Rh^Zu}nZ%D}ethW1Qos3$XCkM- za`yfaRf^Jf1^E*_s+E3xN?zs18p3KnKJ(*qav>+&o~PEbxXzFDet2jGsT=5Tq)PHH z{rJj{Z~WNg$5uZ!^YYo^$JesX^UP<8Ce&^8xBIcfkJfbB=c!J4>Rb9d{n+itE^>F) z?jiRif9J=;0etVr?|$s_;`k^-n5K+OPB0!U_zB&?;|rUsA}FrUQ|y$I9^ATxmUM5K;? zh5__s z0MC#+Xs07#3Y&Bepi2P#0_aM!TL8TS=pH~%7N4c|2wcWF5~xJMu%3>D9nVu60@xV9DYpGBPhH7VU+LOSgfsHtZvfwrzYbt)0Ncsi z0$9wxB+riju$Vgo_#uE@0elz0ZU*lOm`{`vxmOM_PYHidXI}vO86Zv~;71mJ3gAcp z2Ld=0z(G3yM_m+e;^nkNFd9Kgu{&dV_da5jL` z^v?wTeOdPjNA(-ca{=>x_@uh#k1$>c;37@oON5eg|4+CY!0&8+Er9C*+@P6SSJh$f zf9O^+)LQ`{h(GE4#pAslz&`=}O}-PrU0DEZl})`zKQRv~h+;w97c{p}dC06552ADs zC4#s=h?4aGH~*#nQ!EoS&r4ZqIjS@-uk%zO$o}>ap(3>swKBB|wJKE_RtutlV|zG= zlpr3VUqja>1yPfnOs%DTqpnKToEAiF&2@rE*PIcAgPF6mlO043IafP*ghsM92=#)f zPmq1JAczK<8xmx+j|NdlHmCvSw~}o-#xDJm6Z?is`)-0K2(Na0LHNl5?MRc5<}e`= zL^No=tcwNl7@at^C{fD+Gz#Kz7G;Eu>zX%F0`h1QMAINzvg*konh}~)Tj=YPVY!2d!AU3c{a&BbpmsAP(im-{=pDT8Yj@(L+UbY3XJ%}CJ7w4NGzGZPI z^(zi$H+c_LV)hcgqslh5Py71`KTv-H}wuxGEc6n{vqF^BE&a;sP~0Xf>4ZFoH~`6ONMYii|?{n zI)thrlnLQMnq{fwLU@26y_6?Zpw6zV9@2hALZuKY6RK!`9@AC}p*o$1wf{&6H8dxM zu$W=V+NniIp{7#PsI^0=6GD0j%NZ}@SyNYKhLFSBENXVhyt)$`LT(6oG{vbKLO!eN zQN^hr!WO-e%4ORygh&XFhTvk8LaGshB?Nm2Ru*m4?Yegdi%#mUy2?%Pgb)b9OO_G( z2>uYh)2)Ibgmi5n9n5<(AFb)|Nr zcBeiY!bL{*452rj=R)X3kUTQHKIG@AeW}+NFSY$cc!AD~A-o*IOCbylVE`Sey;)Zc zBFnjxqC5tNFoe!sW*9~u9>UlVM(9=}38O+7O&CK({=e^0j|<_I5GI81D*f@)*Qk=e zM829xeqB402xaos8zH8b!Y6cOK359!Ieir!30Td`LL)a9;S2|DP zWNnsfO<#9k6Sju1O*@JFJJ{qK>bD{6B<#|8b`$nc>+wjxBY#g#^s=8U2l8VGheG&C zE*Uxp*pZC(e=FxOk5~HrIfP$WD||GBN?{xe;Z_L8L%1YuLpT${i4aaP&q=C1-@N-e z9fF&1HiYvb{1(DFx$yP5lYk3yA%yT49Vs@-SC>P$9>NuNcQu4-Av9$M=~@DAgzyLR z|IUCGth%Yk_NQ#rVf+;W!nhs6-4Ol`;f}7A3?1{;KOx-HPPcsZT)t9a6c6LRFp7o$ zz31t}@stRoWEd~ztAY7yaK0LnuS$hcK8(^~lnbLw7-bnhoWUbFk_U8#3Sm4H#)IL1 zUsH_DR~0qOQB)2iKa472)DEL+7)fDN3*(V6s)zA#7~}KRB<6gJIctP5GhfZkS2e>( z2_rd-TDq6{3`-3ojmekfs}*$Wgpn0SI?aqQGQ(I!KQV{dVdRC86Gm}5y3 zs>}FYjI0-iJ&gKcSi&d>9>46)jo_)EIt!P2kmzZqf$L{&+HsVw=lYBzbm0StGb8rY#2T0Bo4DiJ@p)my>xu< zF#3?6*G^wTKUpwL@AXmNi8_EfkUA)gmkBbMta@rl7^7Gm8pbf~4-aF6=8<94 zWoC&V9mW{#k0p!?;}z{RsHeuuf(+xeFy07bg7zm8UJqjuVKUXioNtCPEsQC2-l9&W zzD<=Lo%Pgo@;lUbsWYfPW_XV*k+Z^>t@(Yz9O~RK!i=29;`}f^3}bV_6uVhOs=16=8hD+K;JE)KkstsZYo&b*rb@(W)?3Yv(gU`+91PcGiZm zj=Wwwo$IL$VSF3L#xTC7`DGYi5jIgb>&Pv#Lh7mB>}4y>ZPe}59btS!=+A(iVSLZx zt}u2J_E2T6_J;8tc@QJT*~j93xn_0Dk74{2#sOIsj2TTm6vlA|9Ht%#<7XZJ3*jjB z81+?Y62_Gg2F(=1BAX9%w|`EPQKvp9uCslCAB#V{@rE>p#y&VZ{d zUJK(o;Rf}09rIp2bu)~+EZz#^PwoFjxE;pd+PM?PTqgX7&OIt3y#J@(N0okyMX*qh ztpv@I5!_EGMJ-J&LoG{Ps^cGspgf%lRLS-r;h_jB5-MqbMLktTa|*Y+YAjZ#K1_Wi zf*Lv|De~`gljKaMS&J%rNNNOG5u~wLTgTUlAUzSFoy-VU>2YS$%%SE|^Qd*H^17g2 z1Pvmn&!Y5Lz}{tR6_y?!rC%6=AsXdvr$N(!M)_jr6?{JRX5B zf_Mb}2to`9P=gU{XG}PPD4hs(S3MOY?ADo!B6y5WBkCUdjma|FCn9JPyN7v zW-K<3phX1jBX}x;))BPSty)F!wB{cf--gAu5ws&5)xAH%VuuJi5;{?(-xKvzmk3^n zper4jv~Ce}kKj2LpN*ggp(phWv-OIgFN?h+=o7*7vj;o%#+{0^W^ahUT(t@*az`BA88hpE`#+ zm-;~j^9T>tS4nKLAcAFbEz?{?mCTC?OQ;`Gmr_&etK|`VPW~u@k0barf)y-Et4|0k zsp(9tNG_><6p^L#skJ1qXqRMP2P7XP8%qateV z{|4g)?u()r9pU0plpvR+-cNNfvUC(xqbL)_gHe>FUydrR9w3ybR-n4rX=G| z%28C&jvQUJC{kIh9>v2^)QsX0U0WlHB+Wi%OOB$Jc2c4U>+z@2tWB*GMLHovN6Mcz zWRbI@s2fF26nQM>Qf0Pf`~~v} zTulfv=B9)vqiCibscjL(vr#-1Mb{`=M$sXPR#CKNz|&E*){$+Zcv8=EJDTmO&rlPW zNk?)gYG-N}$;npTSnN(s1ot4zsCp8fi=r2yxAyzUFxa+l6houv7sbFR`s>;k2rowQ z5@CS$JFv;1C|;&Bm^wt)$~Sq2X&xTM2=YknjFMH&^ED=liBXKDKaTne^;PQlC?*hI zi~jqmLE??X*J;WTO(IN=;tlP*8O0QG;@GD~u_TJOqnH=Pv?$(>VtN!aqj-lg?^0(_ zyXrZAkHuM0%qE!g#;Q3{%#9*hzQs+y3CAzB^P^ZmXCZZwZnZdy-fZ}xc9s&BQI}Ic zqJA93|FV5TXC?L1C{__xQ>CxZ2%l5?)mLk^zb=aPA%qSz9} zW;#-ogkMLomBkkmXS2TA&f*T;>YJ!}HwgLsm(DKgZt9*WevD#o6#Js)7Wy6ad#Zfl ze18-TQ{l>d(|)qUNV>N6Ec7&f{bm@UKyvAfKe3 z(*Efv&S)N1U;Rctr=9arT+n=xaEW?3`tN_DxEjSRI@hAOPPjq+ohtqQLAV*kC{EO$ z+W(7iJBq&vcc^!Dt$Y#aUKAx`=H?Hois3#&F{=2*V<g_-Y%@>wkYkxzUu9~}iXl6O{1|fRxuq#7|eVz7`U-b%2=U?+US5jx2(syhZR!SkO0U(9@GRhr8q5JQkv!l4+# zCdB`WhU=kQj!>u!198rN=ouh7mE0 zk6~mC<6;=a_|eocRGFEvvH$y@Ft5b$D*c9fgs-tUA%=+r=}Q*mB=ThKyg_)AI)(aH z3{!ROn)+&*OkE7qWB5SMX$-SscvsiXh+!uAJ?d8+`E2t0)Hzh?cP?Q|eKk)z^W{uw zUKqn7@-}_!OIZ9chNXmM)aBHVs5^Az3R#(SR#HEW;qw?)kylft_s?S3#rXfN;k7ZW zW9@n!^F<6BG;bt)88g3;D9tx%e=}hV^=s!Ll>UIppJrS@ehmlWRKTv6#39OT1f$$*pD#I$qQ7MjxD%MbG10ClW*#ydnAq; zbdsnwsmWByf4ja)(VR+1qt=e2j`q_D8FAdzIkV!(j-y^2IjqXnk$G{{CFfJ`D==TD z*N@}TI0|%3146^NxhEv1s4xzLrbWVNCbm;s9CqEx5r>oP(vF+pp(f&eWIr_!|M%V| z#A28#gNYClH%PHK;@U4FJQhbI!sFD&)I@ONv%IEpG^6<>^Gm|!EVj@^32qt3(==Pf z&A)}07j&XD%l;rGniKBZQUE}B$N8)}-vQ1~s zXBk$uK=mYue~o@G=I>4ILw!DuzJz{M8BBk|@AA(d*!HD3UX5b_d0-qP;}{gjusB|h zV+hT`RQYC?^fFZQaKZ>(l&Vp2jAe0j9AgM#mgj+tWAT+Zs<1eo#n-44s1vCY|GJz7 zb~KsJ8*!|PSuT$Ba0p#xXsPx8s<`uxbVB;R2Ohpx%k&T{>w6DuaE^ zWbwT?W)bA@6Q|?-IOfMOCyo#3&y^+3_<1ZANOSq)-#8YrxRBa_0gK}(EKrdG^rJ(VD5+Q8&i1DUL7W_=;g2Xm%}7o8#Cb3x-8W-lITmjbld~+ZeW; z`W$P&A%7dkPObzAmPcY*cE_RLUMJU6D;+HK#{*OWV zGZX1T9+enyM*jIj5vmoTY7vCR7nMi#B0S81#CKE0uTg}gBBau+Nlh+7EkX*lA7>`5 z2w5!FE<&9mWE3Ht#bK3w)IQcW zV6h?fQL2nBL*6|jJLOLRiXbYctq6^ZV5jdWLR9=Bc#GiDt=vWMXg*Y+d_@Qq!C!=6 z5dzwm%<_G#wA3q^RT2rtrxF zR*k2tF}WH~RAWjtrd8w7YD|^EVI}ro?*G+zyc+fLoO_QJdFGrv^JF!qSK}$yPy0MG zL;Q+7(>2e`6n~}~vqfeJ%hY^MH9R78^;|WcR~7jSA`Eq2HC`2;UyTJK3#;+6$Rf@x z{{*-iFR7S&(p+4PSEMhIxRi@rtB96-k+Mu8{nIn?wQ8(zmDfd9R%4Z`yitwS;!#Do zMtp5G-WGYQ`q+DecU=3N&-beFz7!TesKz>NK`*m+hRy%~ApA%MEN&F}Sje|?o2s$7 z+Id;`iIC(|5r+DiY)C#Aq4TZP_@)|Ps<_Rq-Cm6y;$I2B7AA8U7T;NoJ=NGHPH*4w zd=cL*%*yfyw|1|{zH00j>8IMCs_}OQqC2g=fQ;{Z9O<&gx)UjV3KR!&V%-@evt=LrFZZkU*aXgONEzt zaJk48Li))Qc_Pnr6e)1^LXl3w&cZGpJni<_&4VI|xnNPpqg!fQOZ)~y}j!Ar6q%mM9#(6N=gYh0b?7{sWJScAu zxJ@1s`Cc7O;F9xTq7-I>4tYG{!ESXu#e>H^c+`VwT!FceWbl}HuJS>zKBKK0-W@hu*F#)YSA*5^`Mow%X=F>wM?m>Fn^J zlNVoc6Z7J05B~Px8xQu=%!BVe&c$V?2fIA@jyqDm^T#GUF32~#J@~Zuv zV4nw9Hs& z-t>DEQ zvaI7pU9U5WUDm4_<&sfnr}|`;&LyVdU387&Ae#k#Tj0-@S?dI{+Vx%fxX_F9y|{qI zj;4D@6X<9{9Zfqg+Ix|a<(0yVy|~ni4qjZMt{LROj%K%38e7morj3Z;|hJ_PCPb*{Eugk8PpCQ>A%UhKtf9i0VM;wq(Hl!@og`W{|bUR1cX zJ-z7Vh2M+bUUdA~Qzi{Y-# z|F-noWpIZVBV5Zny|~NeBSr2OF6(GUiHsKBD`Y%lytq$%tgDO@S<%tlFY zHCsLG#RTaSy_n_2Brl%y;t?;VdNEo06fYhXS*3xW!q;M6JTB!i;d<#$c(GOFDT&j) znCZm~E`BfeaP@XH#}znh=^52F5uYtS$BVgMJnO~tDn7?kMzu74flFO{o)-&LJ73tX zz%2A)k$6>siOA+9FFx?%WiQrnj=XqPV_YI!>cuPGWB(FiA@Bdac+-pJUaa!sHJBTNNyrsa5kn+73KYFp-i@lsLo(`%VqioRCJ}>r58871p z3d~Pl9Pr|2FMg3eS^8tLKd8PK_OD(TAAa-V2)7+C{`BIo7k_Yp6_^>aoLyl4^5SnV z=BxQj694hyDEEK4T_U}fTdU96saCl0)bZg2ACB`mCt6(}j#urQGJe0n)bpXf4<}08 z;5MOULm#?JY~;g9KD6`UWFK1k(AbC5eK^I3Q+;S61NOC14Nvpo;{vm}z%=!txev{J zI76M%fDVZ*d^ppG&kM{K>U~>*Y30MYKD73sjSpw}aJFl|T@KGtG1vAyAI|rot$NHU z7x-|YYrjMG?S1Iv!$m$^?!(1CTf!S4Hb{Cie z9}4C9w*vFKJa?8s7azL$&{dqn`LnIEKGZ2Re5jB5 z5c9!u+vXng<0=m2{_g|P_95*<$`#o>^B>M)jf#DJxY8XF_rQKWTpv-I2^dke$!VYCmo`f#TY!+f~i zhv7cl##L8nniiTCg{D=ZxxE^K1BE6g%ke6v#UBu7+XqFmh2~*}%E%}9FwuwSeVF9KQ$9T6 z!=pY-R_zpFe+_V|50CpW&4XEw;w<5_Ql1mOSZH4G;bkA@`mo4{c|I(VK3}+0_6x;d z6MxZ%msEU1#l_-FgdE*cAKsPzzd2o|46yi`Y*q+g7p@ep622j%*=nwN*TWhg*1Gyz zKD_P2hd#XH!v_-I_2E4q-shg++VhG@59?IBUP$F5ZY<&(gd2t3WVy+Q%__1LEkC6z z6}R~CnaC9~`@)B9K5XTgB9SYNw-#)|W4jMKeE8mnuUMtpubE8#Ukf1(cKYz0^j$($ z<=XD{VXu@uKK$Ssvud9YKl-p=O3pHeboH|jzo^Lp;Xxk`iSWmLesu}WeiuJ1{6k2Q zOOg1O4}VKJ;=@1gyim`bJ4aQOvxMKd3K&1?h#V)R(nNla_u~Xtspog@=yD$FOKjjr zLlN#^jr>kFPEzp|wQVeZiXTnUCGyOG z%Ty#O_oIh+ZfdCX^rM#_K0kU(uk@qZk19X<__5197dmtQ_rog#a<=-u(D?lb`4MnE z2SxT2ny{-xMA(t#M~!&QkGLNx@q`~q5nD)~eEv8d! zhPiyW$Zf*g{kX%`NBEC@SCeD8%a4(M+~ddHs{LQKN4Ya{ud9y{$t{er;^Sm9{y+Ky zemtn+Lw-CW^007%9}`6;2@kpRHQA3TQXUmDo~a^#a2t1($3>nHKIz9(BGZL4gn!H1 zOz~%g^fOCjws4N{S>bbj9F_eGD$W(sex4umUA{nMp&yGx>U450zC2#ydF{tCKNh=| zOZ-?W{)(%-DpIeLS?(&Y`LV*~uZyho<3#yGyv)Rh!@lNL4015&)FMuloXdA%A z0h}K|JH`{hg#q;MWNzqWhRaF&04`F)@tw@vPG(If(;vYzjp>1yB?~=K#6}(8aZB)7f+rFYWA{O~vBf-P+!rO=$qv z2T&G3I)L&3d;#IBobs~Hr)b+R1L)!fw8jFUb%fEy&&Ycot_xbU_BZWo#1+K&j}PS^6T07i=6?JBcnHcG2^G?$zf@R$JJ3gEr~W-{mO zTE^o77$3lc;`ayefXE^>e<*;70X!VQ1c{3!F7Ik41@MTJRb9Y}5@!c6 zCxGX~pAFz=**~x1ui|q9SP;NG*TZ~~Kf9WRB8!BzvV19k*8+GsfL8-p9Kg~5mZ-LF zH`Ab-GlQ=L(72m9y_;DkeYx-~RjmkMRRFI`q2)@E^SYTg0$3Bk>Hyvhpo1(~dxgl_ z0192@ZP~x$?kBW)Ps;lNd=PLxwc*_+aeV;W1Nbn2&s6(S02>0>EWR;-k3}{K>4Dq$ zC*q$9w+OqrJ$@d*7gDwgY5%3jHespEb_DR1ieI}n-;lU`C(l`#edj9QD}K7#<0?Oh z0{B(lA}Z!Q{2svJ0RC`&CRFv8 zihl?2PXI^6)6)M9;3&`8ZsuwgujytGM8hCV5cPtn6GYvhv%?=3#L#YLcsFx=5GP1s z{3E-WvE9sxLDY8@iVcF!wS!F>1#yzgPj(5bc$}hQ6XB`C(}Fl%q^Yo(Fz1KZJct%< z7iWramRrfDbr5ZXI4g*=Rixe~=&S^`Iwy#8C7vgISOcVfzC2tI#Dya5gza-;ZS7>4 zU92V@g1AJ4!^!!)OvTHCxFU!=aq3(`#EwC9lTsio6m}AJ7IqPK6+WR}ih?LsvAdA5 zl>|}h@`=3p528ZF9zurEQ>0fA)j{+YuN1Ovl}Mi;o{@7;5TPKv8kaAKfQUbc=ejxX zJ%TDO6b}bs1rc#G5Dj99behE^#)ZqfnWVa~-5yiYIrfaJWP_*)qAwSTo3UKpu95*A z_IE9>4&oZ|Yu))8pyEK`AmOTR=6aFA!W)9PC5RivZxV9UHwQ69e62gbLsh(0I7~QP z_+B@2dk}X8afgZ{g1FO-pMG+2jtt`NAnuU?l~F-V3}SQ;uq_8+t#*>1W7Q`b#JQ~F0Af^OCW4@Q5 z6WUCb+Yh@L79R`Zi69=A!YZ0Q$&*o*#OVr^@y`%>+8xm|LClddD~Q=5{HQKB#%EQ$ zfdBt3i1|Uh5X4+pnJ4m*PM-zh3xil1#3Jz*g)arMSmb5l=5A(*2xHi$DPS+JN?9gc z9>i-Rx!zX<@p=$%1hLX>wMt}<+O7`b%^=nUaf5ricu@LVLA))qcidL*2JxQD-w)!0 zAl3!{@9#4BVdaNGd>X_@uFZy^^X=u0L452gn}XOJ#3w-G=O7LT@k*N2-;hzADf6w3la>?&Ou*j-E zr2HxTOPFhNgxh-v|8U?E|NT!@Elc%<3h-_Wo*ZXa6-u0)7eSmO{*2_5@uO19-oo>N0;8p3JpMV3kZSQs1f zXclsQO6-gfnunZ6l@{uegbiDYw-UAvp<4)Nh0q~{vqLza#vz;=a^~V3VS^%bUI=Yj zRb)zwOsL2tip&Kev=8CJ5ZZ;1E;897GpNYwa82>GV_Z}K?t2gC=8*KEEmcxU3CeeYY59# ze67f=)MDc*D%L2v3punB<$-!x2oHu(9zwqmdV~-Qp@LHoLeCJYL+BMkRS3O9s8s$} z%i9`ZpAgn@fI59VA$VQSRQw@?LI_9+3O5v)kBdw=gs6&<5Vp#RrQ-G?^G%V7bM8V& zFi{edA=n|L)bDO}#ISi}LdZ%a&-LCnge%qLD&Y_E+&_dnL%2GGn?txJgux+P8^WLv z281wBWSB^WEVvjD;aAQmdiG=2oV(*t`_N60Xt^ z7E7nih+;Fk*eng<6*auS*i3RWu#9V7;%gzS-~gph(-=9Tl_9JOVQmO+gz#nvtL2b7 zeXjXW3~#v|vFaVy=3SBZLU>=~1K~R1df}69FCT@lLCQuUoqQa^CYNsx;S-n7RFf?s zeC8^jD-52GTV3VL5VnQzO$ghi>~Qt3Lik#Ij@$3IA?$Q(cZKks%b%CQZWZ^0@Pn)G z71<};FZ@xspxFEz!r$V*@QmQbB7RVKD1=`{IIiD9Sm^eCSmGZc{OQ*I#VJ$m5m)&~ z@5NbsbcJ}sVvaBP1oRDJOFpd{LL0He#PZU{MY#M~oP@EZSp;kEOJU1 zOrlxsOUjC)-^M&v%>SRp?Lp@;Ed z+^^yTVLTGXgJDbvJGV~{h4HWmdG5w+Vi=QLg|}5~n_J0K)SLlK4dXHKY5$3kHcy1H zB#bA+SQy4rGMFC59FZAeJRQa}Va#-$(Cw@+X8$L9^!#iXFNE=&Y@Yv*<=imlt2j>> z>TVYNrr2{nI1#nr+qyPGv(ycfpWFy5B(Rv1^y?42;)m2yLObBmPsRs2ABo0RooYz^bX zFg^+6qcA=WV?!7l!x*L7`@5S--OZ*jHmk{F-OY6ApN8?7lr3S*lJa>NUxe{|ck^O* zv$VTe-ral|#y4SX3u8wZ+hx33mS2VOHAC%gK2UL!@Y^tUhOsNmUyXOpm+ivu!}u+X z-C_I`#-1?th4F*@>=k}1oBcV?uYii|miTiRzi^|Fav+TT-OYjS=1>^FO8Kq3`K!A* z+THvf#&HoG4&&c2{s`mmF#ZhVuQ2MAn0h6qQHg0$VvdCIPnf@rZZ0S>7nhj)5_2>R z6G3elh&Y>nw-QrUV)~SrIx2=rOr*paLfr_CmvVwIA@Rfr3L>ZC!gXg^G_vFqw;7e2VZ< z;nWDGiM(8DmXw;u#o5sl5j^Sgry_Vo(>g=S)54j;XCjyr!7SHub_6`3*qq0+5j-b7 zciDPDS)D7K7r`P`%@-~ZE_97w6nRPbvXI^uyA!lDf_E5C1g}T%Y6P!w|Bqlf*Mt5C z8u5C5v5-qhgt#(-)e)?U;0=kn*r>l5!5Y_WZN&K={#(Mgg)Fw=KmS+n?+M=*QqOtd zT(6h%VFVxj|7&2Q#z-^TY>MF12sTUklGt z!{6tdzZ9{#`2n_$z{c<%G|kG+QmK<(d&O zQRiHvNLR;2aZ(g@qc}baTAs#tk5T8V`}LyWcS}x;qG1&Eqv*J>zOm&%wtC)x)8RZWOn+TOMW0yI9{KE03qsT;^HRJToubuM^UK9hO=o`hgQCu0t zHH^od;(k$Q7wR9y)ltxroJc2Z&P7E&FpBG=7!<{ITn1Xq)VWp%M{z?Gxz)&C*w;-_ z42|OED28a6aR^)+w}{j2tx?>`d5K~~6vNd!z1|#t54@Yrd6yu}Lozht0I3bt8{UQ$tAB^ImDC)TT5{Jpa z=zn4qk3=y^b6Q+mdoe$9ieg$6Qxqr1_^3uYRXwuEhV1w8C}u?QL=;a&@uU_uMdo3; zjGc+*?>}-PqL|6tD$f+zmN+|#IZUZ+a(lvaQM?+(^HIDK#S2j^jbd&T3!|7P&vZ3E ziUlsODKm@2UyR~qk(Z)imT0y(iX~F|m6`tTk~r0!)@4zwh+;X%6~$nUf>X?}Uyovy zvbr*gWm+~ICTDPU6dy$KW)$y5u_lVOS|s;!|5q2B_qU^XM|pc!c(u-sulOebN*xEd zj;B}@>!bLPYfRhMN9t&UaHH^JAu}^j%{QyjmTNHmp@p}}9-II$t zYyXVmF9po`qW`~jIv8O|SNw$RPO zc@{3W(AL6b7S6YvYt{u8I#{^SLVJbL&f<@rI~&?X48wBHYsSWd%0mABi-k)ygqvi; z%rlHDEEHPKB`;4^`NEFE0^u!XrjzAt#SE;og)Ww}eevjO@rTF_Ns)yL3&j??Td3lX z26C6<&cj-EEiAK8ZlQqc)`MK3(s1Zqxd-%_WqoO z=XJ(0lgtd`pKD>hg?a8oa0VAxSg3Q2D{Y``UbL{(!b=twTX;igoE*zK3p*^Vx3Jy9hZeS2_{hS?O8W*28%1i%3}<1Jg-=x6 zEaWIY6*-~Ysr}5tRtuj?VetzK^`(=4X77P?6dHbh5Z(Ow458H+?pr;%w;BT?2gw3rtYAH zBNh(v9JlbRh2K=`obReV%(QDd{*eABb1w3?kkMXLZvL@wQVjoEIBGffZ}eGf;lvma z!|^eg7>f2V$Rn*DpXrvyn*zFF*J&yce!D68uTeQ zC&zGF42@$>N6sZ6=3GIV#BgfNxhMCPJ9oMDHQuH%w2Yxy3@u_fBZlTN=Ssxbn1ro- zWx@SlP3XB*3}?sCI)<}kLj#Ijgl%FtC+1uccnZ)hFAC?y&_0H?F$jFwNvoLevQt=#`(m=nW{7@pxOieaYG z!YzWeT>rCTn5_sI|5z=OXJdFFhUa2GR7l=Fmbh3Ci7K8_2-FBH)YnN9_AA% zwD-#mDZhdJECTq`qFI9IoUsu~o>jd5HT$6!@mFJ$cvt`qW` znCdugj$?>wPpmNYD@?-*GgLN>DxBodY*-w_;}{jkZE=i<<95~FAv{ez-WkW;aoiQh zNY{C;A@QC#n#<4VIL60uZyaOe7!${RakQ*3=c%fo!i-Y@T~)l_b@Bk`QT`u_S2FI3DHHSD4-vrcZ_ORG4Y5H!dOCKOV;uaXcT#lW{x~ z$5V04kim4%t9UX5c#9LvO6yF8B9#JS0^_<9^~ zsJN1z`3NASzFOj&ZYvt|SR2P%age+%BzY%}cg5dxmG?z%tuX736G>&iL*b>LqI6jNxRoz;A9>*7P=K z@oVrE=Bqfq=8ENwL4~35`@C)DW3_B{#<5G}J0W%MvAf0h#BnH&AL95?A?=N0UmW}6 z&W1d`!n~^hev0FlxO0>Ivzm|`;EBTw@UP&tw@~>tj>B9M-2XW#ZZEtqn#KJ;jz8o0 zEAHI!QsKb>j>OR-fq&v?l)%4n9G}2Zwo0Hj4wC>9$DUGY$%A<~F5zULZo>J`9_*KR zLIU+wte3!vA{2A>4H9Vh9}g!ba7F?rCvZvvjpc_iaDYt`I6Z+=6F5!cgB8wW7d<8MjQ}f&^M6aBc#v6F58JjP5K|-NO6-1kMrX(;1u7$$1H! zFPpZ)C|`7`>cRvrPM}=^7siF6K)$ED)*c6q|N@4X`7Jj?LN zOCVpoqpK8%6bgBj=e;QHxi;9g#GSI-qX*Y~F=LR(6QLx5UTRe;EK8tVguV1gpu*)n z6L^@XHaGtSu1TOWfp`K{2?P?(CAd!l)d~0#@Fd_(V6rk z1o|g%Rl>O(_fvCvp!2KcImfR};HCryNEw*G;Doa$3`*d-1g;m)#j`;UZ;;uI!i^Q? z<^)D0FeHKD3EYyvtqBZO)h99@CeG$tD$H#O+^+oOyxrk?zEd{r@h&MNUHzT}?n_`4 z=Q@GW3FmQg6#ow%7lt@rd~r6%CNMsMacaUz{DtrT6L>(Yi1xfkB0iMB6P&LECM7T- zfr$)5RYcZ4lECAfBhBm-&KKYRBrr|snwsEmi<_@1oY#_%scKh+^RRFi@Bb5+k-$?4 zOjp+}w7UG;x4y-}H!!1D>rPT<*uv#ZQW9DA$4uAdX<)A0**qE>T-^AeaZ zvOvi7uuz0uzo;f8T)i(Ruq=Va2`o)ui45qIDSCycs#3&9Gb&vC%M(~jC4m((<8#gH z8qUfDRwuBE+kz7EMgn^(Opd=PagA_ag?TH1x7`@HOK{n|o505jyqCa+1l~{JBRTva zfprPzWebn>JSlkpFJzICupv*zja-dN&ZY!DQT8?`ock^&`O^fpFeF`}XwQLv&M8RX ziv+$*V5?SduJ>&TY*#$FhaHaSs|3E0^0j*8a{4xbor*vAs+JDFOJH9D-zV@x0=qd_ z?M1ncxKokrL#I162~QR zu)-Ws(eyOOC($5@6OuSF>D>RH)1aqw^Hx8JrXmfKI4OxnN#}ZTPESLJCnwQ3 z$sb#HIJ+bESNu%isYz#7;Q&uh;!Ju-qInX{k~l+=4AT1tCZ|QxdBEJHRxOh_D~VP~ zv`#wn#adQz)MqErCh2@KMTgWWo|{Bo66YmxK@x3~I6vv^Ej;x&kF>uqiFQfn+L4>b z_KYxz%aXV_iA$2sUfMy}si(PAq`0SZtHa}R6|WGoZGI93NoR}bm~>VbNnsM5lFnsf zuwD=L=lB1U=$=H^B#KzYZ&+z`G@x;D(mC-Aaa|Fjx09B(WrtNyL*#B>8jdj>0OUokS|h-${42rm@0I5?OaHavuuxP2$=l zu1umobCN_qWu8&-1ZRq_PU0H%&g?N@`WcYKKt;=m8riE&!__a!k_WTMtQ*Z+7G?-x$)X*gIewuh3KoW#RPOiE%x z5)+fhKDnEvIeJ9HVVvA0rX=xH5|48EDJN4E=d>gqOX7(n9#`>O}ggc@w%G< z4wK7u6_<^Y@J7{Rf()Z=$a>`UT%aXQ>BvL}fjlGrQG$)!%* zui}rwpM*dE$KU|>QhhpkFo{DN6vy>z62FQ6?ke1Qn2lz-*f2}_enk6Z zBO52#$M!=e$Im7VC{Rd+ z_OWNEPV{V}i;5@qa-MM-_A=dUbhlAtqu9+Pb$Z~z`=wGFy=;`RiH&lNm-#&W8I^ryF zEm5~@By7ZN#BFCEW)8P114$dU?Oa1S_3W#J@BcYRHZnH)+Q{0dQNJzRgcR4-UTHhm zDH`{)aSf-&#?>6S-uE&#p4Y6pR{3Xfpp6@C46-qp{o1(R23HREe-4D>x*<0;x)-|1 z#t;>6ww>LZPHs_hhH4!g?A)bpUtoi^^ZahHvI zY>c#Vw+-rC5=<{=e3XsR?%LoQV=rTDjI(i{jj`&Tx#HZ#x%u0;UtKfW+@-xZCBT`n&o=&FNm}cWq8&h4K-ErYPW@EaI$8G1Ve?k+@Y&YR;o~e+SZMvFc<2iYLmMcNZ^EPt5bEI=^yl7*djfFPm z+gP9~dZrV$W%3uv71Q#PjU_f-wy{`igS8Yn#r)hVyQ-Oa#PHomj*wT*A3eB}3soUU@<%p05|8nzpIa^Ud%GqzpP0HEda-7+yE1jd}9(6(rC#Fy@ z<(zt)9g6i+&ijxCDQCNAn8K+kG)kdy3MZv-a?06nyY(_x^)e6lGN+`_B!xx2%-6ll zkzS^CZ*!UqPEVm}iob_$GQG_mz0K6#&cZ$;h2|-ANTEdv=cjOH3g@KIGKI5J&W_hg z*jjiQ@Bc;G2$!n)x#H&u+X`Qkeu4OfDO{97J9b)I+g?bYMw`2;L6zmkzDd){+D&<_}Xv`|! zX=GElI)$1P`f924=jN||uTqiT`lZm{8}q5pwp(z3!$IZb{+h6o$y*K&{xd{O<}W+$y&WiDwoU@bDDwO5wH??nvQw zxn;Ju@^x+scPbmXMNVa83ioJ9-|c!BmBMKGr%g-sJ|=|+Qn)XLak3e!Y9CWn zY>ZufFsK@D2*yGbF%t<+STr;^&)afkYY$5ZuqqpHpdk-r|Df%F(CK zyk0bya}qjyPd&b$!Urj=Phnlkc~i}{#2jH591c^LTRG$(tH~w}YO|2FpNM=a+#>ue z<-D|H6*n}t-Kym`OUgD4fdOw%VTbrv!mm@mfZz=ql!tW{kq2gg7KUmLw zww}W{zyFzX-i#d){=+F&e(3FJ3bks2v~y}3AqnT=xHP(?Q8$fq(>OkjhH0FT#@D?0 zPoqKFxzRc?jrwUkt&b##R4(K9|I=ue#z|?MlE%q0Yb@L$gC=R5rsAnWwmLnHrY`@v zxAQ{jj5J!O(L9Ya(`ccpgVI~3(JIZ~yElLIHhg1$w6{4cjW#kko3T|oZF!u-P{q$n z)Dr1JbxgRaCC!1j)ldH+4+cb!pt3#`S63kajL)gVW9xpWDcd zY23td=_Kkb9FoSZY21>=(6n>=LF3ih<%Xp(oKqtur{A8&-D%vB#$9QQNaIe|o;LJ6 z(lzGBa!(rfrZFmw(dvr^?2!SCN#nk>^NNODrV}8a|>AY`zERDw%SYD;+RC(;1 zcu%JBR2tLM=vrxtB$id0r_-1v%b96BBM)reOHO91IL8&AOJh+Q&!_Q%tISPfej4*s z>{Drcm1aR23srRP_cYiS(^!(mOX}j~G!~1nDp$MIb@hr%mZk9qw-K4Wmd5L8tZ1l5D4S2y*p|i?&E{vq&xKzIol8I(Uy9q6&SjLx_B3|5wO@&RoyIpJ z-wJunqS>xA_Gml(PWXKqyG6LQF4yrx8hfR%xX-QnF^ylue-i%8Q%S}LT+4%L91{Ok z_?xTK>~I?Yq`@Wnhm!oK@Gs%t!XrXn-MFNg%%f@4>ilAEbLll1oS1RWxH=gemvK&_ zy29gyES``-J@KrjrUxGZRBVtz!wk;Ipiu^=W^hslr(|$)28}bgrqa2kzgG55WXvL6 zot8n<3{IEAkOs=2S;l#4xW3Xf&)}>KT4c~t%9%p8YL!9j|2U!X*%_Q8rA-DmRGOjO z%2cE=YnhF<8Rv;+Aiw{g!G+=!IeZ$l&)_1Bx49kxXx|}&OES*;@It+cU(AbI2A6Xn zx&z@!!4o+zgYpdWGw7N@M+H`paW<<$AxS3&kUrpJaE~wVXq9TGU%N_Wd{6S9|uK|qv(@CAcJZddxYK`@=LZk z4;kDo=Q%&24AL2dGl=BE<|pGKR>t{;A&*!F@eGnGCWH_0{eK3j3`l5@!%PPKGRS7| zQ*CXHJNCXJR|>DnV05K(FT_xtd}eSx*Fy%^WpHiA`AC$LG9ZJ28RriT$On=0*4;hd z2XjI*&U$9pH)ya;YIVE()9gdu z|7V$l#?67H06GiiUs%RFW>*D(^oQB zA@XVl%S71ea`rCHvxddj#a9Yf3EvRTsx&X~xma_@5nZeYJ?>^)3H`OgDdz6L>0}i5 z{|w$&u4u_AVCvRous-A5zBX4{ILjYput8(*!w-LD{4sY4zWmQPkCU5)p9op}G=pa= zoxijAEQ8N8&b={x=B_wfGx#QhFWoe5%V4`=W+Xc@_{!y9b1TR#8$Ial%wU(Q=#vBK z&oBRHuv_~K6Ud3-csPSU-1B9)o_7D@HlD@b8Pv%-pCBK};GYbT#lIR6yFQvhZN|Bt z@?du+>+EBr^#Xx8r&u?O;Uv7D5}DOsGH zMPt`&kY1qCxJlO8;o0!CEShC;dKOKySgT7ChuoNVt#qYUxeO4`%pxy~mRVe!MXRiH zL2RAH1zDVx#W`8$ls}uKwzf^yd0Je^{XdJgS)3=4I_=LFrzMLQino(-`z$WXVo9Z; zzM|5su5|urs6!T)Xvmie8R}(OT%N@hDt@cvP|VMwqsGEHW!Q|fFpDl(bjqT$;(vyx zwzAqai*8xxeK-}yz_v6l&N}-;_bf_8$SIa(QNgtE^Iwij&dJ$|*fWb>|4}Gbs#ujp zACYRI$F=dw56%2pgt7=^5#)5}LlcUOfg=qwR84D?SxVEMZ~g*XPrm9L>AdB zl3Ap)u(L>I@nNO;w9Ac$ae)?uKk#2Wn;BIRAqP9WHB&{ zYqJ=Tb@sFt$_e#B>{=0W1#+Db2WN3p7B^&Zqnl5fG4h+U7^3MT=PAa0U}zTiW^rp4 zqnQm}0I% z+)*$#_B$?%2eKHS#r;`lOW}DzG0y!zi-}o0#I?#F|H@*5rh`?CiubY1JiR@V#mp=w zGf`Pg(E?^Kk7hA7i>I=fmc`>)=ezNbWkF-6_lYc?RPUegm4z}x`{`NC;Hb4F^4w%* zxU`V>F{>N z&prQtn;6YFB33QtSAep3HH&pwEX(5EES6{S24mK$SdqobEMDiNXgEY3tGF-e>2Ebp z|192=B?r4Ei+`lQCFSib-Vr&j$~3Gx_Kg3Yl=p=n2#@FIzgg_y`pjY@w=7-)ve+O( zpDccy#phXU%Hq>3HfQmPTAdh7EI#AjQf0<)uCnKV+{Mg#}gS02idr)`P-B!e52I34a%U%bS1hjWzf)i<4^bR~B_^@OKtRvp6DG z|8VoCWtAzdGL=;(RAp+jFf~ApbH4Mv3f~*lsljnIh*p_&mC00@Y?V2_2K8%jf^6#5 z;6#yrit{>QgBmofL8BU6Uu6bMxw*=mT!WT1Xk3G4H8`aPr`4cI4Nk3b{?@fF@13-7 zoL+;b@;0Q(468EK&!|C*8Z?*4kZ!9oXNog67F*TeY!zGAIRDx8Eb%+5Oq&{7dfJ2HjNTkg4Pb zQY^RKU2ohfxopa6;Hg1*jdK<5QR6(eRMenSq-PC!iS!n-YFw3bV^*bNpPK(i)t7+Z zRDJKi2Z;uh5~Y-AP=rJ!smwln22-Npo_p@O_nte?lv0sWQbdL%5mG5qq*5WFLW+ts zC`~kI(1h}T&wHHj-|umR@Xx+;2L0E0v`P}lkd%i49KhXgP*fSW{LFT6o`V*nGh7XkrT z;+O#hMLZ-vm4^bb0|<*bRm|zVjA#IkIP@(RaBrXD3P?hj6sCk}A;Z|7@BahHX%wf! zGm***0rv)g^@qn+iK!KEYv!;Edd?-L~8}jqt0Olz(87p4&|H%NJ4q!n5PjQ!t$ysm}o(W)~7J@!g z(qldsz@h+N4`6WsO9Oab)|dD`yddI5nvl=S0(d2Wm;B!4B3|a|YhHBeRdH4X@R|r3 zCG!o@D}`*X;xhU4nN31w^*8Ttv$PI>zl8oWM)Mnzp01Oj{ z0)Xijfx8sX_N@OVs+;b86gBVFrZ~#P(I#q|Zi(X>F~e(_sBOB>N>s>;nvXScx{2dV zG%#_ziFzjLn5e5E+>#tcZ6}yG(R4REw+~0vH*u2bo;$owHr+c<5~r9r)kH%RjpP;c zkQdA2X(k$rLoxbBJi|nD6HQDsHF2hivwZhxi_pWn&Em7vT)V!X{s@@w-+$7Ch9SZQUZB4omr&RNoVHt+vUL{0Z; zokJMCZmj<%k|yF@EYm&s$fs}Qr%a?}kzAby^CA|*u=C2?3B$l>A+ zH!;G*%_eSji zm>8?&<{H_ub)SiGTz8pfI)#;)iF)_pMeN@DP`)6Qa2+d>o1NuC{Lpt_^OF-OstSsubJ3j;&l_NX@cy(#8wmUnfSoOW)tt5 z_)7BM3%5wEH}FFf+f009;$ty?l)%rujO`{q5$CU7#=%~O(cAdc#Fr*MGx3G^pR+3V zHje3S>{PQ(Z}++2D-&OYlerDYoClK@$hWWX^EZ zzgl!!`H$sVV-a)(UeK+v zb%JhY))jhcPYAlDlFa%+Gz#LRAR21m$w9ZOG!T7?kgn20N}d{Yj|OTZa;A-gI9;4G zG{l=bCC?1vtRT*ot){+3Z(#Ev&XwJBgfw)X?=1(m2%;tBgSas0ZgWd(L~mOKaYfKQ z@-7OZbr6>Z(I$v?GTk=l9$Oa+Y2p$Q?StqLME&0GQ|d{=%f!E2*wGheZzpQw%by_1 zg6K@6L0lEYHHz5P!UnyKE9+KtRO<-P?BS*HXMW#L?no)Vn_}zR*YB>`5@vF zrlCX-$sjU8q!cA`(jr)1NM}Xog6OWj#^OUI#UO?UQ3_(1uf)~EhsPjB2HpFOTY?x7 z#4gtVAZ`=EQEYlXQ234@Mh9_c5Tm4Fw7NK#yVT@##xPO&OHbiFLHBbIHt!AM{vhsS zQ|ZKsQx!*z58{EK`*McK$tJBZ0uzFm=x5zSK}_=L$wBwc3>ysHOc2ip@k9_$D&^)1=LzQvd-XOJ1o2D|vv_+M#M2^3 zf5!SB#G)Xc4dOXTl2fisp31L)iqnGiKZqCTm8#Z@LA(^iQgtm8UN8CO^hau$?Yv&$ zy7x8;y^R$?Y!2eJAl?q*^&sBjM1oiy#L6I61#uCVvbRx^hBt#)BMqZ^8xQq1*tIr@ zbwT&-0Tr^jUgl=?Hr@$hBU6j@Kj=PmZ=gRk)Z5sk;qUowaDwj#u`P%Xq-0AF9|o~i zMz{7hKH?R`$I|(AZv$mUy)t8a5TDRVS=z&_z0!as$73E$wKfD_TN%-FBoI1t1^J|(O)hxF( zG5>iSP)Q9nDNkli3$-k_svIpQ-KcHh7|X4Yp1^WFiL-gUb@+a%j)l4w>RYHMF?O9` z;Y6S2<~_-$PqxrN^eGk^TJAF=g?W*nX&R-&441|FZ|Nfd;Tggv9HOqX)TB&P3ulXN zCTuR;C7E;O{CO6xwQ# zu&srQEwrPi1H z7w2XRdn7+X&0B@H2`Te)nQ^;?4=mha;VBDuT6oyPC<_m86)fCq;VujJSQumBZYAfw zGUKQ|M*Tjj0Y_|WMP6h6NQC7hrdZO z$--oDZWd>Xg;^G+a#<}*6MwppyWoyK#taKHEj;RT#%Rc6YCh1%c-+E#3$rcEwJ^uR z6XH+mW6YA+JT(`Iep2)T;Zkv)wy@m7GZvn=uu%MGEiAI|oak32vsm;>(e!7Dg%>O= zv+$yYrRsXCkFlkXv8#{qlA8Pa7}fe3FI#xi!YdYD^Hd2}2#@J&yl!C?v&F(nR*Akw zgT6+SzHVezOMvyKWnW{Bg?BByWnsOAwHDS{XxrDgLSlXT8gE;8hnd;e2=p}~Vs5bT zo`sDTHc3gQuQ9r>ac^H^vxWD?nbFsnDakDszOt}Y%nyYhS@_Jt#}+=Zu+74DF=zEP z=1P8tg-^vz`{Y%Ub+5{1wVvCEdC+4s`GwnyEaa>5UPjVyFqRc9s%q+Duh}g)C}S1kXzGI zy2!5`!Z9KD=G-gSJe!USp?(O*hj3!ZJxA(do5E_MWs_0#Pjqm!p<(C&nogPB-5Y7mpSqM!+?jy#Ta_lT&Qz894Tg2|Z zMlA*8oDj|pxd#*PNU3BszyA}$g(0+{hLC%vP&p?>$6AKaO5RdQLor*2&@qHIA+!y- zXU$&T{D<5JoOU7iLEsW$`w%V*p#vQbxert1^CEG%dOgk+A#_r-=>TojVNW4-_VS1j%0%=L{?ylCS9u5nL#PO$UkH^URE6B{ z08<-HbIJOLFhH>-hZkcqD1_@mxRzoe_uiE$L_VW2B!r>9BwsRc`Zt8!+nXEZ@J%5E zMDSRl=1ckge?`U$!3iN0a$m*svO@^_bR>kR=zsbeUT;jzICIIDNrsRT{a;_BM)~0{ z5m7&_ZVQdKZg>Y}k{Sd#JK27k5`$O(` z(Z`EV4@o~5!jupugxsf(i6Qs)l_%6gAx!e=$ss)K)9mF0nE=y5m`-Q30lAdS@G$TH z8AJXAAcUDA%o6>WkZJa~a%{GcGUPlF!n_dXO2FgHSMQU;1xH9e9l|RiJQKq6AuQyE z<%hq*=Y)%di-p{$?B%sY%@;y=F@%>wSgPi-|0}ax&6j=Vt4d~$T@k`-KK;7a8^TJT zLldh*crS!ELwGxcH4=DBxK_AMxL)Y_^Nz;8E8HO5DBL8ZMT%_}{l4%6pT8x9tv>ys zukhm#wrRz=e9VpQA$$_T4()p8d^4@iXCdqi;qwr_&_4&lcT_Jr_*x@woZ+m?2D{S?BntFB-CvE;BQEkES` zX7l$D_OS-q_=6?a#-AY=HvS6X-w^%|;Xnxggs`9Uk{)X2ba)-qZat;k_)o;45Ma9{ zx^cO2dbxZ4RCTH<4iSO)4ch&aklLiXEw{rjmmPPxs5AqoMYo+8|T`%(8hUm z+s66+s6n!OftrKMjg~fA+h}FuB5|m5s07;BXluhPH*7T%K4i6I*i@@0a} zu-`@BqBb1A$*#DKBJ;;a)<)7s+D1x~r5;X@S4K@r=42>uqoCp34%9}ml8u|yHB75N zT*$qDi;Y`tkQgC+NZa8yjh$3(+-_r>jXTu5)5bkEM%fr+W3-LCY)n=rKU{81DL3wx z%v22@YvW!usg~D$Hl~Sxzm4(Y)1L=yJY?fR8x!OeJ?AyiU%^Q>rcl3)hy7`CA}m%M zI8_>$z}yjB5grG3DfkUF({B9okB!IZr#@@oI^M$i&&hHjbW+UG#5w#48*@d^6V4Yt z=_{u*PuY0dcJKYTC8?amLL1L2O3P)MN*38zEDmMZOTaZ`pX) z##$TeILs?IHrUuGPblMM#d|hBu(8?3`+gEK&a5q4Y;0BJSyGtT zw8bfZq%A;I+iYxS`4XRDp{gA=K2`l;lLB0Y&ux6cog$f?3geeH4%zt1#xFK@+1O*_ zYa8F$_{PS!HWro}Ys!sv8~tnJKXJxY7~?C92P+JOQ6~%|jHAP-7RFIwR1c#@7!xau zAgwZgJPL)Qg(zvJ6cwEA# zhVewDF|X2S9LDKk_b=gd$r|a#vPsxIyqG*(!L!0>8g@ThdN>54F}6wxV+=PTWJ`@A}bu}t*U>LTYF z5nY7KD~)bp^a-PT7`?>l5k^lDoVcfPcQ1RKzG0MyQ7L{!*gc6new8?k200WS z5XQi;d&|e&&FN6#wP6hA5@<%0A#+F=L&I)up*%0I7IDf{!X}Yx5nv=`olPDP4j?hfPrFz%85vGU|z;eEn!LRVF#yTwR6!0i*pgJDbvgBlnCZ`Kcm zF-dl5i+o1!;V`C!F(r(tOht|5V$r4PVLYP9@F3tvEi+`|(J*F;c+9srD~uJD?w#B0 zFy_)0H%s{NQ#R*IJ@c5}T2pVyD7hevXTo?YjHfjn@0P4R>wg%}`l&^+`mFz9ED2*V z(^b*%0!8^3!g$diJ6aQ27RIaMyrgZlJna6QRjea7%`< zGK^K44g*gWvxNV@nwChVeld8{`0Iy)leUTJHCR zo5OgYR{R}D0X}Nc#MUrA)ar0)xExgYaTuS3v5l!4MpiO(hF>t-5yq!dP7gVd3-oyy zUxx8T7(2x`#i!&~VeFE76yvH@@cW-(d>_WQVSFb(pE~I__tEY!_OM)Npl9nx1}co7 z!uVOyU_!>#`%4(V`ngIcnP9(%@n;zOxI4n`ts1S+9CPfiFb;(Aw~7*%=^y#FKkVLh zQ-IUl#rhuxBKR+iL%tQpoEnS>j)|aJ1T`XVC8-`cd_R9w1T`aWJ@nS)=m=^>+-g=^ z_-3WCrqVbzf;tf#7s2rnw|dYJla0w-H-dW7#<2`Lm;S^E&WWIY1Wh71DT2lkoE$-; z2pUA(M}Siz?iS$HP{jI5-@K1}lb)H6vr$=x`#H}rigU2~Dg0mwyD}tut(|LxD zQ*IVPa}DGzD+f}~xe>IA;5;gi;QR<$L_k-)HRS{^jG(1v%HdSbDO?mm+Xz}m&?e$m z56bW&|KbSRNi$u&L_~W|L0uh0yj|)3nt*m04L*Rg407O!@`|3s#Ie;}!>73j$|JZs zf}Rmv6G1oHilD0>b2>vS-6QD1xcRFLP9(m+qBVL$`}wTRx-7`JO97!twY2(FWLhL=i~^9d+|>m%+-;jIq&H%1VP z;HC)d2m)NY2+RnA5%)_DoGGWqvQLE}Eh}w>BZz2qNJk@ZWS4WNDsF*z1X<==1S!oW zsdb@bI)Y5ZeeXesF$RaGDKk8Rn;AysA=j6j5t`1eLdx70 z!AQ}!3-5?vl>E6ff_HVYj~0JZrLnov7!$$W($6S)sWmo&dn1SU6l1~-I4*+wct}XCL1oI=95y2A?JQ~5{ z@?>TNk3}#`G|i2YW3$zq6LH@%kwcs-&O9MKug&j&ieA9^YRFS+lK)Hu3%Tyv3k_9C zo{M0aJXs`M9KrJuED_Bmqn|H`eo?qoxVzGzGjS#i)iOO~g89Jsyc)p@|-e*E<6E|6d~bDuSI6d?{6& z7xRIk-W9>u3Ni!2vcn>>5~hhiBKR|ce?3&|mUvbsn#5c3qji`p2LQ=>R7>i!mkF{C+)ogT%R zQJfJ)lc-yhEA*tyG&?JbbE0S}ZD&W_1FKmS%_$~tzZ7!%N~su&A{RwGimaxVh`MznDNG5|!i6jEmyl zDDLw!lc6C0{wT&r51)V>Lj4bF;*7uq5fh_$$mdLoVzOw?hyqi5{!|gu7(?+NQFDgh z`)Cw1eVPKZqL>?X&&S6ZJxzr4oG6~~X)fhFZqF#@ON>nlEbx1u@|n*>u|)Jj;j_Z$ zgo}iWh0hDAgx3pEycoqYsaonQr1F>Op5LSx4TP>s*uQifkY}ZCXJ=C^NJB|c@>xBQ=)_+P@mh5rcm3l9icHx7EuO5;D7J0zsraNL4vIH)F~x{#b2A`Vp=H65Jf z;AjWOJE-O07zeeT!!I1@!?6yIbKLI$lWwG#)NycvgSrmtIqtE-V6uzEi4N*J?%g|; z^JKJH{~a`T(7-_>2d6k_D0xo_SL##;r#WtHIdR5>N=|ohrh_vaG;!P#M;Wi{EC)>; zclV{VXKAaMgEkJDJGj8XIS$TuaIS;%9Jl0B6$MDNkU5_3)O?|XR%*6%+$U&yc#(tF zl3y+Xa@sn$%)!N+tb=wAE>V0qwu{{8z@{|ND++VgmpkaVx(A!Q9u5@sf z#&#Bd$=`oDxP}p~a^EcRs$FGtbnKUkb{A8;1t=t)^Uq}OdI?<2LT5| z9NgewsDtYr_rHUAlVXr>bZ`?_O)=y&$u}K@90VO$Qb@bpFRpb5VM)?Gy1}g!bui3< z;~?W8<{;@HPUju>Y~_k@2#J(~v{sX}$H_Vn`bh|sn-%c-oXR1%dtE@===l+6XgSGMvSM-BnOiv!&TsL@~1eM%H$W# zolc|E9X#T=e<*{Kn&IG4nc&h;=S*3DOdJk*+`&RdfXl5FXPi0w2?ui>Jmp}X#O5od zpLDQ5O{PTSDuej6nsne9pZ_dFA)04&HMzIg!7BOxyn`hQ^$QMObMT^rmmDmW@G>DY zld6_Gcty>Zg|m21;$Ve?)2rO~RBWD6WxTGgH-u!a6cOQFii0<`uNhm;g28#q!FmU4 z9jucNOe#*0&w6jG$%LWUyAC!w*dWe!Wf2E%a^NZ1>|l$7_Z@uTxTg=z%~6@!>fl4i zeHF|YG8E1D{>Q;54z{sC$)5^sYMR^O+q#rrly$I^nd#sQ$xsy)j^^jT4!-imn1tMA zUpv_2;2Q_u`h14;I|tuu>G@O8-P{7&J3l!1QNGb(t~j0l*}<<4_B!}Qvml3V(9ho- z{O#a(G50B9{t*5tq`+U=!X)S_Gi|?ve;pifa8RX#$-|n-$^Pfyko>1wD(8+iVyF>A zwHT_$+=}fLTkeRXVyGz&#khZ|wpI+s#!x$kV`Av95OF_p$Z;_oA9G_)6BH)ajp4)? z>cwzE%q=*K6*aJe)sNw%n0w-oLrD&45W^WUoDxGrN%rCb#oRAipBi(^HLufRXe|14 zVUsHN{dtoZ&WyQF`c%S;nw!SZJchGlXcof;Y4$uhCx&w+>CKmEaDEII#?XT1Xw>(F zy)9#C6?2~~7$u^m9oIUBHZk`RhF9AdE*9NRc!{vR@XRXryZT<}IF^pZwQ!v2UcUd2 zVL%L>V(1yel`&i$L+2Q-in(VEo%AeT6GIP8uuBYGW9S}pYh5=Xqr{6%>SWw{#n2~) z-Z7LZlC(=b^tNvd$0f5g4rR*w}K95eSQj z2%|zLhM0)BkTM;rjMeho5%MsiX5J?>RFe)+#+w&I!JRvr?|)(_DPqhw_ELVhrce6j z7;cGSM9lq*Nt_F>TNyFF{}GN9vg?i*?$oS#Tgc%R!qL*n=9n1nj=2x5j69oOaK^^m z)0SS{$1Iie+(8_Ee+=Vecu0|XAchA;aMXktCW`)2O30a{=49c+F-$q4cUlb7)$}Gy zoWYIBFaHQ<#_&W8kI}stX2tNhtWz!LMVUF0VUzS+(es3CGGb50@N^6dVt7h(=Ulwp zdnSg3(nH6XNW|x2cs_DkUd5yg1)CV|Ytr*Ju^UTpPnW zUmM+Y5^yz9q`OF#!U#;{3}Go+2eObl9SC~rACE)$)h6;|V|F?<-qr!jm) zmty!hhHcCl^)jA~c>f>64r!wv&Wre23_D}^JccjCr%^Iftp725<;Rf9=`-yzMAX9w zd>g~Q7`}_)=NP_^;fEM@$FN886r(VW{uskgK8HFP;k_~Z8pAI##88v-TMWNzz8u1f zMfHyu4#x0j4FAONR}6ov5YYkJW&PYA!-1H4pG@Zm%hi8lKpg+Ya7eqAI%$g~%ZQ^| z{P2GRp=PdNjkvp@M+s{Rj~3PvGJ5PiMl^|IMI0B$@jjvEX9GA;FYZN`FNvW_ zaZMauBr{y=LYZ!HbdS3)a5y!l6R~F;WpVV1qqm$Shhm&^ADN?aHp}A}7)M1M{o<&M zqe_zGvyL&5`o}Rq9C}Ng^leZa*J?P|eQ+Gt#Si~n(X%)-j_c#@qX#vx2vEa~5@wUT zDG-OLCL>H$dwC4S5sJHS#=Nl9XYr3CB8yZKQ$UhQ%={j^T0KrWoEF$1NhLd_)|#`gF%CV`Lon z#BqBZqr|);jypwMt$Wnbag3q=zWkT^lIPuV_Y0p?H8zg%aoiin{c+qE$2fl$beO%o zNIVe7gg73Q29G~6j)(rQD@fA9+E>7T#My?J>;@3jN@7P{G31cMR6=< zS%~9#pR+`Sm;W!uvDD|2^HLnIa4nb&$_H|o16-z8)udNk+}Gk*702swyrCRp2GWz2 ztQG2A9mkteNIuIK^XIKN*2l3nj&+*LS}Ek}za7UriV4*=l#&f`Y>H!}hBFnJ4;=oU zOmk}Q$FVhz58~LO9AlPx`TSuVAH@&9>!ui;*%rqR)`vJg(OCNblk$ySpVDm&{G7=U z#}{$zjJx-rG{kEZKmUzmm-3UNJg>fqHukSpE{2Ir;IDU)ccUj~R3UForh~rO1hErayDo5oeKm3iuNVsKfzoK+N zcu@GS@V__?#eoER>Dj+`l~Gw`R7;?F0@V{}kU)(Dj!WRE1ddL)b+x9nk*JlxF$vU8 zxVKURtBh-_jAJE0m)LuJ0`(K9lfVfH)J>pX0@rI#u`4LzL@MV?fGXo8jUxYK5f||D z-vmxiprM+L5;!e^Q+=6CmC@LzhgBJ8Bye^DO%gau%rk|Ic~cRiS*B#GnVK|rP68Js zaITu?3C|a{5ON~7Oa8(HS|-pofmR8$R@X&BYNnrU5^kQ5xL8aQ?GywuhbsZNlpPc$ zWBNVvye zcUdRVlS?KJ?J}ddamo^?OrTE!<(^}Vy!@nw3Q00IsuCEGK)(d~C)`gxm>BG(wt)!@ zO1RG;U6hvO4^H5w1g=XQ{)?bP5*RA_df^QT+$iF0?m<<1Zl!=YrZAX*C4&4AH7DSS z5hDrY6Nn~|Nx(@UrdZL3c*6a&3<*szDNH4h7BN_^a;Dh?a*UWt7H7>QFCmaHASJADx4;qp1`9CJd(f+HSel2##9+os*IUxa$a1iS&ADyWb|eyupogs3Cv62 zi3H}7*7WHEqc=Z+CpA09jSJ0LKb64Z1fEXd8SzK5_{&L#@!5oX3O^@YBz&yOcs_w8 z{w%zpy~w#Iurz@c2`o$CB|o0aB}VsNPT&=J`>Jr3>db2iye^BQRHmqEWdf@;WR>{j zys2hw-E6#-z`F^oO<=v4>mL-8s6eZsvvqCa~Q_(9f5d%4QE(dVC)S9^t{{Y>Vj zX72_Kq$0sF@QvHi=V{I4+6$NgSU< zy(H=+Q8#(`Zk#z!4JRaVV$!WVbeo|go|MEXNt~QS14)ue6WllrlW3GYd`IoN!IwWt zG)1jgJ&7}tZXKp|YUA9`OyaDhdq2;D!#Ps(*-4y}M6)ECC*4e@jECnYabD6b zYaB?=Ikgr^T$;oMNwiJk!Xz$AqGb}Tl5Rbu7)LP)TPM**9#Wom$+ITY;arjOBq}&B(OfBu^*@OLN%Tvizal{Ash0W& zCNU`KKJ${pvEEmMXq00)ia6MRd?qnmqv*+vNjOQ|lteg*KoVxs&1Wj4hG5eDwyI-o9>QvZF8XinyLef3WDL+wbN41RJ zq$D0mVsa8wlXy6ZDVhsYi`Ka!(~_93eYf4u(iurSmc*k;%;d5vCA@prSxG$Z&zIrl z@Hq^15>F&CS8-;1VtS)BKZz%m9^|x_S)VuiA9ly(q<@Ol!f7_KB% zYK@pYUMX9xjl4_x*C=9d3D+jEK8bZo2@YpkzI{YI-%a8@u51z;{hX(Jn-l@6-7LxX zlh~5P2i))eiN7_854l4Xb27QUA1AR*!d&9*Nqm~bCrRwkvN8v_98~+60?uvHko8}} zJB42gzY^{e()8C!d?R{6mBHqBKL7h9cKh@m5kCljOyVb>zfeQ=s`*P2zxw>&MEst_ zKA-bP5{o5F6Mu>MxA31N_KP^+OCA*QuYy2fUWdp@xwVCtkwP`m)rB>D{!uBsDE&vL zFpT&A!rCdM`Ti$`*8F)d@8S9WUz~-!4dai0Q>dRpT}jqU;e-_U;STvHN+!fdd)EIH z8l-TttdK(osE6p$)YB-1Q#}phH%{SnnWG+FLw)%(#XL)r9NRR7l{^Ac?q7nXSIwp0 z(|m3U=cjO|4)I;F6!-?LN~wH^QVXO^h}{V zg%AAO$blgHjkQ=CyKwQ@AdL zAt^k;QZKjn@cTb0+~8}wF@>9aI*@{uf|)|l*T#r(j?^ELPSRnmLPQvq3CCY|`WcrP zjdEZzg+dA`O)Z^5Rys2ZCIxaSZktsYN4|i*Vl=0+8$&=A3j7i}x-+4~t?jy2jYzpI3xHpCSQ@AgMam-;U@dECx z)B}=#P_9l$VM+=UQ<#*(Lq}x7WYG-o!&)^CoGK29X_^a(M^c!T!VG!xsCs9n@R%QY z`n-~#|E4fEh1pyz3C!_(nMgT>lv{7UG?2qtFGyh_gTP0C6rNTNKco22e@c4(KbOLi z6c(lMdpQZ3c3ZKh2YT#H_lAUttOJxE%yN(!3 z2fk4NpOxwFG>|gn6ZfR>gE%zJ;CuX^QutXxSjp2fg8>9~}Yr`~7OQVsLpDOe;GXjm%|G&ObLzA?79(n6Rf}Ez}kfsT*!qYVQpYw1$uUo73(1qoCNGM$OrurWEyZ-0O?Hu>hBoQLC!ME_%Gpc$k~BJ~tG)D-fua6y~y~HD51!#H^ynnB>#$t9V|8G>W46+`;B-E=t;c;u|g`=aw|?ladjP z4BscDaa$U9r!g{(QEA++t~=7WGmW>a47$XNhKQrnxGRk@X>6!6Hdh%R`Mvj~F;=4} zb8i}-i9b%9`_q_}#`rX*r13x+lbA(mOjOqd;n!8hLn3~xGJe&-$!b2F#&2p)P2-U? zrin@Y(?xJyW~4Dw^rON*tBl7){Hsxqi=Lgv+%)Eh=GZ4hRO{zXY94o%&#%$XSfEfm zC45@=jF9nJDB{^Pp7S}pFHZckL z5wI`wo=A{TC{{C{Rse)iXFMgBqgA z^tx)QN%|Z<0%Sm}oxw38jujr4L0u8Y3+o7L_cQ8=I3a@*GdRAV!GXNKY z88r8M&k=EM2Iu)4%Czw3c!7uug)K8^CE_B#x3yfoRIawo;9@yLf7)emiRkt|r-O(~ zGpN_k{bOsF`}~d~t`K(0;K~d-XWRpYG9Hq+TD{i@yJXNcgPs|5Q8&JZ^9ayP2MezgQUeojXy))c zfmS>MGPsc;;!mXc{eKaG49pBdqJu(9_!R5EPlPjIlS85z_r;WxL0UvCgSZGX6B#6Z zIwhihKO>VtF@vnn&t;GoUGO=L`WYNsQgfJacm_B7y-oVLUppL;QT-R*CLAfeT|w|d zdS?cs)Eu3`SP^##$7FD~hD;xVKVM)tn}z2#h!2zFtP|;W_nPY^9$jKfa zWn@v!r#%fdvN$>mS~)6GJTcSWBd z4W8!uS)7!`x8k3iMZ+u_WN}Is-W)xdMw0jRoR-BI(%d+U(~r>8MD&?QaGGY(OwF^i zZh@k2&9gWs>sB7pp62tixG;`_sx@Uodr*dHj->BJr`%uA&Yid zT%s;&Zm-@m)O+a>IxnX{79BY?U$T>WJ%2i9aaH#4`g%TGlSTI|x@6JS=XaC5Hy2`$ zEP9IL`NmPbvnb1=Zx(&T_p+i~^aA-)nZ+G*yFSY|k4-#^koXcP?dKTA- z<5?Lh+RGeoH9dbkpFNAFWY`+7@Ts2W`qM5$6Tri^8SC zbM#{Wr7YHFu{?`aS-hOZYwCJM_^NP4*8Mz@dR|xa4dF^5HSmmEE&5I28X<+>%DSI2 zkXV<+ds(b!&Zz5c;XB;m>ZQPjEH;X{Nyw*5GB;9|*Sy8Qu@G*p|gdYJM!_ zVZjh_;C3}XQT)mIRL#$Xp9{Yb?i7A0{7Oi*9R76{$L8=&7XPrGWbtDb->LU|;cnrc zEPl``aENF0r!0O`*U!SeS^Sd4uc9fyE5Y|aS^O!^KH(o(_eRAMjetc=S!W21gZ(E3n|YPIZAZR9FEE1XwkKDsGU2!j*R^OJU=dn zhB+Lc!-+Z6kz`$AJ>dyLI>{mRb2vrKlY}Sd&>-h7qBjL^H5-wW!>Ku(k;7>cYb>Oz zr{~32vg+Ib5u+Ho~?->TD;1GMD7seM+K34p-*fgYr^!T_(I-*fEDIa_*L-SSN8v zcg|rz4p-&SD~GFd=q7<{a_AzWtB_*V@H!#IhN_o@w=_3M+l@KgBqAU* zg+U=DEfEZhEg~$8_`T5_9MLf@rHHtY`NpwHKc49v?#UsO!_7Hlb0|nAC(H{u<)TlN zH0xnG3>U#JTE8WSQ4$y-yfug0a=2aeNFif#M-F%Tv{x}kb1nG!uW*dI?$)w;y<>BD zIEQ<4n3%(TIXob-aXH*Cnejr-!b|1{bC}?VaW?<>XU=^LCoxIP$wG3b za(G{yjX7+}VYBG>d@J5^d?4l)e;}D3%I%ND`B+HiHhl{AkC=L8Vxbuj$_)45zT4<{JCWr6E`BwOykPp16?*E|lLUf5Z^rV9fU8?3~d0b9alJUf@5WkaG%_kDlu7l}8_Xo=2H_Y28a9YNl9u9yjJuk;ip;RBD1%c?`;lh71 z@|ciEG>=>IaPr8iHJnoRdNa5{F4~6Z1A9#8mPbB`D`KaVweJekJ}c`V4|nY?=pJ(b7P8s(ibG`&#GXY+V2 zkHw-F30cyg&tr*b&q)q>F^@O$SenPn(zYy*mn5)U_&=SmGM?fBXeVVTRn#Uh` z_c`ddJbuq(pJ?jmkr~+yiP_y9P5gje8RdA06PyaEZj};y#q!_#E6mXK7bqlChz=;K% zpeDO0P~WF%=wzR6P{1jo$)s4L0#21Dq)#iLSpkg;I8y?r7jTA%CjMA&$XNw673XZ9 z&#m3Ofb$DD$LE||zD_M%cE1iwkaHZztry zOT=$4J>*|nK>q?RE1*XKmltq#0UZmtLc%PVoeJn&z?Bkalf$o~4?0PS*NE=IIE(1Y z=;xn4LkbuwSG^)hXE^qTg8Qu@5;qkPEFj=pH2r{B;)DvY3x{tN zyge8ZKPq(mQ8DRfh9?S`SwOOY(FLRm7)DPdlM!YMC=`$@An(g_3iP2^KuH4h&~tKl z0VBk@xqw>~H;OShw-#`R__q}>vVhwaTdtQkiZXYKGs=(oT?I@kU`zq`7jU-*-c!K6 z1&kFwpcLbhhhC90aI=6oUD zUf_H3l!&K=-pVd4;8{iNIU%RB$oJ>@0+tuBM8XW_3kAGbz*0Xgmlg1mzhAs~zFfd- z5`IPaY5^-m&>wFKudDe+0V@kwC7Qmm*IU*%3s}Ph7XPgR))ug#fOQ4DUBLRn;pb?c zw!Gev%)5TxQp3gqHWjeBfcJdoIlK2I=2_oT!0rOJ7Vt#@9~Q7(v-qfhj|p9LH&xM%ub1^msjprY|l0sBQC z@HyoFD~lxlE8tK8)rvsT9cT!>fz^xd5kO`QF-h~PDdy3_T19sWY75!LupC=-i_CGt z@G658ss2@w2E|5$6`syohro{~>+hF1v5uk_ck zUlD_f=r2A!8BoMP(X`8{U0cLZH3ti?D`JQUZ{pX>?hQrUD5e*Rn=}`CVis{*5y2u7 z60?d36%i3_3&TPhjTR9r!jY2Mnjo2RKPJf{N=2lK$Wy+EToIWfvhtr*)H6zX5(TD~ zh@w=H9#+IHMGRN-W}ivn5mJ7uIBZgKWD$24aeEP?inzn)-zkL@;5AyzyNVd2kdiZ- z-~TUSy!c~_xVMOLMck)mCw~_AtLYWM2a0&Ghza7*+lfUyB$~6}E+c1h5s!)Uuy9Hd zQ$kH49#f?R5Qo*5hUUXx#M!jFe2TB9aF>2mg#CCOkDEvtHaS_|(WL@p(Pm1`Wh#lg5 zD*UX7&qc5RQa`=jS;V*G6tPSEuUK%@^>q>7$P=zOCAmkwD`K}~z8BJyJw^N=uP8v5 zsO_gBjxD+6_va$^7V(!Pe<|YEBKC>?t%%=6c=CUU{!{2F`MZc3CHzywe?{ys;$RU6 z{GCF9e|<^bk{v3-C;>7@)3f;~Q9^Y!Sv2S{<&RRcW(l=RIJ$&drT_Exm;%R?+{(}4 z$CYqe3CEXkatU=bs;;nJ3H3`jp@b9Fq!kKt;7MwF!C|w3nx_aGme8n#Q%ml_#4ZMk zLmHRRzJ$|DIKPB5N@!j}lM%aBsQEJg04jH7sQc=r-|C>m^f{`At6 zJ(^fnLZ1@)(Ps@T7gh)>g;he90t)l$ujYUf28tkOPzl$H_9Am#3561dln^grXbE-+ z*Ow6Ze^i|X)Kyj2g&*whz{GCF?!fNCLKHDkP*IHA-6aYZU}9ikCyIgC-GTktEq2R4 z?>z7RzV{#Fj5+37d#$zCUOUdY=e}WsAu*0}+CxL~8vZdcj*oGy4I~~HniN?-)-_Dy z()*tnC&juy=q2TFYepC)s#Vu1F;0zfdW?}F&S|~kjEZrF^=BI8rBu(3k%i` zNSdg~DOV|Nj8;)LMmt7MX~f8fIE5I+7$u9^*HMuxF&frXW7J~Q&7-MQ*UjMDigmw@ zid;G|&I$U_G0qKKUSne19%F2b>tdWAJ${1H$Inj7kSf8@LMr+B{p42OjqFo>3h8Q=;xY7E_vF^jeO}%X7 zdyB=8a009B#@)t7V2x2K@+-QDNV8g!hc^8$U2k^kDxJh5D31GD&}Iw8SvcPPd42_n zTo#S9f1JhQY!zqmIIG54BF-vtmW;D}oTcI{6KCl-eH|y-swe30|HN4?^rBGeVud&> z#aS^rcwE?9cR5b>u9jn$VHd*>&Mw3M2<8Y z#@Rg1MsYT=eq-mOrcL8)7Pu1AtZiWfHEkJ3n?+>nID5p|Ce8piZEM^v&h~M3i2v_f zW^K|Pa6p`6;~W_0 z&^QBabC6L@2b&xcIqLa8&e3rO#W~VF9v)|KoFjVmt}za=@lkPxdVZsUM^k)^n`Cob zoRRVFz5Dn$C&W1^&M-Hf7!1_)@HnT$84>4XD-}WZ(ofX;fA^@_KP}E#aZZnOhHXX# z_cH^Ly{@z4#H@+ONw|80!p=&?xin5X&e%AaIPEyuIK?7qCaSG--Q6-k*)Z>)n zRIRMUy9Z;GSj}B%M$}^?PBTu+nrPW8ZC#x>=ft~@2czSh7w^9NI@hQmW2~32TF;L& zF3tt7ft6jIN zj0$^=U81R(WPV+o>rK@9hBxMoac;3@a-5su+-x3=NF%+~Vl?F2XulwUni!(LOLvbF6^Pnc(1ymPNVh_7MvVX*3r^k6TR3Q54 z<;UZ^RE`6SM_ zaXyXnO`Ol-d>Q9+hx)>(Z*pb-mAS~*9<_+F6@C}z$2i}|yH8CLXU6#2jGkBiJ7Gz*w47%Ue~uuOtQ5-gSIzMomtxLAV4O{7`EWJ#kU zOS80j-=JAG!A1#|OR#2w<=x#1308K7D<@k60DnGJ(;=qQS~-(Q~yMF4M@MCMe&W5gZU=LO%rTpvU!3nG*U;< zKt#4mFd)I!3ARhHjcv9yM!m>p`vf~!BR*5-zxhrHb}`vG(evH0T2*2F63}i5c9$~2 z9*OQR(Cum5%P4X01pAol4lYsGeirvP9$-8$!N3FunJa7*`H%#$1cxR#J;7lKPD(H+ z!O#SUCpglX3{G%F$TLcQNP?rRiN8pYYYDj&Bpks#?bQpR+Gto0c! zMR$}7zR@vNNKj1BNKkU9vQY_F5>(A=3F={0t49sIX;Gw=pq*fJf{tUJV~i>jRaiwk z&#P-pg0TrMPH?`(3ykXJLWjD@juOXNFR$??6O5M_74WhIHzc?`!Bwv96$!4i<3wXL z9GP8h@fzc`2`0I)*Cn_7uNajup$chsQ2At!9YQt z5Kr)Ag0~VpmEg4mPbYZ62G1mT*5tVa&-YphS~f3Q|5Aci61;4#P#U<3{A#Gf>!Gl3 z*x*g0ia$f!B*EK3d?%PG!g~qcPw-)a4?;}ktRqxSA6fIU@e|{x2|hE?)O?=cOV8RD zM%hQ7&P2XW@QuyBHA?ecg73{0d}e|l0$0;d2^LE7bAknv{F0zgl3x@27Dn{Dj(r>d zk?48C{7VOZg1-~|lj!-WcvV1gX2~Vl^V}{`6`L)|yvgonoIS}LN#-)2(8I_fknR>T53<=cv_OvO*B|Foss0M zBxeSV7U9`RVqtyCMu$lv$%RRhNzO}>N>WLZPLgw9nIu`Ks$03z&L=5aEEwfpN>bK} zbyhQdR#cO;lGKtkY*P=GGH!JdBi| zC;1}Dm%%Jjer-`M-p6L6l-q16u9{*Ui>swrJ;hon z)=05tFo}GLSqei;BiI$V* zYtIx1rPwRQ{welWiBjy7>i*#}IcknX_EY68N^?Mp15*qPaU%V}DF&xFB*mZVCMJ8Qy*zk>bb{Lu@lC^fEL>CB@Mx&Ps8Nn~qg+ltzkSDUP@11fx>YdOk75 zaEm7y_1CmUq&PX%^Pcb)hdnjL=_y9qK$)KwW`C45XQVjOWSEUrsIya~tce-pDH0}0 zqaw&Mog$wiV@=kWGe&PmWmB+NOi@ZvHlOJC0E%BtaaoF5im@r`Zfc|$ouZkdlcJTP zZKX=8F)GwF{RmLV`CK=hmtu^GqD33BFU1X(dJ}$+0bH&slqvP%p ziUqsO(FW0=t~S5Mcx{U4&VF5rw^Ll7;-M5bxar0eccqw| z;iSkMA*G~FZ@2yqZEX|f5T$WpN=o=Ne7 z7wWSqo=fq(d(>f~OOCo;O!1N zcPV~L@x7a7ruf<92c7>Ze)9RF^r9q1eo67G4WgO)J;mP^|1kb({44dpH<|yW_%|HU zJ!4GMC(Yt%W=k_yn%UFcTZ67SOy*4Yd}k-k+-c@Xvp|}8-85gC`AwoY8pVQX7D=;E znuV>GM%!GDi>6u3nyW0TGE1acCC!p)mQS-(nq}O&w6Slxd()B4vKE&!>Tz9~71G_s zykeS_tn8QWK0`{svi0gnJ+7K&O^d6gSv}o7gyph^W6D6{TJ~MrxK6s~ZwjrKX3sS1 zr`aUU25#zaR3;mmY-HTnsCBq$nyt+@OS8F&f^U&#%QRbAl%qDUaGNwcTC;7M?b7U! z?%qwdH_Byzn8$&FN{*NHfY}w9L*lS9)?kJ5ADJEKS@bVN_GJr&4LsX>w^YX|lml3q}Tc ztyPnm`r*$soirsIl+!fRRMOPbRMXUgnOrpFhKC~}QCBNX+g@8*JSWWZgitrFaG712W^$U#(p+iF%Z*nU^|Le+ z)7@9BSEac&&DBA9jh3iiGE7QyeVXg6S17IC8`9k9Oe7xVg?dw(2h-e~<}Qc2CC#mA z?nrZ6n%jF-K=Z5X&XC*PY3@&RPns#Vxi{VYy%@#3&wWKtM-r!|dBB>}d>}lO<|*ya zG}F^e3t2tl6{s0`G|dxf9!vAMo3s>F+i1$3On2`Kn);{HyqM;hG|#!mXKg9p=hM6p zvW+rP?@IV(CoJ+xnpe$VGrn$o!}z9AHgeH5!!h4Z^G?X{U6c3HydN|l`26YGr&%z= zM``{{^KqIV(tMKU%QTaWs#pXTc{-`e0CS3c_fJC8ymo#`f# zNdIG+pVItl<&YxINS zQF&*xIJW zMKdg6gT;)Cy9;^gS~9~@L6m#n49jI$#+qe&>6dpj8LW`$?jXhQmtpS=D`nU!!^#;p z$*@X>^)jrQVXX|SWmqG_>W-lN^{Q=6bKQ?5u5G?fhIKRDpOKJ8m%^@}VZ#g?xV67A zDy;h5D8t6qXw(unHQ&s*xp51X!XyeMo2@hKmSLL=J6OMMhV4w$w7rQ!4Nw9ZcFc5- z<(-Ub72m}MBD-1{{V@OT8TJSf_B7cm)AMO-pA09cG8qobu%Dau&oI#B0ONsSHV?{h zNQQ&0R9_mk@X!ncOa^5b;+h?hWj$y?}8{uIjoHb97hRA`A~+3GfWFMb67b&!xOf7G{a*V z9?x|DE4_?$Y2Z(Wp*>|AX`V4r{?BH3F2f5Mp3ih|5K)!n^!-qQdt^AMsQhh$Q7!~kS^Up%& zO7#nCzKmS-6|jjOY`)P^mgU*|y3`7U7gEOTXrGZZV^+ zt>Hu?nkUObS?0|$f0p?iM7|pJ0$CQcs4*&siP|_87s;|{wtKkgP82=$EuN)cmL;+* zYl9`TES05imZdGKJ4IW@TyZp&%b724Tp`Pf&Pq*DM{&o%c@z{@>o{0 z%j#Ly$g-w$knu#Pw|18GvaAz&S=VHc&i|m&9iKrWm8AqB-Ba) zH?x5br7f~-m1WBys%dL;)lgj5wpq5zvXhnDXW1dkfG`%d?wIY~*F<*CvYTyo$+BxO zP$s))*(=K)S@z6!pX;KSD%ajw_R0S5Y*97#%W_1P{j(gBBP~*`?MLxzvbvQ0dGt2Q=5~^XAGqMbG(}`J5&2mzf zld}xZGQu^~l88nvJS9|hWR_7Hc$U-csD-DyunZzg^>t>Jv$EZfQD+-tS>m?T*wre% zu4I-}mSUE4mYmHpS+X`$YqXg277Lzh`IfR&vy`n=kCklqM|2dhmZjm`>e=qyR@Kl= zLCLhTT$81p<@_uid!1vm(OJ&(Y@TbS?kr=njMdukT2(;xbwQR(-Fjh`i?WQ*a&eY% zVGYPe2~5axNtmN(?3Za7XSv*tS7f=;MC&$cy~?6|uQt)g-fOd5rwCd|9*FRIH;LSk z<;E;GWxJpICR?fWZVp62Zq4#amfN!2ljU|NFXbJoK;U=T`0n6xZXqLyVdCaI$JQ0W@JeB3SEKh4M=={&}Z17bP zq=gUdr;a#mBTmUHMnDe4gdCEFWZfJ%|y z?^^jzw)-DRqa%>MBIwIs zqnf^PC~3Y6EWc;@Binu3qkz%TE%KLVS*z|J zo$9&nI{eqOGs}oIeR9lZGJB3Wa@~7@%yiBO=gP5wo950jkBOA?n#`AD{-Bwr_dhun zv$#->g@b+(lSPe6NxqBcSi<6x!Dgvk_miWV`sNsrW0@T5=DK&NWpgZ-V~rfk=U64j z3OV}aSkX<|lY$`+NdE*;wPS~bUNIabegXHB9mMPAc`S}VsoIo7tzf9oU1^>S=t zgY|Q4kYhvh{zkcPWc!Vc(O%m$$F?~(%dwS}o2xI4#au^(Hm`zjZE+i;mSS|~Y-e%% zT=#6*!CblRm}95Vm%7_I$1XYc%(1Htq}eUU?m70b*w0^%OQ~xwYxd5uPmX<6^DthG zX#X5%2pT1JVvbXCoMg@LT+ffDkH~Ry;EI2$TSppC%Q4F2 zbPdf*@r)d2nyc&o=5uzASdMazc#e$i6UJnYRF1T2Xk%?Fxn$jx%TdUYH&^kcFXku( zQ4<%N5lG>v2N4{M!7W2TUw~DOee>~InK#(VUE$NxqkT5cwUb4bBxI`Hpdqry}WMBF*)evbyMKCY20P; z?%;KAj{D8081D;SQ*%6+C)af*vJz|`muoVE>8p^m#1<( zWAW(_|JfYR1s;uE_(F~sbG)46rCz>KkFR>-UNgR)lZSlwn2m-xo4E|6nIq3)dFISBzm;?4nLE$CdFGLe4Whp0%lDi)3*@^G z%nM4i{X+SkcSnolSv0sP2YD@?r>~8d$g^agrOlTzs$X3?RhG%Ke4b?;O5$?)o?}X_ zD_FT=zI%Qu+DdtL$+L2vt@Essr+=PR^Q>i?)$**KXAN@=P}iCvE5%tm&pLV5%d>92 zdqdQyh3n_pz+yBynQdtIjq+@sXX8AZ=GnxW|DLp)S&UvvY$4w~TlE^RBIw%2HrwXe z&Sd*MJLcIT&j9xo*{JuO^6Z@N{(H4(I+Vk%dG^b*Tb_OFxVv$WJbRk#m1plTq79>m z(tP(HlPREZ|2zXN9$-8$G#wN=Jvh%HfgkFC%3+X`*O_^Ep26lv7>_g#$ul(1Q8tdw z)uXLfkIME~^W*ZIndkUCr)W+cf0*&aJR|a)lxMij)R(R)`sH7@ibR@I^Nh?h%F5I7 zoNl6~i8eUHqPjaPPugjmohN1z&y&oPF#qrDq%6+R-+yqYS&KQNg5*QAVxH^sl=6(t zQ+8`5Ps5~YtmUZ(FU?LfPsd^_PuoNpssiWaIWN!XJm*@en~pBo>lzbg>ij%c@Ze_5W(L!32icBNe==D9{Y!u)EZW+yVZHqWFy z*X4UYT`G=(-=GbZ=SEvjHr|xyHj|sR0`uIeI@mI@SE$>ym2~GaDuS-NY=5`$o;>$z zftgP+YRLEJnHsW{y+S>h=bJna<@q4b!+BoJGcC`Pwtpng^gNH}c{I;s`Re-~^1PYn^Q@gw8Mc|M7hp8C(sKR14n z=PQ#hjnQ0x-K$F9TK`?1@ALd*KGXPv@kgV)e$Mk(o?r6(p6Ay*zgZvEL0SEg=g)li zAtc%es++FA^Zb+NU!8cpP8bSoRiICSRSL{jV9^4z7nrxuy(!F5V9o+_o6l9~`II63 zJcaJru4>FzU_rOeUtj?fwW>+DP=SSIR_NAQqOM8$|6c``E3kNhz6F*juvCF1?G;V& z(&oxp#><#5+bibs1^QWBp}>lTp4-7ho&UjRoYuyN3AQs_QXYWS+{W(77c^xP1) zu)&r_d1>QsU0^_gZLHbWxSfr+4>miPL~CG2^PLLpTwr(eUDQ#5-NLvOQ~B)SCXqc0 zJ>RwMT_9Fqp906pvcSLs`?>7KRHmn>VSF(RGZ6cC1mAIljQz1x_e1vcRwcCl@%ez;H)CDU4`@ z#c25I_ml#sS|hG5PAhOmfzyL#RH6G8QTj6r-NWH5qb$XBiNp(BR3K5HRv=lRR3KF# zUm#r|TObqSXyS5#D^EEVEEbJgiseFggH()Fqim$97Z_8ZQJ`aGvp}mr+gyu$kk`pM z1;spgR>}95`E-r9gfpG;cvwplQIibKM1uiw0yXvg{ zb-AXdz!f&TQf2XeRBN>Lt}bw`o362!BCBbV%O&^g3*27dh61+~xUs-Z1t!~AHYeEf zW{aAXTLZZ*%$IELu=36VcNMtXTouz3iz44!;D-WJ3Vc%Fz5>q|xWB+71*R5w$d(Tn zA2jN}rao*k&8W!QQ_~APS>VwEk6Zbe`_&p#>l4;Y)cIfF8S|%&S`W__c+OlotH>Jf z3kBXN@M3{it$(S&%R0VX4TaLBLcLbtO8xy$qq@-izFFY?0&f*~r@)K?Z`(Jjp89>a zzlvx3Zmsx+K-v8TCz33V2(*j==_{=B9=SJzju)&u`jr!{X z--M=bt^7_~yTJFoHkvw>Xi#=z;f)*DtE?i{M zB8wE!NvQb3#jKCSC5kLxWJzn5Dzc2p(#F2QY*~}#f~X+6Rw%M!k(I6NXI#msm9R=6 zGFz?4c12b%vX*kQUbDPrvFEH_yT}Gsu2W=P6S=HsvVO7W=F-2&mPIx!vWfK@71`J% z+GU#-*}TYR#hx3AsqaZC~V&B0Ch>tH^*NyA;{c zk#{m`AUlV8%6QizyA|2PO}iV_g(h^*V$c0fHhUM@r^xUIoy1(QGLl?*O5hr6geu?M+-^Hql=tazhY=kqRt_^t8O1rN$Z%^$6gj!qC?@IsPm!}c_K`(SGdbO;oJX0QVLVf%^FYqF z7&FF=i6ZGDNynF0%1ZT{2_$QxTqoo*D>9ElxJxGzM(9}D!wm>xdcNdvn=@`jbK8|AL+O>+%x zMv-5Nyj|q0BJULW(E4|ayk{c!_f0-9b~lL0M@2p_@^O(*Eq9GhR)k-R%u(Vu>whoux5*#IKa2bo z?A6^rMf#MwC;z`iW~q{;o^J{?1XX@EH;K${qI=(*B^EWGtHj(T7A!GOiTSLVw}hrZ zq2@2KK&g8cX+cWV5?#m!3zt}=)O}QrCQG~5=+@vj=EHzzHSm< z#zd2{T!|IUmp87UuwK3WN~~qFiIYk__g}ea zHI8sJ@#t7P#p0<(<$PL+Sc%h1oLOR2i8HKMZn9VMXO%cR^e&C`@e)bfB#e5tPq`Fo zov8D_M6E=&M7cz+M8QpYTdK8KqV)fxRoqlHDuVW4y+qq$qeQbr%Ul(U7F(ypxh2ji zG1_|Nuax9PXd$`2Y zC8m{l%*sbfOb@M(YI!@_%itM{&z5+h#B=8A@p%)a`eKP!O1xC! zc~qruR4GI;Opx;0L#2l;$3^aX?)8#qr}_Z{_hy&rS1P-iJwcnU*hu;AC&l{ z#D^t5iVU>=2lg30u+PU9PxikC`_%k1V|03aQR2H2UzYf$#8)N0cGFolj=K2P8u9N- z{7_=1jxU!&_5ZQNPtIJe6RrHE#6Kl|E%ArWf2aMsF_4 zv#z_=fh;riwSJjR%4|?(qcZ)=Z0Oc#o2YeTk1Mj=w9IBsa*}@ktIQT*jB1trR%Lc9 zvvry6%4`!xw`~~I_GNakGOFQ#a?h`B?Nnwr+w5FsmomGC?qsI0yO-Is%pT?Li#Ux- zxL29I!`!J;Ww>vdgB@W%L#CIibH6f{~_hq#MFjfWWr84ouOHp*9@D32_2 zMVTRGa%GNEdCLqfGpx+fO5OpFF&-Q8k=OCooDhb8Vwn+TPO@^iQ8pUL$$@KfPc3tn z#gS!BD>KUc^m6xUU&d#YIWt6)sOdhtOsY(*OrlKO*+y$dt;zELz70>8$&|@DnhbPl z_VZ<$WeQ~~Wr`t(Qkk;3Zb>?4s^+ya4U@VSo-ZHtu*`%q7nK=T=3*NtHyP*}ZyWV;Ntw&sbZHp-{ZN{%%iHl zQs%WXuUexnf+)g=Wj>P9 z`Y79v&DEpU=cneMh1TQr{9k6K#V?ItmHE2Nw`IPu*w4%6yE5Nfj5fXotLuj{KbHBu z%ui*0aRq)hs?%S~{1(m-i5uwsf0@6^{25|Osq1fxdhYsH2W*8|I?^lMBN}6$3bR$1 zv%>5Z=CCFzno^R@T$S$OFEUSs#VX8OVFBCBXPm#%J^we>_rEf$uuz4CD?LA_Ef<}x zi%Mg6;o@qtxP)=Z&?L*HEA(|h-76Jv*$Qh{SgyiK6_&Stg$n&lR;={gv!bk4uCSW* zt5jIkM9~ys^$KfNSR-gO>1$QG|J+R(~Q;JcB@Bt8FE z*u27~7B>s6)AatQ(!J|#Y23=VwNY`T-?qZe6}GD|pu+a{+QAszTz0hOPQC1R>BSXc zw+g#gIJCkZ751yJXQjIZ_EOm$WbX?5nEdyhvs(AJ<^bb?6%H~P=$TT$gDV{3E;J&E zs?}i?PN^`c!qF8DuQ0^+gDV_S;mDATESIrbyR$|TBD13a_B+0N&z5JYie z)+kz{LNe%6Cg}>9O848$XsO6JS7CI8e1%ShLWNd^VuebDQUxtM%}6;!s8*;~s5!Wr ze=y_Owc=YrHjD zsFzf@tiq*1j9M?Zctuc7tZ<8VM1|`rTwUQ>t$FbK5%JJR`Q>+o6>0c|m zzrtq~rmCtH9;oo3Tc_#$Pp>LXtMF=tM=Cs1VS0tf-SnvOu}b&tfd=wKg{LY!X?OLd z^qvk}y+2#wd5h0!i#eGWD!gRPi#~-kFE3Yk#Ts!1)OcU3@P38YE4)?Vjj$=+w2k7= zsPImOw=Js2iF*HE;XR)@C%6j*`Jlo_HuzA7l9XEfULGGi`A;f*>Q>ziH463nx%FQd z6;qn8bi7pgy227wzR{^$<=YCsR`{;M5BB}uIMb*ef2{Dc`A_akL3I6M&2;_pSA~Bo z{9fU&3V&4iGweaxXyyN1;U8Ph@NZ;XHA`P{F`)DOBSY@H0QCSu-U(~o*mBm9}-HPd#zpAWUWvMDF zR9V_KeXA^2Wtl3=TGULb7p+?vFKi&r%7XI#ms$E{VWtW#yxDr;0(&C1n7Q#7JA ztE^RJZ7Vg)x)nxgtXpNhDjQh8zA<`+>0j-+%WPET;3^we*|EwdRkp6OX_YOiY-Z!l zjZr9dw57$Zs@-Qr?FDJJsj_XA9ja_sW&3LP{Y;dP#xlUhQR#N7vTv20tL#x_mnyqe z*)_CA$K&o6wG#HMvUioesy#Pl#o4FYeE`z~h9d7*<-jWY+xP&*)DLfX*QjY=m4mF0 zvOT2AkyQ@0=CCSTgQrC1i zA7RtcqJ90aZUI$xyvZk6+^oL6Oxm8$1h&qY+*3(TX>2p3hEROMnVwkqSQ zTwZ0o7te$$mpP3~s$6Okt*8i<^A%ODwB^LG*wl2jE!BEWm1}$HuhR;ta=kS-RJqw^ zH&&T!a#Qe%g5P5CR^x3U$Q@OtXtJu@W6fPv?zX{y^SQT|cwg|E>RLTedCuhdAS%A%ylCT>j4xMt zrOI1XUe)T-`CsJ?>t8oY^QL`8NHl->dS0?cdiS<1RjwXpJ5)q>=B( zRX(rsiKBh$rq49LVMBdk{g=kCj9M7-`X+SoZI$n=|K6zmqShZA=f^6)oBZUZ_;ZzC zZ1bz}H)B-22>-O^FXP|Fe~kYc6?T?Lt>^HUI9siI^3Psl&Kh%=ON?%*YMr~rjy2|~ z(YMCDH5RHdU$B|K#scOtTd>yM&i!;~*I3-jMQSWs>;4yYMO(}oRYT$uRxVj%sTxZM z1KFq`%hXuA#yB`1~u026|ld#EOm};WWI5YO-!!xSft;q#@019ud$`| zTNtI^%0vg9Qr$*FtFdj3?X1*L#MN-03kjj;(P*jpJ$@Z(q%b zI#LmaSyT?T&SjT(g-l^R8Rm1>l|9aIXr z$Wf$PqgJCHwn~(yGy}(J_~csw9`uHO{MXu3fYOrH`VGtuemF`86)8aX|=p zVXf!w=*12)E`(B?3Fep7xXk2Iqt?&mHLlR|aE7X|$iy0V)wrt0Z8fg0aYK!36xR0F zY6&^9>uOx@d6fMy``%dN<{Fc0++@p%R?bv~Yuu_OZ86GRrMTTTcNp)i^*ne;e|L?0 ztQ5c3WQtL}++X9(8dGb$P~(9bk6Qm=jfZMHQsdzo(|X0xN}Fy25rulJ##0s_ukl2U zCwp1y*7kIbXI;Q&YCYdzK3C)U(68K8mKQC)RO7W8FV}cgE4G(`Y?R^aLGwna=UdX$ zm{H?hH@#is9TU|-_V3krzgH$7xamWqHo`|WzNqnWjnAz4q{gSgSowTzrHH!L^<|B( ztP%g(LnvuXO{xTzsIz9BCF?9-XDREKHukNvY@KE5J+FM#<8s!E z$ZLfVShddT)~r_VuF|L!YgnVK)~d5fowe(1RA-$!>(yB| zG%5c2bvCTCL7o0q$~SVK=3y$@#@1`Fo7UOde6u>6*V(ep7QJ%b%1u$u+tk^y&bD=S zsIy(2?L%#&R&_cc^tDqUQtnbGUuV}k$JN=b&Ovo{ck3QJebil@y7g+iV2b&7R5bxL)rb;@-fwtK}c;+dOX^IlbE$1Et8<0PuEnb3@R`YqGg&qElrJ{R(iMTk1@yb8DSD>)reQZFO$1bBE0& z>QZ-ix#@1>J;r;DYLdZybsnvAf1O9_Os(^fn;tMe7|b3vnHIz-^7J4+X7af43FDKY zNtRF7d8y7bbzZ3RtP^|A_bz0sRa?GR=XDd+P(_Gbgm2Y( z$NCv{-gbmZZhhDMJ>&bmB7a!t7unbO++H8m`Pk$Wqx$`{&Szl(DE=39zID@=b-wau z{Mz`9Q4dJ!?mHWNU+2de*U{NpBx|Ar+{2J<$U$HuaW zw)uP(kJ8~Eh+GzGuyTWi8}x0kNP{ICEZSi428-E726A5_aE)TAz?U|WW|;;nG+4I5 zav`hbgN=MwH1F47rO>LFs_iNb)@iV6gEbng7VK9ynW`WDG+C>`+6~SPqf@kXgXMZA z>l^iO+rPm<4K{4Bb%Twp+_=H!4K^{~w9&ogZDuZ_oRz~C7PoA$l}V)BrorwFwr#MZ zmD@GgzQGQ5m&<@g&#hJ)aHj^lHQ2eqE~-cnFhHA+2E)O16Hi58f!*<*wJ_!4K8ZXY%sP#OADz%yTLgPI(F2uk^ATnEz0e@24k%GZynBW zaDg>4xX?s9=;8*KG#F=byivJL&<=7wmo}K#;Ial+G`KwYMom`+d7-0Y_78eHGtM)MmyvbC3VU7CLb(eFy zJ7joog9jT-vB7-}rZ%|WTwTccfnNNf29H>L*f`CoA3m8LY#ud{*W(RdZ19A|CmTH1 z;Hd^rThuxKOoL~Ys^iO89ZC6oqk9W@!6=Qcmm0j>;Ee{aGhJui1aE!G{grx6KE}o;eL>viaEj6PNeX2A`QouT1`nU)uL8&JkWu!FG+Cm_q81l3 zs;|YH-Ble`W635<1^v<{YFehrI!%^svPzTXn)GY3yqi{NvZ9H6H9&n9RLkYEknwsL6;Xhc`L8$>1hKnjGP#BaO0D8b<{_)I^$Nnha}lY?I@yIWFi=2tL?QmuGUQP&7YLn?r9%%A#lLv$TA(Pa=KC+o+{)kc2_o&HZ zO`d4-c<4I%u>7Q(RQ9Kx+cOrQHR_v`=S(z;7n;1<W0+s{Etly2ZauW>e0y^gR}|x{v*RjM9kD-eRs6bJ$=`W7OB&E#|d2k5RqI ze!k$iK#N7JU$DhO;yRp-vJqdj#S$$Rv%%uVXzWXxFJ+YFiu(D_7MrwKrp0PjF562=>RxP$P*XZQCwYgG~ z%eF0cXtAAZvb{0V4`{KI#T|p=&L&aKcWtqEi`}f*y~Um__ApmKJ+19!9!-Qa`?T2C zn*CZmFK6^Y?*MBKY;jPFf#&~xW>$uI=XR(oc9?OHZ4^zugIgTe;s|Sw4EiB0j%snV zjfaL(D~DrR9BUi#sBXd&S`=CgQ$8(DY;md$PBIQ}F`~uE!9`xDw0fRKMz%Pk#c6I* zCa0T>GHMy0+2X9=rPi}s#9HX{owzXJreupui88%%c_CFmHy|R*QCvPRLxL6n1or@h#4^&3P>@Y%!+A`4-0-73u<)F0#MK z3*h1wIf94q@tejK{0#SJa4ZgsyanW$TU z7QcQ4%s8pl{hNW;wYc7*_zZuEc4MpiqIGhMn_Ar8;^r22$-TwxEpBabn~kUV=L)pN z?r3qR_nMZF9=*2E%l{Vl+U6duJ^zIKlot0n0d=jna8gcfF}=kDEgo+1V2g(wK?kXl zR2tJ-JR$=pqj9O1M_WA6;;|Nwd!&jWeMx`+v&B=b?$2X9?B1n+#)Ep+_?+>1qr$$> z;zje9Tr_DkFWtJec-3LWUu*HYx!$@+e6z(LE#7MJb&DA-K56l`d|SMugj>AZ>VDDi zo>5(k>)WLdT72k%PxnaG%SSCf)~@j%HW4c9r!78f@nx%ffBf9|g-YQG`pTm85*6?p z2miLkcP)Nt@qLRQTg+_nL#z9P2bw0;Q^r5F_&L-;Jt~=B-Q#a9es?k|tcoxEv&HOf z{&F1@|L+$6XhpTV1NpbbEE^AU1O@5S?#|$B?e1Bsu)5}Gch}6E#<`4h8|N`<0nFF# z4rG4g0&NyCSIg(djf0fX`&BkpuY_n0j`*-A|*E*5qCT%u#t)_cY8v6PFHoM6tWVL0R zt=jCMDz(|xmfN^u!)DFeuFdvsri7X+y#Z}@ZnI;Xo!Z^omiC2mP;GZnkpBLIgUDFo zA#ILsb7-5xtvsyFpfC!Jba0y?ZH{PjWV?H$C=KPdrJn!W40X2ZOG-5z)8?c$$F@14 z&2epxw|zGsk7!t%6GLKs?V=#V-O&i6BAn7@e4A6-RN9Pe6K`{xn@(?YW}8vwXBhQ) zUxiYHv)Y{9Cguujf)qqmO0+51EZHX2Cfg?6Ce!Y|C6IxpK#sXKdFP|Wsr=f32^zxv)*W&FD6bHtjaeHZ3irFppYAoi^vRyKm|gaEkjnx6Rl#=d~H* zb*|i^*7LRSTs?KC#go(f|IquzZN`}^RRy2W=4OxXk~WvNx!U})HkY@#()WLt{i{k3wt1}0Lv0>WYny4_ zs+vtDpw{Va9t|r^j{Wuir_GbLdBV{Y>ZvwQdk2YY`N{0rHm|mM&iOyz=A||-w0Y5@ zQqpv2pT6AY702o8d~}@3{WVwM^)_$VI9kkawfV*3j5cq#`Mk|LZT{2dUAeb;&jr8A zN5KbeJ`CBaBL)1Z%_nU>c1IeHme8kdKJ!fJ@k8-d-Y?pG*XGMM-?aIv&DS>8@Rg_R zzqP1AX~TZs=EpWO+x(z4>G&#?%zkR~vsbUobjj=2Hgk6Pt9B0bN&}3_ySz0kbXc)NzfSi_K*pQv@X_CY?y!+tSLv{7hjluv)?v*Kt9MwV z)7_P_iB`*69oF^`Bx)IG$m@34pu>6{*6(!BQfYK7Xhi)xZ0MXdSoI~`xWiT*HtDdr z``XmFS*LrK?5ktMqEgz@L^*FAG~1YLYt+nc-{Ig6J9OBi!+>D3V~3qO?Al@H4!iWK zzvArHVfRpWZ82%~wAWr8_BGkN!#*L7;_uhtzz+L&I6wv-iv}ylfgKL&knmVEQjJmB z9@6RloXnve4(o74hd~_%JJjK!8j2vZBRdT3Fr>p#9r}7zMD;(~#!;waJG43+*CE;A z_zuH6oZ!}B#uJSv8MO=)Q`d+NCwDlb!zmq3>u_p^k)7_nMr*0$3{USc%00?OdTpyS zJH$Gi)!}T1l15E3j%#SHQsf?`l(J2_L#9KyL$*VqL#{*Kdfm=6*BXAYL&>#Lv_Vd+ z(xKj=+M#B>YOY>{jSkIFRaHisc8AM5bUK{h;hYYm9r-v1IoJHW4r4lu?Jy$*QRyz| zFy5^f8ZYYbe@vYPv>Vmd$A5#nOK~giuBEtZ+k1P9yFT2D7l%8UWRgrKo>$x+4#lCk zyA*j?aVhTd{pX+NTW_sdd+oE&KHJYeCzIT^GDtdz3{W}Ac&V#-N>Qp0(io&Un0?F< zUBxUYdV7%0AXjUznREOgR}OOdAXnJJE{`m{%CnLzy;^mRhu0cjXDE#~3^H+$8)bmv zZ{kgZ+%?F}gWNXAEvDRRIKe_B=k`JF801b9)h@aL7kz>%XOQ~_xkm;&o3f-^MfVT# zfNkrZyb|@0mp^RSZOfAI$RLjn^7J5&4f4bwk6VZeSSp?z@5;Of==?K|UGel|fz~>|fnKH;1 zgM2;6mxFv|2Z#9DDY4)5tdgj22l-);?*{qawcU-IWd1nFPhK^_8fE`4gG?Lp>mdIO z@|z|6KFFVg{NX01wjjxW4f414n(J1=<(EVeX8k`1nI@e2$*~)a=}e#Aa0bH}4dwgH zAuET>60%artR~JDvPj76A@haI5i)nkoFQ|CSx40_6V$4CLgo##jwE#oh%BE!WJt&Y zAq$3CKNqKn%IrcR3-@#lG5?|=%Y-ZzvSi5OAxl`Ygy_N}{-r{e4zq(vK1#S$3=LU6 zWZ97A!mK}wt{M=-3Lz_6vQ{1J54K%)Ih?w~!sh8M2d&ktLG6OUSO_)N@%9)HHTC|A>&0 zHb%uD?Ya{8^=$4B86C1m$Uw*#<<1^Sl$_l&WG@RBF7KpbAFtXswSr-RY>1qeIRNIVR-fkYhtm2stj~ z_z;CcW-F3%>co(fOi@xa{7C&jWNgT(A*c1U$bK=O9&*P2*e}XiA?Jmh9WpNDoRD*! z5!osEn(b!u{E&-6E(p2Mvm$n5a&gEdJ$^+)OD+q!F=Q~L6B34`Avwn<3W-DV#tVkB zQ%i~=Nk}QA9A^LQyt1Q5^on_;MUkl*7qJ#n4{3VXuou$U3TgMMNCu1l-#z~EA(w|- z?co(6SB6~WjLUuv}bvKHYYPEZ&_?hCmmdO&qE;(hddE7 zQ2_~g#3dnq+5A|@4*4+TBOBkXQo)ZyK5=K0uI@s?&q6*A`O=1c;axA{S0P_pnv5TAXQzbx9rA6@ z{_jG*5BWLdhaTleBR?6AQ~x*eYseoVzlHqXvrRdb!GDJQ*ljh^wNfrSk7WERrmvb~4I`@=u5PG| ztZ8Je9BbR2t|cmdNmw_>dY+Y#^^I(hW5XO9S+cB>@#5bk$4)th<=8UErd>8A+Q?=( zHqWtzak;4tt_W}C;ns%RLfIUV%T8qRkFw-G!+yijh66eF%rVCJ9)?|hE!j)eqMv{&v(DhYc5uHO zhvnGcxU?J~dyF5H;}9bU8_J_YjdaZr=ixbyFy%-?QT~sNIZn)Rf?ZG?B=e*kC)-E4)(yg`IZn@UT8^=%i>O1?!8mIywH`3y2I5|K&NZ=v8TV$yGV7$#HcqySNTm!nHZB^D3#34Wi%R$lvG` z|Htqq!nJy~lt6tY>w=8m4$4%mz>BSuGT6|sH9))Cu9+2?|7 z9Ig*V@wgl9ua#->>06Fl$|@OC9x?H`$X)kfH+fKxPQb+5eGyZ6>(t1p%Di~9NhEk z5St-^QgK+skr9VS9AOE=Y{`Hl`7cLafjTPK82m&7!Gl` z1W%3#BTk99FyhpRvm;K6I3r?g#OYCXW=XYNQ_RndI4jD2`JgCu(|u0Fc@gI-O}0lC zs%UjBKR@Dv2rUttREU02#HA4zM_dwR-9|;SLHGV2G3Y&_(v_)Fl#6IYL=okPd_*y# z5D~j(q*|4!)R!Dmi5<}U|A=ZtB_h=}^r0gL>8(Z7?eBROEBVccR+N34Gocs!PQ=x! z3bTzjyxi~#!z&H1GE_ZFrk-meu9d+iUKeqF#4Qmw$R1N}boQ0*n<8%R)tijeHS*So zJ0fn2xILQMMa3q6?~J%B%HB;WAP4Fz82PAS#61=$jbanjmcKvZqlgD0o>4SB`%uKA z5f2-mX!wZXxDi3u+Q%Xuk9aELiHIjXC5=Oz)2BTYoAf>#@m9oh5wAr&AMsMe3!Z(^ zP7C+tW89-jr*`RWn+pn7^$ejCiM~>s=$0E$}_#@2jFB zJ~ZA{q!dq%_&MU^h;Ji4iTFI?)84|*BD%}Ji1^0DFC)H+_}bOp4U`IA$P~}2B!qt# z@x6z_e~9=o;-_Awq)yiU67i22evSAo;?IcRBmVH#Q^X`h@UMu!y~_q1Gxu<&kYd4$gB(o>MibAJ_$K*NP!(;Otm*RCSq0Y+}}Pa&O_Oc}`Ot zJUh0BD0*k)IoCXA<~hsA*?G<}GT`h;l%8>>oR{Z(BcjM=!3#aS$navrOAIeHyv$H( z3iDL+_I>NH=Y<)R6_P8wb`<&mgjO$)$=s+bc{C*TY1{f zj)W-Sdj6efycY`B+AH$hnCHqo*XFq@&o%k%UDMTu3XTFIzpl$?N8$Aj<_(4-YWaWi z+-WU0<+(Y}ZFz3VbF1r6RV3k(aC@FR^4Te%0`4}eyYk$x`pG!*f%e0KSHJkJwG4)h@|ip0us)xgs>`WV?GZ(s5-UYN>a~m1nvFf2-ja_$LpAtoO=samw0h3QSwbicmyB)${ZPW-2g4ff)m(JNAx9(ENQru?dkF_Q($O;l?p6dV1)w96L3~TFCBu6Rc63lE1oTu2Epk0_&JrQPAP`n zaBWjyTgPAC4YBdt7ueAncW?&9xs!(GkyB$`C%YCHRbaOQBMa>BlSAk;+997_GPyN4yV+$N-%ezh~ zo+lJIslbUYC$Y)GlWm5iDdw;1{#oF(LUwSEEpT=rdy{i|fisKCC`*LgU>0hF8@3fxrSMy1cy+l~J; z`r}`--BRF=0=E{p-Bov+ca!dllBW3IS>P_SX-DYM+Pl>@3*1xS(E|4tc(}lQ1s*WZ z{UZ9eRSy<;$eEQ8MM+*vEbxf;pd?7O;9~`zE%11OrwTk#;7OIMHE!S~PZxN`_H?UM zm%!%=yjtM-0xuPKp}>odq~D~Wy$Km zVwNTE6!^Wsy9K_K7X>~p@Lqur3%p<819OT^iga1}sK8`rR!a3~?I#63FYsxB&&;X4 z-!)0PzVLpLF<%wE+*AkI3&gkB{~8#7&;b$baEl)4#W zHjSAvX1s?tc1Ni;|4xQ- zS$j|_c8%FDX1AE#d$x^;851)yraxv>OkbRxN8%svzA-vxz|k16Ub(YJ%-%73#_Z)h zicO!JMBgW7U(1v|dgR^yF-OH55Oa9UfiZ`~929eKoV|O|tR6XjXv|^Gqr##`a*lA2 zk5n-2j-n^C$Ei8Q92av;%(3>Ut3q}jA9I2!itvG!aFW6jb8^i2F{i|w8*^&R*)gZZ zoDnlN=JYtbb+nx+$vHFTEHOKb5-6(_!*gtg0y|CtQ3~vovL+Q5#H2A7##|C}QOw1? zS*?<5m&O!gE{n;<490|xo?IB>N{C|eu6E^Uz<0SgrW{j@DLHx)B9jz{B&OoX2$vb+ zug0`uYB3GVtoP#3v;iyF>~>72M^}U;ZG6o0F_*_Y9CJm?tua@|+z@kB%(XFB$6Vu@ zlnNOsE!V|duN`MIv|QS6jJa7FV{URrBvwQjses>NOEkPK=AM|_WA2K%Bj!%qph${G zL7Sj}yC-xPDyR3xJP>nV%>BJyq3mZry^eXvYqhEyw23iK#5@x7nCXu?Q)(BFdngOF z7oLoHCg!P_r%mhzP#!%S^IUh8Lm`1L#Jn2wV$3TsFU7psJ>7QeMF-4^-`HIGGF~3{mdA;QRsoq=UFZK2!f2-#g`A6Hcm{q&1n&5@g6q&Y| zbvC&p7lce-WVRwR6q&imj74TDPJIK@^>>ycvlg?y*Dap))clLgRb-ALa~886t_Uj# ziqG6d<|$@7QR)9^_p&N${ifmqF!y?0r zY*b{EA{%?THpmdY|0%MmWoq|Hh_vY0tjDlLkzI>yS!BB+TNT+x*)j8hj@Y)w6}k!f z{;|kT%0-bK9TN$Wc1`VEWEcD1l`Ivz71_O*o#twKf(quyB8L|lRb-E1b~o-T(r-lg zXd?qf#u#aj$ganG7TM3ky^8GJ1gOBch*VMDCyB_y{@G$Z18!8acg3 zKf}nGhBuE0#Cf*ya}3Wl9A|i*;rT@_Fe1)7Mg$i*(H9qqja*`QX_3o{IJxbF^%TS6sJq!O`WW4dqdz34R zTxtBO9_8*4!8OLO?NP2Xa=qaVhBvByjNI=K-E3SDxW&k=MQ$^4dylT-yt7D9;;tf( zsTzyfCFkxU4;8tm$o)m`HRV1-wIik|Qksw~M^v+)e21@&8Ixk@t$cZ%!#vmy-)07Wt?+ z^>0ArskD4ty@gO4=7izI63!=gKNkzAo}@k#CAjv1AG9_O$Pc zd~b@_)Ol3)KNk7D$WKLnG5u#-D0hA>@|!J}J>4GlhZ=s7Kh^x5vTpm5CDsw{;kqT(E3tlw$43O>d3i+e?ucN+5}PQt zB{nYc$%tTzr+ys~3@fpzVmmUJYh|SC-iHk-C@yMV)GPq%6FsejfiTg$dPmBzn9T`j-8H_HmM~Q(FV=Uprk-?WE zgC9l)dzRR%#6Q+D-Kb#JQNccD*tf(XCH5>7&Bk^m4G|ba9)UaLRiV~d?m#dN;sPUeX1cg!R)ReRtuPkv@iQ7tCUE+ok z*J#J-{ZEPOOI%mV{uETt0eyj>=z=#Yo+WNBaZ_(rz2cSxz=u_msG|gu2#!B_2?H>MLMF?Xm|;JXzwQ5|4N%K3rm=z0lMod0pa(5|3$H zdGE`Yu3rPb-#%p_-5&dl5?bQf5^t4wuEeV)o-grIi5E(|*y}=SV(K0*mw3eshqyN? zO|O-Bv&8Eq-mq%14R!Q{OmeSNB;PLaL5X)Xv?cG_S~0v=;{8(g=}ERpxP1Ju#ANe) znLkU+Qsyt`;%^)Ij~Y=K%1l!xC}(|MpC$zLOzWW% zF@2dC%gj*D5-0h}%S>fvE@xhdqDLv1)w6PcwsMx}*$w5AQS~X}N@Z3rv$E}3#c$}rH#vMQf7-X!^#XVv#HHc z=mvE8FK4f$Ha9%AFOWxDmf5DvR%Ny}Q4&P#y0EPyCdaq8{2j{K3!ELx>|SOk<2xJf zQf9X@yBgO*@#vYxa73ArrjIJqZ=}!0ba_Ur7|f(!Wm;t#Wt!&y|NYV~ z)A8<*WUUo_e3>iDTwdl1JGFr|s=BT!bG0?f9#y{ff|Ooc=DIRBmbt#n4VEna?hg8o znYH_rpqsTH%iL1t_A<9BeTt05N{&veJIdT!=1y(2GI!ZcsngWmW$y7%R_T%6`xLY? z_m_E~JoOEOnu)6Jp)wDbvpchLBrnAINSUY0JX+?7GLMyc+`Cw|DK*mgWSOUIgK$yA z|4f-@9fvMOP&Pbok6tMAq7hMED)X}OS9+9JU3Hpzz05~t-YD~7nK#RPP-c?+()*t> z@0EGG%)4dYF-5*~UxEI&%yjxyfWB4H??2VJOxH`TQ~lM3hLg*DU*_X-_UD$Ll=-I2 zr)9nkBmevdq_IzVeiYszyCprDsZ+Z_9jVAscuL3;v*HUgk%8@l%=K z%KTjBS7-beL&ZdF3h(b$^oPq;W-G#~uD@Kdf0y}3n>~SqAVE{zJ}EeD!gL8oJ8_Dz zC^IB1o6y!rfP|S67EG8qVXlN(5@t`BHDNZ-Y7^b<);&kUoJn?|$Pz&rGk3y#3G*b( zn@l}Q6!vkt|0gVvO#NP1Whu@f35zEzl(1;R!U>Bc+3ud;DOKZQNp^O0O4YT{ zmP)36`jD>idjFp=)H09g)$?)*8zn5CWGBlC32P^;n6O&HN(rkZtZb9yovhWfYLcBS zs^QfW)=XH#Ls=`mnq4c&e)Av$*0Ck)3MQ65d2 zChX;Sb}6!IpM?Dr_D$H&k)Ni=d_ck}Hv7PYgA$HOI5^>mghLVzOE}cR6(YHCxTd_{ z1&>s*NlwC1Cd!^i&7+MhGmcF-(SbTH;rN6TjLVWC?gl3%oGi0@xf8#tWvu@Fw}cB5 z#wJ{laJq0c|AccB&h+xL63$6D+w=+E#bVIfaSodFo|kZb4;RBQZ@r7WO)gH**Q}Q$ z6cR2~@DnamBJ}S+IKrCJ@?1hbA#y0>tRxRHj1!WCVnW$wl(bE3xftYiC83s(CR8m@ zTS<=+T~BEA@}kmGb7&>JuN^0Q5;_Sts6-R4Oc-ymGUoDxD=b8~?71r8+JvhUuCWV> zo}3!c`~QUNy+lD1o7CNyaG!Q=!W{`WCES{DbHXi>>@wCuZPMEkZdc#1N3vX$J5?SD zcPRp{hptnqsCyFbbyy}^oqW7M;Q?nxEa8!aM;&|}H1b!g z9#43}cFGKSq*o$OB|PogRyE3ONqbfsGvT>}mlK{(c)^}Z{)-7OnNv2%FfD&2;q`=9 z6JE0=a!T|q_5LT}P3=D4Jf%YRzm@QA!rKY&So;tgEOq})c+VC}yUY{igM{fTe3a}} zyDgmH7%EwRCj8}|+|7kd`bV9=lC@I|m5ymDOk2r%f&!vPHfvT6&QM|Q3Nu!iqryxT zX00%Dg;^?DXI4DLAY`@*vsb3}_AX`43Uir98pWX8%~N6i3iDQ&&veC2=1Ii@6&AE! z)sh5$pqD=t4ydqjg^emKQepK9i&j{&!eW)|)9d0^w8a0YTdKke6_&2BY=vbi47Eq% zoMhF@Rao8>877U|k}FnNrNT-TR<2~5S2pO;?5Y)3GpDlOrL0k5{Yv)caLo#9Ram#e z+7;HRWDQyTDu5yS{#SAwF-aD(frlF!YPW7&VaE!aRM^7C538_gh2h4fdb0|f+Xh*y zM`E|Euyuv4D%rhs8t?aQDs1QBwuaKUy_Qs_-lJ5pGIgg4BP-d-wR44CD(qfi*9yCt zqBzS`P3alY%i5?4dsgVHFi@et!szZ=cXF|fsj!FR&@Elb->bsD751*MPi5)}C^i+z zeiimNr+oSUNFM0a9AtQKg|qY<2E#)Q4>MGtj;JuM!jToul`j>>RyeA{2^Eg6WFJG0 zsc>9{V=GLtqRaICuW=!A=fn!9Rye7`$(8I_7mt>lVg^ap@U$L&y3|!Tqr#bvvr16` zkzZ$5ILFaYoHgu5NuHip;rvQ=JPE&`LaD-q6~YP^Rk*am#T72GU-Espf17bxg~3YJ zHzZ+#Mdd0KDnu3Xm8rKNMMhI`g<>V^`LaRLlhU$9B^7EFDo$uxp;|#cilG}}ZOppu zls#MPCqNZist~>ZF%;5K?t1umBbPgyn!3`%s|>HMaD$O+DqL$s4A&XCUK`EAZ|u?k zQ{g7#H}@zv^abL-Rh3`iK@)GUa7Tr^jo)c_m*E6M6|?y7sc>(F`zze{KSa?V=nWq- z^047V!$&GS=H2nA;d$!+rVG)+Co9=uq~|FkPa8gC_-uvedb7_PxkZgsM}YB{D!kmA zeWk*y#$W4EUaxScncuANn<~7*;b4@#gcms3MimQDRtlox7h`IMDXR!CVfo%-FxL_5B+&DKK6Uo~Z& zl+{w!Oj$i;jT9XO-S{X4Yo)B6W<7R-6$!2@$5YlzS>Hk=uxr4Eve~g!w6$DNmT!_W zEM>QpO;ff=8E$9C>j+4*lHR;G+%jeRl&w;>P1!nS8`B@`3numjPxb}d$zMx*t}oa@ zN>g@B*~vUF^aaxLvffvx?3yyDtB&pxX5KwzpOg_Pqf0<Ict2OHVK&H96jQZ80T`h!LE zi!2i_O}Q*Za^&V7k@u2M~=TyDR{8!DAoq+FS1C$;z$ z1i`CQu1mQl<=S2Z_UsS#=?|{=P+sicAKaL7OUi#zZt7{&!kd-i{@~F5;MSDeQ*QIr zF*ffGn|i$QyHXxWnUL~;_E*ZiDff7GtYdXw%Kc8?S^dG;{aIUnFy&!W9x|IK6TRJ} zQTU@NPp3SlkfuDI@`QQD^=B_g#h~Y@l#4ukCgu5*XH%YYqqxlK!v5d|FR6O?QpzVO zFDoD^ucW-0@@h}%Ybmd%ypd8jXSX9M+Ok2|MzZP#Rh+x@{4v*$~Pu{p7KS?S1DiG64k)9{lVA9 zZ?J?ZDc`%IzU}5ThE!Ronq8;G+!eJ*mBp(pT4k~7)VsPms+#-~RhFz~XM`HEC|bUBm1U|^-`)(B zWJ_4K%5qhfuVyzoajsyxkQJ*aFXCBQLWEaY+j>_uT+MKG!!@d`S!FHbGHFZqe_6Or zm36DxvM#)$AUkR3263X!}0F0_EeeRZgj9FRzZPa=eif3{NyX z$?#;ui=7v7s?tuYQdMmAF31r(y~-I?F0FEAmGhLcD(6_^+105xfpfJBs#E_`SOu@D zIKRq8RW7J<%wQdPKaeN?c{IN>nARlB;HSelh56u$; znMEm9Nvf2plx;&dn_5z-lB$0ETNEW!FKla7uBcL%@%r-DQ%#pjOChS#uF|oO-JK-~ z+ZtulSM15ktQ}M5Imj$Y{M7+DoJvLSRqDaeqRi5yw`>Q-)0zpC4I@TCRHgMQy*zuU0MlrS$hIe|VMjYICW> z{8eSz8h=*_YW$;uuVwqL>;744+O_P<9kB^cS7XK+)7O~6JW9O;s#IpGF>`I|9avhl zcGemz)R?Wt!Zl{EF<*^2YRp|@&Kh&ovfpHOjZv)TsWERYt8m%h)jNNUAvG4Lv0yDb zIAo_B5nQO2Z6evM_$*RmsTzycSfa*aH5RXB-9XFr$f_l6jF=U)rE4r(W0@L5YuULV zqIAifwS5HEOJBV}y5!Yu8xU zHmp<2jyCCCPi}gZ;O=^v39BM&Td*`xGmIL$&}-p*VwAY7B#js zz3ZJC+SWC;sby6m%ey^iyBhs9wy&{kjU6Pm#*Q_165cCCA-mXM1zD?ht1+_1?lnf3 zsLm#h5;&?xU(eGn=ja;yNLP(LYmBL}hxw&c#%Rf2HTLdBUPBT0t#Lq&{c7xQ?eax| z)zpDC4pR1e3&nXzja-dGYaCVMFf$)+c!c4RhW|2DC}jW9HIDI6_8(j0>>9__IJL&{ zHBPE=LX8u9*;G+!$;mZN>3OH2n&)XX&ZsfA#_7FKY~W~|S>r4hjCjPUE5SK6E~;^^ zD!<0K8t1t_H6^nJFQ{>0PnSHBJr~!wti~lZE_E~{R-)wlV2!Xg_1kT=6j2oF$X?_v zVZZ|88pRsd*C@%18s!@G8cB`RJe3+sx&&5h)U+=wXQBh!sL`&`tkJ3=28Fs?-W?}V z)=K{P8dul2+$D5HjVtX-*X*l|t6Z@w;4XEPdfSvxW*g(f&Rwrt{V3!CN=J^@pgak-~M27fAC{}aBq$K z6fvD^qXWSW_4232M0sH$57l_s$SR{VX)oye-x`nCc(lf2rf+Kc$kEwXrDAx}#HVV! zP~+(u&(?TGJ3{qrw&!X*@8OZ7gQK)$bnv42Us64I`7nJbt})5PR}EjQ@w!|vK3f0y zPYuDQ5LCljdvAo6@YcgnEdGAeb0(t!w+kGQR5?1CL4J>yba4OZ z;CJJH7)s-xM*cGV+wcP=rOrHcf_m1Lr>SSHb=o>J)|sxJUBaiYXT>%{otgBr$6|@@y}alzB)_SnZM4W zbrz_zP@M(q46!=#sGeop!gUs@XWdUrw4v0=7pt>moyF@cQO|B}U1{2t;$Nzson>NP zrq1$phSpimlx6GLr{D?Zk(?D|cAXXLtYiyCS7an=l{%|h=2(AgAepPz*{aSOb=Ir1 zW<9$cu4TBk;W~!v8cM8Y*RQjw;!tPfIvdv6$i7Ij_Nn^JCUu6@v)8u!_beG+XY+b? z%xz{nrFV-uTbd$Av{1HfZTZ_6Zd<3n&USTnt+Rcdo$BmRXGimkQ$A|d&UJQ?YM+}* zoDAEo&d55u*BN2&x+kyVHmXjaBOpauE6&l@GGHj;7&+eS347MrOX?h}y^ZW+xUb=U zhWpof)b)Izhhjd+$iaq()H$?AKg`JC_3ST>#dc(!lVnM6_9!Dq*Ey!n@pX>v(T_7C zJGJBl<0t+P$}!oqU~h>ReLi+&UN58CU0g z*Xnt7o*ErIH#)e$!{x6YKGeuK_bv`qv@LZk9YlSP? zg*s&q<2pqnB9?j#Nu8?kiecKLch}ZEY}C2DPP0y@PRknGhLR&TJ^%J_e2;iVoonk{ zS?B6HSM`Wr*t~0cL#@5e!msaXyiw)kaH&pis&hx3o9o16kJWj$&f`i)ohRx%Y1_1A#Gvwiy3RAUTogTOJI~d5vCi{#UNBt}bo`0)r8+NL za`(cZ-TG>s*&Do8=Z8A4*ZHu{8+G1RFVYd9j$!02Ls5Pi9lTTLy*lsqDE~F`hsvNw z`M}8Eql1s?d{t+1ozLrhT<25MKdCeAKrq8V@L7-lJl_z$sPm;MvkU}t3^5GqSc4sn zEYYJcX=ImyVCe=cG+3s=at($yShm4PbN2UiEpN^}27(ohtkhs-BYO`72bgEo1{*e5 zP41Y!dV@6@tkqym59QsV1Hsx2*72~L!6OHP^*mhPa09~=EN!C(o61vDHZhchVMb0F z2!D?A~BRW9q9pZ9wgaQ4Pj;w$HG?!RQ79ssV2$Nzf6nM}z$u?Ac&% zuidMW9Rb?8`!v|sW)E?56X*U74r*{fg995=KT*mm?XrU#9MYKjivszs%_yR#4sURT zD#The)ZYJBgHD5^8eG=kXoaG|F%3>?aBPF)E%UfWc10PY=HKAN#?+rPU1WPsZg5(I zQyQFV-(}BwZZcyVoNh{XGWvHxXUf?IXEivt!PyPYv0vRYQLDx^IL{QF{vs*}7c{uI z!G#SjYGj{zC8rzPOB!5i8|1 zG$=PntWj)|F9*{GRdY(L9`WlmuQzBkXg9Kxz1g5;2I1nDor3>vaFdDS8(iMt`UY1t zxZ0E}4Xrv9y22R@di)y@F#7*A}{*WCO%{Mtl@Kp&znaK3gC;TykyD{-TxcBW!qjge67Lj zMil=yjJ#<$$#6iw|2OiE;k$FCNP4@%j^BSIh4W z{_qC>)5E_S(ByC9s-J%vbPFtKW~J4|1*dIh^yv(zZ!&|C84YJL)a=YgINJ!)z1P=hBUJsy**O}1$=yqUEWJ)1SzyvddxZeci}fB)IY)`sewQYy}EJ>0Iz_C|JS zvXhY=?YkIu_Ao=#{EhF{WR#KJ4M!M`H0;XkvxQnRy2*)62Ab^M%y!?HX7;P>J(}#< zWG~TuzY<;H-KWXnP4;baP?P8~cer|wQ!P=w|ZW@ z)8ung-j#Po-fQwnllPl^)Z~LEAG#ySm*KW>a+8mn*&h+eQ^i4Mf9h4A8FmvVEnleK z%>PxBZyb%UT>}c#6eGH=DO}$*`PG&1eUl%IY@j2c$xl7}=O(`x7ym>x|0e%5`Q4O1 zdOUv``AhxZHb{cD7_F>12ZlnXF*2>;bcQm1hE~=PW^A!sicl{IkfQ_arZVv!c}v{FWEhIrLN zEf%&w)u$fGS+vEHo?5KM;w_diu9WE!!%{7VwphBwGNwz8#L9AQgk>#9_Ul>RhOJN*w2C5yTv{&_HAW#tMuuS8T)(c z0EhPjNB*D|gDnnjakP~lVtAglAl4D*JC z7I9C)7Xv}5MYBb@McN|isjIY@Vo}u=brWkXel$g1G`#$`fuPl*ZCn~VEyj13oAS4r zFE>8znBdA5H@3K{#dR&NZgEX-)wMmO8^G&Z-0(k?|FpQh#Z4`4QEl{WlP*2CdU%_e zXBrdSVMIdiY;l+I*~esgR7u?3;+_@{w76Ggp!YwnCDHHqP>3GUA5vFo^Kgr=TTE>6 zQj14gJlEpU7EiT!ti=;89@if9b`aF_WGlPTP0;1v^k-T;>+PdL?b5~byr*7h@uKyr z52zcw+~U0!ue6xd;?)*!w0Nz>>%ER~mcMg3V z{6-D7&6F0uxA?Zj5BB9dNB(<5UCe%L@k@)JTKsH#hS)(#__f7vt?U!GywD^0e`rUy z`Lo48E&gipx3$YQrAhp>3EJ6hTof@YfYY{_q0Mw{rf+8rTs(p@Y{oV-wWkJ06bYZD z&5$;;wwb5RY;ERjGkcpk+Sx&%?$K2-SDU%pS^5sNM#-PI&HQcVYoorcp+0*q&}KpF zQktZ0oG$-umTa?do5k8J(q>W1RJbHlJd3wkqMhCGWQHCgOSKu=X6ZJ|w5NVApa@8m zrj~7ItyR`8-)0+IvO=2`+icKgr8aA}S-H(>ZB}Wss)$}9nQ~$EHfxxo;Y8EdYO`*e zwcD)I&W=9`mt^H}J&BbZ+a`*#vtgUf+HBNjSeuR8Y~oqPP&^9trfr6|vlB!SkVeVh zyvu4BorVK5Y)Lo%^=g&xq*z8yRn& z1C1Zl=HNDm8$YDYp=}QPA0BZY@jt_VwK>jNKB~>pMvgI5B91j8?Z@{hC$u@Sho5BR zf>C*kb&0THo zXmh8%R#i{5;}hhL%GmD6e(Ac`GVe3Izs&App$jZX*x`6WV#MB8=2m4h7L1!n92BS`gb$@Hg%Q` zb9R`u!|WZ#>LY;RE4u%iO^5`}W&9((FVgRSIxOE|-VRH3n6Jaa9p>+3hs6RNv?CVm zuuz8~ove|{r0JYQ(HH4tH`PTuEYV>xr^C7)%Gykb zdT%Ey`wco-C)u#WCLK2FuyH5*a3oX3pxe%{4#Ul`siExIti$FGf@Dtee%Z3as193o z*uiFR-C-Le+Zt|XxV@p4OXH3mcJ*+lF0sQdM!G#vJiB?gyWt4Kk=CfGJ`aWTcNpEn zy9>v3*u#`P4fpEJ?%iRZ9=@-PbmaH%Q4Z*EV28s!JgCFLMh-DNw8LQ?7WMtGtKx_b zM|!+#kbr7SyBvg())$C`MY;gUW22_Bx<;UpvCJlV)8hNpHoO{J(}>+#D-h4&0+ z{LBt#bvV!X*&WU?a;~9x#;K&ue14B|fsqRhFESLvB^_!VF6~h5a9M}A!(fM~L)al_ z9`$6k$|3rRNQXja>TN;IP^K0;Bppf}%HA4Ms^&jIpZ+?ej;GFU)r^+wqvd9L`QPEH z4h^NOL(>c`Lpjwp(lK0ROfbGjzud?b9j-L8#+dAz+N0lQm zqAjmdQUCAoLWhStJlSDlhsQcR(&16tqX?)@6tu@XJfT|hT}y$|R(h(#vmKu9@Qm{% ziX4#{&vkgdlijSeP{V9L>J?Cjm)v25zufaw&g%Ght;5G1UN`ZL4*%`&W{0;sOzQBK z<;X&DO6fZt-tA;>L?u>_QuAJi4?Dcy;REkw@#vAwA9a{4QMO!RmocAo__4#M9lq)C zS%)t>eBR*;cNi_{8vj*?uN@^(Bwx#?bokDcZ_Oz=-*@=I{%Tf_g#Yw^OkD}MO;!8< ztw?hz4Vr{VnkeEcm6WLXXg1&3bh-BuA{t53AZen}IeVXBpR>>2`5oY1}bU# z8mTnUOe+81{vG@O^gR1{pLf0Mo!7hGwaz}rwHP}WnPgB@NDYX=#KIdgMQE2IO=4&j3%?F%8pED3w1}Zu3wAjuQw5juPrwQ36hmhrr$_W&Lrj+#dd1K+hI2(cGY0pdIWLBuF`O@dXpTHg;{`EX9>ay=?9F&% zxG08;W9Sn@-&lB1GBmClnJ>&3wIgY(GacO&=@LX7#2fW48vm>5es(~l@Ri{FOQ)j zqA&#dRz>j`s$-~;CuAd?kbaI*Q0$5pkUjfHZD}?wsW-r3)VyG8RL!6o*PbS7N zDTZsMghbk!9K+NYrbH`yoe)OKscA7>ui^A)b_Nydp2OK2W4I}z-yFj&!f%ZzGh>() z;dGw-vtzhjMLS3Eju`HWVQvg}#=`p&L*v83W|)NcM6&aQ+$%U=@IJu>g7-(O$zpgg zhKFKkjN#!J5-}`{;fWX)#qekhk0`zLfyy6?;c+cGaoXixcru1~42!8stIQQAkvy>pX6K_ z!>Wjrfza;DF|3VYbqs4_cqN8cRSayxR8II>46jEuPiIJcBZjwQcr%8#x`4By3&9jY7nP_ufd`5}fM*_Vcy-ownOVdmOlW?Kw@#PCxLzsB%$48O#% zV3=`-nYF{ryTi1Xmn%zH+1Ej4aLddCuL}?xmdm~TVL*i%^M~gU)isR7u?(Yi@i{o(N zN5s)m7P<6%j*Rf5<2XhP)Ol=#km0yE&WNLR9PLGH6GvMioH|}eyGX+cahwuI2N6$< z<0K&+1*!Ao2%+Gqadgt~w20VQ$m!9LJQV2?M^`G3<4n;>>?Wl9zu3--<7^FkL_8Ec zH;yagI4_QiNqnW_!hPL4;o@g#6TeQ5=0V?E5d`C2^S0a zSfZ1YX9P7Q;z){8YJ>DM9mh*?IB`4`MUx;Z)0Z9mG+P^}O^@ zZ845UMZHvefwq>!@mw5F$FYn&aXcgOQr{r|@;IK2hbMle9$qzLY_E`QCFu`vr$c9s9 zzKi1rQNEAk^fJR@_%V*HstPjG0b2hlj^E?>IgVfA;Y%S>evRX|IJ%da^UF+$?GGv8 z)ON+#tIYfvhp|G7JLC8(j$Lv59mhZHw|to_DLO!Huy*U*!@}McnpoJ=LQ@HHmg3DU z?4{wwWv0Ib_pz|Qg?%mTXN4!o|NBYJ2UxgDJO^1g!9sHjM_D-7!Vwk@v2dt`7E;AC zmr{pWI9x-nK8N(DrG`X~w8H$5c(jE!7LKvd%EGalC6SIDXQ8!tN(o`2+FEF5;dm=N zm4?WN_7Ojw>|mj@g%d5DY@uUBKS|8gaEgUfMf?vh{}wt4FNH>Ux`qE(IK#r37P?sI zDk;)ggd@sKHw)dZ-QRj}OVYiwESzKEYzsZaNy;yxpKIYfX)Y}*>E~M*WTBUZ0TwPG zvxN&S^bt>Q!Hc2{_to%X3ztM1$`m7&^b@7O;C}^aZlHxLg^2n~^kkXd4i9Nm7C(KXb++6Lt6H%$?Jh+uT~ zibhvjSfv#y9S5YmY~fW4t1Y}@g>S#9hvh-I#=>h_DZVQ!t=(D+A6av+%oymGYB$+iqc(g&h|Dvhb&cor;3i=@Q}J z7XIPtMCORVMiU#x#vXQ9Gi=}_(zm8I_O!$DpsQ5N9PVY~FdKW@IMBvEHukfzuf6*< z7yaMg#sT85)qi+L%0V^`vC-Vd!4bU_V+$LHiW2h3?Za&xYvTwTN7-m;<48L^Q#eb1 z=*-bJjuAiIAcgc+Hrm)Y&PHqHij9W`|!`cd~K19pl^oOo?BfmT>rH=3{ z8)w_$U-9BHQMQMTb8PgoajuQ?BEg%;|8a-oerHhSB*Na1h^s3bhH zHCx)em)IDj*e|uw&&K68`r8=5ylF*xO5s2omq~;xNE6J`6*jJt&MU>n7J9XfYv`&H z$Us6*Y>bwNLu?GSQE6kCjWQdrTBTx(;Jz56{Fmzbuf z*tpIPKbDr>36L_)#?3aaw{e4w={9EA;ce$XdZ_0{8#l=oH8ZQE++t&vjazNZjB-T> zNWaa-Y{g5wv|;DixYNcRHs;#lUo4?c(pkWFF-vOW#P4D1Y|OK9ul%P!^KB$-+-GB< za<#z5{Wc!5@qmp7?eME2=93jdReT;+bUYvy*?7{%BQ_ql@u-c*wAO>QthD=tT%~fp zxLZsmnvDsPXxXrZ)1Oi-NgH_^DH}N(X&YG^j*X0>V-mHOLS| z+6s1fWEX8LvC(MbDb)!@_%KUPb0H+fZPHSdWi~#rvE0U6HlDSy%Eog_%L*GWXce9p zKdryWl-j#b`7rrx&Ng1P@v@CqY^)X=^Fy^PGn!jtW37$XY`kuxyv$UTnaVO#Rc79> z@g^&<%#12Cb!Dc$%)D*mU5T%=v0gD!&pX-$w8H$nXJdnnjpBLV4sXKrhjd!`P^HD; zM>amT@u|c=5&WNWGO^5jrks3k;|u9zeyE?aU)k8KU^gjCBz|oJ349~sw>EyZvBk!Z zc6jc5XXAStKd{2f%l`n%FI7DcG>v4%xn?m=Q1-(r{Nw6 z?3qB51ezwo=E>@6q5^1^z+Q=P>AAA)l$?DMVT@xc8qvVVx+W=K&>Eg z?iZeAmnSedfh!WYI)N(_xGJ&xb2r-{7~zl(tlYJ$B7w?8_}9Ye6=Nq)HN#PuHG(4rM+uG=9FxFUIY55e8kfLC(Z>tc z3DyfX2u=`O%HRJaaBl*W61XLS$q7tPU`hg06Sz(c41~c>OW^uMcrT@LQkb_H3EY&x z4GG++7};z|XQVeP7T)10b!!55Brr39*$K=_;5Mb57E9gc_5|i6!r%8YIV3Xnxe45z zz?}))B~IGnLtFPGFfR&?R>(X*fyWZKFM)>=SdhR23EVFRrj)s&!Uq%K9it_ie*%vr zurPr|Tr9~_CpD1gQMvjb{^PF%>;#^m(FC4MU~yvi3)s@?#1pWT3VOobN@5~`bOOl) zQu32glgI^i#76uBzW+~PZ31orIaSe2#o{I4C$J)cAc3b7$S2U4Kp}ymyk%NSXVy~* zED?oH@?l9VO<*}G2`p0umR5oA*#w?Tgg=_1Z#4<$_*C=#PXb>g z@VOkIle75#CxKs8XSXY);^Z1insS3;TZp-zIR3l$Z2>m%#UtW7J9Fj~Z?j zEb;s#{O5@B3!7xQXqwf{Vm5>8~+H| zC5UABN6biM0{2LU_oXI+O_SJD2r12yXjg8C?43l*B=$+-kRd(2kRy`e?}#`&GKscH92LzToy0Lo9H-&2f~^Eu8?A-3 z5u_j~$0u^voJ8DnJe}UlI$1oTfVoc^=U4LBTF+2oEbW3k4SmK9aI_LLO(~iTTMS zK1^b963-X(~1fB%`pQ=(K!u$1AaMOn&H5pkJ@%LShmWU-AYH!G5O zD~acmcv-|3l6WzRRY|PW@Y=|emy(zye0379CGkoUYm#_XJSB6?A(!v9FN zyeWJ}xp`a2x+LCDVto?tCGk!Y@2a*b&gZ6bvq3y1og0OJAjsLl?Eh?@Nqn5dH%WYw z#OIp&UlN~2Jf8`fRc^iz@?{d6lK4va967T&iLaBGS8g8C!9lg(Ch=1eTg3BS5u!keiP3xg1@pqX!iFcb|mpf65F{bqR_;$a`R^r zJH`2YxmhLp-$@*p!ar>6DeU4@3P^=}#|W;DWSgYWRFv1`aI+NlO<^xl_D*4+6y7cm ze^ExkQnl}w!u}~7kirIO_)_qo6pl!tc?vBgcyJ1b2-%|9Lxmrf!r>|WRBm>N$RelC zmMI*W!Z9fvmBP`f-8X#FcZug%2{x@T$ECn7%BQuEHiB&hk58dpG}~TCTuq=uD(uN8 z3U(AcN$_OBQ&Kop2zmJL@jIn(dI~-H{wKBj(-7O&?fmjLg?m!yn!+_HoSDK!DRfKW zycD{p(1YHlaJGCtOK`7>@T$PL_?(l%xgruLv1bYwq;P&j=_O>}3UgsZ=`Cl-+=oaC zeN(tJg^M+NiQxZh?w3OUNQ%S(DO{eyKv6D>=*=t46)9Y$;gykQD!)3y2c0DuIBc84mW_$|uDb$HlimM@o3Cyhwl`?j13OA=PDTV1N zOip2H3R6hKnl96QZP2a70N9rbNt;SYh%N#!VqeA*U%X1wV48v=;dk z8dE5wP-JKlWbDg?JSCCmE6md=yq3b!6jr71ObRPfSeC-Gnq4mVQiXX=2xVWXFwdv( zqJ}RBu9dcxDXgn7?+bq^g_l!!HHFnFyds{DMK8IuMwHJh%0 zXQ}X-^mz*33Hd_s%M`v!;cMZW=!qH#*?9bYBmCPGwxo97x=Zx$#r%Wdk170?!d5y% zKiMAtB~IpFQutMD)K-%HUBf^AMcl#8nZ}=Np=s=7YvS)eQ`j$!zuDN+_$LLE#x6Gh zbohFKZH@6#+a75&Nrztxa#*?81AExp{(>NlH!_qiBz5C9;Qg&OWab!B| z()Cj&A1i=o1B%YW?#|S@( z`C%#Y{eK#lrEzK+z0x=>jjm~QlEZYMa~h|o(M7{EWQ9aNv~p$|=cLgsjk7e{oiLIz zmF8^WJp{>2k#mKgm&W-*dj3lrgS{Y)era5oMqkbLPU9jW6zn5T@?0EIF5!v@Z&n$$ z;{Fl+zd{BG4&?G__VP4_rg4RcSEg}I8dpX9SO3e0K_U)LV~CJ_B|9wQ9G=FA2ro;c zJdKJp_7hJj8&zqHQB_n6)(DOi9F-3L9`9&D*1%X1YX!#%ju)&;qe1mhA63PK2$|0J zKWWTMV^SK|r^8Fj1o`Y#tczz5WG?FCP6a9`TjqRIceOQ z#%&_bOkU8tE<1pf z&`QY}BJZcMDUFS3e4fS!X?&W-hiQDwdf-O@LE8ExjsMAE5>KlPUz>jx4LSRT@Gk|w z`WJn38b74*bsAgJ_(lPe`CBp2F7fZu_&%bO@?#o5r?EASpVHVS`cmbg#7u{OQ6_&? zkLB?9G>&%g2ivI=z8~J6#twFD2Y;qv9PDJnPvb8(f5xQ_OcD0*U1`7x-?iR|s*KnMFc*iW|h6(<$$@8AGu_ge)<#CCU(gF_rN zcW|&1t|MQc@}ywrZ{grjCwyT-S80^8YrYh_P9$_bAc8YS~FGDo!> zwvsc)IcP7WwSzW7+6vOoL z`cMAz9Q2eddA2H7-0Zy^T;PO1{NQt;klut5rH_NY!n;-)GF;+>4Uo^J4*EH`OvC;T z{wrjF;J}C{&iDVquMoUa@G8M>+6C8W5eGRK;b5?EuKo}qLmdngGF-3+4>eUwnTF+p z6@rxxsvJ~1I6vaKs4{$ENb92p?9-~M0EZ4PG33Y{!1=o|-kI=I8ZT=~F~E?Kd=R3I1!9oWM96adYeg_XY;q8dbOeURw$ic%5Q@&9Nom}MLF$a%0 zc+?5c7c%$Mj(FU`6Ha(TV+iCVeX$ZnqfA%aLE3@kAmzYz!Y@I{kZ_RH0)+)BCFFD* zWRwjG(j2w94!&@ZbMP{EG1rlQ|C3HS2pkj~ zm#D|mTuc7aMuo>ne;4wH;C8_s?Elg1P9Xy;&EF2XXYdbuS_Zou9F+kwI3NR)!Co2c zkwMc;xU-sM!fydCuQYpR&@6-Dm8PoFu;52mn!PjFH-mjL;c+mo(oCo{`(?0yChVEh z)M;<2GzVsIXa)yma7YHtGdNf}=Tw@z#Lz;+dn(QRN^@8SN6?nEQ6Y`C%;3mOxc50M z!J{+ikijt-w8`Mu42~0Xs|+5lG>a-t>qwSvx6Pn^2FGX6PQ)iFcmFAp6aK|>B3;$6 zV+JSv%g`wqoF@9If;8PJgU*?76Va1crAg?xKO=)K@}K6q3OO@_ZV@G`=KP-w&JyM9 z3@*u_M+O&Ua83q2GdMSc^OzZ}UFmby`5E-egnOJ{-Igl$!VLOk&^v>Rq=aeb4y6x$ zGq^Yt_Bygr1NZW!8C;%0zYGRs(4WlmoQ|q7J+0C ztxsqF&tP;W{FUHLc|InCv0|&uU_u7tGN{X7Jj;*w&r0)jrK!)LLBnS%&GJg~Y^9kf zelpOpNpgO22D4P9Q!=Iea5Q|x+2g?~wEy~~#DWrQ`XrB0wu}Cs_ zJcGpM;t8ihY4xJ2-2!KH#PSBC#l*D@-}V0i}5YNc2V&nc)C8NA4~ z$lwK~;y>T5#U#+xmos=f6W$(IXYfh}ugkYr1=k3^R)Upgt&le|cq@Z9 zg)^=<6as@~0=Z?FiuD=1lfnNocsGL&GI)<}u>T9bFSt>VL~i^Kg?|)LKF;71;nYk9 zKA&p%Sq7g+JYQt+WrV*|X*OwVZ_b1l4~D}Ge8a|@!M7Rwl))C!zsumq48G6c2Nf;z zKxX>9HG^$z0_qhlwZE9CpELL+gB=_RXSc7JFr}XBN$};lEFz=X~hZ-dXIE4bKQ# zp`T2`epwut#r|0wkPS}(YM^P(9+XA%Y`AtDl1Pz5vN$@67Fisc4X+BNpFkXz#o<}B z%;Jb_*sRD*wMS-gl)U1Q^-p*Vm1l8mHvFd+t+HsJ#c^4*&7yS{ZRAfW543W87VQ)W zE1X1{J|T;aS#-$a#B6x7wA7E>$azvEIGFE$vfnz`XE8X7 zE3&vciz~CZDjS|S%nw~+&acU0kTlRAmOXdMkSvDD!=c&m#9{u2XE7ohHdW@0Y?LaO z=87z;vZ&M)vrRf-b(GkVS&Yhtzk?;6YAHJ=i`iL>Rc30ln32V}ET%BSSu|u(Cwjdg zJ>l9-$YN3!6SKHhL~8g^o0`bvEPkmp+bhj=nwpx$^;t|4PC+tE7rskJzztd4oW+fz z-1IM=Te6s?;jJt!Ax*2o_i48YXR3+cp2eLS&JnyLi@8EdRtWFX@NU6-vY032Ucm#T z?Y=DT&tgF~JOs(lY&?*Kt>J@NJe0-bSv;J@BUvoWVi8@^4&nmwIDRyX$COVdpQ}dk zC$flT@njZ@v%BB2k}aIg!V-l`uvDD%pIegkOsP~BK^EyOd}(v2ghxOYSs}#TEOJ~& z4VgVYBvJ#Bd^UV_z#;J>-Bvv}X7QAE!ICVV%i`%QmeD$=6gVB=m4@4Yc^1#AGnBld zh80=7n8ov1yr8n7ZzXS6X0a;bBpdl(&SG^oyf2aG6&Zasi`TMPqv9+T+v{1Zl^%8m zCV|XvDg=tWmBriS%wk;@8?sn0$KH{ice8kpokv#Ki)ikBZrdz2X7M3|rF+uGg`gWB zX-I{ia39GT@_(AecifLzY|i5IEWXO(i!8oWXQM2cnRX(ZqOSOL7F)9TCW~*`7^}jc z?l8C9T;!x1-)FHciyyN1F&o}FNoRChwVGVPpR)Khi=SEWT02r!%4fRqTjbIo+QOx^ z-oY;I;?FGhcCl0O{*}c)isEl2fr;A1_U-~M_He`gZv?5ZiHoLgcn}buE;oobbHkp$ zmmB`A1IiMw=8r$!u!K0vUvsgU@9&1c?>fN6fi8}5agd9{T{L&m!o|TZ4v_{j(^gBq z|95d1d7>y7>=7=Ga?#Sok#1PkB{ssNPcor_j3+PFB*MQb-KOX{RJVOtl+ zD+=O+MQQJ%gD5A^8BtDj(NPp8pUO)meX@&Fh~#Mya#od@ z=wh;qYh6qdrEitFy2=cyGE-b!C(6*O@GSvFrn$J?#q};`x|r_bM$OJ}af1*tknJWH zx45`jl# z?0gq!Ac44v7 zT*NheT+B~a8Cwx8t}>}AlXMZdNV)LcuzjUnI4)cl85dbMymYa&ScI&ooC{BaTcdj8 zfklSAi-PtVaTYV{jr+Y(_4bsDB`)4`@wAK8+_|hV>U8m}i)AjBOMlC#!$0R@g(xev z5NuX2xLD=lMHegG@J>iKO3u9G;$>|U*6M{~e#OO`E?#xLfFj|LEc;7h7FyQ$)1*j!u)GUHl?jOc6Ctmm9yi_?;a)hd*5W z?P5C{zKb1f{*oTwrOq!$YKQ2rTyV(45pdM1VthBO64oz~qJtu`rzh@46=g=&N zy>h$jghoH$_rE#pn+wkfvQYyA**}K^b2uOu9uw^p1!oV+p{JZYIEUkMI3$Obxv;~u z5Ii)8!-O0zNcs^uELQ;^Dauh1{b(V_|a&iu*L^ySxmc!{ebjqQ#qAt}5!#smLIdsW|#}A)N=i})|k;fe^qQpjp{(TH+Q4uf(Srs3cm zh6ouN&9133!y|k|4rRh$la-1bCg)I@LzR4{(Q3`sVO%c!y6255Ls%yzZ&#UhRi+__Yjc>8!^9lcSDAOJ%)3?Qy(%+FJR8J6 zC5PEm!hZss!_*vZ%3)d#Gjg~-hv`aeDTlmJ-H^kLx$x9x!7$JC;pQA>=5R|6x8}lk zU-Xj?-J6xeZMpD9#8}8r<+tZ>cMfxMn47~Ln&MWak~?#_OTm^7aW3dRIn2*tUJmz) zjTCBL%fJ7S!vbZ16khEv;{88|Ob!p`;N-7j!#oDaylps-F!S?x->wbJ(222RUrY;X_S*#HCa%eXPR!B&y_3 zbNC{M&vN*jsnbHUU|O>O=kS$Qzf^l{>2!%xU+3@*OG_2S;-MQ`a`+*K?{fHFErl85 zL(U)BNIh)L;h!9~v9agyQx3o8@N*8oXhTuw(o*x!;rFN@Sz0XG?K$ksVMh*ssw2?{ z63PEp4u4CQosgWQ>|$g001r((7!P}R;R_8;vF0h#)We=$xU*<`C!;RU9Zhf_Tq=ivkotvwv?p^b;O-tO-KOYyez(B9kq5}4Vh zOC3C%~Rob2HgSs_o!^V2+Z_0Y+~=^i?3iaDW@Gdy&WEZwF*WImI# z9=dtxE?cB<1)1}+1Gd$FJm`qL&6FoF|nBXB@ZQN>8tTxN5&9xpTd3d?nY>?C^ z)nK&9eS$wfU>s>{VlK z^)S;z^BQw#jXAo;99Ls*^DxK5Y!A1yz-mm#nlLAwYs?)U=1TVb8gpTd=~H9wqLUu( z_VB2OdptbgVV;NkJlyMHK3Ac}46ZTN5?|oqe(tFnQ&(eV)P#XQ=wYFUhdew?muk$s z8uNhYi#$9+g_3$wl*d>t9v=7bq=zTu0LAGNpT!yyiF-(Rusqlv;x#5KLDG{RQmiFu zE7X{!HOBF<#6!k|?;-0UCk-x(RwAB;t7^>aH74*-^pN*Z@bH#qY4^h#)9B$TR%4CX zRAaubG23d)(;l8>AMmhDHSmmw?U4h^MWNtx9$xUUf`&Zos4;)ln15=_9wW_*9#%5{ zBTc)JrqjqUGu%oqajiYP<6*UjH$1%J;WZDhdRPh1Wf-RqrYdDf^~}b@bN5 z+jLvoggddNko5|UobP)0$isUcHhS3L;eFA$sVUB8{(*-NWra9Rkod8OPd$9XkktW7 zM8eNJe6C%|Jkw`#e(B*C=AZur*uy3d-+S2X;ad-1d-z7O>}K5f^kIvK?_`BI&jrf< z;9(oH;ALmifM^7Jpe4Ov&LLa?+T)=0f=|9p8 zA8E#pG`)RX5GKg!%X%8c?c*2iccV|?5_%G@`~JUPnbMwwb4<9s|d%B&h?)=Gb!kI6pjeN6Px z;A4W1b)(G2QD%!~uk|s>$M2)e&QYf6XmikLGsVYLAJ=L5T8<7qpXTFwAMHk)Q%9S# zM47>K`MANyT|RE~ahs2ueBA2eW*@gO^P^4Q(dKG#&h#;h5sfxuN1F+w&Gn{ zxZTGbA9s#63r3qK#5tEk8FfaRC8N!Aqs`qu?)PzzkNH04`MB4|tE0_(qs?cd&6d&T zJ|7Ew>=P*0dOFY#%8f2_H$8 z`dHI-tT|__={we>eK=g!v8HycnL5_Y9c!{a3O-yPzKJ| zT8uNT#+eS|%)36`_wk;O4L-VzGd;(dOU9WYOfc(`vjqWxP3iy!p<@&py8QvDL>9K7M3p7;k!yH&=`g*gwEQ0S*XoV1QnA=F&Pdu+Eg%ndSiw4lugT zOsX?8>dY;5rbU3m0~{LQumE%G%)GiV%!lgC5dm5Tc(l%B>dcZlv!c!%6`*5)qXV=J za7=*X0vsElRe;rXW?h}xAi>rF+64Hr&U~ZcwmNfsfD;0=3(!8m?;bj-a9V&<0-PG4Q@!a~Z+h38|JIvM0Xhd5Qg24qoBDb)sotCs z;LHGB0(1>9qu$(7Z)Vq<`|3@%0Nn#TRBs-wH>rA)uQz7}7#`s406l~78~h#t&I!V| z9Oni&k96Jn_t4ei{2)AKdIcC5;DP{`1h_Cjp8&ln7=-6357W{IguVeT7Bh(qVJS}; z4g>TH&_CGyzJkXM4;|_s5TLp436}-9CcxzZt_pBPfGdOWeqK75X!q)1_e;E%{QJ)g zHV8i%4Hl%8p#g@;2XfLPr$z)QlMfv7+#Jl8{{bEgP#IuafGSoIkM#g`0crx&1{fJ& zOn^}=08R0%TvBhA)rVgwj1}d1;p2pl=gQWbx0&q#6GdqdoDg80*scvQCBUQrlSSW9 zZ$7LypVgb|0!$6CNj%@yo2~Wc`T%zYm>%F}an2CDA;66RZVK=R*OzymhR}^$0^A

FP}IGbr|f5F+TY9Vu2uA04rrQ2ZIG?+Uzq!MboJHWyK_XM~;M@jtQG|oiPFs^3%+tcBiu0KO&j(l*;JED*@gR@znrp0=ypJH4SO~38`AE zVZ6b-$$|;+Ry6x|fK)^Hd!+RN-WBm3!EA$hPe`u8ENL+BvjJ+jQSgHR9}1!V3rMJ zG>>Naur=+O5AXAX`Q>jOd*?$bvQdgt`{uD<9`x-$YAO5YaX=o;^Efb%gYwAftpz#R zNe<5Ako@k?0%Ruf&^#{47V(5UI^@w&_=$qs8q7%%|8LT8N*ET$0Dd!uOYwONBQVPILXaUXj#*JO&ECETXiS zV6MpHDy`|2f<4*)^SDO2Dt*o!l*izFcsvcsqau%?d5p+oSRTVw8!L4fP2>Onn@71Q zrIU!OS(!&o9#wf%=fjhTdyT7HdP_Ev>#O1DJR0&ClgHS6_%Hs*P%AgasW3PkFQiVe zUhwblauq9lE(viT$jh}Jf`MxQy$aun32czG?Cx^{oPW@ z-jK(Q`Q6_^lxp(kJZ9!`OCGmMKiTL5U7eN3ZSt9A&m!k>d3zrB^@Ak47ncN^nUY z%kp?y_)X9b@VJZ6Gv_DK z$19p$tx}=3SMyjS3O(oZn&@pOn6-JlCHfnAyeWjt9pu2<8m^0^-pS)b;qT`0ULG6s z*pSEj(JXaR@B51oO(EQ;dkCIB!89#kp91zQV6Q^h zgqsPHfzRG0PWFEh_Y))!6&_GPivkWTpm`xYI}R#@&4jgdZ~=!Dz>|VFcgj-s{{oIE z;4rExgzth#A*4vl0*;g{%a6oT!818*P%Lal#9MT$0!}F4xB^-i@Ph=~6vAtE+d_E6 z@HxJKcEa07lrtt6+U-yXI{@`CijD=GRKQ4DFW`~_PNAy>oLWGa0!}O7^a45+(7CYt zl1~P92 z3@C)}<=7|5MtE5i0*6-=aCHG!7I2mHFco}Azorl#@mwjY9b76i{72WdT)+n%bz7-qtX;k^WHyOe$b>0d)n8DWFybGgf({ z=5Ym#FYNwx0auwC>I;}qK!b=}R#GMwaBalHRFg8ffEfi$DPURw*A*~T5e=4~^y>No zrWeAKh|aLt(%TyfxKY(ei#HW;a}+X*fuY@6z-IlF+z3bX z0e2K|PXTiaxQlM{D`3H>Iig#|n!sYOhbD35B$sdL2KQkStO6btjbxB!c>6c8_j?=$H(pG(>Q3rIv1 zhC@n9+bUf^PKZ-LMo3nWs$3zA+7sdzP%I!2o{xA6${U&aG#2ob=u4tmZmXp<%5mthf5;7sYy1!e%dkTm6h63J?@Qp$~DBwdO{l)xo0bdpHNdaH7 zu2}Q@{ZAqMME{xK=LLMBeNieW79R7%CEHZMW-T9w+(&eYg5MPItu$;A{7&$DLC*eA zz>g8m1>IJ_&r0u4>Jrrd3wvxa+~dC%@Egmlh~L@R3;3geKMUAizz#M99ejf(n3@S@ zC!0Ta(*$$R1oQ9&lbm4wDZmu5i=G#;YJyom!EBmfw(}ZUM3W-+oM>84H2o%;DHF|} zMeJWhvm*8>Vy`0hF5@^ruQdl0(Y%NQi#Vu= zu9HkK$(%RYlutGX7jZ}tvnLy8vUz>7`C_u+w-1cvup-VX;_xEc6>$WWv;P;-s)!?t zIJ$_Vio3TkIgcsg*kafvSj=3nrTqKc|ey z4nl~ZD5PT%Bc_C3>YZG~8AY5@M5iK7E#fp8Em`5JbuQxcVt8usO2(X%(xr%QjIM|? zi)g7er89J_dlCPUEOAm;8)p~MBMRZ1V%TFZ{-FUrUwMrk-& zaEu^1#}-j5e8LoS-4rvPt6xN25tECk7rmi0D>$);Nkv>Me45n8BY&n8aa|EN7Q-LU zOf6zs5z~cVFUV7PMiDm@!#f5UO7Ny4ZY|z zinyWn4el$gVf$;nPMR~A@g+)A6#KS6nCYeoxU35_q zb`g(oL3#fde2n!|#N$Og$ui?dfFfp03Ga=IH6%h}T%495ha~blHCAJ?h^LB36_GC@ zU4&nRQ-oVYriiS>*=9@pIhIOP|Gdwzr~+*+Rz4Z1s=&C4XcUnRjSM6%DdJ^Oo-Sf( z5ziAZ;@KjW6|r1pPoAaXe6ENUwd;#`N6~SXA`I$1 zt;L2SzANJWBEBkOV-cURyB6_D5g%&yqar?L2~9CKO))c7dtA!@Y3fr!YWuv1FN^p> zL(Y;?f}2FyEckU1-w0t5ep|#A;auyvQ^I#s-xsm7h#!jhwTK^!_^F7kVxXRF5$Del zXQuMjYLUV;aMr$tB~%T58pZ;~K-Q zL7Zz%kv5Guz7cI3cOMWWwrfOt4JkrS7BgXoMx5A)i{*C5Mx4}$v*=+X&S=Cbjp)>f zQyXzwWB8Y9SS@_0xpN~L*oe!b3{Z;1D;jZiBd%=xKdP<+{-*kWKc}TM zHBcc%MU$kIq^VufP{?d(pvZSNjL^^^AySgjQq;X?-+j*=X-Gq~(^3iT?f;zTIQ{y+ zUg!0^p3nR9UZ3}8oO92;zHq5Brw%WU>+%Hps`4xmuQh!Clfd8v`Xz8x0{s&hpk8{I zDE)y63{otbGaS!>AqiZaz|aJSNzM^bnb}^$(#2zGDdF%0ZcO0%1a3%#CpJA$lmGJW zrUXVOFhb_k9GSqVM0k6>S$K<(P5u*%F)HJ&35-u*Yyyo5)Fe=sK&|Aq9M&h$kO<%Z zM450k-j=|f3EZB*9U6Po#W~`5$Eix>6B4*5fr$xBPT;NtCP|YEkCV%>OiAGG1bC9L z$tcvnH-V`M+^3w`25FcXGg+$R%QlE8ul7A5dh0t>a>IFC`b z)LE?J(CyO+JeR;T2|Ozg498x|pHE<^qSM6On+=(j|~eAgxT8c@#REKu%TVL{P|Zg#=0o6cY&IoTHkQ zwFr6Ia8T6*UQgha1YS*Gh19OlRK6yiVXDa+39L$BWdd);E0F$e{+2$0x8v$D9EVSz z+<>b!9q%dgHS)POflm{7pUMe*kidtWwXxwFtwm#v7seVNC-6xE%Os(2xyWY;tdlJz z91-!01in;OUkSe!t{1ZRn*_d%`O9OC4GC;Y;QItNvI6=@$efwmW(|Q7`uvf{R5CpM zeoEly1olkgmjt#;;#VH*3H+A8p9%b)z#m$@d}`%#vibW@9{!ThkW)Qi*ky;c-bEFA_QwIYD@$uzM1w zp4NIK(KCsYli@$3Tc^;Beo8X@`}wCPaauBbU3R+gj3mxV;>;v^smYXhvG?q_NzSUC zo5XoZ^ize;XRIVHN#epJdTVAc5^{N8oJ1dum!Gg0kwdsNiM~l(mc-@B@JyqG7Z=zS zNnEMQb0Azf4ADP{p-Bu#Vo(xSB{49bDf+Sb{wIkc$?!3N`q88eOXAuju1?~bWO&!6 z8cWLF>yjAGE>)63Dswh(Na99KEBQ@Hj1V6w93{Lt>Kz;Y)$Y+rj7?%p61QqBlrVF8 zW|B2rMT$j9T@v*g6nTS4V-mL|ac2^@t9geoHP)cQIPvj9Hp^p;iAmhc%JV0ANlX%% zETm+L$lXcYBf=q2cwgK*RpkC89uRpjmOmu&%2;E15|3*=Jj?}<#G^?(q9%thQ)E^W zvt!8$Etok;%#9_FiOdtO9BVw0#C&nqp%4ESoZbs9kmRW(7ACPM89r{Y)I^3@lEkw~ zJe|Zd$?y@5R$R>NeNGkTK%P%xX%aqXKZ#@#FDCI)63dcUuGMAB52y0wBogvW^Oo{p z(nAs!7h5vCr!yAko%(JPo>m|w4996oB~eTwokWfWPa>NP|MwFf3(^0=kWZpOlXx|5 zFdp(IaqC&-zH5V?Qg|c1V}xCV#|pa&ndEUM)<;hQlAItsQP^F0lCX!6`Wwd@Jxz=0GdM3^=ah8cQP4tTELn~JJY!l~bzL*N6rJ-p+6-?rV@%YWxYb0BDl=C4HeddjsN)zl5Z)X)oCXuOnP`mX zm$tW?xWnA~ofJ)2qH!jkH8I}A91{~vOfxaj#JyZgCZ?E}#3cFsudqo?_=4+h@q2{3 zNOGTv2TV+rGz zm(EfX%SB!gzGz}uY}=*Ac!`xX@v;fiM8ZVU#0m1yU1&-3WO2uYXTp`_bV+>iUgFFu zt!74;HIXw>5YL-9PdY_4FBC7CsG2C7sBp=}kEWdBS4^xku|mREO{_NYnu(PrUN`Xu z4;CFDjK$UUrir&rtTOSIiHmBC-g4Ww#(2lXyIk!x#=x5JW!kVB<2@4}npk7veG_Yy z!vg-%66t@Sl}3jjnfOFq9}9Vyd}`t|?p(gB;WDlD<~4JR(f|U}BSr&G8Q9_N3b%P5dOyaJNeGi;2HY z{A%J46Tg}GU3;7!c!E*qPZNJ>2Qg1dSdD*p=3CgpGspVhvpT!Bv9PTLMt@S8#O*B{ zWMKyjds}E?VK)mqTG-jbP8OP4;TL?-Mx*U67IwA5Pp{loy!EhXyIa`P!X6fyS>auP zdyN+fuf44BzRywbW1*FW<`(v~(85AXMZZEi%zQr!`&;4tCAt^Tu(gG@7TQ=iKt4Gl z=D>v6b)alX+F3ZpLVF8`TR7N42MdQ-I8=Vv%L39{M+=8(>|7+wiozo-9Btu93rEQ_ zU$*d|qr8)a&KeifpgFONg%d3tYvFhcT{#e@Elnyj=WZ5Gpn@dbq~G1b$rets&_fYf zBFd>uZ#|i$YIUlGGc25D;dCp!^Ijnx#yZo&)fRe5?JNtISvcFmMHbGnaK43eEu5!V zc@;CPl7$Pc@NP~gJ%zn3^s#WU+z!zr+$9z+mBR^Apw;CTuCmbALO%;vSh!Mo(gR1q z+V;0FK;~>x$ovOd7-C_Ng~8VU_9N$FD4Wbmqhm_8%&C8^g*pq@Sr{JYcD>YYuyBio z8!e2qaFc}*ic2d#i!#tC3pZ;{d1vH^=ytS)u@=TyxK;Vk^QVeZW1-dx?{usxUl6fw z^%fcwi&l+X0DS*r;XVtuTe!=@9Tvu0xYNS8|5SS$-q$QlR1VR4qr*uS?zS-5!W69v zt`^=z=>HxI_p(-6>fxmG`(F#wE!=P6K?@JWp{el!VC+KXiYLh zt^wA0mWA0GFGsOPb)I8ko`ty<9#gp(h5s!Dk?GOo2@5YdF5C7Qw<(7M``R z(83a}+eH=@Tj5=dxzZex{&?QOheVS|OYEqrR> z9SiSUc-O)j3#%=>$F-rcPpUCyh^%G(MLyudP;owF&1;NBHO9vlKC!U0#;~No=$~2m z+QK>uUr6(Fp<82oY2hpJv^0w~#(E3iTKGo7*LWMMF}@RjPq(4(E&O3&qlKR=Y_jm9 zh0PXzV8S%4F*e8v_XsEPXA8es_{GAn7JjZV{#I9$+VDZ;cOJa8M)O+ZPYZ^Pzj)wV z_}jui3bbFX(YDrTS8Koy*TxaGMrT@yZ);;a8(rn3d#%x<*4V*DTN_Pm>}6v|8@t-r z$;Qr7ZffI{TI2LuV;42)>g-x$Hyh1t>~3QZ2{{oL$s2q3l%!9svA2zVZR}&Cg(S^w z^sO}p)fz3;yjuGE*=TKJe;ciA+!%WpQ){%bae$3lN$9+>);Q3{(KZgU(a}ab8;96v zZ{uLOnpkU0mFA%~I!H3D)|g&v%&0XEvvH)2!)+WPId|gRILc9y%&#>%**M-tXB)@b zIL1a7$rsgzU)gXtU2PmE$&y&oP0bT*oG7xi)_6%iPqHz{Mh_e3**Mw8Y3l7MJVkh_ z&}A`goNeO_8@+6tDPgwO$k!TYiF27T?m6Nl=ZchSjq`0>V&eiEy=`0=_g-X&r*XB` zxLA@t!q=70r8cg#aT&`l;pN;HwZ__7ws99&6A@e?U#xpja<$|d*F0C`JtTTqx8PD5z(Z*66FW4AfXN;*c?qosgjAio4 zBb`xRvhjwEmu=*1By4y#k~VA`rVWeLs555N8IRW)^Xm-9hHHm+rA2k&AKrha&hTxd zZKUk*1;w&DBUxu;Y-DZZ>x@cW`0V{^osqXuwNbE9vQe}V*jQa>ysw-;uQSRvDoW<7 zI%9L4@mrnoij7xotdMYv)Lygkx|&A4v15I>HdfmB*v6YS-sAai;~lPZ8*fX8GrM!W zu}8h}E(7s!s}KKNIWyri{2Ch{*jQ`heT{;*PTopd)Egh#_(-;`>x~2Ijdu0MCpNyc z@u`hO2;}08uYTce!Z(N|!{cYnPY4%ZZE~z)*pos&+!FCR|aj>m}zUt~H+}^N9UbiKU?&Gn9SoLEG!QE6;$TR!2mm;C8MzSn&NE?C+qyKK#yw!rSVN)(+Y`Xyf2O z2M0K4>tLKbuy;beagc*{PWa|_V!d&ffzvI2OJu=25p(@DGp9k@2L*v)fc%sgSN5Gll4X~2bVcG%fW>X z&USE~gL535>x7@S=!8!=#Pc0oz)PHG0zZOXR<#5 z$j{Njs~ud!Nf*D?!F3|f)*CO@8`nFy(ZLOpyrlWPN!%8v2M&bKz@r@8%thkh76+r9 z@U!XyJ!hIUQV44rV!c zz`+a$4?38p5W%3R9v0{5qM2ePA5oq&9pqK;*$(D%ElF*TkUA{;V-6lybDnSm zpZ^`qk2$?jvcSO-2TwULHAf2_EOM~eL9yOoFLmhZX$Q|cc*enV4xW{HP;ZnKno*WY zLbVq}C|Ty9;9$7}&%sL$YzHsXzk`H>Bxg`@SJWFT<-wAK=8nu=;i`J$oqEG}kaduf zB+V_LQFEd{kYP@88sCnO*+E6U>$pewE6RG~6*X4~Ij1yv&B0#| zUU%@dgEt(!?_i~acOAUx;B5!19K0pvZx!@ACZ;C6ZKyX^J9sa4wZ_3(@gL*LeBfZ6 zgAW~i!gc82WA!d&#T55b2cN~RmFZ;f{HeIy0!-s?p58A0;i>LoiwxmnTNj3lZFn^pO&Y@5GWvEdws*txB=StsgbE6= zql=wfG*vGpJ2r$jon6$st8h0L&0Os6Vh?xgn|3BnnNH=If)v$u;DF7|QJ+(l3Q zny9^gGs%6&QS9rYn~VKibacZ9hW%Z%a&eH0)-Kw*Xyf7lH+*x#1CXw0V)OlvBs}-p zxj4i{dlv`0;X46(EaYwQNoK3Pjhi5>*L}KY0^K>E6RJhI7^z$fd?Ar;v5&fSzD&(;yf4UGnSm( zp=EHPi;Gx5Y|T}OWg1bq)*m?xAn_hTpnxEc}u=}a?#Jll@f9|H1F?X zfa*Ypw5?O1fi4C~hr+=whKLW1CBsCn<|1hb@7>qB;cw%w6Al+%?_#uz8(fS~^G4xK zLi!)+Vw4;HEm>OK?BbSK9!V%1I5yU-b)u-o*s2*oN>&XuMiC7nRrtITmdw{cp3 zX&1hWR6Gk5a%wUzvXZc3M{7;yc__IkxcJmX(ZyRX0vE5kD7mP*D7&c0GsnoR?&AA@ z7c1m}4mnKTzF%{((#7j8-jHTq3z)rcx>yyTJXE9PZ5Qvmc*n(iF5Y#q+6})wWWhOP z=C;Pg+SoHCEanF;K6ddTh4RdtSqE;qPu%b)4Qx{9GZ&j&taGv6#pf=*a`A^=k(Zg{b4)bs{N8#Z}=^x>3y;~in z1Zc}C?&P71ht3|3iAUE>Lq66+SNWuWN?6R}J@lX-4<}0V1TXv#1=!o&!%1HFtWJki zBcANxR1ZBpoT9kYp`7dIG!Gmyy|J)oFc}YLDwAHqvxL+85zNhjXeBOqFW)#;LM7 z)x*Oc?)UJJhX*`7sJPKrNX%`Thw1TLa|Kd=hKHGwJQA;>SsrFFsR+`Gub;+S`7FrN01_V5fd_wcM2{xt4656e9~ z&ordAR0HJbUi7d`oZ+}bnbk`kk{(|6kkI^6!VSVYn;xuq?{H`oa*U3=xkAr_FOm{= zQ>qycS#Rs9%Wv%&CGX)=DHJ>uJ-p>1@bIdKl835?vWJR#xl^Lzyy9Vn>db68K}DYb z9#(pI-NPHooEb)%Z+cjz$+{-4?b{yS_wbH~_dLAoVRbxG=1*5^Jgil$ydD%eoDV#F z?BPSINs|W}&pocsPk3yKa1HYw^qGfsl=%4E!;c=m@bI07FFmaH@Rf(J<&$fSh79zL zhi|pUXvjS2VS|TF9=`XmQBkPF<;Skg9)8d|;nEuGFEB5x4cRr;qJ??CfKEA3OTk z!ABE6JU^q#ui@`MeKhsM^M8USj+yV`V|O3B`q<46?-!g44vOCP@X^ca6eMWk9fz6I za0q`a;p1Q*?R>QN!)ovz6rC!E_&C%L&vvSH@Nt}vjy^j3ILyaUe)v3mxQ`=z94XE; zSi@m_Ch@~tVJBf!8EPKmql?sz_0d%|VRWWMtK)r~Ol2S4eVpLqMD_Baf*CUONj`eS zIYdjPr;pQooZ{nDKfJHm%9eP#k26$5a+=e&myZ!X&f;KwoXt8*c#gcC>*G9;^P?sM zH5eDFEEoA0=%crfzCJGYajB0!J}&XY9Y@d1xf`GVeO#_uMWv?X3LpJ_T|>aZAwGus;qL*cNms1N)oed~P$#p(%@G;!S_3|9K zw2yYcqcoyFl`k3XT*2hduO`VT=A5(lZ z_!#e_(Z?M=Zu4=wO2_kx^T_CT`WWYjPZ6A4HW_z|>gb>6%jp;>u+23?Gju3T+vJb=yfd z$Jss}^}}C=^pqx3og0VPs66NSc-+TQA5Zw;|GP2Y$6_B(`gqF60u}rYrM=L{A~iWW zhGU2&KA!dQw2x<$A&17@MEP?*o|h&iR3>tM8TUmWYke&9k@d0MN6N=bK3pF!``~NC zgb&L{(ub+$b^HN*^udthAip^vJM zf{(Hv{tC3{Bk)o3LFaY4Xj_rhr*cBuSJW)?>jNKe`FPF8N}BWcpFZA*yQuc2oY2oI zkyd>E=ZN_4zkIys<6R%Cxv#lIbukLBHQY5K@B2ve{P*#tj}PVZBOjmn_}IrMYPRD$ z2R`4*Go6g!?>~9|`}l&}R%Icc!uLO%GCu$N_}0gI9)LXmgYC#yJ&_=k`EQ~1-zwkiDO;~yV? z^W2s`CyO=Q;)nnHEmAO2VQ$-`!h<@h?RF{bmBRKZ?3%(3DKt%?Nh=T z4~L|1XzZLL4GYWnKPjA;!r>`&lJXHL9GMCW!mgtvIa)|bXOUx4I4*@QvG7!AOHL>T~6zat5g$=?e!`sAf7t#Y) z)ScqvQn)LH@!}JN6NQ`(s!bA~ESw^YyxpTr?oHvz6z)smu@t7J@Nf$Er|@734`@kn z*)Y#9c?(EkS_;!8Jfp!lL|be|3bQ16B!!u=KC_yg!W=apO@&W8+z9kDH-*_EjU!KBCDI`*0h?g~STr)hniQIrZ5UdnzY4WsmQgBn)S^p}5U3BiJkWV3% zLN@@fjNr|?P&ucol#KXP`x zrZb0x*BdFURPTii2AiuC@hu^9>&Ww8{22cIhZKmb6_h!wN#PSFsV0+uKZOrc;9$c` zQDyiPtDj()xnr-v`4$NZPl)}%_q{1(X@~cdk;cp_pr_j5>VDnF%?IeGt@OKJZQus$6SOMO) zXpVF^v{^j=)7UwUZPVC3jqTFla^gzhD0WC=$26Lx!(*TNG^GAc>F@w=D%;IG|I^qf zja}2&GmYKS*j;ie?2$&Zba-<~@kyRvQ_90$vfW#F3P0WO^;8-y(r78krCK&Uq`6-j zM<@rT(JCF@o>~jr2oDgpP2)fj_A+8S@%GC9;4}^qVb?wK(;X`CuQbbeYIr>8-3hVV=}%;P10w5c#hFC3G)w88QvlsoyM(7ats%$hRl4ZQ={HmVV(Tc zEAs|nV;Z-M+$OxL!MHm zOY)>}K|1`SuT&;3lw?t?Pt7H1ypzV$Y4~Y8lg3MFJgX?r37=2n#Wa?t@q$c7#r~J2 zu{?G{&z*Sqr(ww?kw#L4a#K3dt<6ruNyAf@%MBR2qFO4Afa_CTnKbeuSz#`XtTd@s zNTVnrIZISZCOOlmoyqU%->D$5c0rSWYVpQrJ) z)V@gL%QU|F&*&I*y}G^;vdL_}6W<_=CUK)mx=FZMW&AwX7Fno z|D^Gobbc59k;Y$X{3%;nF}=SfkIc95RL=kzY@dOV!M2%jxo(pQm(VIc*sDpa#WLJM z%_h{>>e?xTT{37YA@z5b6;CR9*foRQVq13Yk-N-KlC?{snUA^4JCuPD1;~p8D zoIy`1L|dCyr>c2c24`h(dIr5RI75;%h5wF-nrF)!J(Hg+eqII_W^jH67f6|Da3Jix z=s%hlXK;mj`v@<|;8KyxgqI8Z3jeLll^OJtq<<_QAaa#(U_2v(6=g^U*Jdy@gKIJv zCWWhoOok4lY$F_=!JQdgpTX!1Zph%~3~rR>O~Mhvkr|ANlOL!Rc#E3Rz8I51otn31 zFjo5XTq9EZAGP`n8Zx*ogGP06Nk^I7p1~cGMBc__@Nfp>Gq^8<36f9DU~&fBm3Ijz zNyvIm$>8po-;=?;iWN-_d#9@F{tO-xc_4!aMfhYJ#hs?+bYWyQBZEiOoGGN*tPEzy zyg#456k=`$k7w{$ET5;W7?JwK`58DFJek4M87z>_Q^JKAEE0)^xj2I*YDP=$nG9aY z;8{tY6VluBB1?sx`TU=OnZdFQk{K+|;AP2Q5^_=!B23_Fr9pE`5)RFd*M^(HO0M|~ zR%GC3kjo&IK{__1ZALsRe3kFJGAL(I$RNmsuQiH7dgfJ%os(BGsAlj=93?6R<*!QT zwG3Vtq2vvnOC)bfvMPi3GI&e;?F`-(c}K{Fx>_VE*BbG)LYhiSJc`SX1LBRTn>8T=*A3>oMj@hutbkOi{XE(;^8 z!#^7?`)$QXD8%+uh+{Po-|;_^rs6wiv3nM~$ZA*NZrSiA!jdv{lwmV^&SK9j_ReB2 z=}^vO_Q_&DHJb}t2wMvG&2ByOskwg^tt4zMY$K#OyV{B$n8m>&2MOB=+Y707hzOMr z73m=C8228YMdvJzQ1eJ3HIK^TXz@<5MTZOaZMK2OMb2JI^l33$8v+njaiJ$;wJGCaaTBN8t=_njFs>f;b`HQEN)dG zKFdXFHIml~>$0fNqCuQdsK7DaCVe(<7r8@tr*K>r@Q^oJkVp?F!|b=+L@|MOv1AN)u1kz9Q&{6rWIP~bhe=74|v-nMt-?R85 z9t(Xk|Gy;X!u~rOerHPI7M{{MAcyU9FmhWzt8OE*Z4TRsM02-;c#|A<$zjJFc2bjB zHO*n?-2YDLXzq5+VYeK1mkuRS@(kB3hdm|SOSpFq%|-UfZOw-|EhLFd_RV3x9NJ2< ze-5ogsM9)!HZeaS);}oWn7(eisqu*)^6N7h849;fx$k$f0KrC&sVsNH|S6T}Yn~=P*Njwu&}0hXrcR%3(IQB+q~0oE)CWVQvod za(GM%QJo+E51%hipHKd07U*H2%Fgr_<*+#BOLBNx{2Af1LfTU8`B-OZ4ll&~MUiC+ zv0O;amve9=PvnpkF=Krz2Rr6;>*kPB(-Zna%F{8Sw`>mO9CDK6g#}?zNQFS8B&2O6 zmRChy5v~xv8fW-=T$49MR_5?#4)5f!O3k<8-nT{gMu=|T&0%#8Yjb!nhc%KjG%t3& zuV%D0*!(buk75rW=kQ6)Kh5E@n6Kk`C0pu$k;9ice5bCja`;+gz3?01w?b<2*?WWd z_ri^_d{YjaV;-gSqnbYnf6n2TxcAo_evA3SH$HpvA%skG{qnCtKJ1f>dCzhNma$X+ii(C-Pqq?yO zz4N$ORvc*`kxTNpB9BYOsdiZ&m&d%X2xs9+k$%Gd!U4kQgDtHFsyRqFIFBJBLxt=e zmdDk3T%#sUBCG4--r;#%AM+dXXvVJq)VwK=5h8&W+o)LQW|3Qjqop5>?p8_0=20V3 zE36Yzp+1iWaei=P^R`%idmeX)-4rrl>h7kI8xPS(i?TcT0Fr zKD^~Usb9<77ccm!dE77lKpxZccu<VFQw#H0B>Cbzo)uY=$J2Q{BTk>Z?Gm3; z^Z7iM#^ETZs~6Q=77Le4En3VkizkH1JWLUqSb5kncNj~4yx0R{rShockO+x_gdgYeNhHr>oycdxDD%%_&tHmsCHz`Qh4p!S zlgGEQ&Ublih;6@*g;d)V>u=8Ehdh2%la*xGPvSodf63$5*qllJuEG8x{4RDTHfj`vP{5PFChS7Q*-TI~CAWLVm!RsD-pk z0ecp(YXQ3#u$v6&pS^n&(5w)ye8#0W?wY*{*r$NKWzHt$&0|i_EeklPfPD*Sr9k@? z!rRdP1@N6VA4FRhZ~#N__y2|PY^Q$P0uGc8!||f9T>%{mXkWk~1stqQqJcB|q0;0X zzaz~R^sqQIGdZHL^>?R7#SR&oK08ULa{z?I^o)IB0euR%NFjO) zX?SrQk^B)}kjdOq!04Ed5#eCRDyy0}x7q^g z#On*Vt$+r3ZWPi3L*E{2-XRZ^jEg0l>j~1F80T}B$fN=$i%f~-cZ)DOecmfS_Z2Wz zLQ3wJU97|>t@Q65XxHAjkPh6rYo-Nx)3z#E9pL0bXD`1}Vqp?u= zi2~*quvo$;g$smF2^R_%#hY`8(tqS|RRM1mu%>{wWBEHG?-sCH9%%gg zpTh5i8)VDgjXZdZ*i^tD1#B+h=K_9^!jA>~R0!{_U+SAan*UP3Zw35XK;)Ci>vuI7 z>(2s=BK|61O96iu@DEREh31Jmo0C!u6CfdOQ^a;fZ2KPxh1+vtVjt=3En6z^q5`o+5iQjf zS?yQE;YI9UM7ttd#jaWx(WZz4XEN2DVfP|VDxwFS>&J2@7jb$KJ&QQC7~b7ZDPq2cPyeUMVKkOAia1jy zv^tm%|3&mI;_MclBuEAxgT?ku9Qh&zh7P4jrW3eF5!_9&mhyag07z6g$Vg3KpM zhjJEVQW5tTFATUkrcIO-^~S zh)NMb5hYcCk~aM9nK%t2omYzZzK9h?yjjGn#qbB5uPKMuH4$%UPMPz{IO3`zJ}Kg@ zB0enQ?IKne@s7IQjTNZ;UJ>sXv4)vw$jp-)ieq8d2eH~mA|J=i@cb#_D{cyorHFM! zd{M;baq;Pa7tMK*d|kx1MXZ-CCEtjQ;O~E8$p#s+Ya@@!0Go=~Ccx$*elOyOB7QF7 zM``{f{MYj@Mf_UCZ?Q0v|53!2BK|DmAD;h3{QaNaXhc*)03!%bX;zpQ<8B+EX@Knl zGzr36!}bAo2*Bc#6L*wwCt)PqIlvwPb_uXsfL-N^vqOiwODD>tSr8s^^suLd3kRK8!(?NvGtYZ)^Hg+8zplg650(1^=WPqa?>p%WGDKrBy$}s_sRkMo} zXv>RT#|1bs!0`dPsW+0Jpd8rSJwT5DC&`4Bp`Vij^!$$pmi^QKX9YMdK(7F&tLqH8 zI`co#c^uL6*#X7`I48h>0Otm{B*1wAE(mab?2u{~2I#HkMX~VW0DY7XqjST~=I=iP zToK^1AiPOk9-yx@qhV5VrJDT$^bf*+kwGh7T<2E>7#?6?fNKH_3NSRl-~dB{@Ckvr z(KFSC1-M$~yxs7kPhQssxb8n8t`BgNnl}h<)G%o~BEZc7Mg|xaOX!yJTLO#@!h1b= zl;o`e?hPbMM~))1gkqn@oHv(C2%7#HA<0Cxs@R#Do#zq4z6 z5Z;R!ZeoBb0q&B*qyUrSOrp?tt4W9V#2)So@JN8E0Uiu+e-PeBnBfDl)k6Uu4lpgi z^w^NS3`Cp}OJ)XmEWoS)bLca`qw>sShdK;2S4|QoFfYIpYCf)NP=VL{Abjv3Ss?OM zfW@lA!T^h;#=3DAP+>`crzuffP8J8tE%01`7Xmylw@ZWY(I^_}iveB>uq;46!14fI zfR_T;0bUMZ21szEGKq4ai4`w+x^)zS#En-S)%*ad0NDWP02wJn1?N*%POeDkr@)=a z^FKgY!a!IOaz|GJtO!sI@QPL)*D96ihfi^@vP;d^1H2vJjR0>2Sg8cw)a0%bQkmt7 z9_ro+@L7O&1AG`@H4lUU?*&-HWz%3xX)x$*FyH?N_#g<6FV>0@l8*v>qF5hGelLGY z5rlUiDnx3{`1gMTYzXj$(*82Q*8#o~XB{}k_2RR6{s;J0S$!v@ghl&a71$WyN1p!y ze&G4f9UZS>J}R`~%bx(h2l!cOFsokz{2Ji501q@6)0O$m2ICL38jD=F5)fTRYm>VT*Qwj^XRFdsV*r$Z;OW31?9ZJ}-geIkM%P@adZ>JJ=FQI8E zoT;5l*tHbiDRwDs{Q$CCDcnkw5Si^@Sv4z#cbPp)*h^M>t4VVTc{MMgMG37+Xel`* z`-<#W!v4~ygvzZYY!gckP_wO&y$3N9zW*uVkP_M}+k++H`rpKtKjKvAAkwjf!<6UY zLY`pE_Q(>BjhvTov`8mmXW=ozF2ZQxbuHnv5{@f{N7L~obT5S;7P^&ig2;)&7x<6v zc{Y~NQ_UX2lS|3HOvRzJ$poOekSu+fl(Qw==-OL$2RpDJOY$f6RKm9V&k=So<@iRLoXY%&&S z^I3(UbF;yCzJ#S}vi>iW@S+mtz^TTpmdhJ6VW5|_bV;b0EFo2bS%Rgks9=lGzf*!M z?g@RN(_pYGEuK-i*ktCp5`HWpU&7iF3MITzLQxTe5~|9oR6@CgN(t!(gHd=D8jM%C zz&NKRyeehZgg0Lf=XEvdIZAkC32&CLx`b6FysfUcR5vQTQ^LFPNNLUyy(fh=LJprg z@0YN?gbzyiNWu?=^!#xNpOx^5M!}$;mcm;<;%9m?3fj3#C5EXj_- zorFz=9MLW!y9##`a^*xm_fWH08GA-L{0cziod#o{GL9;vc^LZCxt1{ZCx3!SHEYShw@CMXY$Z!Xh(O$jngzP%Fj1FZSB5!nZsN~e_SjG`$ z99G8RAPn`1pWegCfkX-}iZ4g%o&$=>(i3|}A6<)~S|CDiU8P~*3YF;N! zGM0yb8KcU$p^O_Pj7o7+86z|VCO@(qzI-Ez-k*@%QpRZYjw$0-5h{!osVSp2)~9CV zt)4T*KLMmv8&wmYGq;y9ql`Psm|n)6WlSxHcfE0Cj4xwK857F5tBi>fexcvTPAX%v zn(Ni1^SjHqw~TufH`<02-dD!P`1iE;m+^p19uz)Q#y!ErjBW27~ z<`i-jR4s<}g>5mo+0ZoM*=mGP1cmzUAB(b%QYc)5(k zf1>Z!XqakRW!Pox)o8S6H1=%_k14l|Vi{f;*)sexQW_o0l`bR0?X3A_li_k@lh<@hL|VU=5;j91jPqKr4ncva3>!`DP!=V8)lv~4t2mhny*Zea>C62(1`vl<1dlFg_Qpz!YHUcL))nmo?uO-ymKWyu6a1@N}URJtKjeocCVmy1$$Jm zPX*1SOecF*uvZ0p%T*thmrj~jux|w|q|;K^x6z=S*M1f3UqP$boF0ZW8f_{#w1NXF zXkS6w3Jy~5fx>GWjdrmz%@3~Nkhn=(N;<^NjujjhbIOmXgj@1RC3ckXXkn*F5+CNr zNR9fuj;)}p1|E4nzJe1g=vKiAv0KVnmhP3UU)G#d3D-QMoUEettl;_zPN|@81*cYU zUInLBaHhhYE<8iXiRe|q*)ln+g0WhP=Tva6dTZ2Vpz|xZxPl8R=v~2u67 zjmE$V23Ighy$?4Uv(z<2O=dEzf@_uA)skEj%dZomhv6b~WOW0>sU|nYy(20ZS;6fU zjH=+)N_h9bxf0&dZmD2&1!KhNgcpTlE2yiWMun}7yXH0;^%dM!K|=+Nv5?A-aplBk z4rhTLI6LDixT}Kk6-=mvAAT8bqB3C@btZA(6-=&RN<4S-CFksOr1w_vKn3?zFtrli z?kT)q11E|6M+@Mg3Z`jEOc(M)AA4t1FtdV3D&c#BNS`FqpDibkD)TwQxfML7g*Q(a z?ZGE1SYE;W3ZAXt$qJTKu%Lp)6+FeQ!I%FU#iF>XG@)~z5{&+|{6C{E3ZIkD=POuN z!BTZm_(BCQN`YrrXd-h~@1+V}R!ST%o5Z9{OrfP3a&%4wX{ostcop~>IOWt&$?afq zO0pFM733-?RKoYMd2JTTIXgvFmAq659|p=5RJ0x_saEiI1+P@_dL{fEy`q9wD|n3+ zXf)V-O87$<_8sg ztb9JyxIWT&naL*={8+)K6>MgbJPj&XSHb7%-1|*D1?>H< zg6}KX5bLwx8!Ol(g{QTJsq=%HBy{*w1;14Ab1dOB{mKoiKwRq4iX#3Yg+D9!OH;rp zW6qTSqvn=)_eB|QQ^k%|Y+J<+Rcu$q_SNvdKz%wSHmQbpfoSb9y(o>QRqR~FF4e8y zsM0^3vun3%xUhGZ32mEIu~!v)$|2VPCDhrwihZisuZrf?@a%1&-j+i4?pqD_R1}51 zt*SVniq=)MsfNcXqi|9vZ(GGd)$ldQfpM&MRkW{$3x>T>=7&_n1B4QK>mdIftKrRy z&xh1Gyow`bdxZQ@5|#1jDmqoe^Cz%FZ6dQ}@7YzHuhE@T z#kp0SR}FW~zdH1AfnqV4i$r>}V*K$>6@9AVJ(`+PtV@{{=Owniyo$b6T&bL|5YiO~ z-cMHjl_b+(0$0f`dj~N+O&k*#5)Y6jR2wD_R|~HZUMsv#IJ}DMMX1U0-dM#GRoqm? z$SOuuu~`4yl0P{fRmI&^++4+NRoqfVZ55-d7+b}dDsHWY|G<#H2jfM;t45M6-~Uum zUk(4w0)-7#G>Q+@Pd8Wb`M-(@Roqd@LICvari|bmH7ohP{$A<_!P% zTN%=d->qOgGQxO#WyqGnUxr8-0@4r4PDq>{!^TLo44E>-6f>(DFGGSilzNjw=8`sq zadIprxib7%hCIh||CiHmc$@I9EW`I@_^!)0XMO&}S(8mp z@u4#OT86`AI9`UI%Wz1)!265BK2nCGGIC65vJ{MgmM`Sre=EaDts=(8n*1iU-^*~S z41b8z5wFht{V#6mF8p1F3NHM^jh8R~WeqMn3tF=bspvX=bFmap58f zousH%S51=oE;Mw(;?I9w_Km<88oAKe^wP`I-2Yu@??N*dE_R{03oYfhh0ERnXpo~? zx$JwH&DJioQI40$0=wF}(9T$+J4!mZ&{>j>3cHgy$4->@%UtLxNf+5<4KH`0oATuh z^6KtF4;QX59vLvl_HyA`7kaxez=b|8T;)Pvg?FV)^^+rdr!uj>3s<{vjf9M!m(xW% z*Gd0+A#fo=UGk76c-9)kosH+%&X9aQWuI`C~;w$3&k#b%VKQ2xR>&x=5!Zk$l!A> zG*ZknU3gxrk-ZFz_@WDoT$ts;To-1$@QUq2MV8Sr8k-f>}x3(H+t>cU$tylE6@YMBbiU}$rN3vU~1D~%4j-gV(UHCJik zRtqVA--Qp1+K0T&%~*ChMfgO$YlLfE_*4q(%sN>wIZLs@h3{PW+=Wdpd?B5U#uV4v zW)}i3Y;j?i3tL^-;lh_(AsV|)$aS(^n+ypjVyA>(%Yw81ce~(rVUG)CF6@<@nhesV z6~#hv;yf<+T<|Kj&gx}x{3g?&3u$r}5-x;Yh{{MrjyOE#Lfiz*CU=#j3n|m2L~7zx#`bK_<=u6N@`H*Ro)8|grW#Nke|H>pYG zL5#Xg$8{^Li=?U=(!ihqb`blcK?FZVYv;bJ%XWW?VwjXa80OilBfLv?^8ZuQ_ zC@fL{3>Zqe*o_j&DJd11?#6RQGDBphS!OS|@sb-aYO-dzFSCm5zg9tHx{|Ez>S4&`y6D~>u$UuFXX&vkhqvRnz1$b$3NXz?#5e^ zEIUKKLi}yFeVlO=<9Wx84;i_Nuu8aE_@0mo?~8n(A#8r+#(GIUcH@B^b@GK9`@t~3i zRXnKd!Py@B*S^@xi=&9NP}PHTrA&UF2!nBYiPa^k;lYI-)b!ZPyOzg(%)3BXTfMZy zA-qWHc+kv)x*jy~pq|G*AXvcq9yIXSyK6%a8jCa%(j$cqHkE{yn|pAv2Q57IQPony zRv!Cwqb8Bct&Q0>9$fB0TMs&T&`vt-J*Qt9uq+)t=%nF{Y653g3YQ8m^Pr0dT|NKz z#7MKNQiwUztUrWO5*Beg!J2Aku&(K zJ-Ej30Ulgy_;ns!FHR#=8|cAp9^B}`U=MEc;1&;VR@j4-%iE^5x2j1Oln`(CV2B4i zKJHLP+$t%&Qv-*3>_h4<$tfJ>!APbf;XM-GD^vGLd4$J46ljwbxZi`(n$S_o%b8Gi zjq%_y55{`%2rDKF56QyADj*e{d3jV#j(VKEvNMj$Mmdg`FRHP3f(K7|Fwuia(&y|j z+9y>I_CD>wvmQL-!DKUpDeyxpySOVswU;1ds4dGL`3tEKs#@O?`7^2dXB7`(FM=EhP}_^}jNx-}lG_h79D z>og;un!IS4y`Pz=SiR2~vj<;zu+@W&9&Gktla%MHGF09on~aApzVu+5Zbk;lTVT5f zJ4~r}s(`E{bJ?XKyFKuFut(AEmCZ5_JRZ2z>(*>Cce>yZ8fOjZ#qUAFgMbHN4}#JR zsVvv3EYyss=1~t~yv4MZ;);Ph=|M_EXp<49CC_MhRsrNZ$a_#Oxswq`ee1yw9(?D) z_ez10?3031()}JB(6rJuEBvGQPag0tIH*z_lJXWl{CjZHgI_%O)q^A4qqzSo7)El; zgX4y?=Cpi5zBnDfdGLoU{O-Xit;u)wj)bl5C7a90`P~1#XzfKSFD~}lhYn+)Qx3mGnKE+nwqA7dqMa8Vlv;Z) zCP>b%jvB=nI;)HNmnu_6*u{%$yy)shcXeIvMK{@Gc$|?QUR*DD5kVZJx0 z{`7LA7lXaH$%|XPxLMU3q#?H`1u9UV8L>XMd2y!~w=1eU)H}q4%DEfr#a&+e=ya4h zaF`dPycq7q2rur@jNI$!tL#*u=13Lcej%f!7vgBydBBS?UW^szJ;E>^lUEo@HoVv-k6ssf!A##2iCX)j)pGW92`R?o`F z6qzkh@ux~og(5FX6vi|!ie=mhzEr~L!smokp5etz@#mESbL5hEk?y>hCCO|qLN8uY z7}V#=p$=E_94}r|1zuIO%y+IA^Gq)Dy;$J2p8;r%m0$Q@%3dt>Vv(#Z_S#zn2QJ}l zrN#567t5simU5vNUdz2$K}|_$koqgl3VD|ida=rj_mskFFMg6oM)BSC?lHadndAmv69wG^2V+y;x*sUxW!ybjiLb0pN3%?gGFFanjO`1-ZSKfUx z!le@MA}r%UZ9XB%X_<2rkvuB1F^!@y;l;OJB)!Ock@6y^-n17Pul)p@)m&4J7M$Cv zT#|2O%9$PZe&@yaUL4TaeZn7v`-Lau{YTD%ng_i&eUf4w;A#a~|h=EWag{O$#xOir2I*r~~%XJq}iR^vZL0v{^*?7PMiRuEPc zo+YH0%05)_*_-p(K6|%knoR#3pM7Lh_2FEfU77QIsOGb`Ztk?yq2KC0Tts~zYWq;r zXCD@|H2eY~&Dy4X_US-7#5z9I^Vy%}>q>#ErM?dhefE*mKrT3&)MT@<56yjO;zKi^ zeKs{UM&_tEbkxF!mh#w2$Wc^l?Zah0T;fA#AKLirjjpW^?R{vc)Tls72ilZ!M;|&V zL1x6ROBDbu(^MB9x@tJ%zubpz8qTQL)m=k+_)Z^%J$<;^hh9Eh2 zhueI(#fQN@+^Panp@!TsPG&?4^m~V?+nqiP_hG0H!+f|)vE8jOIErcvjN~5HO-4BO zKHBtQgaR1p!)PDwm#I-^6!#yx<2o7R!&p<^2Yq-*!LW;FAJ*_kgtYva4^R5=xDOM3 z80W(Th9Twg@#3tYtndS6=k8 z!iTqg_K$1HIcqBw?K@nnCX7{Dw=Dj9KCJWMeIM3P--nMmN1Q>au~1Z?g-?_qr-m63 z*DAYDrNfzBuinpm*y6(m72$J9zVKm_4;y{<^BYIi;QN2A3KE7y=EHWM z{ZB@|k^*~qqwO%Ee(l2^E=wK(^1GW;sj<}A>qD8=n@fq)rrQUPcxZ~nrq73n4}KrQ zJ_Hzv0t>2WoI6Is7>K;zqdvs6KKXbV_aR~Ki1qvkpz5&{X&=7vA>%_%lB|#x@;;RN z>=T(fOqM&?w+fZyJLz=h^S=)#eE7kKBR=f+;TIncD3~98IOM}m;s=E^7@uMtHvDIi z%oNKh%TXVWGX_5YYX-`-0Z1`9~ZS$_L|=T*s%%6@yRC#OOcKhE{z96zf1?b%^?#2VcH z{ir4j42BmqtNT&IZ!ZJ(*7VzF1W7HwUIED<9bM>09X~G8K-#BHT|Zj*QO}RY64v*l zfd~yY6lvr~xjvgy(nOM`!e+we!tbV7^hJZM{OIV%#eTH&qqQGx{kX)BHh%l_f|HT+ znT49|{q_k(n;rc2hQr~VSOE!{;H75_>EcI!Kf3yHr5~63(btb|etW}bI^F%~;YTk& zuJEI$A~~Q?IY+(y=;OyPQ>>#?tUo2>I-$pYeq80Z4?zxhb`nJbC5J?oH^d=$51~8tKe+j=Ev>gcL;|V z`JEz6pE`Gm-z^*_94@>^c(30+<*7D;VfZo9k5Q7`FQ=>|V;e2bnvC&dtct@S5Bl+t zEKrBn!+!gYeneqEs^vl9<9Ak@H@7R`yxg0zZnRGu4km32B-3X?B|A44aY?@lvyHpYvm;A2U>cD%0lke!QUJ zPOXR(&hlfnA1_JHEMC@xI>FEJW1b(cs_QiwpQ}5Iqo^?7kA;3LkUqV0`Z)WPzv0IU zKNk71%#X!>yyeFdjasS#zA0;t1t)9{S+0uxXMw#d{dmWZ)qeYt=3Tj7C1ly(Q${Qc z*VqSsdt>=f_>qt{Y48(2KKEmd9~=BwE90N~@tGg%WQ02FC3MQjJD1j2jW7JzEcr&M zZ4zhi77<3ZRdPzU`Ei&lN6qbiME%&|$6h74(~qzH*e$+`TT_8mvB27+X4L|Vv6cDZ z_rv9fM?$x-T7l*D!{6!fm0z>QrELE3kSNSTR4o z^CRv@){lfADd{J9!^%#YHQ_B^U=1v=ZZ5EHEwFOjf~1od4k@s{@#9-RMif}13akeU ztO*6y_kQg6W1kd$5b_paNC*7*Nh$v*A(!7lKMv`BXD=^Ge)i)C_X@KrSgWI|o-;4U z{rKIFU;X$^!V_BUCuNg+0;hv3@D#UwN&e8i$wl>-AAf7vaIT#x`gqjTNO=trdSn*0 z0%#P#1pzb+pmqRt0=O_>-@+G3$MIe_V6Vn{0sG*nAFy}41_66BB;o4fR?JWv2kb+H zu{831Grg|n~Vi& z(#S0V3=Y^Ib8ZdTM;nC<(m7~u58w{v;%MF(z+K9Bs5Duhy8{@j+=mH=2XIdS_Xluq z03$e1LQVmTGg7>$z?#p+&j11#eMT=8#;Cclz@k1a)8j({JRHEI0X)LWOJc7Regseq zTqo2Sr)9vf#|Q9K08a!kQ8PP1$fTIdBxU`ia^$F|1DGtyGs=RN>HS%GpCT*}P7R5Et#KxqIa8qP>4nXX`-3t&zFGXi)qV86JV8Nl-*fuXMG??^!uSQ zqKl6M_#%K$0{B#Mu2Gz8&FoNfT>$F?_*~QXnQ()U-g$9qHU_X+Gq_2kI&=S5wES#B z&VauRU|Rq?G$UWBYdcfcF2Qoq0xSG=0J{R%6Tohjk$x%M8$g+wOxEQL=ktF69>cv_ z*mU6!Agrtd0R%<30z;+_kpQCNj3=hV=`^mfOd%OSE`U@3*#Oc?pLNa{BUE58d4{3v z%9Sar%4NyweHXxi0KO042U**vEsn1F%(-9s++KbR;E*czQve4g^tY1SC<9|8O+IW4pDe+BHv)K~capPP9Q z{{~Pw2n6jd&I+PZ5EX*|4OHHmf222Z%yDHMB8b?(PqIMAH25~_U=LPM3 zyIK&nf;c~D-`BKLofd+q8MHTWXE+H<#Nk9oa$yh`NuNSGsvAVBAnFCtG>G~^Gzp@C zEH@0|dD(0fMB|{ntwTn*$1y*^1)j5dEq;si|cQLOnK^!cw4i#9J2hlr- zZb4iTME4+i1W|FSRe!40c&gQOs?{@yUO_aUYX2mWw`!NER-YjH1<^N%D>-Va)nlqP zXsR`Ss&$o&&zWj1oN7PbF!)#a3MhyHD&4g~`vo0SX4myW+!VwOLHm3h7_<-W8-*Og zOewrsb?D6fKZrYmxK+IjU~mw(iF3&9W@cHyAwk?3v=4}(8pvtAOXTh#h8fAysn$K3 z1y<=^h8n~ORg9*1P2kUegLoi_Q9+Cjp8jk_gH#?9#6v-Qn;I+E4+c+vP~xbEC1IS8 zk_7RXW{0cdammNgpp1_XVuF^(6Dko0PE_zDlY;gR%-iZIbv+%#GiS{HWMh9y5QRY$ zsEhTPDnjE$K}<88wPlG)RMpZTo|E_KX5G$^8Z)BP=YyD~++PUdMfqjrnZ@iN<^=H) z(^rnvq|H|p1M9#hhrgzQbAwnM#60pK=1XCL>@O6)F4z371@&oRk%XLCHkXJm)et8B zmdG+8?Jo~vh4|a7q{zx3-jT<*rrL+^D)H4q>QlnV-w)ygnf*}sk&trkw4WHhCWy7- zpBl+Jk@Z3@m<=MI3%?N3!bUkF*&M_U3AYHh3cuuCW;DMN*&eii%t3u#JA?Q-h%(7{ z33m(k1hH3Z)d`-OF3H_NctpHH%HQPvA4DvOfFwa94+Rkxj~Gc*200`iL{`E?5J{1g z(MgMBg7$a+sF^eJd=TY^e-p&F;;b!oczv(tKH(3-{XrZMVR%&dN&KMjkdVT|B0mT5 zi;)~L5guazAsi3l&mewP?+M{a;cr3w5ybC7oKlnXLTg+$Ts$Pa{tDu6b^RlxTNRLiPu@poF0i!Xf(!g!;~p zsG?k`Y7*nrWELUhLr8{@3n3*V>5%<|O#7J-va-YByajkM5@NZcrG;-p_+C+c7qZVX z4%w%$nI?zq57|%12SWC<>yIHEVIPKEHh%yN@qY^?AfA^aJ#-@X48!aq{`n_*0~Shs&E58F>r zc|D+#R0!kjFe-*oDU7qir(g3j$d~vEC=C9Hgnp}pacl6mefkYZ%j`hO!!9+=e zFdE7xn~lO~qL>@2moE75*;Mf~Gp1UE(JqXZvfnC))>jnOec&%VcZh7cS4%Il_ZS8VGIxBwlMArOC#rXniu0t3 zK;cuIJHww5;VODIjA>y^k)r}l?o=-0FbdDG=1c@F7pwk^zch^J!ML>&3NFcyR{Uy{M9 z43!tEd0U~yxvRm4|1g$?u~>KF5@oS8jJLvgQ>%_)Fmc9DTpq@Xu>Bd9!nai)T38vz zJ7K)fLWQw9j8%%38F2`&_tgAKL4H7ktcfHHgRbu^v_1)AZ5V5Gn>5jLvX6F!}|9Rttkq_frjV+h)Z;YMq)TA}m zVP6zi`d5sHMw0hh@fG_-p#&JlaX^S8b|CmR1BbL1Z^T{7QrPE zG>_P~Knr0@VJqRq5wsSe1zyt&?VqaC2y<^M*9^OT1RWya8AnI#rJYU@bdK1Eprd&y zoBR{d5qnRdepe-Xxv*OV*GAAif-58F5kc<=u87#@LeB_#DIF%lbU2VP_lcmdgbbeh zZ9kd4DuQbw=pVt=oD0c`%zc2GTpny*7r{*tTpz&=8bVV8RfHRj3tGEb@eGRCC($ht z+$zG1crj)sbz8(<$+v3=;~65tUIsHXg5eR|B?+^>TQwi13UDlS?und!dvjj|Vz8;oYc0CfoqvDSVA2;%GBL9on4{ua^ zB7#W~Oo(8j+;Jk9Ao0lvo>IzO()Ja>GZ9R7R<)}Ata=$qK?J1{OpTy8fihf^EVOhx+WrVJ0NAQw3=bhKf5xip7Fx6g-U|s~T zMKD)7v`|CEnIFLdIiiJy>S7Em6sP8m2o^=KSn;rzVJs0}Dtyy~O*_jpaJlTPh~VuA zR*E|%ddFz4ir_s}Z?)DiV|ZVt=+o>|nxgzjK;Euqf9BGq|ywdb(AZ^k}K>3n~)WzutN9-r(NCeRc zwrMVybzDPOmP7Y_Z)#i=3Xsvb9!ZzI?j!FO6G-zy}lF(kTX zZ2KcP62XB8e&%f(!Qlvgir`QL2entQR#av&NfqzmL*lO{;FBW1 zMet_?zf1E}1b;}#rO1qEfi^kh?+DJ0;-3gAMe%P06{A4Z-ubPleQQ@>(|j^w*k?sg zf3Kdra@5{$nPZhGszz~6)ZX8y%!NuqJTHoxQB;fC2gmtQd)urYwRfQ!l5i}Q*;OlQ z@1itVJBmA^xG;*QQCt*7gDC1K5(ZOOq@J+8Oi{?IVHAywPGgZKQTzO2SFwAQGX z%AKP4O#IR)xk~}ISk3}&)ipSX-#Wnr6xSY$5YvBrhv>CiqGebL5?oyec~^(cCDOL@_UlH=>xY3M`1? z^(YqVexU^?YvLl^EF8Po+y%7B=9^KhisG#(-i~6K>@Sz`6;b=EK8}TzQM?nik7nu< z-&IJoxmq?E|9i4Y$p=xabEb*TYioNP$h08P% zB+j4NaYy0Nba<7WFKRzF_@jtK5#YS285G`DWQ9ez;HeXhA|6Fdk|9MFCA<<*++Aed zS7fE4NNZZT{4!Bw<&>*27e!uo4YMofCZ^km>3|7!Ls8Ez3hKezJC0j9jhp!N`w{EJP6+`8iy_r{v z=`#YK|6@2;y;Wj3N2IE7RMF}0QJfb;wHT_$aDL3bA8C_yqXoLI8AGEOYQ^l$|AH9m z#!y@QLOH!CW}iD$s}r*iBaW&UL&F&A$LtfNf$60|M#vA~jbmsYLlcG9RCbzapp#>Z z7+R`}rg+iv#WA#rp>+(GNSU!QDt5J1;_YJS7DIbk=s*RLj>1mDF-6v;F?5aLvKYD; z%a3R;y<7@3HNME|9z(wvdc@ExhAWJ`XADnDvv&-ACF~=dTx4A-GDW>t#c*8={bRUB z!mDHU@mf-34T#~|7+#jnT;cUnpvN0T<`r2t#&A~*H^p#U%-&#c77mKx7Li+pgN2K@ zs#V_G)x0ByAtDss8N*QVrA5{|Iv4I%rd))>C1=I%iQ!(R!)6Q*#V{g-@9*NwundFbhFiuT(k>x3}LPgg2 z7$(N>L<|#RD3=a%-!C#LhJ!`caYg$StE4%7MyrJxO;*^?YAH@pE?fyyHRFXbl*CXZ z;j|cvwJJD-midRCh@~-1k6~5}&&BY33^NqcOd)$&iWkIRG!h=5vtxKIhL>WP!$@Ly zC5GQjw3ueSYBZ}%v*yOIAclD{%;ya?&AMQkef!Yt!Wdqc8Y8Ja%|7K9#jrGn#fp6`%M#PF?2fde`G`xy4gJ2~y|XD-q|AasgP`9ZGOI1U-%;TV37;e?vM z#Bd~rW8z1-gH5wKOtX&1@GG~YY4$T%UsdvC41aUI#qdWAzsGQj8v+BpuKtq@XFUlK9ft(6W;%F5|(>Pkj(JYP@ar@A3PIu~^ zAap8!aopY*dCs5hVKyB$swxhF0C$lr)AP+`?GLat@)K_m z5#pgZepd6a5&mMv9*NuEf1p0EV{sgh<2QBv8pnw^PI3p+kB=Rl-_>AT%16&1X?7}Jb}k#fr+5?j7i|u1nx;-Z~}KGa9aX*B*3t5SB_NU zHN^0t3EV9UcL`a9VF?U3^FmEZ?oD7+0{0~_k^%4)kdX5GjS=$E8czKOG;4G>Hi7X8 zJea_v2|Sd*!wHni^&=WZJFL}X35-*0j|-Xg|76Fh{}Ty3oxp?yo=jk30+Tee9LS3v zS>C6#_P*k;NF*>hVV}sX!?O}HlI3z&kib;gEEE=*IH!pe3rmErOMiL-&m}NFff)(R zN?@kCo)^9#d{IdI3}AKwud4Y{0xyfalE561j%MF@P0hJNj+!UJqjQ1CLL+}&(uv$X)z9;g20v{O3hY5U? zz{hGXH$_{Mz;6kxO(2xOrz~s&>!h$gflUc~mcSPYY)Ihq1olm{_UrNBC*ek^S;f}o z1hyuyMa_!E);Y!2m%O>uJh#}YR&1Z7+Y{I=$&LheihP~GF76xZZ6e&0fG2^y3Am(C zCTw49KajY^I~H5s1pEp3xF_&;HjAxp#a1AJAn!P-QFCCi6;9w#0+9sr2}Bb}ClE^@ znLs>&L;}O)i<-kVBqhtVmPsHdvsojdkZR=#{6I+p-%0+haAdLdJqsc}y4V^cQ~MM6 zDS-nC{3tnxI~ER_CaoP#;CKQ*CvYr*UnD=0z|jQ8%ECCIGwN6Mo)B{2Nn_;q1ZpI4 ziraD$e?Nz^v_7aFxXNz_lGZW8q*8DDHoRK5+8 zXlP<^LTa2u>m-^a(K3mqNiCR74ua| z^jGt0qjQbO0O7U5>x468`3CWUN!%!MlkjFCy$?#_7Q<&rf3TXjC2_k5|A0T$h9q&1 zns*9^CUKVtyY3blCLAuDQ*7NUa$gdolNcdBQb_&#lNcpFPwpNt@-az_HT=OOoMa!C zF4lqM)JQT#wRgR%_oEtOg$$VohOs0_qV5$C`{rR$tMe+H9Aw0C`e+e znw&>xdoNORny^?{lEm~RO2vDtKFsSmW1oCx63?rb{DmZ56rW`zvqfGKa-qJG!~#V- zCy7@@UK7q0Qej>a^Tlb6&4ot(dJ=DlFEWzFB1?o+e$#k-OJrFR%aeE~i4{iSZOKIM%ki>`L9~sHVBA*D?n0cY=PbFEG#QG#QCh?ik-;l)T;$IjE zi@ZsEvyp5`Vyoc{X`A?0!tKHxrgvu&UyD9r3AqU%WpC!ZERhN+G*R;`H7l9k$|;;}_;P;vGi9F< zysD;fuHom2R1=;rtga!>B-Tu!R?2>3a6t+ercm2hTg@k7@j59qN}+BF4N|C=Lj4pf z^EYStxk;b&i49X=lOLrUr_hXXrqDEnsp_Si%FQ)|ghD!PnL;ZkHeu@&+NE%bcpFE~ z_dg~=>bIA$gRrBJW$A3( zsr!UqNkZYs6z-Q~R0?BK7@ficYI2CP>iBq1wFgspB87+4^>7N~Qg|eV$5VJTg~wPo z=`dPq@?t6eCr$G4BD|3&q%b*!i77mj!lV?QO5sVP<2>{}ttLNMIiDq;O`#x#DXG)j zAOq$#)ijGzcuxA$gvBY8h?J%Q@Wj6TUBGsXs{J!xTPN^CKaL zP|i_nQusWDwGw_RTqk7j`V>Ahd_xK=^yEzW7ZPqvVUx&a;TGXm;VNlvQ_NqP$hW7k zLwu*uc~016dUuQLNnx)@nQ$cE|D^2yk>nOKX0PNvp3R{b<9mN*X_Wo}PD+niR{hTGvu1X@6g=Y(^q;ZZ&)%58XQ(TSbNkaW{>(llOF zb9x%jrSW_kGt!uu#$UyjRbtgHvFemqFGztF+LTzc(s)@mXG{1JS5%4BvBY{MjaSo{ zBVp%~)88$5P0cPP*1R-6Ok;i;E7Dky#?mwvrm-lE*VA}|ORL1{Rbsywp^L?7Ea5^j z7ASl(jb&-PC8v(ga+!7b+iAR)#>zC_mGB*t@2WIbr_oP#`j=RDmRRqbQ6CtckJ4Bx z;m5*Hglml2r)jJgUuPtrrSW+h8%&eYev!sTW6gooRCvMY_<8cCy*N+WIfh!QJncrJ~+;pHUa-wK^)p6^ZXK9L`U`%PtjOyfuzKN+2aX&e$i zEd1HXe-Yu+EOR_6eoS~=_-h&`MA&;$gdbtZe^29-k^f;l{*}i08T_3_#SH%8z<>FJ zZ5w$ZV-qWb3L@k*a#jZCWKhXSDrf9t;%qgm2-&1&)eO#6^E_cSA?5d%Sk(=$AyPAg zT1Ik#NNw44++CDG9X0D_&@^N3>h&_HFVY}`#u+rspplyN%Zmz4)O6Muv6<;@kwM1{ zTB_N~(aE4~2Cc;}5w>yUd|6#$wG(eI>>&JKi8ZOj>XgCd8FZH9QsHGn`syOmRrpMa z)h&Zw;@vaoVRWv@pr`m$-N?O-ypKrV46YP;QN350-u@X}Eq;xW49MVG!>?0`7yuv4 zScHLU-e`n3iLh%>217Eq#f-W&gTdmr8OiM#+#&8%k_PWob7%&4iQFw5CLAtwH1Ew| zbO!fHGD0{~NDKF8FiM;cGi>sDAcHX(Ow3?x2IDh$FoQ=j_S4!!89XeqjGrC&%fA^s zp21^hNXBLGzl{BVE!oS<%{OoS{$~agq(e^Oqzno&crt^@89bH2(;53ekW%xRjQx*C zogvSPPs!N-*w+zGm4(6#ii{e&rb&S|nPZ7+Sen7~4CZCcjl)oXq zNVr(IB!i_Hye0moa2cQfd1dT>KE7PYfxO<%V5Jn^5xy&2C1mgF4BitTF69q0SewCz zn!At8Y<`@lvB!SB%ML#3}s4k8RRqgE`xHZQSyz*w;B6i&9eEun)@;+Q*$KWV@Ptq z=>M3(PvQrKhq%j0)4`u5{3U}UM*nCA$GB}~a9omKg|De%CymZ;87!3KR0b8Z_(SqP zx$S50m$>u!`XBLsGeFk0B#UMuO@+(({zs&R(D{JeDvLH*Tr3H#wHCQV$j{Dgv*;k+E{pae{5lrZI*NA^ z(kvyHieDz|BJ3(;*X1HSdAnzEYZg7SxF(A$vgjju&n$Xn?N3R)h14hStF9}v=$}Qu zEUwC8nW-LouU790Nd{zbLl)Oc!m-z7alN=Rj{|8_%^S10NrW#PxR|LqNX=V>v^hA7 z5n0@p#n3En&*Dza@*P#`($B! z)_yp7LP#<}WMUSRM4l8rWqMbZSkK7RWFg;^(8ZK2inAz?WU7$D!Yqo!rwN@nOH6NR z7Sj!XPGm+FGetf$GxdU+FJ>`IWVZ07EMCjvieB2Z#g)+1kaf#3hkVz)S5ut{Hg)hsg#jKnSO$s(GCH;Z5vK1uw-K-T_G-y9e&u|ksAJd23o z?2Q>7&)Q!xr9zV1R}QHxeo$9Bi%b^ZW|3txi(D4vS>)B_M8zR2h2!Wu$-fuw6S9|G z`?L5fivw94%i_l@4yo%W;Xxry9nRvHEPhtgd6++v#ZlFny^iE~7ALd#RXQhxe1@Tm z-?-st@p~4hB)p!#Kw*abnZ;P?{LT93@J|*Ma`uM*Zx+bG${|`}t>Oxi4&@bdI4g%r z()mw*b`Iy|P$h?|lAn|Nzi-W*D@kQ;{vzk+PT&45`2C+8TIEnPhsHV7%AtM^7vyk} z)M^Va%pt8sSSM#Mr@A@RlbrE05@&%mkfdP_jYKF9^7%i9mN_&vl4dzH&!L5ytQ9Y3 zcs1UDIdsdRbq<|!xI_wVa%i7J+Z@{E?Ei{R&GHh9q(crJbNEi&k$29a3j;G=F3Vvb zdrPdY)a2$b?fIf#cBV(91fbjYovtt=P*iStpcFV138Q_`eSo=Fo$tD zJe0$u5!KFR1mnZr|tKb^xf;**8W{W2wo ztvM9rusDaQIlP=hVGc8MD9WKkYSVHkHWvOVu}X7zPR;2;=OCNGc`3Eu;XI$itQ=lY z*Nei+r53+IH(UHAA=RA2@s%9rZ^B24j<&OG>26=yqUw>IlPs_@*I{Kn_sEyE7at(4X>3sypzMboCS3`$k%$y2G_F2yUdBk%5 z|F0Z2sq2dzHi|f<+bq6CNPT`E@5>wxazRlyq+nZZ5?fT#`GFE>4$+H?@h%r(S;!0TKG`P-=y^)#MP)Atqsj`=05gg?J9h z91@arDz*45loIbEo0%NG%^{mZc@DW8^6GM)UL5b=Q3;ERfF^AuC_$h~#xh4a-cRQ6 zo78%hT6_pR#pRmEACmmZ4L^s!a`-!kzNS9?O09p@+g}nZk1Bao$fHso74tYNZ=Vjd z?3A~19%ttKB*oIK9WqpH-XIjGb+&+t1+t@HEtPE}n+e zA`P!2teZzY)9dVz4f1HHu13Pf!X|mN%%f=@&86Hdk2*Q^iVV%;F3s}Yd5q3uSRNzu7_P2+jOM)}_vJCdNQReM_lu7bI!E>c zrguypV-0^$k__^$0DP- zIFBXbOY>Nk$D4V)mB*M;%Xu@rpWAO9EAkj$YCT(Ol}f%ck9TGE9bdALjpBu>+A{&L9^4Ki0MYvVyxY(A5 zOUY{%Up}X-#NY z7!gK=u{`2=B*hcLIi*%ggws8*)FNi`$V!qk@_ZiU;@=nv-SPU)6q$UVy#F9%;s;Dr zKZ^V$JebEJk;A6<=RDpp`|S}4kLGbKkK?lJtP=-MFFhw#rlmKtk+ zOY%=1|B5(sVU?qQIVzN+bvY`QqjovYD#v-{_KS;3<)~babINgcIjWS~-_qyF$a8^M zwH)V`pFZQ5DIYMZm7_*E&M&u*51xkA%TIrAgw2}es8x;&$}vDC$_OtkM`PM7N4;{? z(I{%x6GO=ShI+f#62|JhLU0J(K&9PGG%EZ;YT-Z(6y&S7bt?K;y z|K;dgj-KV{Wh&6S9DSto|ET&Ba4V<(`?XO*h6rUWV}>#mnJZEfjT#gh43$Vpq9Uq0 z4~_TUqEr&0B8reCMW#f?NavpEp7+e7Lh8TXb?*ND`ajQk*0c87pZ(dN{n^9&p7)+} zZvF<~bvf+dK}Qcdd9X^ww}rQOaF++2J?P0?dC<*+E^63Sc$<(BuAgph7w^t#61hY8 z(R90;EqqP)V1{^suuxcJYl}txnr=!xsPUjo#d0~R@L;Y7 zmEto!nC-zV@xAJ9jyNOym-qkTRaU9?;Gk^gOIaY~TRHCW7sVHCJXr6+`>LgW?hNyR2OoOSYKCbogUe=^ z4Yu}Uk&VK(Gu*dSn>_ebW85sH@|g!)EZ-{fxscAcS^Z0^d@YiHZo{_Udazx}cfuXQ z?}e=8?%V0X&no`t!B1Atf9UZS6@L}7uU)qGcSXzQyFG|V{8PBc1CIxOauvNopOD7% z5bz-6K~PHFAv$Xv55iLNw=_`?avsFgQCxb$gR}=p+bZS3>pFQdQnJGQXT9=$?Ul06 z+UNg@^p6MsO4%>`Pk6xNK7U{;h^TeXY9k~$tQLpYqM?dM)S`jadEg%@-bi>asxSdrsualFV0!Y0BKh3ut0mz?D%*WwiMQ-#fH>mMre%6?icT1q^<7H3%d zGiz~{WGB%xLX`PPMpM&TkQR7TzlCBIM}0)?$o|yVat<#M^7py%xP{ zafh|JQ=~^NdRk?uGSj;jeWdiQMZa3yWosXkLuQ-)2h?Jq^t*+Ftj*wB+++C@Gt7PB zL##4XWLPbRi`*}KK=_oL)AK{M7*UHyYcW##DB;6G){Yi=geg)OV^n-hIM&*X6M4M$ z|DHNNQHu$-_DPY6!l#5!3+MCszsMBfGeY+GtjJX1b3$JCr)e!s7jkXPkWNx4!d6AK zC>AfVN@*?1EH4+y523OaGgX{bi|Sg;7N27+=hk9gEvmTDxUKX&e6kXipQ-sWTVNM9 z`(+FZZQDh)cu9P*aEWlKkY+UIYnh6#2$u_A)xyiyu8{J&@Qqr$DY8}OBx>PTF;I)JNU#=lA|at8Trd9- z@u)B+j0-uq-v2C&j_=^oN%L!bFWgjuNHrca60}G`L`DPt@2+jw%FVrRC9P? zyg1Q|!@M}ki^IKW=*1CU_qxDW124X`{*Uyck=3`)Fh_fFycfrKaje9~UhI_RaVq{Q zeu8)t;h$1Y^5QfvntE}n7bi<+FQ<6nv%NHv*xZYdRZjQf3~PC&NX!nQh1FY%oa3#( z9GvIH058t>;ub1iT&XzRu0Qm*jg zN?Vn$ZKvW@LcUpMs@r>Uy%*O=;fSvF;yTNDcX5Lk9aOy0iP0sdZ}ZlFdY{d2m%{k($Tt_dx}5j)qL&wUN$l-KA20fP zky2Lkf2-=Js{Xds2fSc;F~N(wy|~|tLF~wj!M64uFYdKGEhj@%9O}g|FNTZr_nP=( z01tTah!+of@vs*Uc`;J8BfRcM@%glTl=XADj7O`;sz<$e+>0?@jFshM()lcuuW?@Y z_enUe@wV*~BFy}gUX*w-(Tk~GJmtj{FP>J_Brhg&M$`r0x8}3`j2F*xRp`U{%-eHb z6ngQz7t_^bns6l#e=iCwXG1nGQn6S_h5eRVUgkx)_uL@;>Al|EcIfs6q+sZBCGB2vXo`Qzh{^O zGt6>p^QsrGS>BLe{`F$Dif?%FrpQX+Dr<9if%{hCEic}dvc~G~h#aBXwO*`K@jc=D z)@HpIA6VW{mLI8@&;Q37;6~vmLf(meD#9M~i6w54Lb6rlbKw_WZ1cJ|0AC8f5*|}v zPAD+nc(L7!Zx8X4ceO*x_rf29JB6(M(TktNe-@rx;Jz98Rs1*ME-&i5_?<_S7k_xM zN8)ZT{uKFNv>q0{@LDmi`!(c%#GtLB|Bx4PRXJXSy@;wR;>9US6x+sZt`c74yhwVH z;hyy(ZJjhPFlQ8)tjx|QC3BEMdUM_;9=rjb(7G566kLQZg?Qp5Q|h zA5N4`d%jv1n5I6QA}z)V!zi+#A%hf5R~GcZYJ zt!)gK`OwXW%YC@Phbw$&@57ZowDX~@wdX*t^5N=3#x?)G8eA*}}aFxa-D2L?dA*Y+~R zS`L*mOgP+!`$cH{fDaE^zP!MUko`#8iUto`K3ZmU&ex+7#|ZO1j`d-jwS3%H|Mz-U zJt1*|@JV4-9-i{yX; znrdJ1VL5{of4#uuA91Y67kzlchfnwrRn7Cb(uY+(yye4c+0ZR-Y~Hr~%>wg|4<9lE zKD_6{TIuVA`SHFlzTSrqeDznr{MbM8VWX-x`0%j^`(@Q9K78uKCMhhgE-;(L-`2|C z;zP)Xtv+n`;d39p^5F|>xlQCtA+OY5i+p2izhxfe|2rT4@L`7!zxeRI4?p_wgAY4p z#;bomwx4|XnNy=82g_T9Uwzmmo8K6len;i^Lz?XN!RN!DK6oVV@wuO?S;K&R@JgW* zdgk4Np9@t=K$s7yPMo)1jt_tN5cVPML&S%;4^dUcgv<~9Bz#C7lF1ZvZqJI0%(B9q zZL*g~y$}0T{9E{stzt;~#s3qsc!0;0LWLj3Uw^7oKg^HA{b=NOuLwu@(Lki3kjjxF z>k7_W5gT#ajeJ)zVB0<$6K2d{AeP6qVObPQ{l-%dfrfAPW9t_KbrY*mLJXi z_1CP^{5W0w3~PC&2(MOW`*EJCTKLgY;yEgwYunN-U$nfykIsHv=*Ok1YURg8*5+c7 zORUeFaktBXpM^gZ${{ z#{fV2OX2tasPi?@kGuU~F|Q0(?LESKrPGF0L#$hNH_VTbehinw;{75I`0=2~LslQ* z$5WaV+KiIO2+2o_KjO!uevI{FjEax>|L;>$d9%l*bH|PM;|aTH!TW#d6NU8ll*rS< zNy5o~OtH00DQ%whW2#l2^W%9x%Kez;N1<{%-H#c56mWrQ3i3^g{3!9G*pHL=6IfbT zrGAvDxL(Sm{QSR~R|;neDYE%&+t(bCxqi&EN|hhgme+`IunYWn!48noQdy{~Mb`2q z)pG2tUE;@5=`Z`Sj5)L!X68`tgbQN5Tz$d@RD4H~P`K zP!Iq8*dp;$KQ@beCcHwmTg5*Yveg$NR~4Est@4$~*TQdv-wL<$7_oWSA?15Neh}Fy zq_-bMeiHud$93xQS6lm=AG^eVw+d&0t#&784;iB8LTVxK)k_xIfp-s)kaIw0ffejDBLUwVA2t72jO7lSdM;TdrI=R))6gew^vjb=;-a;5+VioPVDxN1~+w(>8b9Z3? ztyH{7c(E`a+oj^I1GrM8O#qjP(8J{cTycmcm3&9-BwiK3)gtY!JsnzYZ}|-( zHwNmTa(4*et^hg)aC-oq0_YmR%>i@{;1+97Ket-mg)wM!?EN;0-2(Mb!n+61D}XyB z-YM*1TlEa!R;`fUYEBP*0_dyS|9R^dKz}I%gad8cyF~^uJbAcB#e5nW!+k0a31Fzm zFyU|^Yws6%Ab{R#OXVRcBZMOZ7-cOV4q$WuD>O9XqteF&@Js-Y1@LqLV*_|RpsxS~ zFkENpc#$Upm>9r>0G?D6p0Rv!%Rgn!$S0}cWGQSr#a2BVz;snj4dA%|rUl%y;(1}- z32{aMr2!NKP!vF+j5&&YFU0|rNXf@jCeEtz04l^6%W|dyneZ0Pz640R#i^S=}E%Ks=wBx&R^pgaQalbPn-JgQ#s4J48A55l&l8?+b$Ywd@{4S% zi$yL8;?f{m+uD5Bmj%&2h|7a$7sM4ZyHeQJw#}PerQ+2>D%S*YgZQ<=>w>u6RxyAZ zgXpN@O+j=xMDHYia}c+P^tapaRu#Jh(IbeiL3C5`HXG;dLEIswyH(i5otF1hRWBj+ z-Xe^!uT{wViTAfn^7oSiCEhJDuM7_2o*?eE%6&mRB%2{Y3=QJ`AcmR@16`vD6FPx@Orw1`ZMK-T2G=-KI1yL+MS7xO_l&Q!_ z%H=;F6`|^K~Nc1@XRBmh$_*L3|p-hf+QYVuJ|d|5#btsQ5pzqu9j37MlFqmd!zY zX8mjtVUO(PbMY^P+k*H~W zFXF%2+TViMW%=(Se+04HDvJxv9?Lx>K?H*EO7U6UPkVU|N~sh6Z?2sn!crpEJ{ol2 zbTdf4;t~_WWDqH9lMW(dc{W)89l*bW*cZfJtLHQMcM$(r<=-Ioi~lD)VD(oD4eH#} z-Uvw!6X7B`LZpG!8`j}S@kYWIY@A1{c#N=d9gY<_PDpS0!JeRElRBJe^^@w*)bf)> zPN}Q^J6$uYHy1gr4yRk?43RU1X9-^`G%ajx%Q~E6`MDzJ3C|Z^P*;C-Xk~3K61iA- zNgXZ~X>DuU)ZumQagO5hI$UA(E9=nK@^*E&O8jc84CeW7`L!a~39qli4OZvF#+&NU zxegty(ov*S9c~u6#p+Xe|6hmhb?73ctJQC-LpSl;t-@o6ao(ZgoptD8^`0WVge`dU zZ}q++cM1E|p}*A!hzt~REQ72*SmYkzy>+-xWQcI7T?xZf9A1a}>o8LMfjT@W!q^_F z!wB)!%IYYqKP)m@_=s>VZ|6iF6OI**6Fx2+FQm^W>hOWQJ!zGRB2NjQ7EY?eWLrC> z&V3)jhR;fwT8AQ$=Y-GKVOkvu#HR~q2-&1igbnk}i|bHgl~R#1VR>Esx20%VDP?9I zW{J!e&JoTP=Dk&kR|{*bK3`-(9bT{s=VGDwBH>F`Uo5gjxU>$>+PPRJ<&`=t7kO3q zns9}X4jI53;v{d1tmOWczFNh%Y;FDoUZdhWb$FL)uftju*IAqQ>hOLY*4Nd)x24aI z3(beB{Ybb$__2@=?P>6dILRiFPwTMRDxcM1i{)EIKG8&fQHO1H*e>PEI(#MawYB_4 z|5;Ch{k%%yAMY@WMCxl5M#gs@|n5je7>RSrUUzYC`*;j|Z zMg9@~E8H*Krpz1=KUjw&Lhj*@5RAxS!o!6PHAfBdTzF&%M~Bcz{3s#Yaz`8^-dOmx z{2wQNyzm4eEt`m(C_E{IrdHokXil;GRFP)F=EBp2r-$5UjC8_-?#vL*3b}{**+P;Q zA}xjI2+s{+XQBH6hVw(Xib}}c_!ow7xk#%JE(+mN@r#9*gz%Gn(%U+OHX&RV!p~BE z7hWMVI=M20w&LxCf7(`8tJpq-Ypmt9BG-j*eF!&*`wC5plcgp%h0q~{Tcmdkp_6TO zvq(O%oi+Abh3vYk$ZbLzbQ8Hfgzi?kL*&j-{dc`-(=&u#5_^ZxKZHI?PG2FDbC*cJ z5DqJHbH&$y5C+=XyF~_t&_K2K*k0}p;l2`aGLmI(#M7{E`&3sv@9|g6`AqU87++`gz#Jl zPlhl_;=~Z15_wuk13m+pZ26QBo)LdmIMwR3c|L^l5T=Dt6vA}rGi+^vNMWe{rw)s) zUJ^p7!JGRt8a#o3SngkUx%y!Qcvr=>!fWiTy{F>)A*>f+Uw`o7PY7E=_$Y)=ByI@d z;}ABA=l@WC9}oW!HcR<5A&G*&4z&6+aK*3lTPTe`F1}OvqwvNe^K%Hlh44!VziJ*k7MWW#u3aJgE*pLc zy0etsA%sHsGX!r4dsO8ihR~(R+*ag%W%!OF;|n1Wf?u_t=x@rw5b8qcVRO}|$T%Uy zLkNcu4Iv`Senn=W3}PYNV=WUQBvm_<8>+~pLpat!CWHeaWJCCuXGIA6WbjuAdqwi! z*XG#&4&fhWUb!OfSM7hoym*j@sslJU+<|f23jtq;iHuYLM~F8N@=IGsiZpU?jDw>b z9PQM9lZ&k$;_rW|mW0LQ9Gv0ccn8fKoZ#Rj2TfGVsuM*XDKbqRoZ{eQ74tElDn7=J zy}5(aq@3>5A82%brj)ZBv=lkpK?@Oj9;=4uI5^kAc@oDLnI|M(;NU_j+(fNJ@~6ke zw(TWWY%S8p!L<%9v$dByxWd8J4z6_2&OuwNPmuGgRD4>zz4$dw{d)~Yb)7i-&3|{} zMhA->+~i=4gANYvanR90PY0bG+~(kBrqsbL4m!)vGdg&SicA*=U8R&tsVp+x9NgjH zb_d-Z%q%jqq_ev_9rTdp+#<6;VlM~%9rSk4S9%`@FBF*ALf7n!FVOmgtF_4Y@Rne1SSwcoAoo^>$8!Bhv+96aaXc^R`gU!fv1UBz^f z$rhOc2gMEw9TZs)dyCAzB2(g^)WHFp_D02~oQZW%;b5MFN(Zw!FAip@)p5n{rH#(# zIGD>FQS4rA^GcP2`3|Zb)YuqKlJNpHY+7v2mhp=Y7D`#<;3ckbiFqeW9Q@#5se|_& zyzJm@2g@A1?%)*%uQ^!m;8l4(FCT+&g;`Q|BP(AmkwKz;O_fS(qzOIf*)m*-lG}O=Yo3 zI7mB4I!IZ4o-8vCvj6K>z5M0iKL>jq{NrGsgTJjkW2i1R|2o(&`s?2t1n9ajDP2y`B;~C;i>6s!&^Zq}K z^Tb<((K3v4!gx=Xv^keyi=Q7xtFZeUcNc_lp^RP5pY09fVikYk@($zDu=~!JdLG+^ z(LRjJ!e}d-%fq-Lj4Q*SF>Uf@?Nmj6mB`h?6fgH-+!)5SDqbhNo&kvLQQIDT{u4&0 zFgi%2hmIoO@W=l}3i$QvFo>+WRSD@5Mz=7!hH;yUyqfTXj>Ox;=od!!FnWb?M;JZB zxHIg&QQ{v2dx%WXzf0gB;ChGAC+vQ5gH<%>8^&ESAfL-0e+c8=Fb0G%D2##9?>?lK ztpsR`pn73YVsK;#ACjq$vYk-nX^g)#QUPK9us2 z)q9lGU-&jk`NZm*!uT|dttxI7ekR-!MsK45e-p;`Fus*d zez3IsE{q*A_+Ci;2a%m&^i?oFg|R=3pV^ALTWx<0Wco=ClPlS;SBPBjqsR+_c#jNl?iAnzca~ONW_&bb!TxRk{{3ncmZIS+m z@}Ix(_>JH|7{^3#kSBk{{V6|0(1L#g5Yp`M2pUFkM8v%)G!W(oeq;nksn|&PkZ${r zj<`4HG-xbxYy>AnaGY&*yvSlc{823(o*2P!#oRQ4W)Ykm!70`QYfp_}u!3(M!RZm4 zrsjk6V{T_e&@zHEBREUq_dNd@a0Dc5$k!Tv`Bzov3iAr_{7C(E?ZOCJsp2dgFN@%E>+Qi3b7cfqMbK7CJK+e8nar>V&u5lk295kc<=dPdMowfW65qr~)4u~;^DMeuM0{UR6^ zLH`KuiC{nkcSkT#HjKZd#0=teL{KjKStah<+j}DzB7^&cOO^Sd5zLm&@CZgkaDN03 zM(_aR;XXCrt{WUBBLCf2rEUSg(4P#D1s zDFwn6^30qRMNlkdrIgYLW~x{wERUcfg31V1m6*3m%$gFjuEflWpqlxKU~U9+WcI$= z&WoT*#Sc{ckmtXO>}7tW{`-9|M6f!77bAE%f`t(*=18s0OA&0aQ7w_UG=hy%mPPP- z1g}K!Y6Q!z{iYK0S_CU1*lb&EEirFIurh)-WwXudt0MSP{H+K+h~VuA-i=_5_47^y z->7zN1n)^)M<-ea??Ew_n(Df}u@|2Ki;IlfP*#^Y(UFTy6*;+>=96==F{yup$f>Z>t2oe#* zrO=*7-;#p|lPdmDV$vd+i2HNjtR?2;Vg@oFY8+klN!j!ic6#TBY$&JV*GN_CW^~sdAap)MHE+B-ZqMMmPbm=)t0vx$q$ftT@*J+x!z`g z;*C+)u298WP3O zD27WJrjGLQPet)(6i-L-W)zd6m=(q3D5gg-C5q>wcqWQx)r6K)Mc51Z z^OjGG;)GK7Hg!f6rBM__Q6%SuQ8bla97TzYPgar5%c7`|Qf|YjjAEt~`pNsB9mPvg z%!y)t6mz4flI6T8&Mq~rN=d&#@vfQ=D>V<5nh~XDT@>r1crS|gqZn6ep3pSW?FUhO zs8$ngv>T$>9L2{`d=kY*RWUP@O3kJyK2?#e_@ek(6kDU%V&j}5pPzFgzF%oPttQY5Uq9#dq>KyVSg@=HEy0!~fsQk5TN3;wK&&QT!amFaLin z!}u+Vm2$|ae&_iR#ct+@NhmcRO5YR3sWEt>_=jzyNJQa{!imBcMKB6~6akL6)O^A* zmYT0hOgrpVcf2Af% z1D>~K_4^{9y}eQFi{kGnjxTf9Fkk1FnSY}=I)?pG93I1eQ6Po`Q5=k-mD*lZW-c!? zCWgaexW3HXSY|q^?GZ5?8AF2@8phny`xY6KG>YM<7&_Y`6Lm}sO=4&q!|^d38^dui zbSX1;l$l;-=5Cpt5OXgvgUZZ_F`OL3Nij5y;hr)xL>-Nm%_%WFUS=kgnPxGxi=jC? zjp4Ky&W_>q7|x9042AKG?e{Ddi^@!k7|xBMWen%UP$Gw=WoBWSIWLCuV^}2RCET~IMKLUuen||M#;{EM9buaou885X7%o@j9QE2V^M0ARGKRKl`=Jfvsu*sJ z;p!OLTgz*h#u%=R;kp<$l$lS;%vbVBCpX0KO_}+=%-j^itub_n;pP}R#?Z;O{ZVdj zVR~cuxyNZ@NOw2gJKvQ!vmbJ7>35&KPTNQyiYhp_&0~i=Re}Zh4%~pEi(_s z@Nf(d#V{&{5fVoV|5FpTVi%)h7#G7MF+3K-qcMz;0d>A#paEZFr5sR`$72|;B6XCT z35xSc8|_48)7Gahq#W30Oqsq-Q*7DgHriwo&d_IQ47^cNAL&fP_$>pYLxhYWb z)N*&16^R!M^Z73oXH}U!|M6rtWtk3Kb8jd3dM}3eRYlGw#1CTlP_-Wkn@eQX$1!Y_io>% z<`}+=;j>9Ke>O!J#4Gy6umMd zxw+i<#RI~iklnE=6hk%!C+7Y^KO93sRS{t{hL{M=;@t1@pOlgkriB@6(@Po1srSEZ z4D4l}_}?-7Bl541`hK4OmLG_rubLyShyQULCc>y_nNQ9UQX0h3FkXKHe`FkuBpxL^ zT1fi=a@9DFW2G>DipPte5XUJZP2xCFtn#OUm_+T|ZHIB2@QL{Lj$8km+r>RJ9 zr^hkEX8ufxXT|Y|Ra(T+QsOznb8V}!<>q{Hb&(J0Lh)Ad`p*Gg97mftE{UVH^h>Q} zJ_(n_ak-Ry@d~+R*nG8(qg@==srD-2)p4{JxkgBvYegoMo9jhx5Z-8OZ;GRX<&(-y zC-IxDa*If3;jO|hadZ`VM!BN@ZYtg$M|Y7s;^-B}o#H)&wCO2Qs3yI|`w06AOUq3^ zk^XTEu%jCo$GytW-Ej;O87#a<$bH>J8DLI^sO``=?iU%xDdT@i70+kv0r7n1AL0zE zI8w;iM#b^4<)cL&5weRhaZHTkFSc#z0&i#~W1C_HusyCyo_y zyly?@E#G7%R>!eEj<@1i7suOiyc5S71mThkzH&pH=oDxeH>rJ@l_n#Y$RXC(LgbO9mn=KzKP>o8kC!_71)k) z^IaS};_#_RKlJ%S96!aeGmanSgi2ojS;b%M{8Icaj!+!C;`k$uF1-J@S>;G~$MI(z z-Z=KeVfgT0SS!qxn}5rVPuw3zFphxufpSAjzUovwyuvtf{1Zo5#Yi04IHGZ+;)unO zh$GI8%scH0_tRoY*>E;btT1WujPT@&dY`#C{)%H?9DAj+m!+Ehzg28jVg8Ndzc}`* zSgSA&@U&0hpcEwBQ5fNw*5}~~9FahSgf0zg(ohEHRG3Bycc~nez%dDTWgac$3Z&RL z;cgJFI`ZRW#v*M_5a+7?LkVXNPfCEu+LIG#p1>&yoSJZdZG#P)$>9V1uX+6Pmw4U@ ztIm+0GZQ#Vgv!|ov=DD;m2(m}zrwJJYx_L%1X?97be^fm@!mFcu~ULtt?(_ zW4@Fg5@?;kWeIl~w^0+W1oqBQuSlR>0#~XP<7}I7w==8Q5s|L0R#p21u1UE6LWl~7 za9sj7C2+lByCH!aWs|pO47BNxKu6V*Q@J^Tz6sotK%WFUCvay1wy??uhska0zgt8A-W%sZguR1ZE}N z8@!pS&CfM)j@EPjs={ek`%j}*C zb6{=ey3nx~X4-@!EoJ~q9Ol5`n zIDw6P@h`~Cq)w_$32aW_(**uhkwf?_fh}sqb8IxZHn`yImXg+C;)Q-miWhkrls_GuJM4pT?`CxL&pDwxCl3H+BpGv#xO@Sv)Ybe9bcOcIABacmNYC($s8 zhk3;mHW0FxBa=8fiAG5rm2`8yy27|NeEyR}4Y)iziqQCnj-n5+^0m zG>Hz1nSPE}sHY_BV{4YgX-PCsx(k(oadu8m;&KIfMiOTxaefkKC2>v?XD88;AO0sM z-KlxE!hBR=HdGjj=c?*F=`3E5#3e~wn8Za%v{KbZW&UFEuhityB-$j=S_-{=EAcX0 z%%|weB(6%LZ4&L0?ryqHLm;_2iS|k42f`v_zBY+YNnDpi$0V*#y8jr6uNy>eOyVZ1 zbVy=Xg<%!*(4OZ%N1b%{FIO^=o!*+nZAo-VqO0_L7{qS$ki>7YWZRDX;BgW?8C4QJ zly>f~GC7&Vp8!&{oB92(B<@Or8>g@G$qe^PqQC6f9bfP8^9e}|PU7w)2FX8%!xyXW zN#fq5yGe&BFt#0%#PB4BCNWI0arhj_t=v;dJdkvMCyg7B4H@l2NsLTlgi=I>yLA+o zMABW@v}gRZc_fL)l6W+UF^Y}RQslxOo5VO-(jgTFGd_tYlXxPD2{tDb>11LOPbIPNwlam=Tw>xllVA^kCNCRpRHtYai!U);w38P zSIDPHe375`BtFyb*kbp{R*}zztt;Kl!d3BQ5qU^_oVv~7j{as z-P{6d!u7@_#7?75O*Dn)e-df6{f&pe;>ib)OJZLVe@vc`gq=D2DIA+ZgA|TVpKw(1DV&sY4?_;BX$lvnaB>PQQaB}rGg3G;h0{`KmO}HC zd-!u_@in;8oSt$I+u@al;+d*CD}}Q~MpU{N(22N* zl|tVXdZ*AQ1#hMCSDL+*rs+&`R|@@7XfxAvm}$DtG<|290V&*>2nlEn!>{=jOL6>;i#$e^=JxQD$KxRDLkIS*c8TTMyL$b${C-+ z6Djw2r!m(Or{KvH3R0Mu!c$6SzKf?*n3Td)P0eKCloXyx;aTw}vkVh{qF&FX@O%o> zrB6$NBCBSonCFEl6loUNBWIu2tdbPUQz&KfHDz2d9K}ie{kIez^hZ3pF)kMn+jVkNMU&jFKE%esKG8wVTs5h&O!={nYUT) zj%Yc{oHNTTO<@^VqYN&XWiFw@uYjd+nFtfYU|vh%jTBa-@VeZxBL*{$U;a&DrMhOn zM=A5GQ&^M2TPeKFlqzh7N+<6qY_3UKu1(=f`B|63d(4&6^}cYuFvmrb!d9+EPG1Te zv?V`IVWY@(3cmX+vnhqmDSRsNZi%0zu!Va>e2kF8{9FcK2)Cs$Uiw!le67A1-ZzTv zTP=X?!taDTQtnO5gjw#V*M3OhrxbRk@S|EWMZalWKd11E=83vL zl5%f`qr#Yw#kk1iStgl6CWTZAX+_9c%ijoPQ^+Y8_Dhii*_*;YDeOz(Z?&b)n+jGj zdklC#5BwDVOW}Za9PMeq`$nW;((X68Xp_go(`b;!5oveDa>#7nFpVSA?wQH$#^i7< z9hJs0X&fz)X{1@>G>%QX|ACRMXh7xow0p9hkVexqnxx(1^u)BgZBG*NtRQEn%)=>Z zG-um1nkf?MytQ7>=Rawjo_6mfX*N)nXQt62jkD4?JMCU0x~YnuY11<8o|e4+o}0$S zX`GjKuNuwx7w|ML5Wi4Jv6aY0!dkjbJ3VkCl%`R^Jfu-B z8_qA+3A0z3#!M;fEB^*(b{Y%Pn3Kj_Z3IriJWUE+Ri#lapEbhy!U^*Xt6oUsMVaMy z3Zq(-#^N+yl5={dvLx-k`Q;5Ndw)5N(fF-2-cRH0G~P>NjZ(*s-r;^!k86cg)}=9do_kBc<-~Q! zu-7X*y8SSX@7XYo9cjGApMXo_<21fVV`CayI8$kCPGeIVpQiErJoiq6uNm{)E7xa= zq)>dTj*HKQG}xBLH)(t+gRi*c(kNBix${i5$hT>1Pvbjlzepk{ZZpsSG!pI}KkNf2L8J#-21hoDK## z&n&a?dllI7dG7lZe;NU9QtdcKUYABJjZhkqG@LZToCUR7C5)=!YVmj)2^HBkDZ*oF z%{-G%;I8C=OOGH9E@)fu$Q;Hr#!Ir~DX`+*x) z1K&B%{4&p6o56LerK{^Lq4AA$n88gMbjqMZ1|8L8m)7|o^UTdE*2*CpcFy3|47y|x zuu4>E;V8Og&{N~RU9-?V<6e*M5Z;+V50OZ0 z$Y6rf#YotYI5C5#WJ%7$kT@xWXEKWhQovSj{CGALDFY*nVJ-ux2)Q_Z&k8B}KQE$HZ_gEuuPJi6(M4OcM$`5CAp zr|Ins-pyc52JdKh(2S#C%xg1PXXED-a|ykl!G{^FXR4JDW`@__Vcek^Y|s=pv)9m# zJaDLFu*vRjW}6el*Jj&xO9o$Lur-6v)eDEou6b?Rmcf_oMH`=cpQrlQ8Ents8|GZS zFc?NiSKno@!|rI#I7jzG20vx6GlL(MJt}$q=L~*Pzl@N1W=Fqe5X)d!26Y+yt^oeX zpf-cun&Lk**dwx-4}UD-)br)dz{d^CGe`OfRpteKvO35qlR-#Jk^MSaKVe}+7!`7X z#WP5#Q)V^4Zc`a#Ge~EUQO20t{Cwqj&e#Xhdo%bugMCtd(~kZ}=K$YLpQn-Tm(Txf zJ`ZMaSQf~_WZl!A*w-NFfaxWpR{vlPdSBeM}Z7Wzjf` zW3%oZIQ<-#b&sRtv+m)^*9loPvHZj=PSN>5%cj}-tHUW-G|%GHEShEAJ2Z|iKfu$n zI6aGmeC8uOGm92koR!7dS@)n|U-=$eW^qmyTnv0ilW%)o78hjQYt8vt4AdKe3$yhP z4Jb0n7iDoV17$OxNPnd`;Rs4^|8%#GqVWzi{%4q0@};yj&ct%Nt*R&Aw!Gwcpkrgs*7 zv*=@$?p5Zlto!V`7fF@rpT#{{49H>-$Cbt1^3%V{47VrwV0JBjZx%zdxG#$#%Iye= z+`Q~%SQd|~$aFE_2iQaxAkNW4S&YhJL>42n?uDMG2WO2dyj5ij6kqSyXCt z6^efx|M)9!+@2ir>@4PGF(-?;ngR}otB#@aeQTAS+~&tg#)3&dYgU@r<63KuR8IW&|q zyV_LCrcn+j<#1FEC+2W;&b>?=BLlW-oWrp>oRGtDIUFzX#cKD4ZLu0Q$zi1k2g_DX z)s}}C`6)Rx%i+|Vdp_rPee)bH$>B8FoSs9=93JH7e{wi8hqH4yOGPSgSDO}=ud6oa zIox1v@@6;X zaBB`7a=1B%jyZJ7;m2z8r;+7#{@2v4aoV{#aq!(%Eot1;)-m~rB5YTT7SK8J}pJRxO54o@l% zSE-6!Jf-5(IZTp4ryA3x#&oMOQ@F@;cqWG#IXs)g^Eph-;W-)is4;zN%zzp*Er;o9 z#a;%WGbd&9<2O4qL@%b5b*;DW()|Jz=SA@ z5kW;1L{Wqd>@HywyTC4@VnRg(BPfaq6$65zAcmdLJ>g$nLw|q#&*@XAUcLM7yDxT_ zo*6ZV*wkV#wpeqEEo#|*MZ_6Jv&Aj;lA`5y%7PCWF^oY$?~B zI19eXMKojk)1J3l>}~0P%O|h07{+$052bw6 zVxNe7EbKnRKd-T()h+h9luy|+Ew)D7KSiqcFIw!Y7F*k5Uve=9@vz|6tV@=CW?+Ey zbuIR5i+$H(>s#!5W&I#z6_?Dwk1h5~i~ZDMKeyN**%$W>=5A=QtE6mfu|HaDQ;YrH zV!x^E5b2u(Kf`C>&ldZu#kREAR?d9oj+%jcXJDIb9+2{n_`faII%)s4SUBmQyjof; z*<#riOSPEWV(AvkaAME!PhnGMVD=1nExs9#niU8SB56k^{nN@( z!lQ*ub{07%X~&A(UgDoYj!$mCd1rB69i5mo;z`1jlh#G#l%)Sr#i`<5g`C4QJ3Z-d z$Y&(|+Yr{v`Fxf_>Lxr}$T-gt>CUhNrAN~Lo&vKNHm|;VCAU8tIbWoAF)8dLyioYR zq>U=^PrE$&C9S{2i-c4LByFJh#llO3_sIUTq|IZHNqabHS0wGGq+OY`>ykDoY1bs} zs-%C)<8gJ;9xT!GA1Q-{W2FpXk107cX~P2hM@w)+z;8_21P$5ENxM5~!;^M<(ncih zRvFxqv`O;AT5e0)bK-X-?ari)l)>{-MkVboB{|BpB#utneM!3~Y4>UZP#hyNO?BPR zfR%h8X%+JDP!JExj!oLsq&>o_lQu4Ck0))savx3FV;qPe9$HRF+C*hNk+j(*s4Kyf zNqZ`33ret9W-kdRC++E^JtNC0Nqa@&vq6n-l;Amrk+kQNHa%(60{sP%r6rh=w6dg? zB&{@Q%Yxchl%PCmGn2Nm1Rs=ORSDLVpfYLINvlfQ9LC9z=4<p0 zc(=7ed}Y$!7h&)ph%g@VkCL`FX&)zTb<#eOzDgJ?_4lPuleQ*lp9KY}e4ex~g0>eu ze3`WGlJ-^7zD?TK+$Ch(O2u~-u9N*<;@>Cj2N|$zn^OFkw4c~Ut@NLhwn+N&81Juvh;L_J{vOT9TFw zlr#C|FYd7^%Oq`&l(|WZq|8eiQkLbm&;6D^0hIKgQgUM{B+XLRvDAMrnx7O`N(`ke zobvy+pi?QRL{qkN%AAxXQWi^DJmv35ol9{{DY}-TRmyfs`DX-*JkBn~E-BkhHoK;b zK6{p8_ms63zoZmbmipfo*)wJPrEIU1wNF`_lS9n6it-pU{-PH07_>%Y>H;uMl1- z93;F-IJwk+fr|Ih*QD&)lz)RiSa_X~$ss8lDn2Ywrk3J{lz-`XBc}ml<_kqByIEv7 zyE>sx15p~@-;dtSr!pBnfgvjG5n;2naDrTC!K|M-B@mAF{Ot4i^*$ScCtGGOkjDSIttZ>H>Z z=~Uj}YAwZhUT~)DZHaHC?AucOpd#-``HA~~%05ZiawXqO*$1pwe5H_n-cQ+YD)OO} zkAxo!|0=~lrC61+A5*qEW#6RiQ&y_1&r-HVq@@(OQhbrJFO^&?L>azH+1DwHlp$V* z-O8|6ncvcHQ?`z~Q_8-R85PF=L(0}Gxpx`%li5#7{w(}OxIuVe8ICFgKStT8f!@T( zxfQ4E_muscvdt;mqWSQL@XwSTTjtO9tts0k<*$^TSccQf@OR4o;U=TpbIZ`H4F9Dp z&7DnV$&{s1)~5{p$}pe|mzE(T-R0&la%CBYsBA7}(X{1LhP1yD3(7U|o68Uq38yWR zwp(R?PZ=I8gOj$M(iTfwLI!c+qh)9%@fV9mo z^PlN0D8nmd+W*tmF}?lU=+qBM+mUJOl(xfEGKK@-wv@GsX~GGj~I-Dw-bX_L003?Oa8(spCou4k#VeW4EgPPN~Zwwu%TYdJQRBNfCm zB5k(>)v+PBrER2Yxm|ci+Oo2|Q^`?jyDM$+ncJTy(|&Z?#-{C_wB08s_oi)(EEBT1 zKWz`C?SZsCDADhz;ELtpKzSr>6Vf&=ZI7jGeA*sOTdSGdpBS^d9+z2bd3z#lPo-^Q z+MW!`76*<#Ck0J-I&E{)HYIJPX?rGZ)6({A+MbjB)S%S!0b%hM(l$e7rwjK`MJ0hj zS=uV3m#1x}#A1z=X`7w4s%bCm^c$p&cu?m zy`HvL)AkyhAM{~)P|=%o&i$XuiWkhnw;8|AQ16H=OWV7FGIOSX$;8|hTxB|utxVhd zY5#)r11S_g46^8umXGT?e3iu2Y5Oj1pQi1rw13w7Ot>a(pQmjt=cJOeXZo8wk1v(1 zo{6tTsC*;xZQ9m}%#-E!;y(!23x5>;B%CjsU(&Wk0c;TdD%_a1O=;Vlw%?TeUC3J4 zgg?ap6gH{JTg936m&i8Z-)Z|N(Enxs%d$oF7CVRC!Yw@=*knXpp~n>@k_&S4X zJU6lHknv9kq0IJ=eR+4JpKZdPBz|(nx&$`VPtDjFN_NfIX@P!v#y>H!$eB{k3iNJ)eomlt7dba$ zJp$!Ck)9d<=7k=LS9EMwZ*|=T8S5iL^&axDnaJhBRhk=Ds#01G%Gg!XuNG3dCS%u%4-S-XW@3o=&_Ed`a=q||jNKUMHz_bW zVRMFOY=jzki||(AZ5bPtvD-5?Qpr1n>oqiYiWi^4-IcMsGd5bvFEjD04DQYN&)LRg z{7;|n%UC;p`72}NGxk8n#%Aonj6IaGXEhHW)|~uZv-c74al&HmqZyl!vB#uvdOx1A ztus-~dO~7kVRg#l?ld)H&t>f2nf`ML zCjXm>X~7u1klFr}a)y+Wpa?C?GFF+f@{CnToEc=%19Ph~Hiu;;GC4c&GdCbKV^`N? z{98P}Kg0P`m$CYct;*QEj4jVtL&jdqSYyUs%-H;lHDzo;#umyUryP9}n=`gZlYz;i zvN&U}WbCDky)4U?nMhP%&k8Kz9+I)P6@D9w#b4(DW$X=^y_vD4BKyeTkP5t=v1L-; z5q7HZUmkmxOSJ;0RNy^{D>C*G*Jj2(Pz>)&EIR*i2mW!!J_&+6rvj@p_HD*KmBD8j z`!Zu|GWJErKHs6pTJd72Ux|O6v2Ox{o(ht=>oWFT#(vJ&_Zj;!V?ShUy==~}z(p0f zq5?lDIYjoqWNc%`He~Eq&h5a%?G@ORvEMkcr4)nblH9Dh!~yyoTV$!!_?J7fQ4>>o}Z4J&PUjIBV649Gd>QvpwBEE8}}T~9olu|mdj;&~yr-$yE7 zu0BMN!;ovcD;ahz;#yohDs)_ni9A)|KhICNwzHD0T-!-xQU#u`z%Jsuy0)80Wd-I| zpsoU~T|3gXJzU$*wLM*H>-w{OFW1`0j1K2lU~kvjyVg$1Le;X5Yx^qss*=kpu)k{u zyVk+A1En7z{ImiGxz^FOZ)En9@DSGybFGtWhr0Gl1%9i*9~Jnk0*AYHglowP%;s6I z5<6GoC>AUfj&|(?*E+j)oNLFpcC2fyEB%(XsYKgK9IuM@t;9iH@=pmPGCQrEpm=)-2;VFu7_(c zxOSdvH@Vi+wJTlg<=Vxro$p#-*Lu6w$MrY!3xu@4(6#^Z&|*KU(qDc3TpQq8f7dRO zes-mQHFZuU2C4}8d6l?C{8HDhaP2bJE?2UriqoLzZIEljT)WD(YhAlq2Gws*9J=&s_L$jlk1grgYZTneGaX}&8|J{+HluKyEekL+g0Qi*KT#~HrKAN#0{0W zy%KluaBY-pBVD_bScy@U7+r~bDsh)Em5{)U~wK;+RHI=9q|3Wskt~DrG=UTmM^IZF? z65mu}opKvpTj1J!8GKiXA1blXwItCFc z{3G%&_dw77b1mUni)&elN!L=YWyI55_*J;93a)FOYlEsVxC+CnaAOs6u7y3zy9Un+ zu9;`IR$*in##G_qD*rM*;+{PwGb+jXakY^n|Yp6m~mB00|x5&0HTBLK3q?2Pk z>*CpQo}K8~@t&RF*-}o$DtuanHB~stvy(mhxe8mV@Lv_YDxBikX`Y?xSy#_Ov*66a zF0;^P7Ebr<49^alg`;QT*iTc&(8MjT+hz&th;ADW}(+C{BITp&O#5* z&Qma#&B6_{a5J+!>+RY3L6dKtg$sgcN6o^8o(*8qvwjl$3Llz<{+?ar+2eG}2NbhV zM(3VgqTGu;tCW7JXP0?aE6%QaWtRU2#TA}i$?4(wXX-(oUFF$Lo?Y$P5YMjhY_Rle zIRVt$w7JgnFS$vEdUm~Xhk5>c+Ei}v>_*RjbCRb*hC$_K84MSW@az`PcrU;+GB2mO zplEQLXSXZ&4$toLY@}y*DoGEt9Hsba#^Y|!Mk|Y)&Wl%8V>seU_E32DtJ5Cv>_L%- zgbxeH3fbyMJpYAQ5?+;!_v}&6|1_V+W9+?vPY`)RIMK7$XMqM!dA7x~No=fVlRca3 z+0&ktdN#$g=Qtnu6#&nk^=vBJI18(0Vf8GmorUK;o9@{(&t6blzMF*&v+(;Y%h2OE>~>eOp(kiRI=5wtnw@?%h{gIQEqIuKin)^?b&?KY9!WrHqWy< z&+56#WYBT8@4vybMs}B!&a=^FHWqlc*t3P6HG9^ivZu&$5gV@LIkVA6_Ahz%ieh+K z*f*&6RnI>6>^09mU@v*L%(FMxe9zwGBJ%9g*|>T(hR((9edO6Eo_(wUnxwDtY&EN!jTN);nUv3z zyG9k!+nU+pa^w8~@IR&GEbRd(YN; z_Jh2&o`Zen;73jy&pOQUd-C8pIC2ht@obX}HhA`{XB)Xus4R=0HV40Xw%N1a6-hUh z`opt7l{}wjb1+~IwsNP++F#sSv$oB%oM(S~mh$W$Zup-4%gvt)b`EZwgE8{Js*|3L z7f*ZUd6x0amCxyOP&o$+<{%riefb>ZJ&RmJDwY{>oYt~w4ZMUrLE}KK<;>fw^ zIv0CnZO^RrWRbbJcrGrRi#Aznm$kN8+dFH6=VGM1-7^>Mv$jvx?wgBAbMeAl)Xc?x zS?id!{j+vp);eVE0C}E27q89rd;TCLm(Rt@xi~m$hi2`NtaZxTH_H8KF1F0YVOcv| zX6{_S$nt| zPgY}UHA<_|J!|J?t)d#Us!^wk&dXXa)!S3pRK0y&_s-f~S-T)>S7rU%w?0|BFl+s3 zqhw!UKjBN&{$0#PS-UiA1G09p#DT&k%DP0JX>(cDuE^Tu%6hXJ?^NT;tPRTAa#hME z)8^`|U7xjUWOJ=>aMp&fjpE!qX)`oy!<1Z6tt$$NH)QR`tlgTmo3b_{Yd2?Yc-G!m z04(yM$So@MX*F)k+Q_Wkp0zu&_H{LWQZAj}nYB?_+oa@H;oVt#JZqz~cE8HrleK$A z=yMF`k2uc@O!9ajYY%2^Y}OtMY#!z;Rn{X}do*j~vNm2>+vNP8YCINLCaWi;q>#UvwWZ>31q#jhZ0en?EmIrWu6IS23*XDy3Qm=*tqgK!^ZCCx35_{| zA7$-hE(d<$E^FV4tjgNztbLKSPqVg0%4b#ZW>uT zO8i*iIvIQ?{61^zMSc*TQiC5wPM77+S^GuFJ^At{cQ(Bh{A<=Wif;;(-?H|5);4pG zl>yC2{?v$X$=bhJ+nV(s*75j@`+vay7Wqfmtp@*b>&{tA)-qC(!W8G5NcS55Jq|};&s|?IomyFZF2t9Z7tkGxM$A4JliX0d?3lJwmJU$=N|UJ1%D(b9PM54$j%(IXgr)orH(x?69D&VvR@S z>}X{jDgCG*mkv8ir`fSNe+^P$sK@85OU_Qn*@?OB&*4u}%qQpkCpoksvI%VUsX2ch zb`_qM^H=NXLS~(jvoqzq*f})omb0^E$tsxS>gZ1YIseqdqld_OIqNCXiMZy6>u9|^4{{`<6HMk^ax8>~8oZXtU%W`&O z&Mwc{;GA8Nv#U8D_!@l92IcIkoQ}-1dE#_7BP-%if-|(Hep~gd>G_GLoF#B~IhJML6Zi z?@{aS&DjGv8xsU@pA7B~>>rd3jUSQ$yJ#$jUb&A*8JDy1L0OtTmb0god^~3pa`vPK z>j~jRA#I+L0m&qh$vJySO`tMG$}_@eb2c@wd`{%y8cfUC^qjq*xy1RyIWQw<6*()> zG%J-}7UY)aY^M0Q8vp90xcOJ*Y!2h+fad&DKyl_UYi`b}wRX4|*_rI>+MLbHSzXTR zbN=_~XxUC*fp5t9?=~|@v-vq|;&jc~!kqswvmYN$Dyv!bvb$*ZV$NR9+2WkNq#7fN zgjuiTY)Q_)AEX~1_wxPEoV}T|*K_uUEGe=$BVWo<(4;Mf!O8zl&Q|1XS?X_Nv`JF)}&ZDQ|AhyxjJ0c5pPaIm_iNlDB-$khcO)AAH?6@8j^`jfjwv;kVMAg zJ@eZ`qH&wN9hkSac{?EQpL+I|WxKq!&)a_D`v~{V`&%NNoXMYn$XkcJRqC^TD#hv! z%3H_0|H0q?1#n2-4$E7oyd9eN&mgqq1Yqvrd4FQ_;2ZTv=B;zyj>_B7d1Efu$ZX*; zc{^6#*!i@ieth0e%G(KfJ28l4ne>y{2~y~pv+EmT-cHY3*SwvU_fKlY2&tcuw+r)j zX5M<{?X0|Y&s#TE&GjWDIY*>@tv}-D=B^7N`|~z}LFWAvCB3ntTl02X-tNiU?RmR1?|=LI4#q4(9_PcKyxpC*y8`9VT8s`j zbMF-&6DarPjUo#^khcdlmpF|%%546_c^j9vv3YwW@1K3Rc@`TrK5vg|K76U|f?1E} zZDQUgN|}EP8k{@Bfemy>V7g%G;E@P0riXnmKGBcTO5VlecHp4;-4Q>eA;l zD9;P037PeR$dR>}q1926w^DYXx|DswK`G~)&)dwrRmcgQuhchLs`54~?>}c_@Z3(> zt8?;Jlef8ft5$DwY10FTpq63etxjECpSOkbGcRuqd7CfZC=79939!>p11eZZw#JInVu$~SrYE^puFZJlD^9AH}*$@h8t zK`Vv*&md=WbI#k(dHYFbYzzDOm%MG#*lo}(`c=45$T>zoY~b&C`#W!&^R`WG`9nVc z6mAi2AYpQ$<(4BPYRk3jLK71 zHg7p@{^G@~OKbTXS+-Mwe*s`lfrH4OarUna!v%kUuCC=T%>Tb{0>%oKP%pxo94{;ZyqlZxP$S;BS}|89a>-DDZEKjZ1@Wxfp5Lv0#T3 z{3&s8!9QR8#cweb_|G-I4NFmB!NYwgc0|FB^n>&ZvTw)vE8RL5w(r=qU&8DEf}K#{ zpB?a@pnY$=V4x*e(}@K;NeX{5jx&>4T?*ESp3X_ zon5fA3cPFZZx4&b8TmN{>t67Gua!2OA&ja=!Fm>WKJ`QDCd*z0JHOzcytt+)_AdDQ z!v(@V!V87}+m4*cc2&Xp7x;A#|GdoVICBORY@k2T{Jl84OyrV+T`Iz`sb5~OD+~Vb z-CZH1!edatuht-P3uS*^Td?5;8?2Dn>gx*rS$>G$|NL_YpAYjR;fCq+Ikl*+1<6fH zlH6RdIw>OxJoWqi#ztMPefYKlPg4AY27ZOaZ$6vMA!fJSS+G$GfSmSpa(970P-&wJ z{LclyXQ=Q;8(3rvr=Q>O?Td7oe~Drb7x@46_KTw3V;UoRd%WP^(@iMwCn@}E>?ed1g-;f2ek~~Sm{hRI5}y`QSy+o_3VhwjpSQ)B zS?O~Hn^xfO4f;2~6giqNsQJv|PqlD@%_#7XDy&rVfh}SH%qlNfWx-|^tU}({{I=?u zs)9B6i-=vsrRtM8?AU_ME$}}t{7buPA$1Pa?%5f0`4U*KtI`#4hknAiUWd()r)_J-ErY+15JOZ}uj zvaFZLY57ipXHxD1_O8D){666tWdFQZuoVUW+JGI%@nz)i7wpS|eNeEq8u1Sc{PSG? z6@`6Vu+?hLC&E<)d#BcaxAW7Wjh~6II*Okc>@T27%D9+L!3btMfLt>B|ou3N)kum$ZV82M`?4mt$e=XQXe|r1LqVgO6 zZoR<&%dpLAS8-|o#pgc-+oBe+c6QVu{`O@D7`Ab9HvFwA`cJ_!{I#}%CDot*30s7m zY^h+@rA63*F0bwj<`pa(C^X9jyr6<+pe1!8BMceBhCK`s!%l{%A#QLCF~hOy|2dka z2}3KxySxEWw4Ap)8+J47V%XJCDa#`6ZfI@(V@6uC?0dD?)6m|qmtk*18$(<3e;#>7 ztzYVUe_JTDGpw!ki|k|A->|P?Kl2~ljpgZ8HPW(!fyVTCpy43%?|L{2EOH$;f5V}M zLkyi%FAH-1aE={jINb1!?nId6mUyJ0v*9Si(eh9nT#ni?hI83o^G|Tc8O|^qZ|Gt; z!EmzSM8ipjGER?LtgFTMS`=q;(i*zb5Bp6sYBRS5!|8@UWWbpJtHqgyvs9MN>}EJe zZ9m(<;xy>4u1nP-Qs)l}8+D%Hd_zw|F9pL@z~)fzZMd9$V(4e+qpS;s4ETQ{eT9iS z^jFtiWVpmIz;Ll)pp@dPj77Xu%4Iv~oUyFyO2gHLL58c$zrWzDzE|_)8uNcV`C5*h z%my2-V>gNq5gE#vQ0FVx8*Vb(V7QT8s`D)4AHh*J3^(xn#Xjf#1-;#3xJ{#QtB^au z?S?z(S)<%ePrUCmj57a+F*%?dzPse}Zo_C1`oG6;ulSfiVc7Q@o-;h4z#cSAHaujQ zV0hRtPE8(bctop!eZEH>#v2|pJSv6JQY1buOY$cSPZ}mF$l@41B})#vlaaPcHJ&b72hWQyrEPbIL+{a$aEpQbcUfM;Ecb_P-Q6B5X_WbAzmq@L7O_v zGSqRzrOYwZ80H$PWxO|Ywad|StrRAC)Enl>o;s6_98<%5Ef6Lb7#1qG$*|bato~eN zc+t?V4*S$$|2ls_UoyO6cv-nDb)dv0hJ!?Cz`=Um@P>MiNe rR*^|XQy$J5Z^H@ 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 literal 0 HcmV?d00001 diff --git a/extensions/geoip/GeoIP.h b/extensions/geoip/GeoIP.h new file mode 100644 index 00000000..da759e6e --- /dev/null +++ b/extensions/geoip/GeoIP.h @@ -0,0 +1,169 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ +/* GeoIP.h + * + * Copyright (C) 2006 MaxMind LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GEOIP_H +#define GEOIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include /* for fstat */ +#include /* for fstat */ + +#define SEGMENT_RECORD_LENGTH 3 +#define STANDARD_RECORD_LENGTH 3 +#define ORG_RECORD_LENGTH 4 +#define MAX_RECORD_LENGTH 4 +#define NUM_DB_TYPES 20 + +typedef struct GeoIPTag { + FILE *GeoIPDatabase; + char *file_path; + unsigned char *cache; + unsigned char *index_cache; + unsigned int *databaseSegments; + char databaseType; + time_t mtime; + int flags; + char record_length; + int record_iter; /* used in GeoIP_next_record */ +} GeoIP; + +typedef struct GeoIPRegionTag { + char country_code[3]; + char region[3]; +} GeoIPRegion; + +typedef enum { + GEOIP_STANDARD = 0, + GEOIP_MEMORY_CACHE = 1, + GEOIP_CHECK_CACHE = 2, + GEOIP_INDEX_CACHE = 4, +} GeoIPOptions; + +typedef enum { + GEOIP_COUNTRY_EDITION = 1, + GEOIP_REGION_EDITION_REV0 = 7, + GEOIP_CITY_EDITION_REV0 = 6, + GEOIP_ORG_EDITION = 5, + GEOIP_ISP_EDITION = 4, + GEOIP_CITY_EDITION_REV1 = 2, + GEOIP_REGION_EDITION_REV1 = 3, + GEOIP_PROXY_EDITION = 8, + GEOIP_ASNUM_EDITION = 9, + GEOIP_NETSPEED_EDITION = 10, + GEOIP_DOMAIN_EDITION = 11 +} GeoIPDBTypes; + +typedef enum { + GEOIP_ANON_PROXY = 1, + GEOIP_HTTP_X_FORWARDED_FOR_PROXY = 2, + GEOIP_HTTP_CLIENT_IP_PROXY = 3, +} GeoIPProxyTypes; + +typedef enum { + GEOIP_UNKNOWN_SPEED = 0, + GEOIP_DIALUP_SPEED = 1, + GEOIP_CABLEDSL_SPEED = 2, + GEOIP_CORPORATE_SPEED = 3, +} GeoIPNetspeedValues; + +extern char **GeoIPDBFileName; +extern const char * GeoIPDBDescription[NUM_DB_TYPES]; +extern const char *GeoIPCountryDBFileName; +extern const char *GeoIPRegionDBFileName; +extern const char *GeoIPCityDBFileName; +extern const char *GeoIPOrgDBFileName; +extern const char *GeoIPISPDBFileName; + +extern const char GeoIP_country_code[251][3]; +extern const char GeoIP_country_code3[251][4]; +extern const char * GeoIP_country_name[251]; +extern const char GeoIP_country_continent[251][3]; + +#ifdef DLL +#define GEOIP_API __declspec(dllexport) +#else +#define GEOIP_API +#endif /* DLL */ + +GEOIP_API void GeoIP_setup_custom_directory(char *dir); +GEOIP_API GeoIP* GeoIP_open_type (int type, int flags); +GEOIP_API GeoIP* GeoIP_new(int flags); +GEOIP_API GeoIP* GeoIP_open(const char * filename, int flags); +GEOIP_API int GeoIP_db_avail(int type); +GEOIP_API void GeoIP_delete(GeoIP* gi); +GEOIP_API const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_code_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_name_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum); + +/* Deprecated - for backwards compatibility only */ +GEOIP_API int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr); +GEOIP_API int GeoIP_country_id_by_name (GeoIP* gi, const char *host); +GEOIP_API char *GeoIP_org_by_addr (GeoIP* gi, const char *addr); +GEOIP_API char *GeoIP_org_by_name (GeoIP* gi, const char *host); +/* End deprecated */ + +GEOIP_API int GeoIP_id_by_addr (GeoIP* gi, const char *addr); +GEOIP_API int GeoIP_id_by_name (GeoIP* gi, const char *host); +GEOIP_API int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum); + +GEOIP_API GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr); +GEOIP_API GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *host); +GEOIP_API GeoIPRegion * GeoIP_region_by_ipnum (GeoIP *gi, unsigned long ipnum); + +/* Warning - don't call this after GeoIP_assign_region_by_inetaddr calls */ +GEOIP_API void GeoIPRegion_delete (GeoIPRegion *gir); + +GEOIP_API void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *gir); + +/* Used to query GeoIP Organization, ISP and AS Number databases */ +GEOIP_API char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API char *GeoIP_name_by_addr (GeoIP* gi, const char *addr); +GEOIP_API char *GeoIP_name_by_name (GeoIP* gi, const char *host); + +GEOIP_API char *GeoIP_database_info (GeoIP* gi); +GEOIP_API unsigned char GeoIP_database_edition (GeoIP* gi); + +/* Convert region code to region name */ +GEOIP_API const char * GeoIP_region_name_by_code(const char *country_code, const char *region_code); + +/* Get timezone from country and region code */ +GEOIP_API const char * GeoIP_time_zone_by_country_and_region(const char *country_code, const char *region_code); + +#ifdef BSD +#define memcpy(dest, src, n) bcopy(src, dest, n) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GEOIP_H */ diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp new file mode 100644 index 00000000..e390f81c --- /dev/null +++ b/extensions/geoip/extension.cpp @@ -0,0 +1,83 @@ +#include "extension.h" +#include "GeoIP.h" + +GeoIP_Extension g_GeoIP; +GeoIP *gi = NULL; + +SMEXT_LINK(&g_GeoIP); + +bool GeoIP_Extension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + char *path = "GeoIP.dat"; //:TODO: build a real path here + //:TODO: log any errors on load. + gi = GeoIP_open(path, GEOIP_MEMORY_CACHE); + + if (!gi) + { + //:TODO: log + return false; + } + return true; +} + +void GeoIP_Extension::SDK_OnUnload() +{ + GeoIP_delete(gi); + gi = NULL; +} + +/******************************* +* * +* GEOIP NATIVE IMPLEMENTATIONS * +* * +*******************************/ + +inline void StripPort(char *ip) +{ + char *tmp = strchr(ip, ':'); + if (!tmp) + return; + *tmp = '\0'; +} + +static cell_t sm_Geoip_Code2(IPluginContext *pCtx, const cell_t *params) +{ + char *ip; + const char *ccode; + + pCtx->LocalToString(params[1], &ip); + StripPort(ip); + + ccode = GeoIP_country_code_by_addr(gi, ip); + pCtx->StringToLocal(params[2], 3, (ccode) ? ccode : "er"); + + return 1; +} + +static cell_t sm_Geoip_Code3(IPluginContext *pCtx, const cell_t *params) +{ + char *ip; + const char *ccode; + + pCtx->LocalToString(params[1], &ip); + StripPort(ip); + + ccode = GeoIP_country_code3_by_addr(gi, ip); + pCtx->StringToLocal(params[2], 4, (ccode) ? ccode : "err"); + + return 1; +} + +static cell_t sm_Geoip_Country(IPluginContext *pCtx, const cell_t *params) +{ + char *ip; + const char *ccode; + + pCtx->LocalToString(params[1], &ip); + StripPort(ip); + + ccode = GeoIP_country_name_by_addr(gi, ip); + pCtx->StringToLocal(params[2], params[3], (ccode) ? ccode : "error"); + + return 1; +} diff --git a/extensions/geoip/extension.h b/extensions/geoip/extension.h new file mode 100644 index 00000000..4a025416 --- /dev/null +++ b/extensions/geoip/extension.h @@ -0,0 +1,61 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +#include "smsdk_ext.h" + +#define GEOIPDATADIR "" + +/** + * @brief GeoIP implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class GeoIP_Extension : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual void QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * Read smext_base.h for documentation on these. + */ + + //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif +}; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/geoip/geoip.sln b/extensions/geoip/geoip.sln new file mode 100644 index 00000000..3c7e48e1 --- /dev/null +++ b/extensions/geoip/geoip.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "geoip", "geoip.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug - Metamod|Win32 = Debug - Metamod|Win32 + Debug|Win32 = Debug|Win32 + Release - Metamod|Win32 = Release - Metamod|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.ActiveCfg = Debug - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.Build.0 = Debug - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.ActiveCfg = Release - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.Build.0 = Release - Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/geoip/geoip.vcproj b/extensions/geoip/geoip.vcproj new file mode 100644 index 00000000..5128b8af --- /dev/null +++ b/extensions/geoip/geoip.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/geoip/smsdk_config.h b/extensions/geoip/smsdk_config.h new file mode 100644 index 00000000..64d78400 --- /dev/null +++ b/extensions/geoip/smsdk_config.h @@ -0,0 +1,27 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "GeoIP" +#define SMEXT_CONF_DESCRIPTION "NO IDEA WHAT THIS MODULE DOES" //:TODO: +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "GEOIP" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +//#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/geoip/smsdk_ext.cpp b/extensions/geoip/smsdk_ext.cpp new file mode 100644 index 00000000..3bd1ffe2 --- /dev/null +++ b/extensions/geoip/smsdk_ext.cpp @@ -0,0 +1,277 @@ +#include +#include "smsdk_ext.h" + +IShareSys *g_pShareSys = NULL; +IExtension *myself = NULL; +IHandleSys *g_pHandleSys = NULL; + +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + + if (SDK_OnLoad(error, err_max, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; +ISmmPlugin *g_PLAPI = NULL; +SourceHook::ISourceHook *g_SHPtr = NULL; +ISmmAPI *g_SMAPI = NULL; + +IVEngineServer *engine = NULL; +IServerGameDLL *gamedll = NULL; + +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif diff --git a/extensions/geoip/smsdk_ext.h b/extensions/geoip/smsdk_ext.h new file mode 100644 index 00000000..f4d30711 --- /dev/null +++ b/extensions/geoip/smsdk_ext.h @@ -0,0 +1,140 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +#include "smsdk_config.h" +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + virtual bool IsMetamodExtension(); + virtual void OnExtensionPauseChange(bool state); + virtual const char *GetExtensionName(); + virtual const char *GetExtensionURL(); + virtual const char *GetExtensionTag(); + virtual const char *GetExtensionAuthor(); + virtual const char *GetExtensionVerString(); + virtual const char *GetExtensionDescription(); + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual const char *GetAuthor(); + virtual const char *GetName(); + virtual const char *GetDescription(); + virtual const char *GetURL(); + virtual const char *GetLicense(); + virtual const char *GetVersion(); + virtual const char *GetDate(); + virtual const char *GetLogTag(); + virtual bool Unload(char *error, size_t maxlen); + virtual bool Pause(char *error, size_t maxlen); + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ From 5c6eebcebf1cac4ef4103c0ff81927dfe068abd6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 02:14:50 +0000 Subject: [PATCH 0292/1664] added new path format functions exposed helpers as ISourceMod --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40322 --- core/CLogger.cpp | 10 ++--- core/CTranslator.cpp | 2 +- core/interfaces/ILibrarySys.h | 2 +- core/interfaces/ISourceMod.h | 74 ++++++++++++++++++++++++++++++ core/msvc8/sourcemod_mm.vcproj | 4 ++ core/smn_filesystem.cpp | 18 ++++---- core/sourcemod.cpp | 82 ++++++++++++++++++++++++++++++---- core/sourcemod.h | 18 ++++---- core/systems/ExtensionSys.cpp | 2 +- core/systems/LibrarySys.cpp | 4 +- core/systems/LibrarySys.h | 2 +- core/systems/PluginSys.cpp | 2 +- 12 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 core/interfaces/ISourceMod.h diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 1c2bb2bb..a420e1c2 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -34,7 +34,7 @@ void CLogger::_NewMapFile() while (true) { - g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d%03d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, i); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i); FILE *fp = fopen(_filename, "r"); if (!fp) { @@ -104,7 +104,7 @@ void CLogger::InitLogger(LoggingMode mode, bool startlogging) m_CurDay = curtime->tm_mday; char _filename[256]; - g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/errors_%02d%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%02d%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); m_ErrFileName.assign(_filename); switch (m_mode) @@ -119,7 +119,7 @@ void CLogger::InitLogger(LoggingMode mode, bool startlogging) } case LoggingMode_Daily: { - g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_DailyPrintHdr = true; break; @@ -183,7 +183,7 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_CurDay != curtime->tm_mday) { char _filename[256]; - g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/L%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_CurDay = curtime->tm_mday; m_DailyPrintHdr = true; @@ -228,7 +228,7 @@ void CLogger::LogError(const char *vafmt, ...) if (curtime->tm_mday != m_CurDay) { char _filename[256]; - g_LibSys.PathFormat(_filename, sizeof(_filename), "%s/logs/errors_%02d%02d%02d.log", g_SourceMod.GetSMBaseDir(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%02d%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); m_ErrFileName.assign(_filename); m_CurDay = curtime->tm_mday; m_ErrMapStart = false; diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 8fb074b8..1d77ebea 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -87,7 +87,7 @@ void CPhraseFile::ReparseFile() SMCParseError err; char path[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/translations/%s", g_SourceMod.GetSMBaseDir(), m_File.c_str()); + g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str()); unsigned int line=0, col=0; if ((err=g_TextParser.ParseFile_SMC(path, this, &line, &col)) != SMCParse_Okay) diff --git a/core/interfaces/ILibrarySys.h b/core/interfaces/ILibrarySys.h index 94a00bb6..000668d6 100644 --- a/core/interfaces/ILibrarySys.h +++ b/core/interfaces/ILibrarySys.h @@ -148,7 +148,7 @@ namespace SourceMod * @param pathfmt Format string of path. * @param ... Format string arguments. */ - virtual void PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0; + virtual size_t PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0; }; }; diff --git a/core/interfaces/ISourceMod.h b/core/interfaces/ISourceMod.h new file mode 100644 index 00000000..444f2317 --- /dev/null +++ b/core/interfaces/ISourceMod.h @@ -0,0 +1,74 @@ +#ifndef _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ +#define _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ + +#include + +#define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" +#define SMINTERFACE_SOURCEMOD_VERSION 1 + +namespace SourceMod +{ + enum PathType + { + Path_None = 0, + Path_Game, + Path_SM, + }; + + class ISourceMod : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_SOURCEMOD_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_SOURCEMOD_VERSION; + } + public: + /** + * @brief Returns the full path to the mod directory. + * + * @return A string containing the full mod path. + */ + virtual const char *GetModPath() =0; + + /** + * @brief Returns the full path to the SourceMod directory. + * + * @return A string containing the full SourceMod path. + */ + virtual const char *GetSourceModPath() =0; + + /** + * @brief Builds a platform path for a specific target base path. + * + * @param type Type of path to use as a base. + * @param buffer Buffer to write to. + * @param maxlength Size of buffer. + * @param format Format string. + * @param ... Format arguments. + * @return Number of bytes written. + */ + virtual size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...) =0; + + /** + * @brief Logs a message to the SourceMod logs. + * + * @param format Message format. + * @param ... Message format parameters. + */ + virtual void LogMessage(IExtension *pExt, const char *format, ...) =0; + + /** + * @brief Logs a message to the SourceMod error logs. + * + * @param format Message format. + * @param ... Message format parameters. + */ + virtual void LogError(IExtension *pExt, const char *format, ...) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index e1ba5db7..f2f0ef45 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -329,6 +329,10 @@ RelativePath="..\interfaces\IRootConsoleMenu.h" > + + diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index bc777175..90dc37c6 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -49,7 +49,7 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), path); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); IDirectory *pDir = g_LibSys.OpenDirectory(realpath); if (!pDir) @@ -127,7 +127,7 @@ static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); FILE *pFile = fopen(realpath, mode); if (!pFile) @@ -149,7 +149,7 @@ static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); return (unlink(realpath)) ? 0 : 1; } @@ -253,7 +253,7 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -295,9 +295,9 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) } char new_realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(new_realpath, sizeof(new_realpath), "%s/%s", g_SourceMod.GetBaseDir(), newpath); + g_SourceMod.BuildPath(Path_SM, new_realpath, sizeof(new_realpath), "%s", newpath); char old_realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(old_realpath, sizeof(old_realpath), "%s/%s", g_SourceMod.GetBaseDir(), oldpath); + g_SourceMod.BuildPath(Path_SM, old_realpath, sizeof(old_realpath), "%s", oldpath); #ifdef PLATFORM_WINDOWS return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; @@ -317,7 +317,7 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -354,7 +354,7 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -391,7 +391,7 @@ static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); return (rmdir(realpath)) ? 0 : 1; } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 2581a7f4..ec1403f9 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -50,7 +50,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) char file[PLATFORM_MAX_PATH]; char myerror[255]; g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s", - GetSMBaseDir(), + GetSourceModPath(), PLATFORM_LIB_EXT ); @@ -150,6 +150,9 @@ void SourceModBase::StartSourceMod(bool late) pBase->OnSourceModAllInitialized(); pBase = pBase->m_pGlobalClassNext; } + + /* Add us now... */ + g_ShareSys.AddInterface(NULL, this); } bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) @@ -175,14 +178,12 @@ void SourceModBase::DoGlobalPluginLoads() char config_path[PLATFORM_MAX_PATH]; char plugins_path[PLATFORM_MAX_PATH]; - g_SMAPI->PathFormat(config_path, + BuildPath(Path_SM, config_path, sizeof(config_path), - "%s/configs/plugin_settings.cfg", - GetSMBaseDir()); - g_SMAPI->PathFormat(plugins_path, + "configs/plugin_settings.cfg"); + BuildPath(Path_SM, plugins_path, sizeof(plugins_path), - "%s/plugins", - GetSMBaseDir()); + "plugins"); /* Run the first pass */ g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); @@ -197,6 +198,31 @@ void SourceModBase::DoGlobalPluginLoads() g_Extensions.MarkAllLoaded(); } +size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...) +{ + char _buffer[PLATFORM_MAX_PATH+1]; + va_list ap; + + va_start(ap, format); + vsnprintf(_buffer, PLATFORM_MAX_PATH, format, ap); + va_end(ap); + + const char *base = NULL; + if (type == Path_Game) + { + base = GetModPath(); + } else if (type == Path_SM) { + base = GetSourceModPath(); + } + + if (base) + { + return g_LibSys.PathFormat(buffer, maxlength, "%s/%s", base, _buffer); + } else { + return g_LibSys.PathFormat(buffer, maxlength, "%s", _buffer); + } +} + void SourceModBase::CloseSourceMod() { /* Notify! */ @@ -219,12 +245,50 @@ void SourceModBase::CloseSourceMod() ShutdownJIT(); } -const char *SourceModBase::GetSMBaseDir() +void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...) +{ + IExtensionInterface *pAPI = pExt->GetAPI(); + const char *tag = pAPI->GetExtensionTag(); + char buffer[2048]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + if (tag) + { + g_Logger.LogMessage("[%s] %s", tag, buffer); + } else { + g_Logger.LogMessage("%s", buffer); + } +} + +void SourceModBase::LogError(IExtension *pExt, const char *format, ...) +{ + IExtensionInterface *pAPI = pExt->GetAPI(); + const char *tag = pAPI->GetExtensionTag(); + char buffer[2048]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + if (tag) + { + g_Logger.LogError("[%s] %s", tag, buffer); + } else { + g_Logger.LogError("%s", buffer); + } +} + +const char *SourceModBase::GetSourceModPath() { return m_SMBaseDir; } -const char *SourceModBase::GetBaseDir() +const char *SourceModBase::GetModPath() { return g_BaseDir.c_str(); } diff --git a/core/sourcemod.h b/core/sourcemod.h index 9b7aa24e..bd74af48 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -2,12 +2,13 @@ #define _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ #include "sm_globals.h" +#include /** * @brief Implements SourceMod's global overall management, API, and logic */ -class SourceModBase +class SourceModBase : public ISourceMod { public: SourceModBase(); @@ -37,15 +38,12 @@ public: */ bool IsMapLoading(); - /** - * @brief Returns the base SourceMod folder. - */ - const char *GetSMBaseDir(); - - /** - * @brief Returns the base folder for file natives. - */ - const char *GetBaseDir(); +public: //ISourceMod + const char *GetModPath(); + const char *GetSourceModPath(); + size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); + void LogMessage(IExtension *pExt, const char *format, ...); + void LogError(IExtension *pExt, const char *format, ...); private: /** * @brief Loading plugins diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index a0f2407d..acb28046 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -20,7 +20,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_FullyLoaded = false; char path[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); + g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename); m_pLib = g_LibSys.OpenLibrary(path, error, err_max); diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 2bc57460..e43449c6 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -282,7 +282,7 @@ ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_m return new CLibrary(lib); } -void LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) +size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) { va_list ap; va_start(ap,fmt); @@ -298,4 +298,6 @@ void LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) buffer[i] = PLATFORM_SEP_CHAR; } } + + return mylen; } diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index 9c89c0c6..352a6b9b 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -59,7 +59,7 @@ public: virtual bool IsPathFile(const char *path); virtual bool IsPathDirectory(const char *path); virtual void GetPlatformError(char *error, size_t err_max); - virtual void PathFormat(char *buffer, size_t len, const char *fmt, ...); + virtual size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); }; extern LibrarySystem g_LibSys; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index bb168ffb..6528113e 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -100,7 +100,7 @@ void CPlugin::InitIdentity() CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) { char fullpath[PLATFORM_MAX_PATH+1]; - g_LibSys.PathFormat(fullpath, sizeof(fullpath), "%s/plugins/%s", g_SourceMod.GetSMBaseDir(), file); + g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file); FILE *fp = fopen(fullpath, "rb"); CPlugin *pPlugin = new CPlugin(file); From 823fd20a6d11a044c429413408287e904c515f86 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 02:17:24 +0000 Subject: [PATCH 0293/1664] added ISourceMod to SDK by default --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40323 --- extensions/sdk/smsdk_ext.cpp | 2 ++ extensions/sdk/smsdk_ext.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/extensions/sdk/smsdk_ext.cpp b/extensions/sdk/smsdk_ext.cpp index 3bd1ffe2..01e3f42c 100644 --- a/extensions/sdk/smsdk_ext.cpp +++ b/extensions/sdk/smsdk_ext.cpp @@ -4,6 +4,7 @@ IShareSys *g_pShareSys = NULL; IExtension *myself = NULL; IHandleSys *g_pHandleSys = NULL; +ISourceMod *g_pSM = NULL; PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { @@ -38,6 +39,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, #endif SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); if (SDK_OnLoad(error, err_max, late)) { diff --git a/extensions/sdk/smsdk_ext.h b/extensions/sdk/smsdk_ext.h index f4d30711..07362c78 100644 --- a/extensions/sdk/smsdk_ext.h +++ b/extensions/sdk/smsdk_ext.h @@ -6,6 +6,7 @@ #include #include #include +#include #if defined SMEXT_CONF_METAMOD #include @@ -121,6 +122,7 @@ extern SDKExtension *g_pExtensionIface; extern IShareSys *g_pShareSys; extern IExtension *myself; extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); From 91fc277fb9ad0557f7dacf1b940bfa2d0f43d434 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 19 Jan 2007 02:23:04 +0000 Subject: [PATCH 0294/1664] new geoip natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40324 --- plugins/include/geoip.inc | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 plugins/include/geoip.inc diff --git a/plugins/include/geoip.inc b/plugins/include/geoip.inc new file mode 100644 index 00000000..aa82ac98 --- /dev/null +++ b/plugins/include/geoip.inc @@ -0,0 +1,41 @@ +/** + * :TODO: license info + */ + +#if defined _geoip_included + #endinput +#endif +#define _geoip_included + +/** + * @GLOBAL@ + * IP address can contain ports, the ports will be stripped out. + */ + +/** + * Gets the two character country code from an IP address. (US, CA, etc) + * + * @param ip Ip to determine the country code. + * @param ccode Destination string buffer to store the code. + * @noreturn + */ +native Geoip_Code2(const String:ip[], String:ccode[3]); + +/** + * Gets the three character country code from an IP address. (USA, CAN, etc) + * + * @param ip Ip to determine the country code. + * @param ccode Destination string buffer to store the code. + * @noreturn + */ +native Geoip_Code3(const String:ip[], String:ccode[4]); + +/** + * Gets the full country name. (max length of output string is 45) + * + * @param ip Ip to determine the country code. + * @param ccode Destination string buffer to store the country name. + * @param len Maximum length of output string buffer. + * @noreturn + */ +native Geoip_Country(const String:ip[], String:name[], len=45); From 2ac8a6597f7c7bd34a8e191f5b357d638815cdc4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 02:28:56 +0000 Subject: [PATCH 0295/1664] added identifier to geoip, fixed native names --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40325 --- plugins/include/geoip.inc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/plugins/include/geoip.inc b/plugins/include/geoip.inc index aa82ac98..3ba6f227 100644 --- a/plugins/include/geoip.inc +++ b/plugins/include/geoip.inc @@ -7,6 +7,8 @@ #endif #define _geoip_included +#include + /** * @GLOBAL@ * IP address can contain ports, the ports will be stripped out. @@ -19,7 +21,7 @@ * @param ccode Destination string buffer to store the code. * @noreturn */ -native Geoip_Code2(const String:ip[], String:ccode[3]); +native GeoipCode2(const String:ip[], String:ccode[3]); /** * Gets the three character country code from an IP address. (USA, CAN, etc) @@ -28,7 +30,7 @@ native Geoip_Code2(const String:ip[], String:ccode[3]); * @param ccode Destination string buffer to store the code. * @noreturn */ -native Geoip_Code3(const String:ip[], String:ccode[4]); +native GeoipCode3(const String:ip[], String:ccode[4]); /** * Gets the full country name. (max length of output string is 45) @@ -38,4 +40,24 @@ native Geoip_Code3(const String:ip[], String:ccode[4]); * @param len Maximum length of output string buffer. * @noreturn */ -native Geoip_Country(const String:ip[], String:name[], len=45); +native GeoipCountry(const String:ip[], String:name[], len=45); + +/** + * Do not edit below this line! + */ +public Extension:__ext_geoip = +{ + name = "GeoIP", + file = "geoip.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + From 2b7776f075b9c6b6cc6c7f298f3d5289de3042a8 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 19 Jan 2007 02:39:58 +0000 Subject: [PATCH 0296/1664] registered natives and removed todo's --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40326 --- extensions/geoip/extension.cpp | 19 ++++++++++++++++--- extensions/geoip/extension.h | 2 ++ extensions/geoip/smsdk_ext.cpp | 2 ++ extensions/geoip/smsdk_ext.h | 2 ++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp index e390f81c..ac9df7de 100644 --- a/extensions/geoip/extension.cpp +++ b/extensions/geoip/extension.cpp @@ -8,15 +8,20 @@ SMEXT_LINK(&g_GeoIP); bool GeoIP_Extension::SDK_OnLoad(char *error, size_t err_max, bool late) { - char *path = "GeoIP.dat"; //:TODO: build a real path here - //:TODO: log any errors on load. + char path[PLATFORM_MAX_PATH+1]; + + g_pSM->BuildPath(Path_SM, path, sizeof(path), "configs/geoip/GeoIP.dat"); gi = GeoIP_open(path, GEOIP_MEMORY_CACHE); if (!gi) { - //:TODO: log + snprintf(error, err_max, "Failed to instantiate GeoIP!"); return false; } + + g_pShareSys->AddNatives(myself, geoip_natives); + g_pSM->LogMessage(myself, "GeoIP database info: %s", GeoIP_database_info(gi)); + return true; } @@ -81,3 +86,11 @@ static cell_t sm_Geoip_Country(IPluginContext *pCtx, const cell_t *params) return 1; } + +const sp_nativeinfo_t geoip_natives[] = +{ + {"GeoipCode2", sm_Geoip_Code2}, + {"GeoipCode3", sm_Geoip_Code3}, + {"GeoipCountry", sm_Geoip_Country}, + {NULL, NULL}, +}; \ No newline at end of file diff --git a/extensions/geoip/extension.h b/extensions/geoip/extension.h index 4a025416..2a4f7ad7 100644 --- a/extensions/geoip/extension.h +++ b/extensions/geoip/extension.h @@ -58,4 +58,6 @@ public: #endif }; +extern const sp_nativeinfo_t geoip_natives[]; + #endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/geoip/smsdk_ext.cpp b/extensions/geoip/smsdk_ext.cpp index 3bd1ffe2..01e3f42c 100644 --- a/extensions/geoip/smsdk_ext.cpp +++ b/extensions/geoip/smsdk_ext.cpp @@ -4,6 +4,7 @@ IShareSys *g_pShareSys = NULL; IExtension *myself = NULL; IHandleSys *g_pHandleSys = NULL; +ISourceMod *g_pSM = NULL; PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { @@ -38,6 +39,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, #endif SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); if (SDK_OnLoad(error, err_max, late)) { diff --git a/extensions/geoip/smsdk_ext.h b/extensions/geoip/smsdk_ext.h index f4d30711..07362c78 100644 --- a/extensions/geoip/smsdk_ext.h +++ b/extensions/geoip/smsdk_ext.h @@ -6,6 +6,7 @@ #include #include #include +#include #if defined SMEXT_CONF_METAMOD #include @@ -121,6 +122,7 @@ extern SDKExtension *g_pExtensionIface; extern IShareSys *g_pShareSys; extern IExtension *myself; extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); From efe93fa470f65536933c27baf7cb4b5f81b746cf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 04:35:56 +0000 Subject: [PATCH 0297/1664] initial import of threading extension --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40327 --- extensions/threader/extension.cpp | 14 + extensions/threader/extension.h | 59 +++ extensions/threader/msvc8/threader.sln | 20 ++ extensions/threader/msvc8/threader.vcproj | 267 ++++++++++++++ extensions/threader/smsdk_config.h | 27 ++ extensions/threader/smsdk_ext.cpp | 279 +++++++++++++++ extensions/threader/smsdk_ext.h | 142 ++++++++ extensions/threader/thread/BaseWorker.cpp | 249 +++++++++++++ extensions/threader/thread/BaseWorker.h | 72 ++++ extensions/threader/thread/IThreader.h | 378 ++++++++++++++++++++ extensions/threader/thread/PosixThreads.cpp | 263 ++++++++++++++ extensions/threader/thread/PosixThreads.h | 82 +++++ extensions/threader/thread/ThreadSupport.h | 10 + extensions/threader/thread/ThreadWorker.cpp | 258 +++++++++++++ extensions/threader/thread/ThreadWorker.h | 40 +++ extensions/threader/thread/WinThreads.cpp | 305 ++++++++++++++++ extensions/threader/thread/WinThreads.h | 84 +++++ 17 files changed, 2549 insertions(+) create mode 100644 extensions/threader/extension.cpp create mode 100644 extensions/threader/extension.h create mode 100644 extensions/threader/msvc8/threader.sln create mode 100644 extensions/threader/msvc8/threader.vcproj create mode 100644 extensions/threader/smsdk_config.h create mode 100644 extensions/threader/smsdk_ext.cpp create mode 100644 extensions/threader/smsdk_ext.h create mode 100644 extensions/threader/thread/BaseWorker.cpp create mode 100644 extensions/threader/thread/BaseWorker.h create mode 100644 extensions/threader/thread/IThreader.h create mode 100644 extensions/threader/thread/PosixThreads.cpp create mode 100644 extensions/threader/thread/PosixThreads.h create mode 100644 extensions/threader/thread/ThreadSupport.h create mode 100644 extensions/threader/thread/ThreadWorker.cpp create mode 100644 extensions/threader/thread/ThreadWorker.h create mode 100644 extensions/threader/thread/WinThreads.cpp create mode 100644 extensions/threader/thread/WinThreads.h diff --git a/extensions/threader/extension.cpp b/extensions/threader/extension.cpp new file mode 100644 index 00000000..2d1cc3f6 --- /dev/null +++ b/extensions/threader/extension.cpp @@ -0,0 +1,14 @@ +#include "extension.h" +#include "thread/ThreadSupport.h" + +Sample g_Sample; +MainThreader g_Threader; + +SMEXT_LINK(&g_Sample); + +bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + g_pShareSys->AddInterface(myself, &g_Threader); + + return true; +} diff --git a/extensions/threader/extension.h b/extensions/threader/extension.h new file mode 100644 index 00000000..584dbdc1 --- /dev/null +++ b/extensions/threader/extension.h @@ -0,0 +1,59 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +#include "smsdk_ext.h" + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class Sample : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + //virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual void QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * Read smext_base.h for documentation on these. + */ + + //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif +}; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/threader/msvc8/threader.sln b/extensions/threader/msvc8/threader.sln new file mode 100644 index 00000000..c2d90607 --- /dev/null +++ b/extensions/threader/msvc8/threader.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "threader", "threader.vcproj", "{C9F9E996-0C20-4D96-8E52-4530F41E22CE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C9F9E996-0C20-4D96-8E52-4530F41E22CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {C9F9E996-0C20-4D96-8E52-4530F41E22CE}.Debug|Win32.Build.0 = Debug|Win32 + {C9F9E996-0C20-4D96-8E52-4530F41E22CE}.Release|Win32.ActiveCfg = Release|Win32 + {C9F9E996-0C20-4D96-8E52-4530F41E22CE}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/threader/msvc8/threader.vcproj b/extensions/threader/msvc8/threader.vcproj new file mode 100644 index 00000000..d76a6ad7 --- /dev/null +++ b/extensions/threader/msvc8/threader.vcproj @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/threader/smsdk_config.h b/extensions/threader/smsdk_config.h new file mode 100644 index 00000000..13ebf9c3 --- /dev/null +++ b/extensions/threader/smsdk_config.h @@ -0,0 +1,27 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "Threader" +#define SMEXT_CONF_DESCRIPTION "Provides threading to other modules" +#define SMEXT_CONF_VERSION "1.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "THREADER" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +//#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/threader/smsdk_ext.cpp b/extensions/threader/smsdk_ext.cpp new file mode 100644 index 00000000..01e3f42c --- /dev/null +++ b/extensions/threader/smsdk_ext.cpp @@ -0,0 +1,279 @@ +#include +#include "smsdk_ext.h" + +IShareSys *g_pShareSys = NULL; +IExtension *myself = NULL; +IHandleSys *g_pHandleSys = NULL; +ISourceMod *g_pSM = NULL; + +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + + if (SDK_OnLoad(error, err_max, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; +ISmmPlugin *g_PLAPI = NULL; +SourceHook::ISourceHook *g_SHPtr = NULL; +ISmmAPI *g_SMAPI = NULL; + +IVEngineServer *engine = NULL; +IServerGameDLL *gamedll = NULL; + +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif diff --git a/extensions/threader/smsdk_ext.h b/extensions/threader/smsdk_ext.h new file mode 100644 index 00000000..07362c78 --- /dev/null +++ b/extensions/threader/smsdk_ext.h @@ -0,0 +1,142 @@ +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + virtual bool IsMetamodExtension(); + virtual void OnExtensionPauseChange(bool state); + virtual const char *GetExtensionName(); + virtual const char *GetExtensionURL(); + virtual const char *GetExtensionTag(); + virtual const char *GetExtensionAuthor(); + virtual const char *GetExtensionVerString(); + virtual const char *GetExtensionDescription(); + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual const char *GetAuthor(); + virtual const char *GetName(); + virtual const char *GetDescription(); + virtual const char *GetURL(); + virtual const char *GetLicense(); + virtual const char *GetVersion(); + virtual const char *GetDate(); + virtual const char *GetLogTag(); + virtual bool Unload(char *error, size_t maxlen); + virtual bool Pause(char *error, size_t maxlen); + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/threader/thread/BaseWorker.cpp b/extensions/threader/thread/BaseWorker.cpp new file mode 100644 index 00000000..819c5d02 --- /dev/null +++ b/extensions/threader/thread/BaseWorker.cpp @@ -0,0 +1,249 @@ +#include "BaseWorker.h" + +BaseWorker::BaseWorker() : + m_perFrame(SM_DEFAULT_THREADS_PER_FRAME), + m_state(Worker_Stopped) +{ +} + +BaseWorker::~BaseWorker() +{ + if (m_state != Worker_Stopped || m_state != Worker_Invalid) + Stop(true); + + if (m_ThreadQueue.size()) + Flush(true); +} + +void BaseWorker::MakeThread(IThread *pThread) +{ + ThreadParams pt; + + pt.flags = Thread_AutoRelease; + pt.prio = ThreadPrio_Normal; + + MakeThread(pThread, &pt); +} + +IThreadHandle *BaseWorker::MakeThread(IThread *pThread, ThreadFlags flags) +{ + ThreadParams pt; + + pt.flags = flags; + pt.prio = ThreadPrio_Normal; + + return MakeThread(pThread, &pt); +} + +IThreadHandle *BaseWorker::MakeThread(IThread *pThread, const ThreadParams *params) +{ + if (m_state != Worker_Running) + return NULL; + + SWThreadHandle *swt = new SWThreadHandle(this, params, pThread); + + AddThreadToQueue(swt); + + return swt; +} + +void BaseWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) +{ + max = ThreadPrio_Normal; + min = ThreadPrio_Normal; +} + +unsigned int BaseWorker::Flush(bool flush_cancel) +{ + SWThreadHandle *swt; + unsigned int num = 0; + + while ((swt=PopThreadFromQueue()) != NULL) + { + swt->m_state = Thread_Done; + if (!flush_cancel) + swt->pThread->RunThread(swt); + swt->pThread->OnTerminate(swt, flush_cancel); + if (swt->m_params.flags & Thread_AutoRelease) + delete swt; + num++; + } + + return num; +} + +SWThreadHandle *BaseWorker::PopThreadFromQueue() +{ + if (!m_ThreadQueue.size()) + return NULL; + + SourceHook::List::iterator begin; + SWThreadHandle *swt; + + begin = m_ThreadQueue.begin(); + swt = (*begin); + m_ThreadQueue.erase(begin); + + return swt; +} + +void BaseWorker::AddThreadToQueue(SWThreadHandle *pHandle) +{ + m_ThreadQueue.push_back(pHandle); +} + +unsigned int BaseWorker::GetMaxThreadsPerFrame() +{ + return m_perFrame; +} + +WorkerState BaseWorker::GetStatus(unsigned int *threads) +{ + if (threads) + *threads = m_perFrame; + + return m_state; +} + +unsigned int BaseWorker::RunFrame() +{ + unsigned int done = 0; + unsigned int max = GetMaxThreadsPerFrame(); + SWThreadHandle *swt = NULL; + IThread *pThread = NULL; + + while (done < max) + { + if ((swt=PopThreadFromQueue()) == NULL) + break; + pThread = swt->pThread; + swt->m_state = Thread_Running; + pThread->RunThread(swt); + swt->m_state = Thread_Done; + pThread->OnTerminate(swt, false); + if (swt->m_params.flags & Thread_AutoRelease) + delete swt; + done++; + } + + return done; +} + +void BaseWorker::SetMaxThreadsPerFrame(unsigned int threads) +{ + m_perFrame = threads; +} + +bool BaseWorker::Start() +{ + if (m_state != Worker_Invalid && m_state != Worker_Stopped) + { + return false; + } + + m_state = Worker_Running; + + return true; +} + +bool BaseWorker::Stop(bool flush_cancel) +{ + if (m_state == Worker_Invalid || m_state == Worker_Stopped) + return false; + + if (m_state == Worker_Paused) + { + if (!Unpause()) + return false; + } + + m_state = Worker_Stopped; + Flush(flush_cancel); + + return true; +} + +bool BaseWorker::Pause() +{ + if (m_state != Worker_Running) + return false; + + m_state = Worker_Paused; + + return true; +} + + +bool BaseWorker::Unpause() +{ + if (m_state != Worker_Paused) + return false; + + m_state = Worker_Running; + + return true; +} + +/*********************** + * THREAD HANDLE STUFF * + ***********************/ + +void SWThreadHandle::DestroyThis() +{ + delete this; +} + +void SWThreadHandle::GetParams(ThreadParams *p) +{ + *p = m_params; +} + +ThreadPriority SWThreadHandle::GetPriority() +{ + return m_params.prio; +} + +ThreadState SWThreadHandle::GetState() +{ + return m_state; +} + +IThreadCreator *SWThreadHandle::Parent() +{ + return m_parent; +} + +bool SWThreadHandle::SetPriority(ThreadPriority prio) +{ + if (m_params.prio != ThreadPrio_Normal) + return false; + + m_params.prio = prio; + + return true; +} + +bool SWThreadHandle::Unpause() +{ + if (m_state != Thread_Paused) + return false; + + m_state = Thread_Running; + + return true; +} + +bool SWThreadHandle::WaitForThread() +{ + return false; +} + +SWThreadHandle::SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread) : + m_state(Thread_Paused), m_params(*p), m_parent(parent), pThread(thread) +{ +} + +IThread *SWThreadHandle::GetThread() +{ + return pThread; +} diff --git a/extensions/threader/thread/BaseWorker.h b/extensions/threader/thread/BaseWorker.h new file mode 100644 index 00000000..5e91c28b --- /dev/null +++ b/extensions/threader/thread/BaseWorker.h @@ -0,0 +1,72 @@ +#ifndef _INCLUDE_SOURCEMOD_BASEWORKER_H +#define _INCLUDE_SOURCEMOD_BASEWORKER_H + +#include "sh_list.h" +#include "ThreadSupport.h" + +#define SM_DEFAULT_THREADS_PER_FRAME 1 + +class BaseWorker; + +//SW = Simple Wrapper +class SWThreadHandle : public IThreadHandle +{ + friend class BaseWorker; +public: + SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread); + IThread *GetThread(); +public: + //NOTE: We don't support this by default. + //It's specific usage that'd require many mutexes + virtual bool WaitForThread(); +public: + virtual void DestroyThis(); + virtual IThreadCreator *Parent(); + virtual void GetParams(ThreadParams *ptparams); +public: + //Priorities not supported by default. + virtual ThreadPriority GetPriority(); + virtual bool SetPriority(ThreadPriority prio); +public: + virtual ThreadState GetState(); + virtual bool Unpause(); +private: + ThreadState m_state; + ThreadParams m_params; + IThreadCreator *m_parent; + IThread *pThread; +}; + +class BaseWorker : public IThreadWorker +{ +public: + BaseWorker(); + virtual ~BaseWorker(); +public: //IWorker + virtual unsigned int RunFrame(); + //Controls the worker + virtual bool Pause(); + virtual bool Unpause(); + virtual bool Start(); + virtual bool Stop(bool flush_cancel); + //Flushes out any remaining threads + virtual unsigned int Flush(bool flush_cancel); + //returns status and number of threads in queue + virtual WorkerState GetStatus(unsigned int *numThreads); +public: //IThreadCreator + virtual void MakeThread(IThread *pThread); + virtual IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags); + virtual IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params); + virtual void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); +public: //BaseWorker + virtual void AddThreadToQueue(SWThreadHandle *pHandle); + virtual SWThreadHandle *PopThreadFromQueue(); + virtual void SetMaxThreadsPerFrame(unsigned int threads); + virtual unsigned int GetMaxThreadsPerFrame(); +protected: + SourceHook::List m_ThreadQueue; + unsigned int m_perFrame; + volatile WorkerState m_state; +}; + +#endif //_INCLUDE_SOURCEMOD_BASEWORKER_H diff --git a/extensions/threader/thread/IThreader.h b/extensions/threader/thread/IThreader.h new file mode 100644 index 00000000..90e401fe --- /dev/null +++ b/extensions/threader/thread/IThreader.h @@ -0,0 +1,378 @@ +#ifndef _INCLUDE_SOURCEMOD_THREADER_H +#define _INCLUDE_SOURCEMOD_THREADER_H + +#include + +#define SMINTERFACE_THREADER_NAME "IThreader" +#define SMINTERFACE_THREADER_VERSION 1 + +namespace SourceMod +{ + /** + * @brief Thread creation flags + */ + enum ThreadFlags + { + Thread_Default = 0, + /** + * Auto-release handle on finish + * You are not guaranteed the handle for this is valid after + * calling MakeThread(), so never use it until OnTerminate is called. + */ + Thread_AutoRelease = 1, + /** + * Thread is created "suspended", meaning it is inactive until unpaused. + */ + Thread_CreateSuspended = 2, + }; + + /** + * @brief Specifies thread priority levels. + */ + enum ThreadPriority + { + ThreadPrio_Minimum = -8, + ThreadPrio_Low = -3, + ThreadPrio_Normal = 0, + ThreadPrio_High = 3, + ThreadPrio_Maximum = 8, + }; + + /** + * @brief The current state of a thread. + */ + enum ThreadState + { + Thread_Running = 0, + Thread_Paused = 1, + Thread_Done = 2, + }; + + /** + * @brief Thread-specific parameters. + */ + struct ThreadParams + { + ThreadParams() : + flags(Thread_Default), + prio(ThreadPrio_Normal) + { + }; + ThreadFlags flags; + ThreadPriority prio; + }; + + class IThreadCreator; + + /** + * @brief Describes a handle to a thread. + */ + class IThreadHandle + { + public: + virtual ~IThreadHandle() { }; + public: + /** + * @brief Pauses parent thread until this thread completes. + * + * @return True if successful, false otherwise. + */ + virtual bool WaitForThread() =0; + + /** + * @brief Destroys the thread handle. This will not necessarily cancel the thread. + */ + virtual void DestroyThis() =0; + + /** + * @brief Returns the parent threader. + * + * @return IThreadCreator that created this thread. + */ + virtual IThreadCreator *Parent() =0; + + /** + * @brief Returns the thread states. + * + * @param ptparmas Pointer to a ThreadParams buffer. + */ + virtual void GetParams(ThreadParams *ptparams) =0; + + /** + * @brief Returns the thread priority. + * + * @return Thread priority. + */ + virtual ThreadPriority GetPriority() =0; + + /** + * @brief Sets thread priority. + * NOTE: On Linux, this always returns false. + * + * @param prio Thread priority to set. + * @return True if successful, false otherwise. + */ + virtual bool SetPriority(ThreadPriority prio) =0; + + /** + * @brief Returns the thread state. + * + * @return Current thread state. + */ + virtual ThreadState GetState() =0; + + /** + * @brief Attempts to unpause a paused thread. + * + * @return True on success, false otherwise. + */ + virtual bool Unpause() =0; + }; + + /** + * @brief Handles a single thread's execution. + */ + class IThread + { + public: + virtual ~IThread() { }; + public: + /** + * @brief Called when the thread runs (in its own thread). + * + * @param pHandle Pointer to the thread's handle. + */ + virtual void RunThread(IThreadHandle *pHandle) =0; + + /** + * @param Called when the thread terminates. + * Note: This occurs inside the thread as well. + * + * @param pHandle Pointer to the thread's handle. + * @param cancel True if the thread did not finish, false otherwise. + */ + virtual void OnTerminate(IThreadHandle *pHandle, bool cancel) =0; + }; + + + /** + * @brief Describes a thread creator + */ + class IThreadCreator + { + public: + virtual ~IThreadCreator() { }; + public: + /** + * @brief Creates a basic thread. + * + * @param pThread IThread pointer for callbacks. + */ + virtual void MakeThread(IThread *pThread) =0; + + /** + * @brief Creates a thread with specific options. + * + * @param pThread IThread pointer for callbacks. + * @param flags Flags for the thread. + * @return IThreadHandle pointer (must be released). + */ + virtual IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) =0; + + /** + * @brief Creates a thread with specific options. + * + * @param pThread IThread pointer for callbacks. + * @param params Extended options for the thread. + * @return IThreadHandle pointer (must be released). + */ + virtual IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) =0; + + /** + * @brief Returns the priority bounds. + * Note: On Linux, the min and max are both Thread_Normal. + * + * @param max Stores the maximum priority level. + * @param min Stores the minimum priority level. + */ + virtual void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) =0; + }; + + /** + * @brief Describes a simple locking mutex. + */ + class IMutex + { + public: + virtual ~IMutex() { }; + public: + /** + * @brief Attempts to lock, but returns instantly. + * + * @return True if lock was obtained, false otherwise. + */ + virtual bool TryLock() =0; + + /** + * @brief Attempts to lock by waiting for release. + */ + virtual void Lock() =0; + + /** + * @brief Unlocks the mutex. + */ + virtual void Unlock() =0; + + /** + * @brief Destroys the mutex handle. + */ + virtual void DestroyThis() =0; + }; + + /** + * @brief Describes a simple "condition variable"/signal lock. + */ + class IEventSignal + { + public: + virtual ~IEventSignal() { }; + public: + /** + * @brief Waits for a signal. + */ + virtual void Wait() =0; + + /** + * @brief Triggers the signal and resets the signal after triggering. + */ + virtual void Signal() =0; + + /** + * @brief Frees the signal handle. + */ + virtual void DestroyThis() =0; + }; + + /** + * @brief Describes possible worker states + */ + enum WorkerState + { + Worker_Invalid = -3, + Worker_Stopped = -2, + Worker_Paused = -1, + Worker_Running, + }; + + /** + * @brief This is a "worker pool." A single thread places tasks in a queue. + * Each IThread is then a task, rather than its own separate thread. + */ + class IThreadWorker : public IThreadCreator + { + public: + virtual ~IThreadWorker() + { + }; + public: + /** + * @brief Runs one "frame" of the worker. + * + * @return Number of tasks processed. + */ + virtual unsigned int RunFrame() =0; + public: + /** + * @brief Pauses the worker. + * + * @return True on success, false otherwise. + */ + virtual bool Pause() =0; + + /** + * @brief Unpauses the worker. + * + * @return True on success, false otherwise. + */ + virtual bool Unpause() =0; + + /** + * @brief Starts the worker thread. + * + * @return True on success, false otherwise. + */ + virtual bool Start() =0; + + /** + * @brief Stops the worker thread. + * + * @param flush If true, all remaining tasks will be cancelled. + * Otherwise, the threader will wait until the queue is empty. + * @return True on success, false otherwise. + */ + virtual bool Stop(bool flush) =0; + + /** + * @brief Returns the status of the worker. + * + * @param numThreads Pointer to store number of threads in the queue. + * @return State of the worker. + */ + virtual WorkerState GetStatus(unsigned int *numThreads) =0; + }; + + /** + * @brief Describes a threading system + */ + class IThreader : public SMInterface, public IThreadCreator + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_THREADER_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_THREADER_VERSION; + } + public: + /** + * @brief Creates a mutex (mutual exclusion lock). + * + * @return A new IMutex pointer (must be destroyed). + */ + virtual IMutex *MakeMutex() =0; + + /** + * @brief Sleeps the calling thread for a number of milliseconds. + * + * @param ms Millisecond count to sleep. + */ + virtual void ThreadSleep(unsigned int ms) =0; + + /** + * @brief Creates a non-signalled event. + * + * @return A new IEventSignal pointer (must be destroyed). + */ + virtual IEventSignal *MakeEventSignal() =0; + + /** + * @brief Creates a thread worker. + * + * @param threaded If true, the worker will be threaded. + * If false, the worker will require manual frame execution. + * @return A new IThreadWorker pointer (must be destroyed). + */ + virtual IThreadWorker *MakeWorker(bool threaded) =0; + + /** + * @brief Destroys an IThreadWorker pointer. + * + * @param pWorker IThreadWorker pointer to destroy. + */ + virtual void DestroyWorker(IThreadWorker *pWorker) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_THREADER_H diff --git a/extensions/threader/thread/PosixThreads.cpp b/extensions/threader/thread/PosixThreads.cpp new file mode 100644 index 00000000..f08b9210 --- /dev/null +++ b/extensions/threader/thread/PosixThreads.cpp @@ -0,0 +1,263 @@ +#include +#include "PosixThreads.h" + +void PosixThreader::ThreadSleep(unsigned int ms) +{ + usleep( ms * 1000 ); +} + +void PosixThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) +{ + max = ThreadPrio_Normal; + min = ThreadPrio_Normal; +} + +IMutex *PosixThreader::MakeMutex() +{ + pthread_mutex_t mutex; + + if (pthread_mutex_init(&mutex, NULL) != 0) + return NULL; + + PosixMutex *pMutex = new PosixMutex(mutex); + + return pMutex; +} + + +void PosixThreader::MakeThread(IThread *pThread) +{ + ThreadParams defparams; + + defparams.flags = Thread_AutoRelease; + defparams.prio = ThreadPrio_Normal; + + MakeThread(pThread, &defparams); +} + +IThreadHandle *PosixThreader::MakeThread(IThread *pThread, ThreadFlags flags) +{ + ThreadParams defparams; + + defparams.flags = flags; + defparams.prio = ThreadPrio_Normal; + + return MakeThread(pThread, &defparams); +} + +void *Posix_ThreadGate(void *param) +{ + PosixThreader::ThreadHandle *pHandle = + reinterpret_cast(param); + + //Block this thread from being started initially. + pthread_mutex_lock(&pHandle->m_runlock); + //if we get here, we've obtained the lock and are allowed to run. + //unlock and continue. + pthread_mutex_unlock(&pHandle->m_runlock); + + pHandle->m_run->RunThread(pHandle); + + ThreadParams params; + pthread_mutex_lock(&pHandle->m_statelock); + pHandle->m_state = Thread_Done; + pHandle->GetParams(¶ms); + pthread_mutex_unlock(&pHandle->m_statelock); + + pHandle->m_run->OnTerminate(pHandle, false); + if (params.flags & Thread_AutoRelease) + delete pHandle; + + return 0; +} + +ThreadParams g_defparams; +IThreadHandle *PosixThreader::MakeThread(IThread *pThread, const ThreadParams *params) +{ + if (params == NULL) + params = &g_defparams; + + PosixThreader::ThreadHandle *pHandle = + new PosixThreader::ThreadHandle(this, pThread, params); + + pthread_mutex_lock(&pHandle->m_runlock); + + int err; + err = pthread_create(&pHandle->m_thread, NULL, Posix_ThreadGate, (void *)pHandle); + + if (err != 0) + { + pthread_mutex_unlock(&pHandle->m_runlock); + delete pHandle; + return NULL; + } + + //Don't bother setting priority... + + if (!(pHandle->m_params.flags & Thread_CreateSuspended)) + { + pHandle->m_state = Thread_Running; + err = pthread_mutex_unlock(&pHandle->m_runlock); + if (err != 0) + pHandle->m_state = Thread_Paused; + } + + return pHandle; +} + +IEventSignal *PosixThreader::MakeEventSignal() +{ + return new PosixEventSignal(); +} + +/***************** +**** Mutexes **** +*****************/ + +PosixThreader::PosixMutex::~PosixMutex() +{ + pthread_mutex_destroy(&m_mutex); +} + +bool PosixThreader::PosixMutex::TryLock() +{ + int err = pthread_mutex_trylock(&m_mutex); + + return (err == 0); +} + +void PosixThreader::PosixMutex::Lock() +{ + pthread_mutex_lock(&m_mutex); +} + +void PosixThreader::PosixMutex::Unlock() +{ + pthread_mutex_unlock(&m_mutex); +} + +void PosixThreader::PosixMutex::DestroyThis() +{ + delete this; +} + +/****************** +* Thread Handles * +******************/ + +PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : + m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused) +{ + pthread_mutex_init(&m_runlock, NULL); + pthread_mutex_init(&m_statelock, NULL); +} + +PosixThreader::ThreadHandle::~ThreadHandle() +{ + pthread_mutex_destroy(&m_runlock); + pthread_mutex_destroy(&m_statelock); +} + +bool PosixThreader::ThreadHandle::WaitForThread() +{ + void *arg; + + if (pthread_join(m_thread, &arg) != 0) + return false; + + return true; +} + +ThreadState PosixThreader::ThreadHandle::GetState() +{ + ThreadState state; + + pthread_mutex_lock(&m_statelock); + state = m_state; + pthread_mutex_unlock(&m_statelock); + + return state; +} + +IThreadCreator *PosixThreader::ThreadHandle::Parent() +{ + return m_parent; +} + +void PosixThreader::ThreadHandle::DestroyThis() +{ + if (m_params.flags & Thread_AutoRelease) + return; + + delete this; +} + +void PosixThreader::ThreadHandle::GetParams(ThreadParams *ptparams) +{ + if (!ptparams) + return; + + *ptparams = m_params; +} + +ThreadPriority PosixThreader::ThreadHandle::GetPriority() +{ + return ThreadPrio_Normal; +} + +bool PosixThreader::ThreadHandle::SetPriority(ThreadPriority prio) +{ + return (prio == ThreadPrio_Normal); +} + +bool PosixThreader::ThreadHandle::Unpause() +{ + if (m_state != Thread_Paused) + return false; + + m_state = Thread_Running; + + if (pthread_mutex_unlock(&m_runlock) != 0) + { + m_state = Thread_Paused; + return false; + } + + return true; +} + +/***************** + * EVENT SIGNALS * + *****************/ + +PosixThreader::PosixEventSignal::PosixEventSignal() +{ + pthread_cond_init(&m_cond, NULL); + pthread_mutex_init(&m_mutex, NULL); +} + +PosixThreader::PosixEventSignal::~PosixEventSignal() +{ + pthread_cond_destroy(&m_cond); + pthread_mutex_destroy(&m_mutex); +} + +void PosixThreader::PosixEventSignal::Wait() +{ + pthread_mutex_lock(&m_mutex); + pthread_cond_wait(&m_cond, &m_mutex); + pthread_mutex_unlock(&m_mutex); +} + +void PosixThreader::PosixEventSignal::Signal() +{ + pthread_mutex_lock(&m_mutex); + pthread_cond_broadcast(&m_cond); + pthread_mutex_unlock(&m_mutex); +} + +void PosixThreader::PosixEventSignal::DestroyThis() +{ + delete this; +} + diff --git a/extensions/threader/thread/PosixThreads.h b/extensions/threader/thread/PosixThreads.h new file mode 100644 index 00000000..30a5ee75 --- /dev/null +++ b/extensions/threader/thread/PosixThreads.h @@ -0,0 +1,82 @@ +#ifndef _INCLUDE_POSIXTHREADS_H_ +#define _INCLUDE_POSIXTHREADS_H_ + +#include +#include "IThreader.h" + +using namespace SourceMod; + +void *Posix_ThreadGate(void *param); + +class PosixThreader : public IThreader +{ +public: + class ThreadHandle : public IThreadHandle + { + friend class PosixThreader; + friend void *Posix_ThreadGate(void *param); + public: + ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params); + virtual ~ThreadHandle(); + public: + virtual bool WaitForThread(); + virtual void DestroyThis(); + virtual IThreadCreator *Parent(); + virtual void GetParams(ThreadParams *ptparams); + virtual ThreadPriority GetPriority(); + virtual bool SetPriority(ThreadPriority prio); + virtual ThreadState GetState(); + virtual bool Unpause(); + protected: + IThreader *m_parent; //Parent handle + pthread_t m_thread; //Windows HANDLE + ThreadParams m_params; //Current Parameters + IThread *m_run; //Runnable context + pthread_mutex_t m_statelock; + pthread_mutex_t m_runlock; + ThreadState m_state; //internal state + }; + class PosixMutex : public IMutex + { + public: + PosixMutex(pthread_mutex_t m) : m_mutex(m) + { + }; + virtual ~PosixMutex(); + public: + virtual bool TryLock(); + virtual void Lock(); + virtual void Unlock(); + virtual void DestroyThis(); + protected: + pthread_mutex_t m_mutex; + }; + class PosixEventSignal : public IEventSignal + { + public: + PosixEventSignal(); + virtual ~PosixEventSignal(); + public: + virtual void Wait(); + virtual void Signal(); + virtual void DestroyThis(); + protected: + pthread_cond_t m_cond; + pthread_mutex_t m_mutex; + }; +public: + virtual IMutex *MakeMutex(); + virtual void MakeThread(IThread *pThread); + virtual IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags); + virtual IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params); + virtual void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); + virtual void ThreadSleep(unsigned int ms); + virtual IEventSignal *MakeEventSignal(); +}; + +#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER +#define SM_MAIN_THREADER PosixThreader; +typedef class PosixThreader MainThreader; +#endif + +#endif //_INCLUDE_POSIXTHREADS_H_ diff --git a/extensions/threader/thread/ThreadSupport.h b/extensions/threader/thread/ThreadSupport.h new file mode 100644 index 00000000..f948e6ce --- /dev/null +++ b/extensions/threader/thread/ThreadSupport.h @@ -0,0 +1,10 @@ +#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H +#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H + +#if defined __linux__ +#include "PosixThreads.h" +#elif defined WIN32 +#include "WinThreads.h" +#endif + +#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H diff --git a/extensions/threader/thread/ThreadWorker.cpp b/extensions/threader/thread/ThreadWorker.cpp new file mode 100644 index 00000000..fb298185 --- /dev/null +++ b/extensions/threader/thread/ThreadWorker.cpp @@ -0,0 +1,258 @@ +#include "ThreadWorker.h" + +ThreadWorker::ThreadWorker() : + m_Threader(NULL), + m_QueueLock(NULL), + m_StateLock(NULL), + m_PauseSignal(NULL), + m_AddSignal(NULL), + me(NULL), + m_think_time(DEFAULT_THINK_TIME_MS) +{ + m_state = Worker_Invalid; +} + +ThreadWorker::ThreadWorker(IThreader *pThreader, unsigned int thinktime) : + m_Threader(pThreader), + m_QueueLock(NULL), + m_StateLock(NULL), + m_PauseSignal(NULL), + m_AddSignal(NULL), + me(NULL), + m_think_time(thinktime) +{ + if (m_Threader) + { + m_state = Worker_Stopped; + } else { + m_state = Worker_Invalid; + } +} + +ThreadWorker::~ThreadWorker() +{ + if (m_state != Worker_Stopped || m_state != Worker_Invalid) + Stop(true); + + if (m_ThreadQueue.size()) + Flush(true); +} + +void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel) +{ + //we don't particularly care + return; +} + +void ThreadWorker::RunThread(IThreadHandle *pHandle) +{ + WorkerState this_state = Worker_Running; + size_t num; + + while (true) + { + /** + * Check number of items in the queue + */ + m_StateLock->Lock(); + this_state = m_state; + m_StateLock->Unlock(); + if (this_state != Worker_Stopped) + { + m_QueueLock->Lock(); + num = m_ThreadQueue.size(); + if (!num) + { + /** + * if none, wait for an item + */ + m_Waiting = true; + m_QueueLock->Unlock(); + /* first check if we should end again */ + if (this_state == Worker_Stopped) + { + break; + } + m_AddSignal->Wait(); + m_Waiting = false; + } else { + m_QueueLock->Unlock(); + } + } + m_StateLock->Lock(); + this_state = m_state; + m_StateLock->Unlock(); + if (this_state != Worker_Running) + { + if (this_state == Worker_Paused || this_state == Worker_Stopped) + { + //wait until the lock is cleared. + if (this_state == Worker_Paused) + { + m_PauseSignal->Wait(); + } + if (this_state == Worker_Stopped) + { + //if we're supposed to flush cleanrly, + // run all of the remaining frames first. + if (!m_FlushType) + { + while (m_ThreadQueue.size()) + RunFrame(); + } + break; + } + } + } + /** + * Run the frame. + */ + RunFrame(); + + /** + * wait in between threads if specified + */ + if (m_think_time) + m_Threader->ThreadSleep(m_think_time); + } +} + +SWThreadHandle *ThreadWorker::PopThreadFromQueue() +{ + if (m_state <= Worker_Stopped && !m_QueueLock) + return NULL; + + SWThreadHandle *swt; + m_QueueLock->Lock(); + swt = BaseWorker::PopThreadFromQueue(); + m_QueueLock->Unlock(); + + return swt; +} + +void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle) +{ + if (m_state <= Worker_Stopped) + return; + + m_QueueLock->Lock(); + BaseWorker::AddThreadToQueue(pHandle); + if (m_Waiting) + { + m_AddSignal->Signal(); + } + m_QueueLock->Unlock(); +} + +WorkerState ThreadWorker::GetStatus(unsigned int *threads) +{ + WorkerState state; + + m_StateLock->Lock(); + state = BaseWorker::GetStatus(threads); + m_StateLock->Unlock(); + + return state; +} + +bool ThreadWorker::Start() +{ + if (m_state == Worker_Invalid) + { + if (m_Threader == NULL) + return false; + } else if (m_state != Worker_Stopped) { + return false; + } + + m_Waiting = false; + m_QueueLock = m_Threader->MakeMutex(); + m_StateLock = m_Threader->MakeMutex(); + m_PauseSignal = m_Threader->MakeEventSignal(); + m_AddSignal = m_Threader->MakeEventSignal(); + m_state = Worker_Running; + ThreadParams pt; + pt.flags = Thread_Default; + pt.prio = ThreadPrio_Normal; + me = m_Threader->MakeThread(this, &pt); + + return true; +} + +bool ThreadWorker::Stop(bool flush_cancel) +{ + if (m_state == Worker_Invalid || m_state == Worker_Stopped) + return false; + + WorkerState oldstate; + + //set new state + m_StateLock->Lock(); + oldstate = m_state; + m_state = Worker_Stopped; + m_FlushType = flush_cancel; + m_StateLock->Unlock(); + + if (oldstate == Worker_Paused) + { + Unpause(); + } else { + m_QueueLock->Lock(); + if (m_Waiting) + { + m_AddSignal->Signal(); + } + m_QueueLock->Unlock(); + } + + me->WaitForThread(); + //destroy it + me->DestroyThis(); + //flush all remaining events + Flush(true); + + //free mutex locks + m_QueueLock->DestroyThis(); + m_StateLock->DestroyThis(); + m_PauseSignal->DestroyThis(); + m_AddSignal->DestroyThis(); + + //invalidizzle + m_QueueLock = NULL; + m_StateLock = NULL; + m_PauseSignal = NULL; + m_AddSignal = NULL; + me = NULL; + + return true; +} + +bool ThreadWorker::Pause() +{ + if (m_state != Worker_Running) + return false; + + m_StateLock->Lock(); + m_state = Worker_Paused; + m_StateLock->Unlock(); + + return true; +} + + +bool ThreadWorker::Unpause() +{ + if (m_state != Worker_Paused) + return false; + + m_StateLock->Lock(); + m_state = Worker_Running; + m_StateLock->Unlock(); + m_PauseSignal->Signal(); + if (m_Waiting) + { + m_AddSignal->Signal(); + } + + return true; +} diff --git a/extensions/threader/thread/ThreadWorker.h b/extensions/threader/thread/ThreadWorker.h new file mode 100644 index 00000000..6afd64f4 --- /dev/null +++ b/extensions/threader/thread/ThreadWorker.h @@ -0,0 +1,40 @@ +#ifndef _INCLUDE_SOURCEMOD_THREADWORKER_H +#define _INCLUDE_SOURCEMOD_THREADWORKER_H + +#include "BaseWorker.h" + +#define DEFAULT_THINK_TIME_MS 500 + +class ThreadWorker : public BaseWorker, public IThread +{ +public: + ThreadWorker(); + ThreadWorker(IThreader *pThreader, unsigned int thinktime=DEFAULT_THINK_TIME_MS); + virtual ~ThreadWorker(); +public: //IThread + virtual void OnTerminate(IThreadHandle *pHandle, bool cancel); + virtual void RunThread(IThreadHandle *pHandle); +public: //IWorker + //Controls the worker + virtual bool Pause(); + virtual bool Unpause(); + virtual bool Start(); + virtual bool Stop(bool flush_cancel); + //returns status and number of threads in queue + virtual WorkerState GetStatus(unsigned int *numThreads); +public: //BaseWorker + virtual void AddThreadToQueue(SWThreadHandle *pHandle); + virtual SWThreadHandle *PopThreadFromQueue(); +protected: + IThreader *m_Threader; + IMutex *m_QueueLock; + IMutex *m_StateLock; + IEventSignal *m_PauseSignal; + IEventSignal *m_AddSignal; + IThreadHandle *me; + unsigned int m_think_time; + volatile bool m_Waiting; + volatile bool m_FlushType; +}; + +#endif //_INCLUDE_SOURCEMOD_THREADWORKER_H diff --git a/extensions/threader/thread/WinThreads.cpp b/extensions/threader/thread/WinThreads.cpp new file mode 100644 index 00000000..be444a69 --- /dev/null +++ b/extensions/threader/thread/WinThreads.cpp @@ -0,0 +1,305 @@ +#include "WinThreads.h" +#include "ThreadWorker.h" + +IThreadWorker *WinThreader::MakeWorker(bool threaded) +{ + if (threaded) + { + return new ThreadWorker(this, DEFAULT_THINK_TIME_MS); + } else { + return new BaseWorker(); + } +} + +void WinThreader::DestroyWorker(IThreadWorker *pWorker) +{ + delete pWorker; +} + +void WinThreader::ThreadSleep(unsigned int ms) +{ + Sleep((DWORD)ms); +} + +IMutex *WinThreader::MakeMutex() +{ + HANDLE mutex = CreateMutexA(NULL, FALSE, NULL); + + if (mutex == NULL) + return NULL; + + WinMutex *pMutex = new WinMutex(mutex); + + return pMutex; +} + +IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags) +{ + ThreadParams defparams; + + defparams.flags = flags; + defparams.prio = ThreadPrio_Normal; + + return MakeThread(pThread, &defparams); +} + +void WinThreader::MakeThread(IThread *pThread) +{ + ThreadParams defparams; + + defparams.flags = Thread_AutoRelease; + defparams.prio = ThreadPrio_Normal; + + MakeThread(pThread, &defparams); +} + +DWORD WINAPI Win32_ThreadGate(LPVOID param) +{ + WinThreader::ThreadHandle *pHandle = + reinterpret_cast(param); + + pHandle->m_run->RunThread(pHandle); + + ThreadParams params; + EnterCriticalSection(&pHandle->m_crit); + pHandle->m_state = Thread_Done; + pHandle->GetParams(¶ms); + LeaveCriticalSection(&pHandle->m_crit); + + pHandle->m_run->OnTerminate(pHandle, false); + if (params.flags & Thread_AutoRelease) + delete pHandle; + + return 0; +} + +void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) +{ + max = ThreadPrio_Maximum; + min = ThreadPrio_Minimum; +} + +ThreadParams g_defparams; +IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params) +{ + if (params == NULL) + params = &g_defparams; + + WinThreader::ThreadHandle *pHandle = + new WinThreader::ThreadHandle(this, NULL, pThread, params); + + DWORD tid; + pHandle->m_thread = + CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid); + + if (!pHandle->m_thread) + { + delete pHandle; + return NULL; + } + + if (pHandle->m_params.prio != ThreadPrio_Normal) + { + pHandle->SetPriority(pHandle->m_params.prio); + } + + if (!(pHandle->m_params.flags & Thread_CreateSuspended)) + { + pHandle->Unpause(); + } + + return pHandle; +} + +IEventSignal *WinThreader::MakeEventSignal() +{ + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL); + + if (!event) + return NULL; + + WinEvent *pEvent = new WinEvent(event); + + return pEvent; +} + +/***************** + **** Mutexes **** + *****************/ + +WinThreader::WinMutex::~WinMutex() +{ + if (m_mutex) + { + CloseHandle(m_mutex); + m_mutex = NULL; + } +} + +bool WinThreader::WinMutex::TryLock() +{ + if (!m_mutex) + return false; + + if (WaitForSingleObject(m_mutex, 0) != WAIT_FAILED) + return true; + + return false; +} + +void WinThreader::WinMutex::Lock() +{ + if (!m_mutex) + return; + + WaitForSingleObject(m_mutex, INFINITE); +} + +void WinThreader::WinMutex::Unlock() +{ + if (!m_mutex) + return; + + ReleaseMutex(m_mutex); +} + +void WinThreader::WinMutex::DestroyThis() +{ + delete this; +} + +/****************** + * Thread Handles * + ******************/ + +WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : + m_parent(parent), m_thread(hthread), m_run(run), m_params(*params), + m_state(Thread_Paused) +{ + InitializeCriticalSection(&m_crit); +} + +WinThreader::ThreadHandle::~ThreadHandle() +{ + if (m_thread) + { + CloseHandle(m_thread); + m_thread = NULL; + } + DeleteCriticalSection(&m_crit); +} + +bool WinThreader::ThreadHandle::WaitForThread() +{ + if (m_thread == NULL) + return false; + + if (WaitForSingleObject(m_thread, INFINITE) != 0) + return false; + + return true; +} + +ThreadState WinThreader::ThreadHandle::GetState() +{ + ThreadState state; + + EnterCriticalSection(&m_crit); + state = m_state; + LeaveCriticalSection(&m_crit); + + return state; +} + +IThreadCreator *WinThreader::ThreadHandle::Parent() +{ + return m_parent; +} + +void WinThreader::ThreadHandle::DestroyThis() +{ + if (m_params.flags & Thread_AutoRelease) + return; + + delete this; +} + +void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams) +{ + if (!ptparams) + return; + + *ptparams = m_params; +} + +ThreadPriority WinThreader::ThreadHandle::GetPriority() +{ + return m_params.prio; +} + +bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio) +{ + if (!m_thread) + return false; + + BOOL res = FALSE; + + if (prio >= ThreadPrio_Maximum) + res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST); + else if (prio <= ThreadPrio_Minimum) + res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST); + else if (prio == ThreadPrio_Normal) + res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL); + else if (prio == ThreadPrio_High) + res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL); + else if (prio == ThreadPrio_Low) + res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL); + + m_params.prio = prio; + + return (res != FALSE); +} + +bool WinThreader::ThreadHandle::Unpause() +{ + if (!m_thread) + return false; + + if (m_state != Thread_Paused) + return false; + + m_state = Thread_Running; + + if (ResumeThread(m_thread) == -1) + { + m_state = Thread_Paused; + return false; + } + + return true; +} + +/***************** + * EVENT SIGNALS * + *****************/ + +WinThreader::WinEvent::~WinEvent() +{ + CloseHandle(m_event); +} + +void WinThreader::WinEvent::Wait() +{ + WaitForSingleObject(m_event, INFINITE); +} + +void WinThreader::WinEvent::Signal() +{ + SetEvent(m_event); +} + +void WinThreader::WinEvent::DestroyThis() +{ + delete this; +} + diff --git a/extensions/threader/thread/WinThreads.h b/extensions/threader/thread/WinThreads.h new file mode 100644 index 00000000..89a640fc --- /dev/null +++ b/extensions/threader/thread/WinThreads.h @@ -0,0 +1,84 @@ +#ifndef _INCLUDE_WINTHREADS_H_ +#define _INCLUDE_WINTHREADS_H_ + +#include +#include "IThreader.h" + +using namespace SourceMod; + +DWORD WINAPI Win32_ThreadGate(LPVOID param); + +class WinThreader : public IThreader +{ +public: + class ThreadHandle : public IThreadHandle + { + friend class WinThreader; + friend DWORD WINAPI Win32_ThreadGate(LPVOID param); + public: + ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params); + virtual ~ThreadHandle(); + public: + virtual bool WaitForThread(); + virtual void DestroyThis(); + virtual IThreadCreator *Parent(); + virtual void GetParams(ThreadParams *ptparams); + virtual ThreadPriority GetPriority(); + virtual bool SetPriority(ThreadPriority prio); + virtual ThreadState GetState(); + virtual bool Unpause(); + protected: + IThreader *m_parent; //Parent handle + HANDLE m_thread; //Windows HANDLE + ThreadParams m_params; //Current Parameters + IThread *m_run; //Runnable context + ThreadState m_state; //internal state + CRITICAL_SECTION m_crit; + }; + class WinMutex : public IMutex + { + public: + WinMutex(HANDLE mutex) : m_mutex(mutex) + { + }; + virtual ~WinMutex(); + public: + virtual bool TryLock(); + virtual void Lock(); + virtual void Unlock(); + virtual void DestroyThis(); + protected: + HANDLE m_mutex; + }; + class WinEvent : public IEventSignal + { + public: + WinEvent(HANDLE event) : m_event(event) + { + }; + virtual ~WinEvent(); + public: + virtual void Wait(); + virtual void Signal(); + virtual void DestroyThis(); + public: + HANDLE m_event; + }; +public: + IMutex *MakeMutex(); + void MakeThread(IThread *pThread); + IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags); + IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params); + void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); + void ThreadSleep(unsigned int ms); + IEventSignal *MakeEventSignal(); + IThreadWorker *MakeWorker(bool threaded); + void DestroyWorker(IThreadWorker *pWorker); +}; + +#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER +#define SM_MAIN_THREADER WinThreader; +typedef class WinThreader MainThreader; +#endif + +#endif //_INCLUDE_WINTHREADS_H_ From f3eedff7750042f1765f9db9b4380efa8fc0dccb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 05:25:43 +0000 Subject: [PATCH 0298/1664] added an unimplemented member to IShareSys --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40328 --- core/interfaces/IShareSys.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index 997ff2d1..ab8f4525 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -130,6 +130,19 @@ namespace SourceMod * @param identity Identity to remove. */ virtual void DestroyIdentity(IdentityToken_t *identity) =0; + + + /** + * @brief Requires an extension. This tells SourceMod that without this extension, + * your extension should not be loaded. The name should not include the ".dll" or + * the ".so" part of the file name. + * + * @param myself IExtension pointer to yourself. + * @param filename File of extension to require. + * @param require Whether or not this extension is a required dependency. + * @param autoload Whether or not to autoload this extension. + */ + virtual void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload) =0; }; }; From 8a46219d96be741e959c7b1b5225ff30ab76aa75 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 05:33:04 +0000 Subject: [PATCH 0299/1664] reorganized SourceMod for the public SDK --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40329 --- core/CTextParsers.h | 2 +- core/sm_globals.h | 2 +- core/sm_srvcmds.cpp | 2 +- core/systems/ExtensionSys.cpp | 6 + core/systems/ExtensionSys.h | 1 + core/systems/ShareSys.cpp | 6 + core/systems/ShareSys.h | 1 + {core/interfaces => public}/IExtensionSys.h | 0 {core/interfaces => public}/IForwardSys.h | 0 {core/interfaces => public}/IHandleSys.h | 0 {core/interfaces => public}/ILibrarySys.h | 0 {core/interfaces => public}/IPluginFunction.h | 0 {core/interfaces => public}/IPluginSys.h | 0 .../interfaces => public}/IRootConsoleMenu.h | 0 {core/interfaces => public}/IShareSys.h | 0 {core/interfaces => public}/ISourceMod.h | 0 {core/interfaces => public}/ITextParsers.h | 0 .../sdk => public/sample_ext}/extension.cpp | 0 .../sdk => public/sample_ext}/extension.h | 0 {extensions/sdk => public/sample_ext}/sdk.sln | 0 .../sdk => public/sample_ext}/sdk.vcproj | 0 .../sdk => public/sample_ext}/smsdk_config.h | 0 .../sdk => public/sample_ext}/smsdk_ext.cpp | 0 .../sdk => public/sample_ext}/smsdk_ext.h | 0 public/sm_platform.h | 39 ++ public/sourcepawn/sp_file_headers.h | 163 +++++ public/sourcepawn/sp_typeutil.h | 15 + public/sourcepawn/sp_vm_api.h | 631 ++++++++++++++++++ public/sourcepawn/sp_vm_base.h | 16 + public/sourcepawn/sp_vm_types.h | 251 +++++++ 30 files changed, 1132 insertions(+), 3 deletions(-) rename {core/interfaces => public}/IExtensionSys.h (100%) rename {core/interfaces => public}/IForwardSys.h (100%) rename {core/interfaces => public}/IHandleSys.h (100%) rename {core/interfaces => public}/ILibrarySys.h (100%) rename {core/interfaces => public}/IPluginFunction.h (100%) rename {core/interfaces => public}/IPluginSys.h (100%) rename {core/interfaces => public}/IRootConsoleMenu.h (100%) rename {core/interfaces => public}/IShareSys.h (100%) rename {core/interfaces => public}/ISourceMod.h (100%) rename {core/interfaces => public}/ITextParsers.h (100%) rename {extensions/sdk => public/sample_ext}/extension.cpp (100%) rename {extensions/sdk => public/sample_ext}/extension.h (100%) rename {extensions/sdk => public/sample_ext}/sdk.sln (100%) rename {extensions/sdk => public/sample_ext}/sdk.vcproj (100%) rename {extensions/sdk => public/sample_ext}/smsdk_config.h (100%) rename {extensions/sdk => public/sample_ext}/smsdk_ext.cpp (100%) rename {extensions/sdk => public/sample_ext}/smsdk_ext.h (100%) create mode 100644 public/sm_platform.h create mode 100644 public/sourcepawn/sp_file_headers.h create mode 100644 public/sourcepawn/sp_typeutil.h create mode 100644 public/sourcepawn/sp_vm_api.h create mode 100644 public/sourcepawn/sp_vm_base.h create mode 100644 public/sourcepawn/sp_vm_types.h diff --git a/core/CTextParsers.h b/core/CTextParsers.h index aeaf40da..49cadb1c 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -1,7 +1,7 @@ #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ -#include "interfaces/ITextParsers.h" +#include using namespace SourceMod; diff --git a/core/sm_globals.h b/core/sm_globals.h index 90114c35..00024b62 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -8,7 +8,7 @@ #include #include #include "sm_platform.h" -#include "interfaces/IShareSys.h" +#include using namespace SourcePawn; using namespace SourceMod; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 507801e7..3d307e15 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -50,7 +50,7 @@ void RootConsoleMenu::ConsolePrint(const char *fmt, ...) size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); - if (len >= sizeof(buffer)) + if (len >= sizeof(buffer) - 1) { buffer[510] = '\n'; buffer[511] = '\0'; diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index acb28046..b95e46e7 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -564,6 +564,12 @@ void CExtensionManager::MarkAllLoaded() } } +void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload) +{ + /* :TODO: implement */ + return; +} + void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount) { if (argcount >= 3) diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index f3afc978..91352ceb 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -80,6 +80,7 @@ public: void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives); void BindAllNativesToPlugin(IPlugin *pPlugin); void MarkAllLoaded(); + void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload); private: CExtension *FindByOrder(unsigned int num); private: diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 5d7bb335..e05a0abf 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -194,3 +194,9 @@ void ShareSystem::RemoveInterfaces(IExtension *pExtension) } } } + +void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload) +{ + g_Extensions.AddDependency(myself, filename, require, autoload); +} + diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index be249e5c..21a09468 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -42,6 +42,7 @@ public: //IShareSys IdentityToken_t *CreateIdentity(IdentityType_t type); void DestroyIdentType(IdentityType_t type); void DestroyIdentity(IdentityToken_t *identity); + void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload); public: //SMGlobalClass /* Pre-empt in case anything tries to register idents early */ void OnSourceModStartup(bool late); diff --git a/core/interfaces/IExtensionSys.h b/public/IExtensionSys.h similarity index 100% rename from core/interfaces/IExtensionSys.h rename to public/IExtensionSys.h diff --git a/core/interfaces/IForwardSys.h b/public/IForwardSys.h similarity index 100% rename from core/interfaces/IForwardSys.h rename to public/IForwardSys.h diff --git a/core/interfaces/IHandleSys.h b/public/IHandleSys.h similarity index 100% rename from core/interfaces/IHandleSys.h rename to public/IHandleSys.h diff --git a/core/interfaces/ILibrarySys.h b/public/ILibrarySys.h similarity index 100% rename from core/interfaces/ILibrarySys.h rename to public/ILibrarySys.h diff --git a/core/interfaces/IPluginFunction.h b/public/IPluginFunction.h similarity index 100% rename from core/interfaces/IPluginFunction.h rename to public/IPluginFunction.h diff --git a/core/interfaces/IPluginSys.h b/public/IPluginSys.h similarity index 100% rename from core/interfaces/IPluginSys.h rename to public/IPluginSys.h diff --git a/core/interfaces/IRootConsoleMenu.h b/public/IRootConsoleMenu.h similarity index 100% rename from core/interfaces/IRootConsoleMenu.h rename to public/IRootConsoleMenu.h diff --git a/core/interfaces/IShareSys.h b/public/IShareSys.h similarity index 100% rename from core/interfaces/IShareSys.h rename to public/IShareSys.h diff --git a/core/interfaces/ISourceMod.h b/public/ISourceMod.h similarity index 100% rename from core/interfaces/ISourceMod.h rename to public/ISourceMod.h diff --git a/core/interfaces/ITextParsers.h b/public/ITextParsers.h similarity index 100% rename from core/interfaces/ITextParsers.h rename to public/ITextParsers.h diff --git a/extensions/sdk/extension.cpp b/public/sample_ext/extension.cpp similarity index 100% rename from extensions/sdk/extension.cpp rename to public/sample_ext/extension.cpp diff --git a/extensions/sdk/extension.h b/public/sample_ext/extension.h similarity index 100% rename from extensions/sdk/extension.h rename to public/sample_ext/extension.h diff --git a/extensions/sdk/sdk.sln b/public/sample_ext/sdk.sln similarity index 100% rename from extensions/sdk/sdk.sln rename to public/sample_ext/sdk.sln diff --git a/extensions/sdk/sdk.vcproj b/public/sample_ext/sdk.vcproj similarity index 100% rename from extensions/sdk/sdk.vcproj rename to public/sample_ext/sdk.vcproj diff --git a/extensions/sdk/smsdk_config.h b/public/sample_ext/smsdk_config.h similarity index 100% rename from extensions/sdk/smsdk_config.h rename to public/sample_ext/smsdk_config.h diff --git a/extensions/sdk/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp similarity index 100% rename from extensions/sdk/smsdk_ext.cpp rename to public/sample_ext/smsdk_ext.cpp diff --git a/extensions/sdk/smsdk_ext.h b/public/sample_ext/smsdk_ext.h similarity index 100% rename from extensions/sdk/smsdk_ext.h rename to public/sample_ext/smsdk_ext.h diff --git a/public/sm_platform.h b/public/sm_platform.h new file mode 100644 index 00000000..05171cd8 --- /dev/null +++ b/public/sm_platform.h @@ -0,0 +1,39 @@ +#ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ +#define _INCLUDE_SOURCEMOD_PLATFORM_H_ + +/** + * @file Contains platform-specific macros for abstraction. + */ + +#if defined WIN32 || defined WIN64 +#define PLATFORM_WINDOWS +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#if !defined snprintf +#define snprintf _snprintf +#endif +#if !defined stat +#define stat _stat +#endif +#define strcasecmp strcmpi +#include +#include +#define PLATFORM_LIB_EXT "dll" +#define PLATFORM_MAX_PATH MAX_PATH +#define PLATFORM_SEP_CHAR '\\' +#define PLATFORM_SEP_ALTCHAR '/' +#define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) +#else if defined __linux__ +#define PLATFORM_LINUX +#define PLATFORM_POSIX +#include +#include +#define PLATFORM_MAX_PATH PATH_MAX +#define PLATFORM_LIB_EXT "so" +#define PLATFORM_SEP_CHAR '/' +#define PLATFORM_SEP_ALTCHAR '\\' +#define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) +#endif + +#endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h new file mode 100644 index 00000000..d3f41e7e --- /dev/null +++ b/public/sourcepawn/sp_file_headers.h @@ -0,0 +1,163 @@ +#ifndef _INCLUDE_SPFILE_HEADERS_H +#define _INCLUDE_SPFILE_HEADERS_H + +#include +#if defined __GNUC__ || defined HAVE_STDINT_ +#include +#else + #if !defined HAVE_STDINT_H + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned __int16 uint16_t; + typedef __int16 int16_t; + typedef unsigned __int8 uint8_t; + typedef __int8 int8_t; + #define HAVE_STDINT_H + #endif +#endif + +#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ +//#define SPFILE_VERSION 0x0100 +#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */ + +//:TODO: better compiler/nix support +#if defined __linux__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#endif + +#define SPFILE_COMPRESSION_NONE 0 +#define SPFILE_COMPRESSION_GZ 1 + +typedef struct sp_file_section_s +{ + uint32_t nameoffs; /* rel offset into global string table */ + uint32_t dataoffs; + uint32_t size; +} sp_file_section_t; + +/** + * If compression is 0, then + * disksize may be 0 to mean that + * only the imagesize is needed. + */ +typedef struct sp_file_hdr_s +{ + uint32_t magic; /* magic number */ + uint16_t version; /* version code */ + uint8_t compression;/* compression algorithm */ + uint32_t disksize; /* size on disk */ + uint32_t imagesize; /* size in memory */ + uint8_t sections; /* number of sections */ + uint32_t stringtab; /* offset to string table */ + uint32_t dataoffs; /* offset to file proper (any compression starts here) */ +} sp_file_hdr_t; + +#define SP_FLAG_DEBUG (1<<0) + +/* section is ".code" */ +typedef struct sp_file_code_s +{ + uint32_t codesize; /* codesize in bytes */ + uint8_t cellsize; /* cellsize in bytes */ + uint8_t codeversion; /* version of opcodes supported */ + uint16_t flags; /* flags */ + uint32_t main; /* address to "main" if any */ + uint32_t code; /* rel offset to code */ +} sp_file_code_t; + +/* section is .data */ +typedef struct sp_file_data_s +{ + uint32_t datasize; /* size of data section in memory */ + uint32_t memsize; /* total mem required (includes data) */ + uint32_t data; /* file offset to data (helper) */ +} sp_file_data_t; + +/* section is .publics */ +typedef struct sp_file_publics_s +{ + uint32_t address; /* address rel to code section */ + uint32_t name; /* index into nametable */ +} sp_file_publics_t; + +/* section is .natives */ +typedef struct sp_file_natives_s +{ + uint32_t name; /* name of native at index */ +} sp_file_natives_t; + +/* section is .libraries */ +typedef struct sp_file_libraries_s +{ + uint32_t name; /* index into nametable */ +} sp_file_libraries_t; + +/* section is .pubvars */ +typedef struct sp_file_pubvars_s +{ + uint32_t address; /* address rel to dat section */ + uint32_t name; /* index into nametable */ +} sp_file_pubvars_t; + +#if defined __linux__ + #pragma pack() /* reset default packing */ +#else + #pragma pack(pop) /* reset previous packing */ +#endif + +typedef struct sp_fdbg_info_s +{ + uint32_t num_files; /* number of files */ + uint32_t num_lines; /* number of lines */ + uint32_t num_syms; /* number of symbols */ + uint32_t num_arrays; /* number of symbols which are arrays */ +} sp_fdbg_info_t; + +/** + * Debug information structures + */ +typedef struct sp_fdbg_file_s +{ + uint32_t addr; /* address into code */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_file_t; + +typedef struct sp_fdbg_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line number */ +} sp_fdbg_line_t; + +#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ +#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */ +#define SP_SYM_ARRAY 3 +#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */ +#define SP_SYM_FUNCTION 9 + +typedef struct sp_fdbg_symbol_s +{ + int32_t addr; /* address rel to DAT or stack frame */ + int16_t tagid; /* tag id */ + uint32_t codestart; /* start scope validity in code */ + uint32_t codeend; /* end scope validity in code */ + uint8_t ident; /* variable type */ + uint8_t vclass; /* scope class (local vs global) */ + uint16_t dimcount; /* dimension count (for arrays) */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_symbol_t; + +typedef struct sp_fdbg_arraydim_s +{ + int16_t tagid; /* tag id */ + uint32_t size; /* size of dimension */ +} sp_fdbg_arraydim_t; + +/* section is .names */ +typedef char * sp_file_nametab_t; + +#endif //_INCLUDE_SPFILE_HEADERS_H diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h new file mode 100644 index 00000000..921f9f74 --- /dev/null +++ b/public/sourcepawn/sp_typeutil.h @@ -0,0 +1,15 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ +#define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ + +#include "sp_vm_types.h" + +inline cell_t sp_ftoc(float val) +{ + return *(cell_t *)&val; +} +inline float sp_ctof(cell_t val) +{ + return *(float *)&val; +} + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ \ No newline at end of file diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h new file mode 100644 index 00000000..cb904105 --- /dev/null +++ b/public/sourcepawn/sp_vm_api.h @@ -0,0 +1,631 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_ +#define _INCLUDE_SOURCEPAWN_VM_API_H_ + +#include +#include "sp_vm_types.h" + +#define SOURCEPAWN_VM_API_VERSION 1 + +#if defined SOURCEMOD_BUILD +namespace SourceMod +{ + struct IdentityToken_t; +}; +#endif + +namespace SourcePawn +{ + class IVirtualMachine; + + /** + * @brief Interface to managing a debug context at runtime. + */ + class IPluginDebugInfo + { + public: + /** + * @brief Given a code pointer, finds the file it is associated with. + * + * @param addr Code address offset. + * @param filename Pointer to store filename pointer in. + */ + virtual int LookupFile(ucell_t addr, const char **filename) =0; + + /** + * @brief Given a code pointer, finds the function it is associated with. + * + * @param addr Code address offset. + * @param name Pointer to store function name pointer in. + */ + virtual int LookupFunction(ucell_t addr, const char **name) =0; + + /** + * @brief Given a code pointer, finds the line it is associated with. + * + * @param addr Code address offset. + * @param line Pointer to store line number in. + */ + virtual int LookupLine(ucell_t addr, uint32_t *line) =0; + }; + + /** + * @brief Interface to managing a context at runtime. + */ + class IPluginContext + { + public: + virtual ~IPluginContext() { }; + public: + /** + * @brief Returns the parent IVirtualMachine. + * + * @return Parent virtual machine pointer. + */ + virtual IVirtualMachine *GetVirtualMachine() =0; + + /** + * @brief Returns the child sp_context_t structure. + * + * @return Child sp_context_t structure. + */ + virtual sp_context_t *GetContext() =0; + + /** + * @brief Returns true if the plugin is in debug mode. + * + * @return True if in debug mode, false otherwise. + */ + virtual bool IsDebugging() =0; + + /** + * @brief Installs a debug break and returns the old one, if any. + * This will fail if the plugin is not debugging. + * + * @param newpfn New function pointer. + * @param oldpfn Pointer to retrieve old function pointer. + */ + virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; + + /** + * @brief Returns debug info. + * + * @return IPluginDebugInfo, or NULL if no debug info found. + */ + virtual IPluginDebugInfo *GetDebugInfo() =0; + + /** + * @brief Allocs memory on the secondary stack of a plugin. + * Note that although called a heap, it is in fact a stack. + * + * @param cells Number of cells to allocate. + * @param local_addr Will be filled with data offset to heap. + * @param phys_addr Physical address to heap memory. + */ + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * @brief Pops a heap address off the heap stack. Use this to free memory allocated with + * SP_HeapAlloc(). + * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations + * with this native should be performed in precisely the REVERSE order. + * + * @param local_addr Local address to free. + */ + virtual int HeapPop(cell_t local_addr) =0; + + /** + * @brief Releases a heap address using a different method than SP_HeapPop(). + * This allows you to release in any order. However, if you allocate N + * objects, release only some of them, then begin allocating again, + * you cannot go back and starting freeing the originals. + * In other words, for each chain of allocations, if you start deallocating, + * then allocating more in a chain, you must only deallocate from the current + * allocation chain. This is basically HeapPop() except on a larger scale. + * + * @param local_addr Local address to free. + */ + virtual int HeapRelease(cell_t local_addr) =0; + + /** + * @brief Finds a native by name. + * + * @param name Name of native. + * @param index Optionally filled with native index number. + */ + virtual int FindNativeByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets native info by index. + * + * @param index Index number of native. + * @param native Optionally filled with pointer to native structure. + */ + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; + + /** + * @brief Gets the number of natives. + * + * @return Filled with the number of natives. + */ + virtual uint32_t GetNativesNum() =0; + + /** + * @brief Finds a public function by name. + * + * @param name Name of public + * @param index Optionally filled with public index number. + */ + virtual int FindPublicByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets public function info by index. + * + * @param index Public function index number. + * @param publicptr Optionally filled with pointer to public structure. + */ + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; + + /** + * @brief Gets the number of public functions. + * + * @return Filled with the number of public functions. + */ + virtual uint32_t GetPublicsNum() =0; + + /** + * @brief Gets public variable info by index. + * + * @param index Public variable index number. + * @param pubvar Optionally filled with pointer to pubvar structure. + */ + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; + + /** + * @brief Finds a public variable by name. + * + * @param name Name of pubvar + * @param index Optionally filled with pubvar index number. + */ + virtual int FindPubvarByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets the addresses of a public variable. + * + * @param index Index of public variable. + * @param local_addr Address to store local address in. + * @param phys_addr Address to store physically relocated in. + */ + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * @brief Returns the number of public variables. + * + * @return Number of public variables. + */ + virtual uint32_t GetPubVarsNum() =0; + + /** + * @brief Round-about method of converting a plugin reference to a physical address + * + * @param local_addr Local address in plugin. + * @param phys_addr Optionally filled with relocated physical address. + */ + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; + + /** + * @brief Converts a local address to a physical string. + * + * @param local_addr Local address in plugin. + * @param addr Destination output pointer. + */ + virtual int LocalToString(cell_t local_addr, char **addr) =0; + + /** + * @brief Converts a physical string to a local address. + * + * @param local_addr Local address in plugin. + * @param bytes Number of chars to write, including NULL terminator. + * @param source Source string to copy. + */ + virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; + + /** + * @brief Converts a physical UTF-8 string to a local address. + * This function is the same as the ANSI version, except it will copy the maximum number of characters possible + * without accidentally chopping a multi-byte character. + * + * @param local_addr Local address in plugin. + * @param maxbytes Number of bytes to write, including NULL terminator. + * @param source Source string to copy. + * @param wrtnbytes Optionally set to the number of actual bytes written. + */ + virtual int StringToLocalUTF8(cell_t local_addr, + size_t maxbytes, + const char *source, + size_t *wrtnbytes) =0; + + /** + * @brief Pushes a cell onto the stack. Increases the parameter count by one. + * + * @param value Cell value. + */ + virtual int PushCell(cell_t value) =0; + + /** + * @brief Pushes an array of cells onto the stack. Increases the parameter count by one. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; + + /** + * @brief Pushes a string onto the stack (by reference) and increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param string Source string to push. + */ + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; + + /** + * @brief Individually pushes each cell of an array of cells onto the stack. Increases the + * parameter count by the number of cells pushed. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * + * @param array Array of cells to read from. + * @param numcells Number of cells to read. + */ + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; + + /** + * @brief Binds a list of native names and their function pointers to a context. + * If num is 0, the list is read until an entry with a NULL name is reached. + * If overwrite is non-zero, already registered natives will be overwritten. + * + * @param natives Array of natives. + * @param num Number of natives in array. + * @param overwrite Toggles overwrite. + */ + virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; + + /** + * @brief Binds a single native. Overwrites any existing bind. + * If the context does not contain the native that will be binded the function will return + * with a SP_ERROR_NOT_FOUND error. + * + * @param native Pointer to native. + */ + virtual int BindNative(const sp_nativeinfo_t *native) =0; + + /** + * @brief Binds a single native to any non-registered native. + * + * @param native Native to bind. + */ + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; + + /** + * @brief Executes a function ID located in this context. + * + * @param funcid Function id to execute. + * @param result Pointer to store the return value (required). + * @return Error code (if any) from the VM. + */ + virtual int Execute(uint32_t funcid, cell_t *result) =0; + + + /** + * @brief Throws a error and halts any current execution. + * + * @param error The error number to set. + * @param msg Custom error message format. NULL to use default. + * @param ... Message format arguments, if any. + */ + virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; + + /** + * @brief Throws a generic native error and halts any current execution. + * + * @param msg Custom error message format. NULL to set no message. + * @param ... Message format arguments, if any. + * @return 0 for convenience. + */ + virtual cell_t ThrowNativeError(const char *msg, ...) =0; + +#if defined SOURCEMOD_BUILD + /** + * @brief Returns the identity token for this context. + * Note: This is a helper function for native calls and the Handle System. + * + * @return Identity token. + */ + virtual SourceMod::IdentityToken_t *GetIdentity() =0; +#endif + }; + + + /** + * @brief Information about a position in a call stack. + */ + struct CallStackInfo + { + const char *filename; /* NULL if not found */ + unsigned int line; /* 0 if not found */ + const char *function; /* NULL if not found */ + }; + + /** + * @brief Retrieves error information from a debug hook. + */ + class IContextTrace + { + public: + /** + * @brief Returns the integer error code. + * + * @return Integer error code. + */ + virtual int GetErrorCode() =0; + + /** + * @brief Returns a string describing the error. + * + * @return Error string. + */ + virtual const char *GetErrorString() =0; + + /** + * @brief Returns whether debug info is available. + * + * @return True if debug info is available, false otherwise. + */ + virtual bool DebugInfoAvailable() =0; + + /** + * @brief Returns a custom error message. + * + * @return A pointer to a custom error message, or NULL otherwise. + */ + virtual const char *GetCustomErrorString() =0; + + /** + * @brief Returns trace info for a specific point in the backtrace, if any. + * The next subsequent call to GetTraceInfo() will return the next item in the call stack. + * Calls are retrieved in descending order (i.e. the first item is at the top of the stack/call sequence). + * + * @param trace An ErrorTraceInfo buffer to store information (NULL to ignore). + * @return True if successful, false if there are no more traces. + */ + virtual bool GetTraceInfo(CallStackInfo *trace) =0; + + /** + * @brief Resets the trace to its original position (the call on the top of the stack). + */ + virtual void ResetTrace() =0; + + /** + * @brief Retrieves the name of the last native called. + * Returns NULL if there was no native that caused the error. + * + * @param index Optional pointer to store index. + * @return Native name, or NULL if none. + */ + virtual const char *GetLastNative(uint32_t *index) =0; + }; + + + /** + * @brief Provides callbacks for debug information. + */ + class IDebugListener + { + public: + virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0; + }; + + + /** + * @brief Contains helper functions used by VMs and the host app + */ + class ISourcePawnEngine + { + public: + /** + * @brief Loads a named file from a file pointer. + * Note: Using this means the memory will be allocated by the VM. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ + virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; + + /** + * @brief Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ + virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; + + /** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ + virtual int FreeFromMemory(sp_plugin_t *plugin) =0; + + /** + * @brief Allocates large blocks of temporary memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *BaseAlloc(size_t size) =0; + + /** + * @brief Frees memory allocated with BaseAlloc. + * + * @param memory Memory address to free. + */ + virtual void BaseFree(void *memory) =0; + + /** + * @brief Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *ExecAlloc(size_t size) =0; + + /** + * @brief Frees executable memory. + * + * @param address Address to free. + */ + virtual void ExecFree(void *address) =0; + + /** + * @brief Sets the debug listener. This should only be called once. + * If called successively (using manual chaining), only the last function should + * attempt to call back into the same plugin. Otherwise, globally cached states + * can be accidentally overwritten. + * + * @param listener Pointer to an IDebugListener. + * @return Old IDebugListener, or NULL if none. + */ + virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0; + + /** + * @brief Returns the number of plugins on the call stack. + * + * @return Number of contexts in the call stack. + */ + virtual unsigned int GetContextCallCount() =0; + }; + + + /** + * @brief Dummy class for encapsulating private compilation data. + */ + class ICompilation + { + public: + virtual ~ICompilation() { }; + }; + + + /** + * @brief Outlines the interface a Virtual Machine (JIT) must expose + */ + class IVirtualMachine + { + public: + /** + * @brief Returns the current API version. + */ + virtual unsigned int GetAPIVersion() =0; + + /** + * @brief Returns the string name of a VM implementation. + */ + virtual const char *GetVMName() =0; + + /** + * @brief Begins a new compilation + * + * @param plugin Pointer to a plugin structure. + * @return New compilation pointer. + */ + virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; + + /** + * @brief Sets a compilation option. + * + * @param co Pointer to a compilation. + * @param key Option key name. + * @param val Option value string. + * @return True if option could be set, false otherwise. + */ + virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; + + /** + * @brief Finalizes a compilation into a new sp_context_t. + * Note: This will free the ICompilation pointer. + * + * @param co Compilation pointer. + * @param err Filled with error code on exit. + * @return New plugin context. + */ + virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; + + /** + * @brief Aborts a compilation and frees the ICompilation pointer. + * + * @param co Compilation pointer. + */ + virtual void AbortCompilation(ICompilation *co) =0; + + /** + * @brief Frees any internal variable usage on a context. + * + * @param ctx Context structure pointer. + */ + virtual void FreeContext(sp_context_t *ctx) =0; + + /** + * @brief Calls the "execute" function on a context. + * + * @param ctx Executes a function in a context. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return Error code (if any). + */ + virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0; + + /** + * @brief Given a context and a code address, returns the index of the function. + * + * @param ctx Context to search. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return True if code index is valid, false otherwise. + */ + virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; + + /** + * @brief Returns the number of functions defined in the context. + * + * @param ctx Context to search. + * @return Number of functions. + */ + virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; + + /** + * @brief Returns a version string. + * + * @return Versioning string. + */ + virtual const char *GetVersionString() =0; + + /** + * @brief Returns a string describing optimizations. + * + * @return String describing CPU specific optimizations. + */ + virtual const char *GetCPUOptimizations() =0; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_API_H_ diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h new file mode 100644 index 00000000..4fff0f4c --- /dev/null +++ b/public/sourcepawn/sp_vm_base.h @@ -0,0 +1,16 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_ +#define _INCLUDE_SOURCEPAWN_VM_BASE_H_ + +#include + +/* :TODO: rename this to sp_vm_linkage.h */ + +#if defined WIN32 +#define EXPORT_LINK extern "C" __declspec(dllexport) +#else if defined __GNUC__ +#define EXPORT_LINK extern "C" __attribute__((visibility("default"))) +#endif + +typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); + +#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h new file mode 100644 index 00000000..2436144d --- /dev/null +++ b/public/sourcepawn/sp_vm_types.h @@ -0,0 +1,251 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H +#define _INCLUDE_SOURCEPAWN_VM_TYPES_H + +#include "sp_file_headers.h" + +typedef uint32_t ucell_t; +typedef int32_t cell_t; +typedef uint32_t funcid_t; + +#include "sp_typeutil.h" + +#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ + +/** + * Error codes + * NOTE: Be sure to update the error string table when changing these + */ +#define SP_ERROR_NONE 0 +#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */ +#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ +#define SP_ERROR_INDEX 7 /* Invalid index parameter */ +#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /* Error originates from a native */ + +/********************************************** + *** The following structures are reference structures. + *** They are not essential to the API, but are used + *** to hold the back end database format of the plugin + *** binary. + **********************************************/ + +/** + * Information about the core plugin tables. + * These may or may not be present! + */ +typedef struct sp_plugin_infotab_s +{ + const char *stringbase; /* base of string table */ + uint32_t publics_num; /* number of publics */ + sp_file_publics_t *publics; /* public table */ + uint32_t natives_num; /* number of natives */ + sp_file_natives_t *natives; /* native table */ + uint32_t pubvars_num; /* number of pubvars */ + sp_file_pubvars_t *pubvars; /* pubvars table */ + uint32_t libraries_num; /* number of libraries */ + sp_file_libraries_t *lib; /* library table */ +} sp_plugin_infotab_t; + +/** + * Information about the plugin's debug tables. + * These are all present if one is present. + */ +typedef struct sp_plugin_debug_s +{ + const char *stringbase; /* base of string table */ + uint32_t files_num; /* number of files */ + sp_fdbg_file_t *files; /* files table */ + uint32_t lines_num; /* number of lines */ + sp_fdbg_line_t *lines; /* lines table */ + uint32_t syms_num; /* number of symbols */ + sp_fdbg_symbol_t *symbols; /* symbol table */ +} sp_plugin_debug_t; + +#define SP_FA_SELF_EXTERNAL (1<<0) +#define SP_FA_BASE_EXTERNAL (1<<1) + +/** + * The rebased, in-memory format of a plugin. + * This differs from the on-disk structure to ensure + * that the format is properly read. + */ +typedef struct sp_plugin_s +{ + uint8_t *base; /* base of memory */ + uint8_t *pcode; /* p-code */ + uint32_t pcode_size; /* size of p-code */ + uint8_t *data; /* data size */ + uint32_t data_size; /* size of data */ + uint32_t memory; /* required memory */ + uint16_t flags; /* code flags */ + uint32_t allocflags; /* allocation flags */ + sp_plugin_infotab_t info; /* base info table */ + sp_plugin_debug_t debug; /* debug info table */ +} sp_plugin_t; + +/** Forward declarations */ + +namespace SourcePawn +{ + class IPluginContext; + class IVirtualMachine; +}; + +struct sp_context_s; + +typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); + +/********************************************** + *** The following structures are bound to the VM/JIT. + *** Changing them will result in necessary recompilation. + **********************************************/ + +/** + * Offsets and names to a public function. + * By default, these point back to the string table + * in the sp_plugin_infotab_t structure. + */ +typedef struct sp_public_s +{ + funcid_t funcid; /* encoded function id */ + uint32_t code_offs; /* code offset */ + const char *name; /* name */ +} sp_public_t; + +/** + * Offsets and names to public variables. + * The offset is relocated and the name by default + * points back to the sp_plugin_infotab_t structure. + */ +typedef struct sp_pubvar_s +{ + cell_t *offs; /* pointer to data */ + const char *name; /* name */ +} sp_pubvar_t; + +#define SP_NATIVE_UNBOUND (0) /* Native is undefined */ +#define SP_NATIVE_BOUND (1) /* Native is bound */ + +/** + * Native lookup table, by default names + * point back to the sp_plugin_infotab_t structure. + * A native is NULL if unit + */ +typedef struct sp_native_s +{ + SPVM_NATIVE_FUNC pfn; /* function pointer */ + const char * name; /* name of function */ + uint32_t status; /* status flags */ +} sp_native_t; + +/** + * Used for setting natives from modules/host apps. + */ +typedef struct sp_nativeinfo_s +{ + const char *name; + SPVM_NATIVE_FUNC func; +} sp_nativeinfo_t; + +/** + * Debug file table + */ +typedef struct sp_debug_file_s +{ + uint32_t addr; /* address into code */ + const char * name; /* name of file */ +} sp_debug_file_t; + +/** + * Note that line is missing. It is not necessary since + * this can be retrieved from the base plugin info. + */ +typedef struct sp_debug_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line no. */ +} sp_debug_line_t; + +typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; + +/** + * The majority of this struct is already located in the parent + * block. Thus, only the relocated portions are required. + */ +typedef struct sp_debug_symbol_s +{ + uint32_t codestart; /* relocated code address */ + uint32_t codeend; /* relocated code end address */ + const char * name; /* relocated name */ + sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */ + sp_fdbg_symbol_t *sym; /* pointer to original symbol */ +} sp_debug_symbol_t; + +/** + * Breaks into a debugger + * Params: + * [0] - plugin context + * [1] - frm + * [2] - cip + */ +typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); + +#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ + +/** + * This is the heart of the VM. It contains all of the runtime + * information about a plugin context. + * Note that user[0..3] can be used for any user based pointers. + * vm[0..3] should not be touched, as it is reserved for the VM. + */ +typedef struct sp_context_s +{ + /* general/parent information */ + void *codebase; /* base of generated code and memory */ + sp_plugin_t *plugin; /* pointer back to parent information */ + SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ + SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ + void *user[4]; /* user specific pointers */ + void *vm[4]; /* VM specific pointers */ + uint32_t flags; /* compilation flags */ + SPVM_DEBUGBREAK dbreak; /* debug break function */ + /* context runtime information */ + uint8_t *memory; /* data chunk */ + ucell_t mem_size; /* total memory size; */ + cell_t data_size; /* data chunk size, always starts at 0 */ + cell_t heap_base; /* where the heap starts */ + /* execution specific data */ + cell_t hp; /* heap pointer */ + cell_t sp; /* stack pointer */ + cell_t frm; /* frame pointer */ + uint32_t pushcount; /* push count */ + int32_t n_err; /* error code set by a native */ + uint32_t n_idx; /* current native index being executed */ + /* context rebased database */ + sp_public_t *publics; /* public functions table */ + sp_pubvar_t *pubvars; /* public variables table */ + sp_native_t *natives; /* natives table */ + sp_debug_file_t *files; /* files */ + sp_debug_line_t *lines; /* lines */ + sp_debug_symbol_t *symbols; /* symbols */ +} sp_context_t; + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H From cc977859d661c7ef85ab5ad957f323e0280e9970 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 05:45:45 +0000 Subject: [PATCH 0300/1664] More reorganizations --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40330 --- core/msvc8/sourcemod_mm.vcproj | 68 +++++++++---------- core/sm_platform.h | 39 ----------- .../thread => public/extensions}/IThreader.h | 0 3 files changed, 32 insertions(+), 75 deletions(-) delete mode 100644 core/sm_platform.h rename {extensions/threader/thread => public/extensions}/IThreader.h (100%) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index f2f0ef45..b40d716c 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -294,7 +294,7 @@ > + + + + + + + + + + + + + + @@ -413,38 +441,6 @@ > - - - - - - - - - - - - - - - - -#include -#define PLATFORM_LIB_EXT "dll" -#define PLATFORM_MAX_PATH MAX_PATH -#define PLATFORM_SEP_CHAR '\\' -#define PLATFORM_SEP_ALTCHAR '/' -#define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) -#else if defined __linux__ -#define PLATFORM_LINUX -#define PLATFORM_POSIX -#include -#include -#define PLATFORM_MAX_PATH PATH_MAX -#define PLATFORM_LIB_EXT "so" -#define PLATFORM_SEP_CHAR '/' -#define PLATFORM_SEP_ALTCHAR '\\' -#define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) -#endif - -#endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/extensions/threader/thread/IThreader.h b/public/extensions/IThreader.h similarity index 100% rename from extensions/threader/thread/IThreader.h rename to public/extensions/IThreader.h From a25f2f7be618988e57f3cc4f47962dfbce63e9a0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 05:48:08 +0000 Subject: [PATCH 0301/1664] Final bit of reorganization I hope --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40331 --- sourcepawn/include/sp_file_headers.h | 163 ------- sourcepawn/include/sp_typeutil.h | 15 - sourcepawn/include/sp_vm_api.h | 631 --------------------------- sourcepawn/include/sp_vm_base.h | 16 - sourcepawn/include/sp_vm_types.h | 251 ----------- 5 files changed, 1076 deletions(-) delete mode 100644 sourcepawn/include/sp_file_headers.h delete mode 100644 sourcepawn/include/sp_typeutil.h delete mode 100644 sourcepawn/include/sp_vm_api.h delete mode 100644 sourcepawn/include/sp_vm_base.h delete mode 100644 sourcepawn/include/sp_vm_types.h diff --git a/sourcepawn/include/sp_file_headers.h b/sourcepawn/include/sp_file_headers.h deleted file mode 100644 index d3f41e7e..00000000 --- a/sourcepawn/include/sp_file_headers.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef _INCLUDE_SPFILE_HEADERS_H -#define _INCLUDE_SPFILE_HEADERS_H - -#include -#if defined __GNUC__ || defined HAVE_STDINT_ -#include -#else - #if !defined HAVE_STDINT_H - typedef unsigned __int64 uint64_t; - typedef __int64 int64_t; - typedef unsigned __int32 uint32_t; - typedef __int32 int32_t; - typedef unsigned __int16 uint16_t; - typedef __int16 int16_t; - typedef unsigned __int8 uint8_t; - typedef __int8 int8_t; - #define HAVE_STDINT_H - #endif -#endif - -#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ -//#define SPFILE_VERSION 0x0100 -#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */ - -//:TODO: better compiler/nix support -#if defined __linux__ - #pragma pack(1) /* structures must be packed (byte-aligned) */ -#else - #pragma pack(push) - #pragma pack(1) /* structures must be packed (byte-aligned) */ -#endif - -#define SPFILE_COMPRESSION_NONE 0 -#define SPFILE_COMPRESSION_GZ 1 - -typedef struct sp_file_section_s -{ - uint32_t nameoffs; /* rel offset into global string table */ - uint32_t dataoffs; - uint32_t size; -} sp_file_section_t; - -/** - * If compression is 0, then - * disksize may be 0 to mean that - * only the imagesize is needed. - */ -typedef struct sp_file_hdr_s -{ - uint32_t magic; /* magic number */ - uint16_t version; /* version code */ - uint8_t compression;/* compression algorithm */ - uint32_t disksize; /* size on disk */ - uint32_t imagesize; /* size in memory */ - uint8_t sections; /* number of sections */ - uint32_t stringtab; /* offset to string table */ - uint32_t dataoffs; /* offset to file proper (any compression starts here) */ -} sp_file_hdr_t; - -#define SP_FLAG_DEBUG (1<<0) - -/* section is ".code" */ -typedef struct sp_file_code_s -{ - uint32_t codesize; /* codesize in bytes */ - uint8_t cellsize; /* cellsize in bytes */ - uint8_t codeversion; /* version of opcodes supported */ - uint16_t flags; /* flags */ - uint32_t main; /* address to "main" if any */ - uint32_t code; /* rel offset to code */ -} sp_file_code_t; - -/* section is .data */ -typedef struct sp_file_data_s -{ - uint32_t datasize; /* size of data section in memory */ - uint32_t memsize; /* total mem required (includes data) */ - uint32_t data; /* file offset to data (helper) */ -} sp_file_data_t; - -/* section is .publics */ -typedef struct sp_file_publics_s -{ - uint32_t address; /* address rel to code section */ - uint32_t name; /* index into nametable */ -} sp_file_publics_t; - -/* section is .natives */ -typedef struct sp_file_natives_s -{ - uint32_t name; /* name of native at index */ -} sp_file_natives_t; - -/* section is .libraries */ -typedef struct sp_file_libraries_s -{ - uint32_t name; /* index into nametable */ -} sp_file_libraries_t; - -/* section is .pubvars */ -typedef struct sp_file_pubvars_s -{ - uint32_t address; /* address rel to dat section */ - uint32_t name; /* index into nametable */ -} sp_file_pubvars_t; - -#if defined __linux__ - #pragma pack() /* reset default packing */ -#else - #pragma pack(pop) /* reset previous packing */ -#endif - -typedef struct sp_fdbg_info_s -{ - uint32_t num_files; /* number of files */ - uint32_t num_lines; /* number of lines */ - uint32_t num_syms; /* number of symbols */ - uint32_t num_arrays; /* number of symbols which are arrays */ -} sp_fdbg_info_t; - -/** - * Debug information structures - */ -typedef struct sp_fdbg_file_s -{ - uint32_t addr; /* address into code */ - uint32_t name; /* offset into debug nametable */ -} sp_fdbg_file_t; - -typedef struct sp_fdbg_line_s -{ - uint32_t addr; /* address into code */ - uint32_t line; /* line number */ -} sp_fdbg_line_t; - -#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ -#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */ -#define SP_SYM_ARRAY 3 -#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */ -#define SP_SYM_FUNCTION 9 - -typedef struct sp_fdbg_symbol_s -{ - int32_t addr; /* address rel to DAT or stack frame */ - int16_t tagid; /* tag id */ - uint32_t codestart; /* start scope validity in code */ - uint32_t codeend; /* end scope validity in code */ - uint8_t ident; /* variable type */ - uint8_t vclass; /* scope class (local vs global) */ - uint16_t dimcount; /* dimension count (for arrays) */ - uint32_t name; /* offset into debug nametable */ -} sp_fdbg_symbol_t; - -typedef struct sp_fdbg_arraydim_s -{ - int16_t tagid; /* tag id */ - uint32_t size; /* size of dimension */ -} sp_fdbg_arraydim_t; - -/* section is .names */ -typedef char * sp_file_nametab_t; - -#endif //_INCLUDE_SPFILE_HEADERS_H diff --git a/sourcepawn/include/sp_typeutil.h b/sourcepawn/include/sp_typeutil.h deleted file mode 100644 index 921f9f74..00000000 --- a/sourcepawn/include/sp_typeutil.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ -#define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ - -#include "sp_vm_types.h" - -inline cell_t sp_ftoc(float val) -{ - return *(cell_t *)&val; -} -inline float sp_ctof(cell_t val) -{ - return *(float *)&val; -} - -#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ \ No newline at end of file diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h deleted file mode 100644 index cb904105..00000000 --- a/sourcepawn/include/sp_vm_api.h +++ /dev/null @@ -1,631 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_ -#define _INCLUDE_SOURCEPAWN_VM_API_H_ - -#include -#include "sp_vm_types.h" - -#define SOURCEPAWN_VM_API_VERSION 1 - -#if defined SOURCEMOD_BUILD -namespace SourceMod -{ - struct IdentityToken_t; -}; -#endif - -namespace SourcePawn -{ - class IVirtualMachine; - - /** - * @brief Interface to managing a debug context at runtime. - */ - class IPluginDebugInfo - { - public: - /** - * @brief Given a code pointer, finds the file it is associated with. - * - * @param addr Code address offset. - * @param filename Pointer to store filename pointer in. - */ - virtual int LookupFile(ucell_t addr, const char **filename) =0; - - /** - * @brief Given a code pointer, finds the function it is associated with. - * - * @param addr Code address offset. - * @param name Pointer to store function name pointer in. - */ - virtual int LookupFunction(ucell_t addr, const char **name) =0; - - /** - * @brief Given a code pointer, finds the line it is associated with. - * - * @param addr Code address offset. - * @param line Pointer to store line number in. - */ - virtual int LookupLine(ucell_t addr, uint32_t *line) =0; - }; - - /** - * @brief Interface to managing a context at runtime. - */ - class IPluginContext - { - public: - virtual ~IPluginContext() { }; - public: - /** - * @brief Returns the parent IVirtualMachine. - * - * @return Parent virtual machine pointer. - */ - virtual IVirtualMachine *GetVirtualMachine() =0; - - /** - * @brief Returns the child sp_context_t structure. - * - * @return Child sp_context_t structure. - */ - virtual sp_context_t *GetContext() =0; - - /** - * @brief Returns true if the plugin is in debug mode. - * - * @return True if in debug mode, false otherwise. - */ - virtual bool IsDebugging() =0; - - /** - * @brief Installs a debug break and returns the old one, if any. - * This will fail if the plugin is not debugging. - * - * @param newpfn New function pointer. - * @param oldpfn Pointer to retrieve old function pointer. - */ - virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; - - /** - * @brief Returns debug info. - * - * @return IPluginDebugInfo, or NULL if no debug info found. - */ - virtual IPluginDebugInfo *GetDebugInfo() =0; - - /** - * @brief Allocs memory on the secondary stack of a plugin. - * Note that although called a heap, it is in fact a stack. - * - * @param cells Number of cells to allocate. - * @param local_addr Will be filled with data offset to heap. - * @param phys_addr Physical address to heap memory. - */ - virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; - - /** - * @brief Pops a heap address off the heap stack. Use this to free memory allocated with - * SP_HeapAlloc(). - * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations - * with this native should be performed in precisely the REVERSE order. - * - * @param local_addr Local address to free. - */ - virtual int HeapPop(cell_t local_addr) =0; - - /** - * @brief Releases a heap address using a different method than SP_HeapPop(). - * This allows you to release in any order. However, if you allocate N - * objects, release only some of them, then begin allocating again, - * you cannot go back and starting freeing the originals. - * In other words, for each chain of allocations, if you start deallocating, - * then allocating more in a chain, you must only deallocate from the current - * allocation chain. This is basically HeapPop() except on a larger scale. - * - * @param local_addr Local address to free. - */ - virtual int HeapRelease(cell_t local_addr) =0; - - /** - * @brief Finds a native by name. - * - * @param name Name of native. - * @param index Optionally filled with native index number. - */ - virtual int FindNativeByName(const char *name, uint32_t *index) =0; - - /** - * @brief Gets native info by index. - * - * @param index Index number of native. - * @param native Optionally filled with pointer to native structure. - */ - virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; - - /** - * @brief Gets the number of natives. - * - * @return Filled with the number of natives. - */ - virtual uint32_t GetNativesNum() =0; - - /** - * @brief Finds a public function by name. - * - * @param name Name of public - * @param index Optionally filled with public index number. - */ - virtual int FindPublicByName(const char *name, uint32_t *index) =0; - - /** - * @brief Gets public function info by index. - * - * @param index Public function index number. - * @param publicptr Optionally filled with pointer to public structure. - */ - virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; - - /** - * @brief Gets the number of public functions. - * - * @return Filled with the number of public functions. - */ - virtual uint32_t GetPublicsNum() =0; - - /** - * @brief Gets public variable info by index. - * - * @param index Public variable index number. - * @param pubvar Optionally filled with pointer to pubvar structure. - */ - virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; - - /** - * @brief Finds a public variable by name. - * - * @param name Name of pubvar - * @param index Optionally filled with pubvar index number. - */ - virtual int FindPubvarByName(const char *name, uint32_t *index) =0; - - /** - * @brief Gets the addresses of a public variable. - * - * @param index Index of public variable. - * @param local_addr Address to store local address in. - * @param phys_addr Address to store physically relocated in. - */ - virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; - - /** - * @brief Returns the number of public variables. - * - * @return Number of public variables. - */ - virtual uint32_t GetPubVarsNum() =0; - - /** - * @brief Round-about method of converting a plugin reference to a physical address - * - * @param local_addr Local address in plugin. - * @param phys_addr Optionally filled with relocated physical address. - */ - virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; - - /** - * @brief Converts a local address to a physical string. - * - * @param local_addr Local address in plugin. - * @param addr Destination output pointer. - */ - virtual int LocalToString(cell_t local_addr, char **addr) =0; - - /** - * @brief Converts a physical string to a local address. - * - * @param local_addr Local address in plugin. - * @param bytes Number of chars to write, including NULL terminator. - * @param source Source string to copy. - */ - virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; - - /** - * @brief Converts a physical UTF-8 string to a local address. - * This function is the same as the ANSI version, except it will copy the maximum number of characters possible - * without accidentally chopping a multi-byte character. - * - * @param local_addr Local address in plugin. - * @param maxbytes Number of bytes to write, including NULL terminator. - * @param source Source string to copy. - * @param wrtnbytes Optionally set to the number of actual bytes written. - */ - virtual int StringToLocalUTF8(cell_t local_addr, - size_t maxbytes, - const char *source, - size_t *wrtnbytes) =0; - - /** - * @brief Pushes a cell onto the stack. Increases the parameter count by one. - * - * @param value Cell value. - */ - virtual int PushCell(cell_t value) =0; - - /** - * @brief Pushes an array of cells onto the stack. Increases the parameter count by one. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * Note that this does not release the heap, so you should release it after - * calling Execute(). - * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. - */ - virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; - - /** - * @brief Pushes a string onto the stack (by reference) and increases the parameter count by one. - * Note that this does not release the heap, so you should release it after - * calling Execute(). - * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param string Source string to push. - */ - virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; - - /** - * @brief Individually pushes each cell of an array of cells onto the stack. Increases the - * parameter count by the number of cells pushed. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. - * - * @param array Array of cells to read from. - * @param numcells Number of cells to read. - */ - virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; - - /** - * @brief Binds a list of native names and their function pointers to a context. - * If num is 0, the list is read until an entry with a NULL name is reached. - * If overwrite is non-zero, already registered natives will be overwritten. - * - * @param natives Array of natives. - * @param num Number of natives in array. - * @param overwrite Toggles overwrite. - */ - virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; - - /** - * @brief Binds a single native. Overwrites any existing bind. - * If the context does not contain the native that will be binded the function will return - * with a SP_ERROR_NOT_FOUND error. - * - * @param native Pointer to native. - */ - virtual int BindNative(const sp_nativeinfo_t *native) =0; - - /** - * @brief Binds a single native to any non-registered native. - * - * @param native Native to bind. - */ - virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; - - /** - * @brief Executes a function ID located in this context. - * - * @param funcid Function id to execute. - * @param result Pointer to store the return value (required). - * @return Error code (if any) from the VM. - */ - virtual int Execute(uint32_t funcid, cell_t *result) =0; - - - /** - * @brief Throws a error and halts any current execution. - * - * @param error The error number to set. - * @param msg Custom error message format. NULL to use default. - * @param ... Message format arguments, if any. - */ - virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; - - /** - * @brief Throws a generic native error and halts any current execution. - * - * @param msg Custom error message format. NULL to set no message. - * @param ... Message format arguments, if any. - * @return 0 for convenience. - */ - virtual cell_t ThrowNativeError(const char *msg, ...) =0; - -#if defined SOURCEMOD_BUILD - /** - * @brief Returns the identity token for this context. - * Note: This is a helper function for native calls and the Handle System. - * - * @return Identity token. - */ - virtual SourceMod::IdentityToken_t *GetIdentity() =0; -#endif - }; - - - /** - * @brief Information about a position in a call stack. - */ - struct CallStackInfo - { - const char *filename; /* NULL if not found */ - unsigned int line; /* 0 if not found */ - const char *function; /* NULL if not found */ - }; - - /** - * @brief Retrieves error information from a debug hook. - */ - class IContextTrace - { - public: - /** - * @brief Returns the integer error code. - * - * @return Integer error code. - */ - virtual int GetErrorCode() =0; - - /** - * @brief Returns a string describing the error. - * - * @return Error string. - */ - virtual const char *GetErrorString() =0; - - /** - * @brief Returns whether debug info is available. - * - * @return True if debug info is available, false otherwise. - */ - virtual bool DebugInfoAvailable() =0; - - /** - * @brief Returns a custom error message. - * - * @return A pointer to a custom error message, or NULL otherwise. - */ - virtual const char *GetCustomErrorString() =0; - - /** - * @brief Returns trace info for a specific point in the backtrace, if any. - * The next subsequent call to GetTraceInfo() will return the next item in the call stack. - * Calls are retrieved in descending order (i.e. the first item is at the top of the stack/call sequence). - * - * @param trace An ErrorTraceInfo buffer to store information (NULL to ignore). - * @return True if successful, false if there are no more traces. - */ - virtual bool GetTraceInfo(CallStackInfo *trace) =0; - - /** - * @brief Resets the trace to its original position (the call on the top of the stack). - */ - virtual void ResetTrace() =0; - - /** - * @brief Retrieves the name of the last native called. - * Returns NULL if there was no native that caused the error. - * - * @param index Optional pointer to store index. - * @return Native name, or NULL if none. - */ - virtual const char *GetLastNative(uint32_t *index) =0; - }; - - - /** - * @brief Provides callbacks for debug information. - */ - class IDebugListener - { - public: - virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0; - }; - - - /** - * @brief Contains helper functions used by VMs and the host app - */ - class ISourcePawnEngine - { - public: - /** - * @brief Loads a named file from a file pointer. - * Note: Using this means the memory will be allocated by the VM. - * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. - */ - virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; - - /** - * @brief Loads a file from a base memory address. - * - * @param base Base address of the plugin's memory region. - * @param plugin If NULL, a new plugin pointer is returned. - * Otherwise, the passed pointer is used. - * @param err Optional error code pointer. - * @return The resulting plugin pointer. - */ - virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; - - /** - * Frees all of the memory associated with a plugin file. - * If allocated using SP_LoadFromMemory, the base and plugin pointer - * itself are not freed (so this may end up doing nothing). - */ - virtual int FreeFromMemory(sp_plugin_t *plugin) =0; - - /** - * @brief Allocates large blocks of temporary memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ - virtual void *BaseAlloc(size_t size) =0; - - /** - * @brief Frees memory allocated with BaseAlloc. - * - * @param memory Memory address to free. - */ - virtual void BaseFree(void *memory) =0; - - /** - * @brief Allocates executable memory. - * - * @param size Size of memory to allocate. - * @return Pointer to memory, NULL if allocation failed. - */ - virtual void *ExecAlloc(size_t size) =0; - - /** - * @brief Frees executable memory. - * - * @param address Address to free. - */ - virtual void ExecFree(void *address) =0; - - /** - * @brief Sets the debug listener. This should only be called once. - * If called successively (using manual chaining), only the last function should - * attempt to call back into the same plugin. Otherwise, globally cached states - * can be accidentally overwritten. - * - * @param listener Pointer to an IDebugListener. - * @return Old IDebugListener, or NULL if none. - */ - virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0; - - /** - * @brief Returns the number of plugins on the call stack. - * - * @return Number of contexts in the call stack. - */ - virtual unsigned int GetContextCallCount() =0; - }; - - - /** - * @brief Dummy class for encapsulating private compilation data. - */ - class ICompilation - { - public: - virtual ~ICompilation() { }; - }; - - - /** - * @brief Outlines the interface a Virtual Machine (JIT) must expose - */ - class IVirtualMachine - { - public: - /** - * @brief Returns the current API version. - */ - virtual unsigned int GetAPIVersion() =0; - - /** - * @brief Returns the string name of a VM implementation. - */ - virtual const char *GetVMName() =0; - - /** - * @brief Begins a new compilation - * - * @param plugin Pointer to a plugin structure. - * @return New compilation pointer. - */ - virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; - - /** - * @brief Sets a compilation option. - * - * @param co Pointer to a compilation. - * @param key Option key name. - * @param val Option value string. - * @return True if option could be set, false otherwise. - */ - virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; - - /** - * @brief Finalizes a compilation into a new sp_context_t. - * Note: This will free the ICompilation pointer. - * - * @param co Compilation pointer. - * @param err Filled with error code on exit. - * @return New plugin context. - */ - virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; - - /** - * @brief Aborts a compilation and frees the ICompilation pointer. - * - * @param co Compilation pointer. - */ - virtual void AbortCompilation(ICompilation *co) =0; - - /** - * @brief Frees any internal variable usage on a context. - * - * @param ctx Context structure pointer. - */ - virtual void FreeContext(sp_context_t *ctx) =0; - - /** - * @brief Calls the "execute" function on a context. - * - * @param ctx Executes a function in a context. - * @param code_addr Index into the code section. - * @param result Pointer to store result into. - * @return Error code (if any). - */ - virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0; - - /** - * @brief Given a context and a code address, returns the index of the function. - * - * @param ctx Context to search. - * @param code_addr Index into the code section. - * @param result Pointer to store result into. - * @return True if code index is valid, false otherwise. - */ - virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; - - /** - * @brief Returns the number of functions defined in the context. - * - * @param ctx Context to search. - * @return Number of functions. - */ - virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; - - /** - * @brief Returns a version string. - * - * @return Versioning string. - */ - virtual const char *GetVersionString() =0; - - /** - * @brief Returns a string describing optimizations. - * - * @return String describing CPU specific optimizations. - */ - virtual const char *GetCPUOptimizations() =0; - }; -}; - -#endif //_INCLUDE_SOURCEPAWN_VM_API_H_ diff --git a/sourcepawn/include/sp_vm_base.h b/sourcepawn/include/sp_vm_base.h deleted file mode 100644 index 4fff0f4c..00000000 --- a/sourcepawn/include/sp_vm_base.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_ -#define _INCLUDE_SOURCEPAWN_VM_BASE_H_ - -#include - -/* :TODO: rename this to sp_vm_linkage.h */ - -#if defined WIN32 -#define EXPORT_LINK extern "C" __declspec(dllexport) -#else if defined __GNUC__ -#define EXPORT_LINK extern "C" __attribute__((visibility("default"))) -#endif - -typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); - -#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h deleted file mode 100644 index 2436144d..00000000 --- a/sourcepawn/include/sp_vm_types.h +++ /dev/null @@ -1,251 +0,0 @@ -#ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H -#define _INCLUDE_SOURCEPAWN_VM_TYPES_H - -#include "sp_file_headers.h" - -typedef uint32_t ucell_t; -typedef int32_t cell_t; -typedef uint32_t funcid_t; - -#include "sp_typeutil.h" - -#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ - -/** - * Error codes - * NOTE: Be sure to update the error string table when changing these - */ -#define SP_ERROR_NONE 0 -#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ -#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ -#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ -#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */ -#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ -#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ -#define SP_ERROR_INDEX 7 /* Invalid index parameter */ -#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */ -#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */ -#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */ -#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */ -#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */ -#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */ -#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */ -#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */ -#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */ -#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */ -#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */ -#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ -#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ -#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ -#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ -#define SP_ERROR_NATIVE 23 /* Error originates from a native */ - -/********************************************** - *** The following structures are reference structures. - *** They are not essential to the API, but are used - *** to hold the back end database format of the plugin - *** binary. - **********************************************/ - -/** - * Information about the core plugin tables. - * These may or may not be present! - */ -typedef struct sp_plugin_infotab_s -{ - const char *stringbase; /* base of string table */ - uint32_t publics_num; /* number of publics */ - sp_file_publics_t *publics; /* public table */ - uint32_t natives_num; /* number of natives */ - sp_file_natives_t *natives; /* native table */ - uint32_t pubvars_num; /* number of pubvars */ - sp_file_pubvars_t *pubvars; /* pubvars table */ - uint32_t libraries_num; /* number of libraries */ - sp_file_libraries_t *lib; /* library table */ -} sp_plugin_infotab_t; - -/** - * Information about the plugin's debug tables. - * These are all present if one is present. - */ -typedef struct sp_plugin_debug_s -{ - const char *stringbase; /* base of string table */ - uint32_t files_num; /* number of files */ - sp_fdbg_file_t *files; /* files table */ - uint32_t lines_num; /* number of lines */ - sp_fdbg_line_t *lines; /* lines table */ - uint32_t syms_num; /* number of symbols */ - sp_fdbg_symbol_t *symbols; /* symbol table */ -} sp_plugin_debug_t; - -#define SP_FA_SELF_EXTERNAL (1<<0) -#define SP_FA_BASE_EXTERNAL (1<<1) - -/** - * The rebased, in-memory format of a plugin. - * This differs from the on-disk structure to ensure - * that the format is properly read. - */ -typedef struct sp_plugin_s -{ - uint8_t *base; /* base of memory */ - uint8_t *pcode; /* p-code */ - uint32_t pcode_size; /* size of p-code */ - uint8_t *data; /* data size */ - uint32_t data_size; /* size of data */ - uint32_t memory; /* required memory */ - uint16_t flags; /* code flags */ - uint32_t allocflags; /* allocation flags */ - sp_plugin_infotab_t info; /* base info table */ - sp_plugin_debug_t debug; /* debug info table */ -} sp_plugin_t; - -/** Forward declarations */ - -namespace SourcePawn -{ - class IPluginContext; - class IVirtualMachine; -}; - -struct sp_context_s; - -typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); - -/********************************************** - *** The following structures are bound to the VM/JIT. - *** Changing them will result in necessary recompilation. - **********************************************/ - -/** - * Offsets and names to a public function. - * By default, these point back to the string table - * in the sp_plugin_infotab_t structure. - */ -typedef struct sp_public_s -{ - funcid_t funcid; /* encoded function id */ - uint32_t code_offs; /* code offset */ - const char *name; /* name */ -} sp_public_t; - -/** - * Offsets and names to public variables. - * The offset is relocated and the name by default - * points back to the sp_plugin_infotab_t structure. - */ -typedef struct sp_pubvar_s -{ - cell_t *offs; /* pointer to data */ - const char *name; /* name */ -} sp_pubvar_t; - -#define SP_NATIVE_UNBOUND (0) /* Native is undefined */ -#define SP_NATIVE_BOUND (1) /* Native is bound */ - -/** - * Native lookup table, by default names - * point back to the sp_plugin_infotab_t structure. - * A native is NULL if unit - */ -typedef struct sp_native_s -{ - SPVM_NATIVE_FUNC pfn; /* function pointer */ - const char * name; /* name of function */ - uint32_t status; /* status flags */ -} sp_native_t; - -/** - * Used for setting natives from modules/host apps. - */ -typedef struct sp_nativeinfo_s -{ - const char *name; - SPVM_NATIVE_FUNC func; -} sp_nativeinfo_t; - -/** - * Debug file table - */ -typedef struct sp_debug_file_s -{ - uint32_t addr; /* address into code */ - const char * name; /* name of file */ -} sp_debug_file_t; - -/** - * Note that line is missing. It is not necessary since - * this can be retrieved from the base plugin info. - */ -typedef struct sp_debug_line_s -{ - uint32_t addr; /* address into code */ - uint32_t line; /* line no. */ -} sp_debug_line_t; - -typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; - -/** - * The majority of this struct is already located in the parent - * block. Thus, only the relocated portions are required. - */ -typedef struct sp_debug_symbol_s -{ - uint32_t codestart; /* relocated code address */ - uint32_t codeend; /* relocated code end address */ - const char * name; /* relocated name */ - sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */ - sp_fdbg_symbol_t *sym; /* pointer to original symbol */ -} sp_debug_symbol_t; - -/** - * Breaks into a debugger - * Params: - * [0] - plugin context - * [1] - frm - * [2] - cip - */ -typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); - -#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ - -/** - * This is the heart of the VM. It contains all of the runtime - * information about a plugin context. - * Note that user[0..3] can be used for any user based pointers. - * vm[0..3] should not be touched, as it is reserved for the VM. - */ -typedef struct sp_context_s -{ - /* general/parent information */ - void *codebase; /* base of generated code and memory */ - sp_plugin_t *plugin; /* pointer back to parent information */ - SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ - SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ - void *user[4]; /* user specific pointers */ - void *vm[4]; /* VM specific pointers */ - uint32_t flags; /* compilation flags */ - SPVM_DEBUGBREAK dbreak; /* debug break function */ - /* context runtime information */ - uint8_t *memory; /* data chunk */ - ucell_t mem_size; /* total memory size; */ - cell_t data_size; /* data chunk size, always starts at 0 */ - cell_t heap_base; /* where the heap starts */ - /* execution specific data */ - cell_t hp; /* heap pointer */ - cell_t sp; /* stack pointer */ - cell_t frm; /* frame pointer */ - uint32_t pushcount; /* push count */ - int32_t n_err; /* error code set by a native */ - uint32_t n_idx; /* current native index being executed */ - /* context rebased database */ - sp_public_t *publics; /* public functions table */ - sp_pubvar_t *pubvars; /* public variables table */ - sp_native_t *natives; /* natives table */ - sp_debug_file_t *files; /* files */ - sp_debug_line_t *lines; /* lines */ - sp_debug_symbol_t *symbols; /* symbols */ -} sp_context_t; - -#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H From cd735aec716b93a189eb178408f8213418576b33 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 08:22:44 +0000 Subject: [PATCH 0302/1664] finished massive reorganization - IPluginFunction is now part of the VM, NOT the plugin system! This is how it should have been in the first place... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40332 --- core/msvc8/sourcemod_mm.vcproj | 30 ++-- core/systems/ForwardSys.cpp | 17 +- core/systems/ForwardSys.h | 2 +- core/systems/PluginSys.cpp | 142 +-------------- core/systems/PluginSys.h | 9 - core/vm/sp_vm_basecontext.cpp | 129 +++++++++++++ core/vm/sp_vm_basecontext.h | 15 ++ core/vm/sp_vm_engine.cpp | 39 ++++ core/vm/sp_vm_engine.h | 140 ++++++++------- .../CFunction.cpp => vm/sp_vm_function.cpp} | 36 ++-- core/vm/sp_vm_function.h | 55 ++++++ public/IForwardSys.h | 6 +- public/IPluginFunction.h | 153 ---------------- public/IPluginSys.h | 18 -- public/sourcepawn/sp_vm_api.h | 169 ++++++++++++++++++ public/sourcepawn/sp_vm_types.h | 1 + 16 files changed, 526 insertions(+), 435 deletions(-) rename core/{systems/CFunction.cpp => vm/sp_vm_function.cpp} (76%) create mode 100644 core/vm/sp_vm_function.h delete mode 100644 public/IPluginFunction.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index b40d716c..a1f60a33 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -341,10 +341,6 @@ RelativePath="..\..\public\ILibrarySys.h" > - - @@ -372,10 +368,6 @@ - - @@ -408,10 +400,6 @@ - - @@ -456,6 +444,10 @@ RelativePath="..\vm\sp_vm_engine.h" > + + + + diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 6011cdcc..9465840a 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -71,7 +71,7 @@ void CForwardManager::OnPluginLoaded(IPlugin *plugin) for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) { fwd = (*iter); - IPluginFunction *pFunc = plugin->GetFunctionByName(fwd->GetForwardName()); + IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName()); if (pFunc) { fwd->AddFunction(pFunc); @@ -256,7 +256,8 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); - if (func->GetParentPlugin()->GetStatus() == Plugin_Paused) + /* Ugh... */ + if (!func->GetParentContext()->IsRunnable()) { continue; } @@ -565,15 +566,10 @@ void CForward::Cancel() m_errstate = SP_ERROR_NONE; } -bool CForward::AddFunction(sp_context_t *ctx, funcid_t index) +bool CForward::AddFunction(IPluginContext *pContext, funcid_t index) { - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); - if (!pPlugin) - { - return false; - } + IPluginFunction *pFunc = pContext->GetFunctionById(index); - IPluginFunction *pFunc = pPlugin->GetFunctionById(index); if (!pFunc) { return false; @@ -614,10 +610,11 @@ unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) FuncIter iter; IPluginFunction *func; unsigned int removed = 0; + IPluginContext *pContext = plugin->GetBaseContext(); for (iter=m_functions.begin(); iter!=m_functions.end();) { func = (*iter); - if (func->GetParentPlugin() == plugin) + if (func->GetParentContext() == pContext) { iter = m_functions.erase(iter); removed++; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 4748e9fb..617aaf03 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -50,7 +50,7 @@ public: //IChangeableForward virtual bool RemoveFunction(IPluginFunction *func); virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin); virtual bool AddFunction(IPluginFunction *func); - virtual bool AddFunction(sp_context_t *ctx, funcid_t index); + virtual bool AddFunction(IPluginContext *ctx, funcid_t index); public: static CForward *CreateForward(const char *name, ExecType et, diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6528113e..fd82b260 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -23,9 +23,6 @@ CPlugin::CPlugin(const char *file) m_status = Plugin_Uncompiled; m_serial = ++MySerial; m_plugin = NULL; - m_funcsnum = 0; - m_priv_funcs = NULL; - m_pub_funcs = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); m_handle = 0; @@ -60,26 +57,6 @@ CPlugin::~CPlugin() m_ctx.co = NULL; } - if (m_pub_funcs) - { - for (uint32_t i=0; iinfo.publics_num; i++) - { - g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]); - } - delete [] m_pub_funcs; - m_pub_funcs = NULL; - } - - if (m_priv_funcs) - { - for (unsigned int i=0; iFreeFromMemory(m_plugin); @@ -190,30 +167,9 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) } m_ctx.base = new BaseContext(m_ctx.ctx); + m_ctx.base->SetRunnable(false); m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; - m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx); - - /** - * Note: Since the m_plugin member will never change, - * it is safe to assume the function count will never change - */ - if (m_funcsnum && m_priv_funcs == NULL) - { - m_priv_funcs = new CFunction *[m_funcsnum]; - memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); - } else { - m_priv_funcs = NULL; - } - - if (m_plugin->info.publics_num && m_pub_funcs == NULL) - { - m_pub_funcs = new CFunction *[m_plugin->info.publics_num]; - memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num); - } else { - m_pub_funcs = NULL; - } - m_status = Plugin_Created; m_ctx.co = NULL; @@ -230,67 +186,11 @@ void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) va_start(ap, error_fmt); vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); va_end(ap); -} -IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) -{ - CFunction *pFunc = NULL; - funcid_t save = func_id; - - if (func_id & 1) + if (m_ctx.base) { - func_id >>= 1; - if (func_id >= m_plugin->info.publics_num) - { - return NULL; - } - pFunc = m_pub_funcs[func_id]; - if (!pFunc) - { - pFunc = g_PluginSys.GetFunctionFromPool(save, this); - m_pub_funcs[func_id] = pFunc; - } - } else { - func_id >>= 1; - unsigned int index; - if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index)) - { - return NULL; - } - pFunc = m_priv_funcs[func_id]; - if (!pFunc) - { - pFunc = g_PluginSys.GetFunctionFromPool(save, this); - m_priv_funcs[func_id] = pFunc; - } + m_ctx.base->SetRunnable(false); } - - return pFunc; -} - -IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) -{ - uint32_t index; - IPluginContext *base = m_ctx.base; - - if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) - { - return NULL; - } - - CFunction *pFunc = m_pub_funcs[index]; - if (!pFunc) - { - sp_public_t *pub = NULL; - base->GetPublicByIndex(index, &pub); - if (pub) - { - pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this); - m_pub_funcs[index] = pFunc; - } - } - - return pFunc; } void CPlugin::UpdateInfo() @@ -338,7 +238,7 @@ void CPlugin::Call_OnPluginInit() m_status = Plugin_Running; cell_t result; - IPluginFunction *pFunction = GetFunctionByName("OnPluginInit"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginInit"); if (!pFunction) { return; @@ -356,7 +256,7 @@ void CPlugin::Call_OnPluginUnload() } cell_t result; - IPluginFunction *pFunction = GetFunctionByName("OnPluginUnload"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginUnload"); if (!pFunction) { return; @@ -373,10 +273,11 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) } m_status = Plugin_Loaded; + m_ctx.base->SetRunnable(true); int err; cell_t result; - IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad"); if (!pFunction) { @@ -389,13 +290,11 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) pFunction->PushCell(maxlength); if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) { - m_status = Plugin_Failed; return false; } if (!result || m_status != Plugin_Loaded) { - m_status = Plugin_Failed; return false; } @@ -463,7 +362,7 @@ bool CPlugin::SetPauseState(bool paused) m_status = (paused) ? Plugin_Paused : Plugin_Running; - IPluginFunction *pFunction = GetFunctionByName("OnPluginPauseChange"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange"); if (pFunction) { cell_t result; @@ -756,7 +655,6 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug snprintf(error, err_max, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); } pPlugin->CancelMyCompile(); - pPlugin->m_status = Plugin_Failed; co = NULL; break; } @@ -932,7 +830,6 @@ bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass { snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file); } - pPlugin->m_status = Plugin_Failed; return false; } else { g_Extensions.BindChildPlugin(pExt, pPlugin); @@ -1091,29 +988,6 @@ void CPluginManager::ReleaseIterator(CPluginIterator *iter) m_iters.push(iter); } -void CPluginManager::ReleaseFunctionToPool(CFunction *func) -{ - if (!func) - { - return; - } - func->Cancel(); - m_funcpool.push(func); -} - -CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) -{ - if (m_funcpool.empty()) - { - return new CFunction(f, plugin); - } else { - CFunction *func = m_funcpool.front(); - m_funcpool.pop(); - func->Set(f, plugin); - return func; - } -} - bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) { /* As an optimization, we do not call strlen, but compute the length in the first pass */ diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 5e804503..fa4930eb 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -8,7 +8,6 @@ #include #include "sm_globals.h" #include "vm/sp_vm_basecontext.h" -#include "CFunction.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" #include "sourcemod.h" @@ -93,8 +92,6 @@ public: virtual bool SetPauseState(bool paused); virtual unsigned int GetSerial() const; virtual const sp_plugin_t *GetPluginStructure() const; - virtual IPluginFunction *GetFunctionByName(const char *public_name); - virtual IPluginFunction *GetFunctionById(funcid_t func_id); virtual IdentityToken_t *GetIdentity() const; public: /** @@ -174,9 +171,6 @@ private: unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; - unsigned int m_funcsnum; - CFunction **m_priv_funcs; - CFunction **m_pub_funcs; char m_errormsg[256]; time_t m_LastAccess; IdentityToken_t *m_ident; @@ -312,8 +306,6 @@ protected: * Caching internal objects */ void ReleaseIterator(CPluginIterator *iter); - CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); - void ReleaseFunctionToPool(CFunction *func); inline IdentityToken_t *GetIdentity() { return m_MyIdent; @@ -323,7 +315,6 @@ private: List m_plugins; List m_natives; CStack m_iters; - CStack m_funcpool; CPluginInfoDatabase m_PluginInfo; Trie *m_LoadLookup; bool m_AllPluginsLoaded; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index fecfe427..96b6a7fe 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -27,6 +27,60 @@ BaseContext::BaseContext(sp_context_t *_ctx) ctx->dbreak = GlobalDebugBreak; m_InExec = false; m_CustomMsg = false; + m_Runnable = true; + m_funcsnum = ctx->vmbase->FunctionCount(ctx); + m_priv_funcs = NULL; + m_pub_funcs = NULL; + + /** + * Note: Since the m_plugin member will never change, + * it is safe to assume the function count will never change + */ + if (m_funcsnum && m_priv_funcs == NULL) + { + m_priv_funcs = new CFunction *[m_funcsnum]; + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); + } else { + m_priv_funcs = NULL; + } + + if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) + { + m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; + memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); + } else { + m_pub_funcs = NULL; + } +} + +void BaseContext::FlushFunctionCache() +{ + if (m_pub_funcs) + { + for (uint32_t i=0; iplugin->info.publics_num; i++) + { + delete m_pub_funcs[i]; + m_pub_funcs[i] = NULL; + } + } + + if (m_priv_funcs) + { + for (unsigned int i=0; icontext = this; + ctx->dbreak = GlobalDebugBreak; + FlushFunctionCache(); } IVirtualMachine *BaseContext::GetVirtualMachine() @@ -73,6 +130,11 @@ IPluginDebugInfo *BaseContext::GetDebugInfo() int BaseContext::Execute(funcid_t funcid, cell_t *result) { + if (!m_Runnable) + { + return SP_ERROR_NOT_RUNNABLE; + } + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; uint32_t pushcount = ctx->pushcount; @@ -794,6 +856,63 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) return SP_ERROR_NONE; } +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) +{ + CFunction *pFunc = NULL; + funcid_t save = func_id; + + if (func_id & 1) + { + func_id >>= 1; + if (func_id >= ctx->plugin->info.publics_num) + { + return NULL; + } + pFunc = m_pub_funcs[func_id]; + if (!pFunc) + { + m_pub_funcs[func_id] = new CFunction(save, this); + } + } else { + func_id >>= 1; + unsigned int index; + if (!g_pVM->FunctionLookup(ctx, func_id, &index)) + { + return NULL; + } + pFunc = m_priv_funcs[func_id]; + if (!pFunc) + { + m_priv_funcs[func_id] = new CFunction(save, this); + } + } + + return pFunc; +} + +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) +{ + uint32_t index; + + if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) + { + return NULL; + } + + CFunction *pFunc = m_pub_funcs[index]; + if (!pFunc) + { + sp_public_t *pub = NULL; + GetPublicByIndex(index, &pub); + if (pub) + { + m_pub_funcs[index] = new CFunction(pub->funcid, this); + } + } + + return pFunc; +} + #if defined SOURCEMOD_BUILD SourceMod::IdentityToken_t *BaseContext::GetIdentity() { @@ -804,4 +923,14 @@ void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) { m_pToken = token; } + +bool BaseContext::IsRunnable() +{ + return m_Runnable; +} + +void BaseContext::SetRunnable(bool runnable) +{ + m_Runnable = runnable; +} #endif diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index f755335e..d2625686 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -2,6 +2,11 @@ #define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #include "sp_vm_api.h" +#include "sp_vm_function.h" + +/** + * :TODO: Make functions allocate as a lump instead of individual allocations! + */ namespace SourcePawn { @@ -11,6 +16,7 @@ namespace SourcePawn { public: BaseContext(sp_context_t *ctx); + ~BaseContext(); public: //IPluginContext IVirtualMachine *GetVirtualMachine(); sp_context_t *GetContext(); @@ -44,9 +50,13 @@ namespace SourcePawn virtual int Execute(funcid_t funcid, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); + virtual IPluginFunction *GetFunctionByName(const char *public_name); + virtual IPluginFunction *GetFunctionById(funcid_t func_id); #if defined SOURCEMOD_BUILD virtual SourceMod::IdentityToken_t *GetIdentity(); void SetIdentity(SourceMod::IdentityToken_t *token); + bool IsRunnable(); + void SetRunnable(bool runnable); #endif public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); @@ -56,6 +66,7 @@ namespace SourcePawn void SetContext(sp_context_t *_ctx); private: void SetErrorMessage(const char *msg, va_list ap); + void FlushFunctionCache(); private: sp_context_t *ctx; #if defined SOURCEMOD_BUILD @@ -64,6 +75,10 @@ namespace SourcePawn char m_MsgCache[1024]; bool m_CustomMsg; bool m_InExec; + bool m_Runnable; + unsigned int m_funcsnum; + CFunction **m_priv_funcs; + CFunction **m_pub_funcs; }; }; diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index cb6cf700..e39e0e52 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -53,6 +53,9 @@ SourcePawnEngine::SourcePawnEngine() m_CallStack = NULL; m_FreedCalls = NULL; m_CurChain = 0; +#if 0 + m_pFreeFuncs = NULL; +#endif } SourcePawnEngine::~SourcePawnEngine() @@ -66,6 +69,16 @@ SourcePawnEngine::~SourcePawnEngine() delete m_FreedCalls; m_FreedCalls = pTemp; } + +#if 0 + CFunction *pNext; + while (m_pFreeFuncs) + { + pNext = m_pFreeFuncs->m_pNext; + delete m_pFreeFuncs; + m_pFreeFuncs = pNext; + } +#endif } void *SourcePawnEngine::ExecAlloc(size_t size) @@ -356,6 +369,32 @@ int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) return SP_ERROR_NONE; } +#if 0 +void SourcePawnEngine::ReleaseFunctionToPool(CFunction *func) +{ + if (!func) + { + return; + } + func->Cancel(); + func->m_pNext = m_pFreeFuncs; + m_pFreeFuncs = func; +} + +CFunction *SourcePawnEngine::GetFunctionFromPool(funcid_t f, IPluginContext *plugin) +{ + if (!m_pFreeFuncs) + { + return new CFunction(f, plugin); + } else { + CFunction *pFunc = m_pFreeFuncs; + m_pFreeFuncs = m_pFreeFuncs->m_pNext; + pFunc->Set(f, plugin); + return pFunc; + } +} +#endif + IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) { IDebugListener *old = m_pDebugHook; diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index ca0ac7f3..4ad0f715 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -2,83 +2,85 @@ #define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #include "sp_vm_api.h" +#include "sp_vm_function.h" -namespace SourcePawn +struct TracedCall { - struct TracedCall - { - uint32_t cip; - uint32_t frm; - sp_context_t *ctx; - TracedCall *next; - unsigned int chain; - }; + uint32_t cip; + uint32_t frm; + sp_context_t *ctx; + TracedCall *next; + unsigned int chain; +}; - class CContextTrace : public IContextTrace - { - public: - CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); - public: - virtual int GetErrorCode(); - virtual const char *GetErrorString(); - virtual bool DebugInfoAvailable(); - virtual const char *GetCustomErrorString(); - virtual bool GetTraceInfo(CallStackInfo *trace); - virtual void ResetTrace(); - virtual const char *GetLastNative(uint32_t *index); - private: - TracedCall *m_pStart; - TracedCall *m_pIterator; - const char *m_pMsg; - int m_Error; - uint32_t m_Native; - }; +class CContextTrace : public IContextTrace +{ +public: + CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); +public: + virtual int GetErrorCode(); + virtual const char *GetErrorString(); + virtual bool DebugInfoAvailable(); + virtual const char *GetCustomErrorString(); + virtual bool GetTraceInfo(CallStackInfo *trace); + virtual void ResetTrace(); + virtual const char *GetLastNative(uint32_t *index); +private: + TracedCall *m_pStart; + TracedCall *m_pIterator; + const char *m_pMsg; + int m_Error; + uint32_t m_Native; +}; - class SourcePawnEngine : public ISourcePawnEngine - { - public: - SourcePawnEngine(); - ~SourcePawnEngine(); - public: //ISourcePawnEngine - sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); - sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); - int FreeFromMemory(sp_plugin_t *plugin); - IPluginContext *CreateBaseContext(sp_context_t *ctx); - void FreeBaseContext(IPluginContext *ctx); - void *BaseAlloc(size_t size); - void BaseFree(void *memory); - void *ExecAlloc(size_t size); - void ExecFree(void *address); - IDebugListener *SetDebugListener(IDebugListener *pListener); - unsigned int GetContextCallCount(); - public: //Debugger Stuff - /** - * @brief Pushes a context onto the top of the call tracer. - * - * @param ctx Plugin context. - */ - void PushTracer(sp_context_t *ctx); +class SourcePawnEngine : public ISourcePawnEngine +{ +public: + SourcePawnEngine(); + ~SourcePawnEngine(); +public: //ISourcePawnEngine + sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); + sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); + int FreeFromMemory(sp_plugin_t *plugin); + IPluginContext *CreateBaseContext(sp_context_t *ctx); + void FreeBaseContext(IPluginContext *ctx); + void *BaseAlloc(size_t size); + void BaseFree(void *memory); + void *ExecAlloc(size_t size); + void ExecFree(void *address); + IDebugListener *SetDebugListener(IDebugListener *pListener); + unsigned int GetContextCallCount(); +public: //Debugger Stuff + /** + * @brief Pushes a context onto the top of the call tracer. + * + * @param ctx Plugin context. + */ + void PushTracer(sp_context_t *ctx); - /** - * @brief Pops a plugin off the call tracer. - */ - void PopTracer(int error, const char *msg); + /** + * @brief Pops a plugin off the call tracer. + */ + void PopTracer(int error, const char *msg); - /** - * @brief Runs tracer from a debug break. - */ - void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); - private: - TracedCall *MakeTracedCall(bool new_chain); - void FreeTracedCall(TracedCall *pCall); - private: - IDebugListener *m_pDebugHook; - TracedCall *m_FreedCalls; - TracedCall *m_CallStack; - unsigned int m_CurChain; - }; + /** + * @brief Runs tracer from a debug break. + */ + void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); +public: //Plugin function stuff + CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin); + void ReleaseFunctionToPool(CFunction *func); +private: + TracedCall *MakeTracedCall(bool new_chain); + void FreeTracedCall(TracedCall *pCall); +private: + IDebugListener *m_pDebugHook; + TracedCall *m_FreedCalls; + TracedCall *m_CallStack; + unsigned int m_CurChain; + //CFunction *m_pFreeFuncs; }; #endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/core/systems/CFunction.cpp b/core/vm/sp_vm_function.cpp similarity index 76% rename from core/systems/CFunction.cpp rename to core/vm/sp_vm_function.cpp index 6f123518..523a85a3 100644 --- a/core/systems/CFunction.cpp +++ b/core/vm/sp_vm_function.cpp @@ -5,33 +5,31 @@ * FUNCTION CALLING * ********************/ -void CFunction::Set(funcid_t funcid, CPlugin *plugin) +void CFunction::Set(funcid_t funcid, IPluginContext *plugin) { m_funcid = funcid; - m_pPlugin = plugin; + m_pContext = plugin; m_curparam = 0; m_errorstate = SP_ERROR_NONE; } int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { - IPluginContext *ctx = m_pPlugin->m_ctx.base; - while (num_params--) { - ctx->PushCell(params[num_params]); + m_pContext->PushCell(params[num_params]); } - return ctx->Execute(m_funcid, result); + return m_pContext->Execute(m_funcid, result); } -IPlugin *CFunction::GetParentPlugin() +IPluginContext *CFunction::GetParentContext() { - return m_pPlugin; + return m_pContext; } -CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : - m_funcid(funcid), m_pPlugin(plugin), m_curparam(0), +CFunction::CFunction(funcid_t funcid, IPluginContext *plugin) : + m_funcid(funcid), m_pContext(plugin), m_curparam(0), m_errorstate(SP_ERROR_NONE) { } @@ -79,11 +77,10 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *ctx = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; int err; - if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) { return SetError(err); } @@ -127,12 +124,11 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *base = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); int err; - if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) { return SetError(err); } @@ -148,12 +144,12 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ if (sz_flags & SM_PARAM_STRING_UTF8) { - if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) + if ((err=m_pContext->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) { return SetError(err); } } else { - if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) + if ((err=m_pContext->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) { return SetError(err); } @@ -174,13 +170,11 @@ void CFunction::Cancel() return; } - IPluginContext *base = m_pPlugin->m_ctx.base; - while (m_curparam--) { if (m_info[m_curparam].marked) { - base->HeapRelease(m_info[m_curparam].local_addr); + m_pContext->HeapRelease(m_info[m_curparam].local_addr); m_info[m_curparam].marked = false; } } @@ -217,8 +211,6 @@ int CFunction::Execute(cell_t *result) docopies = false; } - IPluginContext *base = m_pPlugin->m_ctx.base; - while (numparams--) { if (!temp_info[numparams].marked) @@ -239,7 +231,7 @@ int CFunction::Execute(cell_t *result) } } } - base->HeapPop(temp_info[numparams].local_addr); + m_pContext->HeapPop(temp_info[numparams].local_addr); temp_info[numparams].marked = false; } diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h new file mode 100644 index 00000000..ad688c1c --- /dev/null +++ b/core/vm/sp_vm_function.h @@ -0,0 +1,55 @@ +#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ +#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ + +#include "sm_globals.h" + +struct ParamInfo +{ + int flags; /* Copy-back flags */ + bool marked; /* Whether this is marked as being used */ + cell_t local_addr; /* Local address to free */ + cell_t *phys_addr; /* Physical address of our copy */ + cell_t *orig_addr; /* Original address to copy back to */ + ucell_t size; /* Size of array in bytes */ +}; + +class CPlugin; + +class CFunction : public IPluginFunction +{ + friend class SourcePawnEngine; +public: + CFunction(funcid_t funcid, IPluginContext *pContext); +public: + virtual int PushCell(cell_t cell); + virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushFloat(float number); + virtual int PushFloatByRef(float *number, int flags); + virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); + virtual int PushString(const char *string); + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); + virtual cell_t *GetAddressOfPushedParam(unsigned int param); + virtual int Execute(cell_t *result); + virtual void Cancel(); + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); + virtual IPluginContext *GetParentContext(); +public: + void Set(funcid_t funcid, IPluginContext *plugin); +private: + int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); + inline int SetError(int err) + { + m_errorstate = err; + return err; + } +private: + funcid_t m_funcid; + IPluginContext *m_pContext; + cell_t m_params[SP_MAX_EXEC_PARAMS]; + ParamInfo m_info[SP_MAX_EXEC_PARAMS]; + unsigned int m_curparam; + int m_errorstate; + CFunction *m_pNext; +}; + +#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ diff --git a/public/IForwardSys.h b/public/IForwardSys.h index d4732899..bd023adc 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -3,7 +3,9 @@ #include #include -#include +#include + +using namespace SourcePawn; #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" #define SMINTERFACE_FORWARDMANAGER_VERSION 1 @@ -190,7 +192,7 @@ namespace SourceMod * @param funcid Function id to add. * @return True on success, otherwise false. */ - virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0; + virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; }; #define SP_PARAMTYPE_ANY 0 diff --git a/public/IPluginFunction.h b/public/IPluginFunction.h deleted file mode 100644 index 7174baf6..00000000 --- a/public/IPluginFunction.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ -#define _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ - -#include - -namespace SourceMod -{ - #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ - - #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ - #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ - - /** - * @brief Represents what a function needs to implement in order to be callable. - */ - class ICallable - { - public: - /** - * @brief Pushes a cell onto the current call. - * - * @param cell Parameter value to push. - * @return Error code, if any. - */ - virtual int PushCell(cell_t cell) =0; - - /** - * @brief Pushes a cell by reference onto the current call. - * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param cell Address containing parameter value to push. - * @param flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushCellByRef(cell_t *cell, int flags) =0; - - /** - * @brief Pushes a float onto the current call. - * - * @param float Parameter value to push. - * @return Error code, if any. - */ - virtual int PushFloat(float number) =0; - - /** - * @brief Pushes a float onto the current call by reference. - * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param float Parameter value to push. - & @param flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushFloatByRef(float *number, int flags) =0; - - /** - * @brief Pushes an array of cells onto the current call. - * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back - * is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param inarray Array to copy, NULL if no initial array should be copied. - * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Optional return address for physical array, if one was made. - * @param flags Whether or not changes should be copied back to the input array. - * @return Error code, if any. - */ - virtual int PushArray(cell_t *inarray, - unsigned int cells, - cell_t **phys_addr, - int flags=0) =0; - - /** - * @brief Pushes a string onto the current call. - * - * @param string String to push. - * @return Error code, if any. - */ - virtual int PushString(const char *string) =0; - - /** - * @brief Pushes a string or string buffer. - * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. - * - * @param buffer Pointer to string buffer. - * @param length Length of buffer. - * @param sz_flags String flags. - * @param cp_flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0; - - /** - * @brief Cancels a function call that is being pushed but not yet executed. - * This can be used be reset for CallFunction() use. - */ - virtual void Cancel() =0; - }; - - /** - * @brief Encapsulates a function call in a plugin. - * NOTE: Function calls must be atomic to one execution context. - * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. - */ - class IPluginFunction : public ICallable - { - public: - /** - * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. - * - * @param result Pointer to store return value in. - * @return Error code, if any. - */ - virtual int Execute(cell_t *result) =0; - - /** - * @brief Executes the function with the given parameter array. - * Parameters are read in forward order (i.e. index 0 is parameter #1) - * NOTE: You will get an error if you attempt to use CallFunction() with - * previously pushed parameters. - * - * @param param Array of cell parameters. - * @param num_params Number of parameters to push. - * @param result Pointer to store result of function on return. - * @return SourcePawn error code (if any). - */ - virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; - - /** - * @brief Returns which plugin this function belongs to. - * - * @return IPlugin pointer to parent plugin. - */ - virtual IPlugin *GetParentPlugin() =0; - - /** - * @brief Returns the physical address of a by-reference parameter. - * - * @param Parameter index to read (beginning at 0). - * @return Address, or NULL if invalid parameter specified. - */ - virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; - }; -}; - -#endif //_INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 45f27065..589b788f 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -57,8 +57,6 @@ namespace SourceMod PluginType_Global, /* Plugin will never be unloaded or updated */ }; - class IPluginFunction; - /** * @brief Encapsulates a run-time plugin as maintained by SourceMod. */ @@ -129,22 +127,6 @@ namespace SourceMod */ virtual unsigned int GetSerial() const =0; - /** - * @brief Returns a function by name. - * - * @param public_name Name of the function. - * @return A new IPluginFunction pointer, NULL if not found. - */ - virtual IPluginFunction *GetFunctionByName(const char *public_name) =0; - - /** - * @brief Returns a function by its id. - * - * @param func_id Function ID. - * @return A new IPluginFunction pointer, NULL if not found. - */ - virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; - /** * @brief Returns a plugin's identity token. */ diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index cb904105..21ff120d 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -17,6 +17,152 @@ namespace SourcePawn { class IVirtualMachine; + #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ + + #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ + #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ + + /** + * @brief Represents what a function needs to implement in order to be callable. + */ + class ICallable + { + public: + /** + * @brief Pushes a cell onto the current call. + * + * @param cell Parameter value to push. + * @return Error code, if any. + */ + virtual int PushCell(cell_t cell) =0; + + /** + * @brief Pushes a cell by reference onto the current call. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param cell Address containing parameter value to push. + * @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushCellByRef(cell_t *cell, int flags) =0; + + /** + * @brief Pushes a float onto the current call. + * + * @param float Parameter value to push. + * @return Error code, if any. + */ + virtual int PushFloat(float number) =0; + + /** + * @brief Pushes a float onto the current call by reference. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param float Parameter value to push. + & @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushFloatByRef(float *number, int flags) =0; + + /** + * @brief Pushes an array of cells onto the current call. + * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back + * is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param inarray Array to copy, NULL if no initial array should be copied. + * @param cells Number of cells to allocate and optionally read from the input array. + * @param phys_addr Optional return address for physical array, if one was made. + * @param flags Whether or not changes should be copied back to the input array. + * @return Error code, if any. + */ + virtual int PushArray(cell_t *inarray, + unsigned int cells, + cell_t **phys_addr, + int flags=0) =0; + + /** + * @brief Pushes a string onto the current call. + * + * @param string String to push. + * @return Error code, if any. + */ + virtual int PushString(const char *string) =0; + + /** + * @brief Pushes a string or string buffer. + * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. + * + * @param buffer Pointer to string buffer. + * @param length Length of buffer. + * @param sz_flags String flags. + * @param cp_flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0; + + /** + * @brief Cancels a function call that is being pushed but not yet executed. + * This can be used be reset for CallFunction() use. + */ + virtual void Cancel() =0; + }; + + + /** + * @brief Encapsulates a function call in a plugin. + * NOTE: Function calls must be atomic to one execution context. + * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. + */ + class IPluginFunction : public ICallable + { + public: + /** + * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. + * + * @param result Pointer to store return value in. + * @return Error code, if any. + */ + virtual int Execute(cell_t *result) =0; + + /** + * @brief Executes the function with the given parameter array. + * Parameters are read in forward order (i.e. index 0 is parameter #1) + * NOTE: You will get an error if you attempt to use CallFunction() with + * previously pushed parameters. + * + * @param param Array of cell parameters. + * @param num_params Number of parameters to push. + * @param result Pointer to store result of function on return. + * @return SourcePawn error code (if any). + */ + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; + + /** + * @brief Returns which plugin this function belongs to. + * + * @return IPluginContext pointer to parent plugin. + */ + virtual IPluginContext *GetParentContext() =0; + + /** + * @brief Returns the physical address of a by-reference parameter. + * + * @param Parameter index to read (beginning at 0). + * @return Address, or NULL if invalid parameter specified. + */ + virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; + }; + + /** * @brief Interface to managing a debug context at runtime. */ @@ -340,6 +486,22 @@ namespace SourcePawn */ virtual cell_t ThrowNativeError(const char *msg, ...) =0; + /** + * @brief Returns a function by name. + * + * @param public_name Name of the function. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionByName(const char *public_name) =0; + + /** + * @brief Returns a function by its id. + * + * @param func_id Function ID. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; + #if defined SOURCEMOD_BUILD /** * @brief Returns the identity token for this context. @@ -348,6 +510,13 @@ namespace SourcePawn * @return Identity token. */ virtual SourceMod::IdentityToken_t *GetIdentity() =0; + + /** + * @brief Returns whether the identity is runnable. + * + * @return True if runnable, false otherwise. + */ + virtual bool IsRunnable() =0; #endif }; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 2436144d..74e47434 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -39,6 +39,7 @@ typedef uint32_t funcid_t; #define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ #define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ #define SP_ERROR_NATIVE 23 /* Error originates from a native */ +#define SP_ERROR_NOT_RUNNABLE 24 /* Function or plugin is not runnable */ /********************************************** *** The following structures are reference structures. From ec93a3eb80d099bc27f126ea393b3284a0411131 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 08:24:11 +0000 Subject: [PATCH 0303/1664] cleanup --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40333 --- core/systems/CFunction.h | 54 ---------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 core/systems/CFunction.h diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h deleted file mode 100644 index f0f05897..00000000 --- a/core/systems/CFunction.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ -#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ - -#include -#include "sm_globals.h" - -struct ParamInfo -{ - int flags; /* Copy-back flags */ - bool marked; /* Whether this is marked as being used */ - cell_t local_addr; /* Local address to free */ - cell_t *phys_addr; /* Physical address of our copy */ - cell_t *orig_addr; /* Original address to copy back to */ - ucell_t size; /* Size of array in bytes */ -}; - -class CPlugin; - -class CFunction : public IPluginFunction -{ -public: - CFunction(funcid_t funcid, CPlugin *plugin); -public: - virtual int PushCell(cell_t cell); - virtual int PushCellByRef(cell_t *cell, int flags); - virtual int PushFloat(float number); - virtual int PushFloatByRef(float *number, int flags); - virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); - virtual int PushString(const char *string); - virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); - virtual cell_t *GetAddressOfPushedParam(unsigned int param); - virtual int Execute(cell_t *result); - virtual void Cancel(); - virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); - virtual IPlugin *GetParentPlugin(); -public: - void Set(funcid_t funcid, CPlugin *plugin); -private: - int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); - inline int SetError(int err) - { - m_errorstate = err; - return err; - } -private: - funcid_t m_funcid; - CPlugin *m_pPlugin; - cell_t m_params[SP_MAX_EXEC_PARAMS]; - ParamInfo m_info[SP_MAX_EXEC_PARAMS]; - unsigned int m_curparam; - int m_errorstate; -}; - -#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ From 607509cec61a57219c6aad52b8488d90d18c2ec3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 10:02:43 +0000 Subject: [PATCH 0304/1664] changed this to reject iface removal by default added forwardsys to defaults --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40334 --- public/IExtensionSys.h | 2 +- public/sample_ext/smsdk_ext.cpp | 2 ++ public/sample_ext/smsdk_ext.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index 36c5430d..c96ba405 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -135,7 +135,7 @@ namespace SourceMod */ virtual bool QueryInterfaceDrop(SMInterface *pInterface) { - return true; + return false; } /** diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index 01e3f42c..ddd0cc5b 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -5,6 +5,7 @@ IShareSys *g_pShareSys = NULL; IExtension *myself = NULL; IHandleSys *g_pHandleSys = NULL; ISourceMod *g_pSM = NULL; +IForwardManager *g_pForwards = NULL; PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { @@ -40,6 +41,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); if (SDK_OnLoad(error, err_max, late)) { diff --git a/public/sample_ext/smsdk_ext.h b/public/sample_ext/smsdk_ext.h index 07362c78..16d931bc 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/public/sample_ext/smsdk_ext.h @@ -7,6 +7,7 @@ #include #include #include +#include #if defined SMEXT_CONF_METAMOD #include @@ -123,6 +124,7 @@ extern IShareSys *g_pShareSys; extern IExtension *myself; extern IHandleSys *g_pHandleSys; extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); From 84beea21cfc61ac0a0a985b8612dd4644580a68c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 10:06:45 +0000 Subject: [PATCH 0305/1664] updated todo list --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40335 --- TODO.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.txt b/TODO.txt index 2323d7f6..81e11cae 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,6 +4,7 @@ things to do for a release, in priority X do module api X finish plugin pausing/unpausing, forwards must block execution - do admin api + - finish cross extension dependencies (ShareSys::AddDepency) - make "mapupdated" plugins work as intended (reload on mapchange if newer) X add debugging output to logger - finish ML api, expose through interface From aa5da7bdb2413c00b8a7491cfc802e7fbea46e04 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 10:07:08 +0000 Subject: [PATCH 0306/1664] okay one last todo update --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40336 --- TODO.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.txt b/TODO.txt index 81e11cae..b2982988 100644 --- a/TODO.txt +++ b/TODO.txt @@ -11,3 +11,4 @@ things to do for a release, in priority X add error messages to format routine X finish global unloading - add hex format specifier + - linux building (oh god) From d351566b25cc48ebdc135e7aed23aa596de897da Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 23:30:22 +0000 Subject: [PATCH 0307/1664] changed the admin config organization around a bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40337 --- configs/admins.cfg | 31 +++++ configs/admins_groups.cfg | 77 +++++++++++ .../{admins_simple.cfg => admins_simple.ini} | 8 +- configs/permissions.cfg | 124 ------------------ 4 files changed, 111 insertions(+), 129 deletions(-) create mode 100644 configs/admins.cfg create mode 100644 configs/admins_groups.cfg rename configs/{admins_simple.cfg => admins_simple.ini} (74%) delete mode 100644 configs/permissions.cfg diff --git a/configs/admins.cfg b/configs/admins.cfg new file mode 100644 index 00000000..4b7fa1b9 --- /dev/null +++ b/configs/admins.cfg @@ -0,0 +1,31 @@ + +/** + * USE THIS SECTION TO DECLARE DETAILED ADMIN PROPERTIES. + * + * Each admin should have its own "Admin" section, followed by a name. + * The name does not have to be unique. + * + * Available properties: (Anything else is filtered as custom) + * "auth" - REQUIRED - Auth method to use. Built-in methods are: + * "steam" - Steam based authentication + * "name" - Name based authentication + * "ip" - IP based authentication + * Anything else is treated as custom. + * + * "identity" - REQUIRED - Identification string, for example, a steamid or name. + * "password" - Optional password to use. + * "group" - Inherits a set of group permissions. + * "flags" - Adds a set of flags. + * + * Example: + "BAILOPAN" + { + "auth" "steam" + "identity" "STEAM_0:1:16" + "flags" "abcdef" + } + * + */ +Admins +{ +} diff --git a/configs/admins_groups.cfg b/configs/admins_groups.cfg new file mode 100644 index 00000000..2f793528 --- /dev/null +++ b/configs/admins_groups.cfg @@ -0,0 +1,77 @@ +/** + * Use this section to tweak admin permission levels and groupings. + * You can also define admin roles in this section. + */ +Levels +{ + /** + * These are the default role flag mappings. + * You can assign new letters for custom purposes, however you should + * not change the default names, as SourceMod hardcodes these. + */ + Flags + { + "reservation" "a" + "kick" "b" + "ban" "c" + "unban" "d" + "slay" "e" + "changemap" "f" + "cvars" "g" + "configs" "h" + "chat" "i" + "vote" "j" + "password" "h" + "rcon" "i" + + //Custom flags START + //Custom flags END + + //Note - root is a magic access flag that grants all permissions. + "root" "z" + } + + /** + * By default, commands are registered with three pieces of information: + * 1)Command Name (for example, "csdm_enable") + * 2)Command Group Name (for example, "CSDM") + * 3)Command Level (for example, "changemap") + * You can override the default flags assigned to individual commands or command groups in this way. + * To override a group, use the ":" character before the name. Example: + * Examples: + * ":CSDM" "i" // Override the CSDM group + * "csdm_enable" "j" // Override the csdm_enable command + * Note that for overrides, order is important. In the above example, csdm_enable overwrites + * any setting that csdm_enable previously had. + */ + Overrides + { + } +} + +Groups +{ + /** + * Allowed properties for a group: + * + * "flags" - Flag string. + * "inherit" - Inherits permissions from another group. + * "immunity" - Specifies a group to be immune to. Use "*" for all or "$" for users with no group. + * NOTE: No one, even a root user, is immune from other root users. + */ + "Full Admins" + { + /** + * You can override commands and command groups here. + * Specify a command name or group and either "allow" or "deny" + * Examples: + * ":CSDM" "allow" + * "csdm_enable" "deny" + */ + Commands + { + } + "flags" "abcdefghiz" + "immunity" "*" + } +} diff --git a/configs/admins_simple.cfg b/configs/admins_simple.ini similarity index 74% rename from configs/admins_simple.cfg rename to configs/admins_simple.ini index b48f3fff..f9462bb7 100644 --- a/configs/admins_simple.cfg +++ b/configs/admins_simple.ini @@ -2,12 +2,12 @@ * READ THIS CAREFULLY! SEE BOTTOM FOR EXAMPLES * * For each admin, you need two settings: - * "identity" "permissions" + * "identity" "permissions" "password" * * For the Identity, you can use a SteamID, IP address, or Name (the type will be auto-detected). * For the Permissions, you can use a flag string or group (read below), and an optional password. * - * There are 26 flags (a-z), and each flag has a specific meaning/role. + * There are 13 flags (a-i,z), and each flag has a specific meaning/role. * For example, the "b" flag means "kick permissions." * * You can combine flags into a string like this: @@ -29,13 +29,11 @@ "rcon" "i" //Use RCON "root" "z" //All permissions * - * NOTE: If you specify a - in a flag string, each subsequent flag will be subtracted instead of added. - * You can specify a + to "undo" this in the same string. * * Examples: * "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID * "127.0.0.1" "z" //all permissions for this ip - * "BAILOPAN" "mypassword:abc" //name BAILOPAN, password "mypassword" gets reservation, kick, ban + * "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban * ***************************************/ diff --git a/configs/permissions.cfg b/configs/permissions.cfg deleted file mode 100644 index 0a72a3be..00000000 --- a/configs/permissions.cfg +++ /dev/null @@ -1,124 +0,0 @@ - -/** - * USE THIS SECTION TO DECLARE DETAILED ADMIN PROPERTIES. - * - * Each admin should have its own "Admin" section, followed by a name. - * The name does not have to be unique. - * - * Available properties: (Anything else is filtered as custom) - * "auth" - REQUIRED - Auth method to use. Built-in methods are: - * "steam" - Steam based authentication - * "name" - Name based authentication - * "ip" - IP based authentication - * Anything else is treated as custom. - * - * "identity" - REQUIRED - Identification string, for example, a steamid or name. - * "password" - Optional password to use. - * "group" - Inherits a set of group permissions. - * "flags" - Inherits a set of flags. - * "immunity" - Sets an immunity to a group (* for all, empty string for default users) - * CommandGroups - See the Permissions section. - * Commands - See the Permissions section. - * - * Example: - "BAILOPAN" - { - "auth" "steam" - "identity" "STEAM_0:1:16" - "flags" "abcdef" - } - * - */ -Admins -{ -} - - -/** - * Use this section to tweak admin permission levels and groupings. - * You can also define admin roles in this section. - */ -Levels -{ - /** - * These are the default role flag mappings. - * You can assign new letters for custom purposes, however you should - * not change the default names, as SourceMod hardcodes these. - */ - Flags - { - "reservation" "a" - "kick" "b" - "ban" "c" - "unban" "d" - "slay" "e" - "changemap" "f" - "cvars" "g" - "configs" "h" - "chat" "i" - "votes" "j" - "password" "h" - "rcon" "i" - - //Custom flags START - //Custom flags END - - //Note - root is a magic access flag that grants all permissions. - "root" "z" - } - - /** - * By default, commands are registered with three pieces of information: - * 1)Command Name (for example, "csdm_enable") - * 2)Command Group Name (for example, "CSDM") - * 3)Command Level (for example, "changemap") - * You can override the default flags assigned to individual commands or command groups in this way. - * You can specify either a one-character, lower-case flag, or a named flag from "Levels." - * Examples: - * "CSDM" "i" - * "csdm_enable" "j" - */ - Overrides - { - CommandGroups - { - } - Commands - { - } - } -} - -Permissions -{ - - //Lastly, you can define groups for admins. This helps organize large admin lists. - Groups - { - /** - * Allowed properties for a group: - * - * "flags" - Flag string (you can use -/+ as allowed earlier). - * "inherit" - Inherits permissions from another group. - * "immunity" - Specifies a group to be immune to. Use "*" for all or "" for users with no group. - * Note: You can use - to strip immunity from a group, in the case of inheritance. - */ - "Sample" - { - /** - * You can override commands and command groups here. - * Specify a command name or group and either "allow" or "deny" - * You can have multiple entries for both sections in order to override/tweak them. - * Examples: - * "CSDM" "allow" - * "csdm_enable" "deny" - */ - CommandGroups - { - } - Commands - { - } - } - } -} From ba1daf3142547586d7e853031261d03c7adf6b61 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 20 Jan 2007 02:12:53 +0000 Subject: [PATCH 0308/1664] plugins get updated on map change maponly plugins get unloaded on map change --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40338 --- core/sourcemod.cpp | 16 ++++++++++ core/sourcemod.h | 6 ++++ core/systems/PluginSys.cpp | 61 ++++++++++++++++++++++++++++++++++++++ core/systems/PluginSys.h | 18 ++++++++++- public/IHandleSys.h | 1 - 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index ec1403f9..b87b34eb 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -10,6 +10,7 @@ #include "ExtensionSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); +SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -39,6 +40,7 @@ void ShutdownJIT() SourceModBase::SourceModBase() { m_IsMapLoading = false; + m_ExecPluginReload = false; } bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) @@ -131,6 +133,7 @@ void SourceModBase::StartSourceMod(bool late) { /* First initialize the global hooks we need */ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -158,6 +161,7 @@ void SourceModBase::StartSourceMod(bool late) bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { m_IsMapLoading = true; + m_ExecPluginReload = true; g_Logger.MapChange(pMapName); @@ -168,6 +172,15 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch RETURN_META_VALUE(MRES_IGNORED, true); } +void SourceModBase::LevelShutdown() +{ + if (m_ExecPluginReload) + { + g_PluginSys.ReloadOrUnloadPlugins(); + m_ExecPluginReload = false; + } +} + bool SourceModBase::IsMapLoading() { return m_IsMapLoading; @@ -241,6 +254,9 @@ void SourceModBase::CloseSourceMod() pBase = pBase->m_pGlobalClassNext; } + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); + /* Rest In Peace */ ShutdownJIT(); } diff --git a/core/sourcemod.h b/core/sourcemod.h index bd74af48..b2c9c5d0 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -33,6 +33,11 @@ public: */ bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); + /** + * @brief Level shutdown hook + */ + void LevelShutdown(); + /** * @brief Returns whether or not a mapload is in progress */ @@ -52,6 +57,7 @@ private: private: char m_SMBaseDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; + bool m_ExecPluginReload; }; extern SourceModBase g_SourceMod; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index fd82b260..cdfff088 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -449,6 +449,35 @@ bool CPlugin::IsRunnable() const return (m_status <= Plugin_Paused) ? true : false; } +time_t CPlugin::GetFileTimeStamp() +{ + char path[PLATFORM_MAX_PATH+1]; + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(path, &s) != 0) +#else if defined PLATFORM_POSIX + struct stat s; + if (stat(path, &s) != 0) +#endif + { + g_Logger.LogError("Could not obtain plugin time stamp, error: %d", errno); + return 0; + } else { + return s.st_mtime; + } +} + +time_t CPlugin::GetTimeStamp() const +{ + return m_LastAccess; +} + +void CPlugin::SetTimeStamp(time_t t) +{ + m_LastAccess = t; +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -681,6 +710,10 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug } } + /* Save the time stamp */ + time_t t = pPlugin->GetFileTimeStamp(); + pPlugin->SetTimeStamp(t); + if (_plugin) { *_plugin = pPlugin; @@ -1522,3 +1555,31 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.DrawGenericOption("info", "Information about a plugin"); g_RootMenu.DrawGenericOption("debug", "Toggle debug mode on a plugin"); } + +void CPluginManager::ReloadOrUnloadPlugins() +{ + List::iterator iter; + List tmp_list = m_plugins; + CPlugin *pl; + time_t t; + + for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++) + { + pl = (*iter); + if (pl->GetType() == PluginType_MapOnly) + { + UnloadPlugin((IPlugin *)pl); + } else if (pl->GetType() == PluginType_MapUpdated) { + t=pl->GetFileTimeStamp(); + if (!t) + { + continue; + } + if (t > pl->GetTimeStamp()) + { + pl->SetTimeStamp(t); + UnloadPlugin((IPlugin *)pl); + } + } + } +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index fa4930eb..721b94ba 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -2,6 +2,8 @@ #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #include +#include +#include #include #include #include @@ -155,7 +157,15 @@ public: */ bool IsRunnable() const; public: - time_t HasUpdatedFile(); + /** + * Returns the modification time during last plugin load. + */ + time_t GetTimeStamp() const; + + /** + * Returns the current modification time of the plugin file. + */ + time_t GetFileTimeStamp(); /** * Returns true if the plugin was running, but is now invalid. @@ -163,6 +173,7 @@ public: bool WasRunning(); protected: void UpdateInfo(); + void SetTimeStamp(time_t t); private: ContextPair m_ctx; PluginType m_type; @@ -272,6 +283,11 @@ public: */ const char *GetStatusText(PluginStatus status); + /** + * Reload or update plugins on level shutdown. + */ + void ReloadOrUnloadPlugins(); + private: bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 6f105f1c..ea5b6958 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -17,7 +17,6 @@ namespace SourceMod typedef unsigned int HandleType_t; typedef unsigned int Handle_t; - class SourcePawn::IPluginContext; /** * About type checking: From 2046bb0e14ba216e90dff6380853304d726bc603 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 20 Jan 2007 02:51:30 +0000 Subject: [PATCH 0309/1664] tiny mistakes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40339 --- core/CTranslator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 1d77ebea..a9a89fe8 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -64,7 +64,7 @@ void CPhraseFile::ParseWarning(const char *message, ...) if (!m_FileLogged) { g_Logger.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); - m_FileLogged; + m_FileLogged = true; } g_Logger.LogError("[SM] %s", message); @@ -685,7 +685,7 @@ SMCParseResult CTranslator::ReadSMC_NewSection(const char *name, bool opt_quotes if (!m_InLanguageSection) { - g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg"); + g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name); } return SMCParse_Continue; @@ -705,7 +705,7 @@ SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, if (len != 2) { g_Logger.LogError("[SM] Warning encountered parsing languages.cfg file."); - g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored."); + g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key); } Language *pLanguage = new Language; From ffd308f42cb4e3d1c5c8ff981d329e842bf95e33 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 24 Jan 2007 21:51:49 +0000 Subject: [PATCH 0310/1664] Initial import of admin system (groups and overrides done) Added a "clear" function for Tries --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40340 --- configs/admins.cfg | 9 +- core/AdminCache.cpp | 568 +++++++++++++++++++++++++++++++++ core/AdminCache.h | 80 +++++ core/msvc8/sourcemod_mm.vcproj | 12 + core/sm_trie.cpp | 22 +- core/sm_trie.h | 1 + public/IAdminSystem.h | 254 +++++++++++++++ public/IExtensionSys.h | 2 +- public/IHandleSys.h | 2 +- 9 files changed, 937 insertions(+), 13 deletions(-) create mode 100644 core/AdminCache.cpp create mode 100644 core/AdminCache.h create mode 100644 public/IAdminSystem.h diff --git a/configs/admins.cfg b/configs/admins.cfg index 4b7fa1b9..856df670 100644 --- a/configs/admins.cfg +++ b/configs/admins.cfg @@ -11,11 +11,14 @@ * "name" - Name based authentication * "ip" - IP based authentication * Anything else is treated as custom. + * Note: Only one auth method is allowed per entry. * * "identity" - REQUIRED - Identification string, for example, a steamid or name. - * "password" - Optional password to use. - * "group" - Inherits a set of group permissions. - * "flags" - Adds a set of flags. + * Note: Only one identity is allowed per entry. + * + * "password" - Optional password to require. + * "group" - Adds one group to the user's group table. + * "flags" - Adds one or more flags to the user's permissions. * * Example: "BAILOPAN" diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp new file mode 100644 index 00000000..82adfafd --- /dev/null +++ b/core/AdminCache.cpp @@ -0,0 +1,568 @@ +#include +#include +#include "AdminCache.h" +#include "ShareSys.h" + +AdminCache g_Admins; + +AdminCache::AdminCache() +{ + m_pCmdOverrides = NULL; + m_pCmdGrpOverrides = NULL; + m_pStrings = new BaseStringTable(1024); + m_pMemory = m_pStrings->GetMemTable(); + m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID; + m_pGroups = sm_trie_create(); +} + +AdminCache::~AdminCache() +{ + if (m_pCmdGrpOverrides) + { + sm_trie_destroy(m_pCmdGrpOverrides); + } + + if (m_pCmdOverrides) + { + sm_trie_destroy(m_pCmdOverrides); + } + + InvalidateGroupCache(); + + if (m_pGroups) + { + sm_trie_destroy(m_pGroups); + } + + delete m_pStrings; +} + +void AdminCache::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, this); +} + +void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag) +{ + if (type == Override_Command) + { + _AddCommandOverride(cmd, flag); + } else if (type == Override_CommandGroup) { + _AddCommandGroupOverride(cmd, flag); + } +} + +bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag) +{ + if (type == Override_Command) + { + return _GetCommandOverride(cmd, pFlag); + } else if (type == Override_CommandGroup) { + return _GetCommandGroupOverride(cmd, pFlag); + } + + return false; +} + +void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type) +{ + if (type == Override_Command) + { + return _UnsetCommandOverride(cmd); + } else if (type == Override_CommandGroup) { + return _UnsetCommandGroupOverride(cmd); + } +} + +void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag) +{ + if (!m_pCmdGrpOverrides) + { + m_pCmdGrpOverrides = sm_trie_create(); + } + + /* :TODO: Notify command system */ + + sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag); +} + +void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag) +{ + if (!m_pCmdOverrides) + { + m_pCmdOverrides = sm_trie_create(); + } + + /* :TODO: Notify command system */ + + sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag); +} + +bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag) +{ + if (!m_pCmdGrpOverrides) + { + return false; + } + + if (!pFlag) + { + return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL); + } else { + void *object; + bool ret; + if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object)) + { + *pFlag = (AdminFlag)(int)object; + } + return ret; + } +} + +bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag) +{ + if (!m_pCmdOverrides) + { + return false; + } + + if (!pFlag) + { + return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL); + } else { + void *object; + bool ret; + if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object)) + { + *pFlag = (AdminFlag)(int)object; + } + return ret; + } +} + +void AdminCache::_UnsetCommandGroupOverride(const char *group) +{ + if (!m_pCmdGrpOverrides) + { + return; + } + + /* :TODO: Notify command system */ + + sm_trie_delete(m_pCmdGrpOverrides, group); +} + +void AdminCache::_UnsetCommandOverride(const char *cmd) +{ + if (!m_pCmdOverrides) + { + return; + } + + /* :TODO: Notify command system */ + + sm_trie_delete(m_pCmdOverrides, cmd); +} + +void AdminCache::DumpCommandOverrideCache(OverrideType type) +{ + if (type == Override_Command && m_pCmdOverrides) + { + sm_trie_clear(m_pCmdOverrides); + } else if (type == Override_CommandGroup && m_pCmdGrpOverrides) { + sm_trie_clear(m_pCmdGrpOverrides); + } +} + +GroupId AdminCache::AddGroup(const char *group_name) +{ + if (sm_trie_retrieve(m_pGroups, group_name, NULL)) + { + return INVALID_GROUP_ID; + } + + GroupId id; + AdminGroup *pGroup; + if (m_FreeGroupList != INVALID_GROUP_ID) + { + pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList); + assert(pGroup->magic == GRP_MAGIC_UNSET); + id = m_FreeGroupList; + m_FreeGroupList = pGroup->next_grp; + } else { + id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup); + } + + pGroup->immune_default = false; + pGroup->immune_global = false; + pGroup->immune_table = -1; + pGroup->magic = GRP_MAGIC_SET; + pGroup->next_grp = INVALID_GROUP_ID; + pGroup->pCmdGrpTable = NULL; + pGroup->pCmdTable = NULL; + pGroup->nameidx = m_pStrings->AddString(group_name); + memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL); + + if (m_FirstGroup == INVALID_GROUP_ID) + { + m_FirstGroup = id; + m_LastGroup = id; + pGroup->prev_grp = INVALID_GROUP_ID; + } else { + AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup); + assert(pPrev->magic == GRP_MAGIC_SET); + pPrev->next_grp = id; + pGroup->prev_grp = m_LastGroup; + m_LastGroup = id; + } + + sm_trie_insert(m_pGroups, group_name, (void *)id); + + return id; +} + +GroupId AdminCache::FindGroupByName(const char *group_name) +{ + void *object; + + if (!sm_trie_retrieve(m_pGroups, group_name, &object)) + { + return INVALID_GROUP_ID; + } + + GroupId id = (GroupId)object; + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return INVALID_GROUP_ID; + } + + return id; +} + +void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return; + } + + if (flag < Admin_None || flag >= AdminFlags_TOTAL) + { + return; + } + + pGroup->addflags[flag] = enabled; +} + +bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return false; + } + + if (flag < Admin_None || flag >= AdminFlags_TOTAL) + { + return false; + } + + return pGroup->addflags[flag]; +} + +unsigned int AdminCache::GetGroupAddFlags(GroupId id, AdminFlag flags[], unsigned int total) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return 0; + } + + unsigned int r = 0; + + for (unsigned int i = Admin_None + 1; + i < AdminFlags_TOTAL && r < total; + i++) + { + if (pGroup->addflags[i]) + { + flags[r++] = (AdminFlag)i; + } + } + + return r; +} + +void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return; + } + + if (type == Immunity_Default) + { + pGroup->immune_default = enabled; + } else if (type == Immunity_Global) { + pGroup->immune_global = enabled; + } +} + +bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return false; + } + + if (type == Immunity_Default) + { + return pGroup->immune_default; + } else if (type == Immunity_Global) { + return pGroup->immune_global; + } + + return false; +} + +void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return; + } + + AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pOther || pOther->magic != GRP_MAGIC_SET) + { + return; + } + + /* We always need to resize the immunity table */ + int *table, tblidx; + if (pOther->immune_table == -1) + { + tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table); + table[0] = 0; + } else { + int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table); + tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table); + /* Get the old address again in caes of resize */ + old_table = (int *)m_pMemory->GetAddress(pOther->immune_table); + table[0] = old_table[0]; + for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++) + { + table[i] = old_table[i]; + } + } + + /* Assign */ + pOther->immune_table = tblidx; + + /* Add to the array */ + table[0]++; + table[table[0]] = other_id; +} + +unsigned int AdminCache::GetGroupImmunityCount(GroupId id) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return 0; + } + + if (pGroup->immune_table == -1) + { + return 0; + } + + int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table); + + return table[0]; +} + +GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return INVALID_GROUP_ID; + } + + if (pGroup->immune_table == -1) + { + return INVALID_GROUP_ID; + } + + int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table); + if (number >= (unsigned int)table[0]) + { + return INVALID_GROUP_ID; + } + + return table[1 + number]; +} + +void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return; + } + + Trie *pTrie = NULL; + if (type == Override_Command) + { + if (pGroup->pCmdTable == NULL) + { + pGroup->pCmdTable = sm_trie_create(); + } + pTrie = pGroup->pCmdTable; + } else if (type == Override_CommandGroup) { + if (pGroup->pCmdGrpTable == NULL) + { + pGroup->pCmdGrpTable = sm_trie_create(); + } + pTrie = pGroup->pCmdGrpTable; + } else { + return; + } + + sm_trie_insert(pTrie, name, (void *)(int)rule); +} + +bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return false; + } + + Trie *pTrie = NULL; + if (type == Override_Command) + { + if (pGroup->pCmdTable == NULL) + { + return false; + } + pTrie = pGroup->pCmdTable; + } else if (type == Override_CommandGroup) { + if (pGroup->pCmdGrpTable == NULL) + { + return false; + } + pTrie = pGroup->pCmdGrpTable; + } else { + return false; + } + + void *object; + if (!sm_trie_retrieve(pTrie, name, &object)) + { + return false; + } + + if (pRule) + { + *pRule = (OverrideRule)(int)object; + } + + return true; +} + +void AdminCache::InvalidateGroup(GroupId id) +{ + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); + AdminGroup *pOther; + + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) + { + return; + } + + const char *str = m_pStrings->GetString(pGroup->nameidx); + sm_trie_delete(m_pGroups, str); + + /* Unlink from the live dbllink list */ + if (id == m_FirstGroup && id == m_LastGroup) + { + m_LastGroup = INVALID_GROUP_ID; + m_FirstGroup = INVALID_GROUP_ID; + } else if (id == m_FirstGroup) { + m_FirstGroup = pGroup->next_grp; + pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup); + pOther->prev_grp = INVALID_GROUP_ID; + } else if (id == m_LastGroup) { + m_LastGroup = pGroup->prev_grp; + pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup); + pOther->next_grp = INVALID_GROUP_ID; + } else { + pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp); + pOther->next_grp = pGroup->next_grp; + pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp); + pOther->prev_grp = pGroup->prev_grp; + } + + /* Free any used memory to be safe */ + if (pGroup->pCmdGrpTable) + { + sm_trie_destroy(pGroup->pCmdGrpTable); + pGroup->pCmdGrpTable = NULL; + } + if (pGroup->pCmdTable) + { + sm_trie_destroy(pGroup->pCmdTable); + pGroup->pCmdTable = NULL; + } + + /* Link into the free list */ + pGroup->magic = GRP_MAGIC_UNSET; + pGroup->next_grp = m_FreeGroupList; + m_FreeGroupList = id; + + /* :TODO: remove this group from any users */ +} + +void AdminCache::InvalidateGroupCache() +{ + /* Nuke the free list */ + m_FreeGroupList = -1; + + /* Nuke reverse lookups */ + sm_trie_clear(m_pGroups); + + /* Free memory on groups */ + GroupId cur = m_FirstGroup; + AdminGroup *pGroup; + while (cur != INVALID_GROUP_ID) + { + pGroup = (AdminGroup *)m_pMemory->GetAddress(cur); + assert(pGroup->magic == GRP_MAGIC_SET); + if (pGroup->pCmdGrpTable) + { + sm_trie_destroy(pGroup->pCmdGrpTable); + } + if (pGroup->pCmdTable) + { + sm_trie_destroy(pGroup->pCmdTable); + } + cur = pGroup->next_grp; + } + + m_FirstGroup = INVALID_GROUP_ID; + m_LastGroup = INVALID_GROUP_ID; + + /* :TODO: dump the admin cache */ + + /* Reset the memory table */ + m_pMemory->Reset(); +} diff --git a/core/AdminCache.h b/core/AdminCache.h new file mode 100644 index 00000000..b551d6e2 --- /dev/null +++ b/core/AdminCache.h @@ -0,0 +1,80 @@ +#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_ +#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_ + +#include "sm_memtable.h" +#include +#include +#include "sm_globals.h" + +#define GRP_MAGIC_SET 0xDEADFADE +#define GRP_MAGIC_UNSET 0xFACEFACE + +struct AdminGroup +{ + uint32_t magic; /* Magic flag, for memory validation (ugh) */ + bool immune_global; /* Global immunity? */ + bool immune_default; /* Default immunity? */ + /* Immune from target table (-1 = nonexistant) + * [0] = number of entries + * [1...N] = immune targets + */ + int immune_table; + Trie *pCmdTable; /* Command override table (can be NULL) */ + Trie *pCmdGrpTable; /* Command group override table (can be NULL) */ + int next_grp; /* Next group in the chain */ + int prev_grp; /* Previous group in the chain */ + int nameidx; /* Name */ + bool addflags[AdminFlags_TOTAL]; /* Additive flags */ +}; + +class AdminCache : + public IAdminSystem, + public SMGlobalClass +{ +public: + AdminCache(); + ~AdminCache(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); +public: //IAdminSystem + /** Command cache stuff */ + void AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag); + bool GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag); + void UnsetCommandOverride(const char *cmd, OverrideType type); + void DumpCommandOverrideCache(OverrideType type); + /** Group cache stuff */ + GroupId AddGroup(const char *group_name); + GroupId FindGroupByName(const char *group_name); + void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled); + bool GetGroupAddFlag(GroupId id, AdminFlag flag); + unsigned int GetGroupAddFlags(GroupId Id, AdminFlag flags[], unsigned int total); + void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled); + bool GetGroupGenericImmunity(GroupId id, ImmunityType type); + void InvalidateGroup(GroupId id); + void InvalidateGroupCache(); + void AddGroupImmunity(GroupId id, GroupId other_id); + unsigned int GetGroupImmunityCount(GroupId id); + GroupId GetGroupImmunity(GroupId id, unsigned int number); + void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule); + bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule); +private: + void _AddCommandOverride(const char *cmd, AdminFlag flag); + void _AddCommandGroupOverride(const char *group, AdminFlag flag); + bool _GetCommandOverride(const char *cmd, AdminFlag *pFlag); + bool _GetCommandGroupOverride(const char *group, AdminFlag *pFlag); + void _UnsetCommandOverride(const char *cmd); + void _UnsetCommandGroupOverride(const char *group); +public: + BaseStringTable *m_pStrings; + BaseMemTable *m_pMemory; + Trie *m_pCmdOverrides; + Trie *m_pCmdGrpOverrides; + int m_FirstGroup; + int m_LastGroup; + int m_FreeGroupList; + Trie *m_pGroups; +}; + +extern AdminCache g_Admins; + +#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a1f60a33..dd3ee7a3 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -179,6 +179,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -257,6 +261,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + @@ -325,6 +333,10 @@ + + diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index c450d079..eaad3485 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -246,19 +246,25 @@ Trie *sm_trie_create() t->stringtab = (char *)malloc(sizeof(char) * 256); t->baseSize = 256; t->stSize = 256; - t->tail = 0; - memset(t->base, 0, sizeof(TrieNode) * (256 + 1)); - memset(t->stringtab, 0, sizeof(char) * 256); - - /* Sentinel root node */ - t->base[1].idx = 1; - t->base[1].mode = Node_Arc; - t->base[1].parent = 1; + sm_trie_clear(t); return t; } +void sm_trie_clear(Trie *trie) +{ + trie->tail = 0; + + memset(trie->base, 0, sizeof(TrieNode) * (trie->baseSize + 1)); + memset(trie->stringtab, 0, sizeof(char) * trie->stSize); + + /* Sentinel root node */ + trie->base[1].idx = 1; + trie->base[1].mode = Node_Arc; + trie->base[1].parent = 1; +} + void sm_trie_destroy(Trie *trie) { free(trie->base); diff --git a/core/sm_trie.h b/core/sm_trie.h index a6e0c0fe..9c008081 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -8,5 +8,6 @@ void sm_trie_destroy(Trie *trie); bool sm_trie_insert(Trie *trie, const char *key, void *value); bool sm_trie_retrieve(Trie *trie, const char *key, void **value); bool sm_trie_delete(Trie *trie, const char *key); +void sm_trie_clear(Trie *trie); #endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h new file mode 100644 index 00000000..b1a43f7e --- /dev/null +++ b/public/IAdminSystem.h @@ -0,0 +1,254 @@ +#ifndef _INCLUDE_SOURCEMOD_ADMINISTRATION_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_ADMINISTRATION_SYSTEM_H_ + +#include + +#define SMINTERFACE_ADMINSYS_NAME "IAdminSys" +#define SMINTERFACE_ADMINSYS_VERSION 1 + +/** + * Detailed notes: + * --------------- + * The administration system is more of a volatile cache than a system. It is designed to be + * temporary rather than permanent, in order to compensate for more storage methods. For example, + * a flat file might be read into the cache all at once. But a MySQL-based system might only cache + * admin permissions when that specific admin connects. + * + * The override cache is the simplest to explain. Any time an override is added, any existing + * and all future commands will gain a new access level set by the override. If unset, the default + * access level is restored. This cache is dynamically changeable. + * + * The group cache contains, for each group: + * 1] A set of inherent flags - fully readable/writable. + * 2] An immunity table - insertion and retrieval only. + * 3] An override table - insertion and retrieval only. + * Individual groups can be invalidated entirely. It should be considered an expensive + * operation, since each admin needs to be patched up to not reference the group. + */ + +namespace SourceMod +{ + enum AdminFlag + { + Admin_None = 0, + Admin_Reservation, /* Reserved slot */ + Admin_Kick, /* Kick another user */ + Admin_Ban, /* Ban another user */ + Admin_Unban, /* Unban another user */ + Admin_Slay, /* Slay/kill/damage another user */ + Admin_Changemap, /* Change the map */ + Admin_Convars, /* Change basic convars */ + Admin_Configs, /* Change configs */ + Admin_Chat, /* Special chat privileges */ + Admin_Vote, /* Special vote privileges */ + Admin_Password, /* Set a server password */ + Admin_RCON, /* Use RCON */ + Admin_Cheats, /* Change sv_cheats and use its commands */ + /* --- */ + AdminFlags_TOTAL, + }; + + enum OverrideType + { + Override_Command = 1, /* Command */ + Override_CommandGroup, /* Command group */ + }; + + enum OverrideRule + { + Command_Deny = 0, + Command_Allow = 1, + }; + + enum ImmunityType + { + Immunity_Default = 1, /* Immune from everyone with no immunity */ + Immunity_Global, /* Immune from everyone (except root admins) */ + }; + + typedef int GroupId; + + #define INVALID_GROUP_ID -1 + + /** + * @brief This is the administration options cache. + */ + class IAdminSystem : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_ADMINSYS_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_ADMINSYS_VERSION; + } + public: + /** + * @brief Adds a global command flag override. Any command registered with this name + * will assume the new flag. This is applied retroactively as well. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param flag New admin flag. + */ + virtual void AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag) =0; + + /** + * @brief Returns a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param pFlag Optional pointer to the set flag. + * @return True if there is an override, false otherwise. + */ + virtual bool GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag) =0; + + /** + * @brief Unsets a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + */ + virtual void UnsetCommandOverride(const char *cmd, OverrideType type) =0; + + /** + * @brief Dumps the global command override cache (unset all). + * + * @param type Override type (specific command or group). + */ + virtual void DumpCommandOverrideCache(OverrideType type) =0; + + /** + * @brief Adds a new group. Name must be unique. + * + * @param group_name String containing the group name. + * @return A new group id, INVALID_GROUP_ID if it already exists. + */ + virtual GroupId AddGroup(const char *group_name) =0; + + /** + * @brief Finds a group by name. + * + * @param group_name String containing the group name. + * @return A group id, or INVALID_GROUP_ID if not found. + */ + virtual GroupId FindGroupByName(const char *group_name) =0; + + /** + * @brief Adds or removes a flag from a group's flag set. + * Note: These are called "add flags" because they add to a user's flags. + * + * @param id Group id. + * @param flag Admin flag to toggle. + * @param enabled True to set the flag, false to unset/disable. + */ + virtual void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled) =0; + + /** + * @brief Gets the set value of an add flag on a group's flag set. + * + * @param id Group id. + * @param flag Admin flag to retrieve. + * @return True if enabled, false otherwise, + */ + virtual bool GetGroupAddFlag(GroupId id, AdminFlag flag) =0; + + /** + * @brief Returns the flag set that is added to a user from their group. + * Note: These are called "add flags" because they add to a user's flags. + * + * @param id GroupId of the group. + * @param flags Array to store flags in. + * @param total Total number of flags that can be stored in the array. + * @return Number of flags that were written to the array. + */ + virtual unsigned int GetGroupAddFlags(GroupId id, AdminFlag flags[], unsigned int total) =0; + + /** + * @brief Toggles a generic immunity type. + * + * @param id Group id. + * @param type Generic immunity type. + * @param enabled True to enable, false otherwise. + */ + virtual void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled) =0; + + /** + * @brief Returns whether or not a group has global immunity. + * + * @param id Group id. + * @param type Generic immunity type. + * @return True if the group has this immunity, false otherwise. + */ + virtual bool GetGroupGenericImmunity(GroupId id, ImmunityType type) =0; + + /** + * @brief Adds immunity to a specific group. + * + * @param id Group id. + * @param other_id Group id to receive immunity to. + */ + virtual void AddGroupImmunity(GroupId id, GroupId other_id) =0; + + /** + * @brief Returns the number of specific group immunities. + * + * @param id Group id. + * @return Number of group immunities. + */ + virtual unsigned int GetGroupImmunityCount(GroupId id) =0; + + /** + * @brief Returns a group that this group is immune to given an index. + * + * @param id Group id. + * @param number Index from 0 to N-1, from GetGroupImmunities(). + * @return GroupId that this group is immune to. + */ + virtual GroupId GetGroupImmunity(GroupId id, unsigned int number) =0; + + /** + * @brief Adds a group-specific override type. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Override allow/deny setting. + */ + virtual void AddGroupCommandOverride(GroupId id, + const char *name, + OverrideType type, + OverrideRule rule) =0; + + /** + * @brief Retrieves a group-specific command override. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Optional pointer to store allow/deny setting. + * @return True if an override exists, false otherwise. + */ + virtual bool GetGroupCommandOverride(GroupId id, + const char *name, + OverrideType type, + OverrideRule *pRule) =0; + + /** + * @brief Invalidates and removes a group from the group cache. + * + * @param id Group id. + */ + virtual void InvalidateGroup(GroupId id) =0; + + /** + * @brief Invalidates the entire group cache. WARNING: This will trigger + * an admin cache dump as well! + */ + virtual void InvalidateGroupCache() =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_ADMINISTRATION_SYSTEM_H_ diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index c96ba405..b5531dd0 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -194,7 +194,7 @@ namespace SourceMod * @brief Loads a extension into the extension system. * * @param path Path to extension file, relative to the extensions folder. - * @param lifetime Lifetime of the extension. + * @param lifetime Lifetime of the extension (currently ignored). * @param error Error buffer. * @param err_max Maximum error buffer length. * @return New IExtension on success, NULL on failure. diff --git a/public/IHandleSys.h b/public/IHandleSys.h index ea5b6958..ba56bb43 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -242,7 +242,7 @@ namespace SourceMod * * @param pTypeAccess Optional TypeAccess buffer to initialize with the default values. * @param pHandleAccess Optional HandleAccess buffer to initialize with the default values. - * @return True on success, false if version is unsupported. + * @return True on success, false if version is unsupported. */ virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; }; From 0b8b26042ed7f7aa984184a7359571338619287f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 24 Jan 2007 23:43:31 +0000 Subject: [PATCH 0311/1664] Added initial admin system natives Added a few API changes to the admin system Exposed more interfaces --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40341 --- core/AdminCache.cpp | 67 +++++++++-- core/AdminCache.h | 16 ++- core/CTextParsers.cpp | 6 + core/CTextParsers.h | 7 +- core/msvc8/sourcemod_mm.vcproj | 4 + core/systems/ExtensionSys.cpp | 1 + core/systems/ForwardSys.cpp | 2 + core/systems/PluginSys.cpp | 2 + core/systems/ShareSys.cpp | 4 +- plugins/include/admin.inc | 214 +++++++++++++++++++++++++++++++++ public/IAdminSystem.h | 54 ++++++--- 11 files changed, 349 insertions(+), 28 deletions(-) create mode 100644 plugins/include/admin.inc diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 82adfafd..f98380d3 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -2,6 +2,7 @@ #include #include "AdminCache.h" #include "ShareSys.h" +#include "ForwardSys.h" AdminCache g_Admins; @@ -13,6 +14,7 @@ AdminCache::AdminCache() m_pMemory = m_pStrings->GetMemTable(); m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID; m_pGroups = sm_trie_create(); + m_pCacheFwd = NULL; } AdminCache::~AdminCache() @@ -39,9 +41,16 @@ AdminCache::~AdminCache() void AdminCache::OnSourceModAllInitialized() { + m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell); g_ShareSys.AddInterface(NULL, this); } +void AdminCache::OnSourceModShutdown() +{ + g_Forwards.ReleaseForward(m_pCacheFwd); + m_pCacheFwd = NULL; +} + void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag) { if (type == Override_Command) @@ -273,7 +282,7 @@ bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag) return pGroup->addflags[flag]; } -unsigned int AdminCache::GetGroupAddFlags(GroupId id, AdminFlag flags[], unsigned int total) +unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total) { AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); if (!pGroup || pGroup->magic != GRP_MAGIC_SET) @@ -281,19 +290,16 @@ unsigned int AdminCache::GetGroupAddFlags(GroupId id, AdminFlag flags[], unsigne return 0; } - unsigned int r = 0; + unsigned int i; - for (unsigned int i = Admin_None + 1; - i < AdminFlags_TOTAL && r < total; + for (i = Admin_None; + i < AdminFlags_TOTAL && i < total; i++) { - if (pGroup->addflags[i]) - { - flags[r++] = (AdminFlag)i; - } + flags[i] = pGroup->addflags[i]; } - return r; + return i; } void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled) @@ -566,3 +572,46 @@ void AdminCache::InvalidateGroupCache() /* Reset the memory table */ m_pMemory->Reset(); } + +void AdminCache::AddAdminListener(IAdminListener *pListener) +{ + m_hooks.push_back(pListener); +} + +void AdminCache::RemoveAdminListener(IAdminListener *pListener) +{ + m_hooks.remove(pListener); +} + +void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) +{ + if (cache_flags & ADMIN_CACHE_OVERRIDES) + { + DumpCommandOverrideCache(Override_Command); + DumpCommandOverrideCache(Override_CommandGroup); + } + + if ((cache_flags & ADMIN_CACHE_ADMINS) || + (cache_flags & ADMIN_CACHE_GROUPS)) + { + /* Make sure the flag is set */ + cache_flags |= ADMIN_CACHE_ADMINS; + /* :TODO: Dump admin cache */ + } + + if (cache_flags & ADMIN_CACHE_GROUPS) + { + InvalidateGroupCache(); + } + + if (rebuild) + { + List::iterator iter; + IAdminListener *pListener; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnRebuildAdminCache(cache_flags); + } + } +} diff --git a/core/AdminCache.h b/core/AdminCache.h index b551d6e2..19382995 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -3,8 +3,12 @@ #include "sm_memtable.h" #include +#include #include #include "sm_globals.h" +#include + +using namespace SourceHook; #define GRP_MAGIC_SET 0xDEADFADE #define GRP_MAGIC_UNSET 0xFACEFACE @@ -36,27 +40,29 @@ public: ~AdminCache(); public: //SMGlobalClass void OnSourceModAllInitialized(); + void OnSourceModShutdown(); public: //IAdminSystem /** Command cache stuff */ void AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag); bool GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag); void UnsetCommandOverride(const char *cmd, OverrideType type); - void DumpCommandOverrideCache(OverrideType type); /** Group cache stuff */ GroupId AddGroup(const char *group_name); GroupId FindGroupByName(const char *group_name); void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled); bool GetGroupAddFlag(GroupId id, AdminFlag flag); - unsigned int GetGroupAddFlags(GroupId Id, AdminFlag flags[], unsigned int total); + unsigned int GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total); void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled); bool GetGroupGenericImmunity(GroupId id, ImmunityType type); void InvalidateGroup(GroupId id); - void InvalidateGroupCache(); void AddGroupImmunity(GroupId id, GroupId other_id); unsigned int GetGroupImmunityCount(GroupId id); GroupId GetGroupImmunity(GroupId id, unsigned int number); void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule); bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule); + void DumpAdminCache(int cache_flags, bool rebuild); + void AddAdminListener(IAdminListener *pListener); + void RemoveAdminListener(IAdminListener *pListener); private: void _AddCommandOverride(const char *cmd, AdminFlag flag); void _AddCommandGroupOverride(const char *group, AdminFlag flag); @@ -64,6 +70,8 @@ private: bool _GetCommandGroupOverride(const char *group, AdminFlag *pFlag); void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); + void InvalidateGroupCache(); + void DumpCommandOverrideCache(OverrideType type); public: BaseStringTable *m_pStrings; BaseMemTable *m_pMemory; @@ -73,6 +81,8 @@ public: int m_LastGroup; int m_FreeGroupList; Trie *m_pGroups; + List m_hooks; + IForward *m_pCacheFwd; }; extern AdminCache g_Admins; diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index c653601e..296be553 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -5,6 +5,7 @@ #include #include #include "CTextParsers.h" +#include "ShareSys.h" CTextParsers g_TextParser; @@ -29,6 +30,11 @@ CTextParsers::CTextParsers() g_ws_chartable[' '] = 1; } +void CTextParsers::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, this); +} + unsigned int CTextParsers::GetUTF8CharBytes(const char *stream) { return _GetUTF8CharBytes(stream); diff --git a/core/CTextParsers.h b/core/CTextParsers.h index 49cadb1c..f1e8c158 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -2,6 +2,7 @@ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #include +#include "sm_globals.h" using namespace SourceMod; @@ -32,10 +33,14 @@ inline unsigned int _GetUTF8CharBytes(const char *stream) */ typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *); -class CTextParsers : public ITextParsers +class CTextParsers : + public ITextParsers, + public SMGlobalClass { public: CTextParsers(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); public: bool ParseFile_INI(const char *file, ITextListener_INI *ini_listener, diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index dd3ee7a3..0855fd4a 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -227,6 +227,10 @@ RelativePath="..\sm_trie.cpp" > + + diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index b95e46e7..b459649a 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -244,6 +244,7 @@ void CExtensionManager::OnSourceModAllInitialized() g_ExtType = g_ShareSys.CreateIdentType("EXTENSION"); g_PluginSys.AddPluginsListener(this); g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this); + g_ShareSys.AddInterface(NULL, this); } void CExtensionManager::OnSourceModShutdown() diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 9465840a..70de62cf 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,6 +1,7 @@ #include #include "ForwardSys.h" #include "PluginSys.h" +#include "ShareSys.h" CForwardManager g_Forwards; @@ -19,6 +20,7 @@ CForwardManager g_Forwards; void CForwardManager::OnSourceModAllInitialized() { g_PluginSys.AddPluginsListener(this); + g_ShareSys.AddInterface(NULL, this); } void CForwardManager::OnSourceModShutdown() diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index cdfff088..c6f99289 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1249,6 +1249,8 @@ void CPluginManager::OnSourceModAllInitialized() g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this); + + g_ShareSys.AddInterface(NULL, this); } void CPluginManager::OnSourceModShutdown() diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index e05a0abf..f72f1f99 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -1,6 +1,7 @@ #include "ShareSys.h" #include "HandleSys.h" #include "ExtensionSys.h" +#include "LibrarySys.h" ShareSystem g_ShareSys; @@ -35,8 +36,9 @@ void ShareSystem::OnSourceModStartup(bool late) /* Initialize our static identity handle */ m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); - /* Add the Handle System... it's too innocent and pure to do it itself */ + /* Add the Handle System and others... they are too innocent and pure to do it themselves */ AddInterface(NULL, &g_HandleSys); + AddInterface(NULL, &g_LibSys); } void ShareSystem::OnSourceModShutdown() diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc new file mode 100644 index 00000000..a0206a31 --- /dev/null +++ b/plugins/include/admin.inc @@ -0,0 +1,214 @@ +#if defined _admin_included + #endinput +#endif +#define _admin_included + +enum AdminFlag +{ + Admin_None = 0, /* Unused */ + Admin_Reservation, /* Reserved slot */ + Admin_Kick, /* Kick another user */ + Admin_Ban, /* Ban another user */ + Admin_Unban, /* Unban another user */ + Admin_Slay, /* Slay/kill/damage another user */ + Admin_Changemap, /* Change the map */ + Admin_Convars, /* Change basic convars */ + Admin_Configs, /* Change configs */ + Admin_Chat, /* Special chat privileges */ + Admin_Vote, /* Special vote privileges */ + Admin_Password, /* Set a server password */ + Admin_RCON, /* Use RCON */ + Admin_Cheats, /* Change sv_cheats and use its commands */ + /* --- */ + AdminFlags_TOTAL, +}; + +enum OverrideType +{ + Override_Command = 1, /* Command */ + Override_CommandGroup, /* Command group */ +}; + +enum OverrideRule +{ + Command_Deny = 0, + Command_Allow = 1, +}; + +enum ImmunityType +{ + Immunity_Default = 1, /* Immune from everyone with no immunity */ + Immunity_Global, /* Immune from everyone (except root admins) */ +}; + +/** Note: Groups are not Handles, nor are they indexes */ +enum GroupId +{ + INVALID_GROUP_ID = -1, +}; + +#define ADMIN_CACHE_OVERRIDES (1<<0) +#define ADMIN_CACHE_ADMINS (1<<1) +#define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) + +/** + * Called when part of the admin cache needs to be rebuilt. + * @note Groups should always be rebuilt before admins. + * + * @param cache_flags Flags for which cache to dump. + */ +forward OnRebuildAdminCache(cache_flags); + +/** + * Tells the admin system to dump a portion of the cache. + * + * @param cache_flags Flags for which cache to dump. Specifying groups also dumps admins. + * @param rebuild If true, the rebuild forwards will fire. + * @noreturn + */ +native DumpAdminCache(cache_flags, bool:rebuild); + +/** + * Adds a global command flag override. Any command registered with this name + * will assume the new flag. This is applied retroactively as well. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param flag New admin flag. + * @noreturn + */ +native AddCommandOverride(const String:cmd[], OverrideType:type, AdminFlag:flag); + +/** + * Returns a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param pFlag By-reference cell to store the flag (undefined if not found). + * @return True if there is an override, false otherwise. + */ +native bool:GetCommandOverride(const String:cmd[], OverrideType:type, &AdminFlag:flag); + +/** + * Unsets a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @noreturn + */ +native UnsetCommandOverride(const String:cmd[], OverrideType:type); + +/** + * Adds a new group. Name must be unique. + * + * @param group_name String containing the group name. + * @return A new group id, INVALID_GROUP_ID if it already exists. + */ +native GroupId:CreateAdmGroup(const String:group_name[]); + +/** + * @brief Finds a group by name. + * + * @param group_name String containing the group name. + * @return A group id, or INVALID_GROUP_ID if not found. + */ +native FindAdmGroup(const String:group_name[]); + +/** + * Adds or removes a flag from a group's flag set. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id Group id. + * @param flag Admin flag to toggle. + * @param enabled True to set the flag, false to unset/disable. + * @noreturn + */ +native SetAdmGroupAddFlag(GroupId:id, AdminFlag:flag, bool:enabled); + +/** + * Gets the set value of an add flag on a group's flag set. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id Group id. + * @param flag Admin flag to retrieve. + * @return True if enabled, false otherwise, + */ +native bool:GetAdmGroupAddFlag(GroupId:id, AdminFlag:flag); + +/** + * Returns the flag set that is added to a user from their group. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id GroupId of the group. + * @param flags Array to store flags in. + * @param total Total number of flags that can be stored in the array (AdminFlags_TOTAL, usually). + * @return Number of flags that were written to the array. + */ +native GetAdmGroupAddFlagBits(GroupId:id, bool flags[], total); + +/** + * Toggles a generic immunity type. + * + * @param id Group id. + * @param type Generic immunity type. + * @param enabled True to enable, false otherwise. + * @noreturn + */ +native SetAdmGroupImmunity(GroupId:id, ImmunityType:type, bool:enabled); + +/** + * Returns whether or not a group has global immunity. + * + * @param id Group id. + * @param type Generic immunity type. + * @return True if the group has this immunity, false otherwise. + */ +native bool:GetAdmGroupImmunity(GroupId:id, ImmunityType:type); + +/** + * Adds immunity to a specific group. + * + * @param id Group id. + * @param other_id Group id to receive immunity to. + * @noreturn + */ +native SetAdmGroupImmuneFrom(GroupId:id, GroupId:other_id); + +/** + * Returns the number of specific group immunities. + * + * @param id Group id. + * @return Number of group immunities. + */ +native GetAdmGroupImmuneCount(GroupId:id); + +/** + * Returns a group that this group is immune to given an index. + * + * @param id Group id. + * @param number Index from 0 to N-1, from GetAdmGroupImmuneCount(). + * @return GroupId that this group is immune to, or INVALID_GROUP_ID on failure. + */ +native GroupId:GetAdmGroupImmuneFrom(GroupId:id, number); + +/** + * Adds a group-specific override type. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Override allow/deny setting. + * @noreturn + */ +native AddAdmGroupCmdOverride(GroupId:id, const String:name[], OverrideType:type, OverrideRule:rule); + +/** + * Retrieves a group-specific command override. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Optional pointer to store allow/deny setting. + * @return True if an override exists, false otherwise. + */ +native bool:GetAdmGroupCmdOverride(GroupId:id, const String:name[], OverrideType:type, &OverrideRule:rule); diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index b1a43f7e..bbf02632 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -62,14 +62,30 @@ namespace SourceMod enum ImmunityType { - Immunity_Default = 1, /* Immune from everyone with no immunity */ + Immunity_Default = 1, /* Immune from everyone with no immunity */ Immunity_Global, /* Immune from everyone (except root admins) */ }; typedef int GroupId; + #define ADMIN_CACHE_OVERRIDES (1<<0) + #define ADMIN_CACHE_ADMINS (1<<1) + #define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) + #define INVALID_GROUP_ID -1 + class IAdminListener + { + public: + /** + * Called when part of the admin cache needs to be rebuilt. + * Groups should always be rebuilt before admins. + * + * @param cache_flags Flags for which cache to dump. + */ + virtual void OnRebuildAdminCache(int cache_flags) =0; + }; + /** * @brief This is the administration options cache. */ @@ -113,13 +129,6 @@ namespace SourceMod */ virtual void UnsetCommandOverride(const char *cmd, OverrideType type) =0; - /** - * @brief Dumps the global command override cache (unset all). - * - * @param type Override type (specific command or group). - */ - virtual void DumpCommandOverrideCache(OverrideType type) =0; - /** * @brief Adds a new group. Name must be unique. * @@ -156,15 +165,15 @@ namespace SourceMod virtual bool GetGroupAddFlag(GroupId id, AdminFlag flag) =0; /** - * @brief Returns the flag set that is added to a user from their group. + * @brief Returns an array of flag bits that are added to a user from their group. * Note: These are called "add flags" because they add to a user's flags. * * @param id GroupId of the group. - * @param flags Array to store flags in. + * @param flags Array to store flags bits in. * @param total Total number of flags that can be stored in the array. * @return Number of flags that were written to the array. */ - virtual unsigned int GetGroupAddFlags(GroupId id, AdminFlag flags[], unsigned int total) =0; + virtual unsigned int GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total) =0; /** * @brief Toggles a generic immunity type. @@ -244,10 +253,27 @@ namespace SourceMod virtual void InvalidateGroup(GroupId id) =0; /** - * @brief Invalidates the entire group cache. WARNING: This will trigger - * an admin cache dump as well! + * @brief Tells the admin system to dump a portion of the cache. + * This calls into plugin forwards to rebuild the cache. + * + * @param cache_flags Flags for which cache to dump. Specifying groups also dumps admins. + * @param rebuild If true, the rebuild forwards/events will fire. */ - virtual void InvalidateGroupCache() =0; + virtual void DumpAdminCache(int cache_flags, bool rebuild) =0; + + /** + * @brief Adds an admin interface listener. + * + * @param pListener Pointer to an IAdminListener to add. + */ + virtual void AddAdminListener(IAdminListener *pListener) =0; + + /** + * @brief Removes an admin interface listener. + * + * @param pListener Pointer to an IAdminListener to remove. + */ + virtual void RemoveAdminListener(IAdminListener *pListener) =0; }; }; From e596003b949a9b55faffe2a0b02056f4eb8e98fd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 00:17:32 +0000 Subject: [PATCH 0312/1664] added admin natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40342 --- core/smn_admin.cpp | 206 ++++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 1 + 2 files changed, 207 insertions(+) create mode 100644 core/smn_admin.cpp diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp new file mode 100644 index 00000000..fc635445 --- /dev/null +++ b/core/smn_admin.cpp @@ -0,0 +1,206 @@ +#include "sm_globals.h" +#include "AdminCache.h" +#include "ForwardSys.h" + +static cell_t DumpAdminCache(IPluginContext *pContext, const cell_t *params) +{ + g_Admins.DumpAdminCache(params[1], (params[2] == 1) ? true : false); + return 1; +} + +static cell_t AddCommandOverride(IPluginContext *pContext, const cell_t *params) +{ + char *str; + + pContext->LocalToString(params[1], &str); + g_Admins.AddCommandOverride(str, (OverrideType)params[2], (AdminFlag)params[3]); + + return 1; +} + +static cell_t GetCommandOverride(IPluginContext *pContext, const cell_t *params) +{ + char *cmd; + AdminFlag flag; + + pContext->LocalToString(params[1], &cmd); + + if (!g_Admins.GetCommandOverride(cmd, (OverrideType)params[2], &flag)) + { + return 0; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[3], &addr); + + *addr = (cell_t)flag; + + return 1; +} + +static cell_t UnsetCommandOverride(IPluginContext *pContext, const cell_t *params) +{ + char *cmd; + + pContext->LocalToString(params[1], &cmd); + + g_Admins.UnsetCommandOverride(cmd, (OverrideType)params[2]); + + return 1; +} + +static cell_t CreateAdmGroup(IPluginContext *pContext, const cell_t *params) +{ + char *str; + + pContext->LocalToString(params[1], &str); + + return g_Admins.AddGroup(str); +} + +static cell_t FindAdmGroup(IPluginContext *pContext, const cell_t *params) +{ + char *str; + + pContext->LocalToString(params[1], &str); + + return g_Admins.FindGroupByName(str); +} + +static cell_t SetAdmGroupAddFlag(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + AdminFlag flag = (AdminFlag)params[2]; + bool enabled = params[3] ? 1 : 0; + + g_Admins.SetGroupAddFlag(id, flag, enabled); + + return 1; +} + +static cell_t GetAdmGroupAddFlag(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + AdminFlag flag = (AdminFlag)params[2]; + + return g_Admins.GetGroupAddFlag(id, flag) ? 1 : 0; +} + +static cell_t SetAdmGroupImmunity(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + ImmunityType type = (ImmunityType)params[2]; + bool enabled = params[3] ? 1 : 0; + + g_Admins.SetGroupGenericImmunity(id, type, enabled); + + return 1; +} + +static cell_t GetAdmGroupImmunity(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + ImmunityType type = (ImmunityType)params[2]; + + return g_Admins.GetGroupGenericImmunity(id, type) ? 1 : 0; +} + +static cell_t SetAdmGroupImmuneFrom(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + GroupId other_id = (GroupId)params[2]; + + g_Admins.AddGroupImmunity(id, other_id); + + return 1; +} + +static cell_t GetAdmGroupImmuneCount(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + + return g_Admins.GetGroupImmunityCount(id); +} + +static cell_t GetAdmGroupImmuneFrom(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + + return g_Admins.GetGroupImmunity(id, params[2]); +} + +static cell_t AddAdmGroupCmdOverride(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + OverrideType type = (OverrideType)params[3]; + OverrideRule rule = (OverrideRule)params[4]; + char *cmd; + + pContext->LocalToString(params[2], &cmd); + + g_Admins.AddGroupCommandOverride(id, cmd, type, rule); + + return 1; +} + +static cell_t GetAdmGroupCmdOverride(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + OverrideType type = (OverrideType)params[3]; + OverrideRule rule; + char *cmd; + + pContext->LocalToString(params[2], &cmd); + + if (!g_Admins.GetGroupCommandOverride(id, cmd, type, &rule)) + { + return 0; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[4], &addr); + *addr = (cell_t)rule; + + return 1; +} + +static cell_t GetAdmGroupAddFlagBits(IPluginContext *pContext, const cell_t *params) +{ + GroupId id = (GroupId)params[1]; + bool flags[AdminFlags_TOTAL]; + unsigned int num = g_Admins.GetGroupAddFlagBits(id, flags, AdminFlags_TOTAL); + unsigned int i; + + cell_t *addr; + pContext->LocalToPhysAddr(params[2], &addr); + + for (i=0; + i < num && i < (unsigned int)params[3]; + i++) + { + addr[i] = flags[i] ? 1 : 0; + } + + return i; +} + +REGISTER_NATIVES(adminNatives) +{ + {"DumpAdminCache", DumpAdminCache}, + {"AddCommandOverride", AddCommandOverride}, + {"GetCommandOverride", GetCommandOverride}, + {"UnsetCommandOverride", UnsetCommandOverride}, + {"CreateAdmGroup", CreateAdmGroup}, + {"FindAdmGroup", FindAdmGroup}, + {"SetAdmGroupAddFlag", SetAdmGroupAddFlag}, + {"GetAdmGroupAddFlag", GetAdmGroupAddFlag}, + {"SetAdmGroupImmunity", SetAdmGroupImmunity}, + {"GetAdmGroupImmunity", GetAdmGroupImmunity}, + {"SetAdmGroupImmuneFrom", SetAdmGroupImmuneFrom}, + {"GetAdmGroupImmuneFrom", GetAdmGroupImmuneFrom}, + {"GetAdmGroupImmuneCount", GetAdmGroupImmuneCount}, + {"AddAdmGroupCmdOverride", AddAdmGroupCmdOverride}, + {"GetAdmGroupCmdOverride", GetAdmGroupCmdOverride}, + {"GetAdmGroupAddFlagBits", GetAdmGroupAddFlagBits}, + {NULL, NULL}, +}; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index b942d78f..78747cb0 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -20,6 +20,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. From 23a2d861401ac03c8aea17316b9c7c51e13d55cc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 01:53:02 +0000 Subject: [PATCH 0313/1664] added new functag keyword for fast funcenums --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40343 --- sourcepawn/compiler/sc.h | 71 ++++++++++++++++++++------------------- sourcepawn/compiler/sc1.c | 36 ++++++++++++++------ sourcepawn/compiler/sc2.c | 2 +- sourcepawn/compiler/sc3.c | 4 +-- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index d89b282f..d314f0f6 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -288,7 +288,7 @@ typedef struct s_stringpair { */ #define tFIRST 256 /* value of first multi-character operator */ #define tMIDDLE 280 /* value of last multi-character operator */ -#define tLAST 332 /* value of last multi-character match-able token */ +#define tLAST 333 /* value of last multi-character match-able token */ /* multi-character operators */ #define taMULT 256 /* *= */ #define taDIV 257 /* /= */ @@ -334,41 +334,42 @@ typedef struct s_stringpair { #define tFOR 296 #define tFORWARD 297 #define tFUNCENUM 298 -#define tGOTO 299 -#define tIF 300 -#define tNATIVE 301 -#define tNEW 302 -#define tDECL 303 -#define tOPERATOR 304 -#define tPUBLIC 305 -#define tRETURN 306 -#define tSIZEOF 307 -#define tSLEEP 308 -#define tSTATE 309 -#define tSTATIC 310 -#define tSTOCK 311 -#define tSTRUCT 312 -#define tSWITCH 313 -#define tTAGOF 314 -#define tTHEN 315 -#define tWHILE 316 +#define tFUNCTAG 299 +#define tGOTO 300 +#define tIF 301 +#define tNATIVE 302 +#define tNEW 303 +#define tDECL 304 +#define tOPERATOR 305 +#define tPUBLIC 306 +#define tRETURN 307 +#define tSIZEOF 308 +#define tSLEEP 309 +#define tSTATE 310 +#define tSTATIC 311 +#define tSTOCK 312 +#define tSTRUCT 313 +#define tSWITCH 314 +#define tTAGOF 315 +#define tTHEN 316 +#define tWHILE 317 /* compiler directives */ -#define tpASSERT 317 /* #assert */ -#define tpDEFINE 318 -#define tpELSE 319 /* #else */ -#define tpELSEIF 320 /* #elseif */ -#define tpEMIT 321 -#define tpENDIF 322 -#define tpENDINPUT 323 -#define tpENDSCRPT 324 -#define tpERROR 325 -#define tpFILE 326 -#define tpIF 327 /* #if */ -#define tINCLUDE 328 -#define tpLINE 329 -#define tpPRAGMA 330 -#define tpTRYINCLUDE 331 -#define tpUNDEF 332 +#define tpASSERT 318 /* #assert */ +#define tpDEFINE 319 +#define tpELSE 320 /* #else */ +#define tpELSEIF 321 /* #elseif */ +#define tpEMIT 322 +#define tpENDIF 323 +#define tpENDINPUT 324 +#define tpENDSCRPT 325 +#define tpERROR 326 +#define tpFILE 327 +#define tpIF 328 /* #if */ +#define tINCLUDE 329 +#define tpLINE 330 +#define tpPRAGMA 331 +#define tpTRYINCLUDE 332 +#define tpUNDEF 333 /* semicolon is a special case, because it can be optional */ #define tTERM 333 /* semicolon or newline */ #define tENDEXPR 334 /* forced end of expression */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 784c6138..b80f3baf 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -133,7 +133,7 @@ static void doswitch(void); static void dogoto(void); static void dolabel(void); static void doreturn(void); -static void dofuncenum(void); +static void dofuncenum(int listmode); static void dobreak(void); static void docont(void); static void dosleep(void); @@ -1418,7 +1418,10 @@ static void parse(void) decl_enum(sGLOBAL); break; case tFUNCENUM: - dofuncenum(); + dofuncenum(TRUE); + break; + case tFUNCTAG: + dofuncenum(FALSE); break; case tSTRUCT: declstruct(); @@ -2970,7 +2973,7 @@ static void declstruct(void) /** * dofuncenum - declare function enumerations */ -static void dofuncenum(void) +static void dofuncenum(int listmode) { cell val; char *str,*ptr; @@ -3005,11 +3008,14 @@ static void dofuncenum(void) fenum = funcenums_add(tagname); - needtoken('{'); + if (listmode) + { + needtoken('{'); + } do { functag_t func; - if (matchtoken('}')) + if (listmode && matchtoken('}')) { /* Quick exit */ lexpush(); @@ -3018,13 +3024,13 @@ static void dofuncenum(void) memset(&func, 0, sizeof(func)); func.ret_tag = pc_addtag(NULL); /* Get the return tag */ l = lex(&val, &str); - if (l == tFORWARD) + if (l == tSTOCK) { - func.type = uFORWARD; + func.type = uSTOCK; } else if (l == tPUBLIC) { func.type = uPUBLIC; } else { - error(1, "-forward,public-", str); + error(1, "-stock,public-", str); } needtoken('('); do @@ -3145,8 +3151,15 @@ static void dofuncenum(void) } } functags_add(fenum, &func); + if (!listmode) + { + break; + } } while (matchtoken(',')); - needtoken('}'); + if (listmode) + { + needtoken('}'); + } matchtoken(';'); /* eat an optional semicolon. nom nom nom */ errorset(sRESET, 0); } @@ -4130,7 +4143,7 @@ static int declargs(symbol *sym,int chkshadow) ident=iVARIABLE; numtags=0; fconst=FALSE; - fpublic= (sym->usage & uPUBLIC)!=0; + fpublic= (sym->usage & (uPUBLIC|uSTOCK))!=0; /* the '(' parantheses has already been parsed */ if (!matchtoken(')')){ do { /* there are arguments; process them */ @@ -4188,7 +4201,8 @@ static int declargs(symbol *sym,int chkshadow) * So the offset of each argument is "(argcnt+3) * sizeof(cell)". */ doarg(name,ident,(argcnt+3)*sizeof(cell),tags,numtags,fpublic,fconst,chkshadow,&arg); - if (fpublic && arg.hasdefault) + /* :TODO: fix this so stocks that are func pointers can't have default arguments? */ + if ((sym->usage & uPUBLIC) && arg.hasdefault) error(59,name); /* arguments of a public function may not have a default value */ if ((sym->usage & uPROTOTYPED)==0) { /* redimension the argument list, add the entry */ diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 77365892..536a3e8a 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1878,7 +1878,7 @@ char *sc_tokens[] = { "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", "assert", "*begin", "break", "case", "cellsof", "chars", "const", "continue", "default", - "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", + "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "functag", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", "sleep", "state", "static", "stock", "struct", "switch", "tagof", "*then", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index f7fde4c9..74a879bc 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -359,7 +359,7 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) { usage = uPUBLIC; } else if (v->name[5] = '!') { - usage = uFORWARD; + usage = uSTOCK; } index = atoi(&v->name[6]); @@ -379,7 +379,7 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) } } } - } else if (usage == uFORWARD) { + } else if (usage == uSTOCK) { for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) { From c656a1343b3387feeab37b03c1de10ca0182a61c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 01:59:37 +0000 Subject: [PATCH 0314/1664] fixed a bug in how functions were retrieved --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40344 --- core/vm/sp_vm_basecontext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 96b6a7fe..ac505533 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -872,6 +872,7 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) if (!pFunc) { m_pub_funcs[func_id] = new CFunction(save, this); + pFunc = m_pub_funcs[func_id]; } } else { func_id >>= 1; @@ -884,6 +885,7 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) if (!pFunc) { m_priv_funcs[func_id] = new CFunction(save, this); + pFunc = m_priv_funcs[func_id]; } } @@ -908,6 +910,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) { m_pub_funcs[index] = new CFunction(pub->funcid, this); } + pFunc = m_pub_funcs[index]; } return pFunc; From ef2bc1aa601eca8c71c44a15157c465496954a99 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 02:10:43 +0000 Subject: [PATCH 0315/1664] changed the two init/unload forwards to have easier names added text parsing natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40345 --- core/msvc8/sourcemod_mm.vcproj | 4 + core/smn_textparse.cpp | 285 +++++++++++++++++++++++++++++++++ core/sourcemod.cpp | 3 + core/systems/PluginSys.cpp | 12 +- 4 files changed, 300 insertions(+), 4 deletions(-) create mode 100644 core/smn_textparse.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0855fd4a..e77b19dd 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -251,6 +251,10 @@ RelativePath="..\smn_string.cpp" > + + diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp new file mode 100644 index 00000000..7f1f1d5f --- /dev/null +++ b/core/smn_textparse.cpp @@ -0,0 +1,285 @@ +#include "sm_globals.h" +#include "CTextParsers.h" +#include "HandleSys.h" + +HandleType_t g_TypeSMC = 0; + +class ParseInfo : public ITextListener_SMC +{ +public: + ParseInfo() + { + parse_start = NULL; + parse_end = NULL; + new_section = NULL; + key_value = NULL; + end_section = NULL; + raw_line = NULL; + handle = 0; + } +public: + void ReadSMC_ParseStart() + { + if (parse_start) + { + cell_t result; + parse_start->PushCell(handle); + parse_start->Execute(&result); + } + } + + void ReadSMC_ParseEnd(bool halted, bool failed) + { + if (parse_end) + { + cell_t result; + parse_start->PushCell(handle); + parse_end->PushCell(halted ? 1 : 0); + parse_end->PushCell(failed ? 1 : 0); + parse_end->Execute(&result); + } + } + + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes) + { + cell_t result = SMCParse_Continue; + + if (new_section) + { + new_section->PushCell(handle); + new_section->PushString(name); + new_section->PushCell(opt_quotes ? 1 : 0); + new_section->Execute(&result); + } + + return (SMCParseResult)result; + } + + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) + { + cell_t result = SMCParse_Continue; + + if (key_value) + { + key_value->PushCell(handle); + key_value->PushString(key); + key_value->PushString(value); + key_value->PushCell(key_quotes ? 1 : 0); + key_value->PushCell(value_quotes ? 1 : 0); + key_value->Execute(&result); + } + + return (SMCParseResult)result; + } + + SMCParseResult ReadSMC_LeavingSection() + { + cell_t result = SMCParse_Continue; + + if (end_section) + { + end_section->PushCell(handle); + end_section->Execute(&result); + } + + return (SMCParseResult)result; + } + + SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline) + { + cell_t result = SMCParse_Continue; + + if (raw_line) + { + raw_line->PushCell(handle); + raw_line->PushString(line); + raw_line->PushCell(curline); + raw_line->Execute(&result); + } + + return (SMCParseResult)result; + } +public: + IPluginFunction *parse_start; + IPluginFunction *parse_end; + IPluginFunction *new_section; + IPluginFunction *key_value; + IPluginFunction *end_section; + IPluginFunction *raw_line; + Handle_t handle; +}; + +class TextParseGlobals : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + HandleAccess sec; + + /* These cannot be cloned, because they are locked to a specific plugin. + * However, we let anyone read them because we don't care. + */ + g_HandleSys.InitAccessDefaults(NULL, &sec); + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY; + sec.access[HandleAccess_Read] = 0; + + g_TypeSMC = g_HandleSys.CreateType("SMCParser", this, 0, NULL, &sec, g_pCoreIdent, NULL); + } + + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_TypeSMC, g_pCoreIdent); + } + + void OnHandleDestroy(HandleType_t type, void *object) + { + ParseInfo *parse = (ParseInfo *)object; + delete parse; + } +}; + +TextParseGlobals g_TextParseGlobals; + +static cell_t SMC_CreateParse(IPluginContext *pContext, const cell_t *params) +{ + ParseInfo *pInfo = new ParseInfo(); + + Handle_t hndl = g_HandleSys.CreateHandle(g_TypeSMC, pInfo, pContext->GetIdentity(), g_pCoreIdent, NULL); + + /* Should never happen */ + if (!hndl) + { + delete pInfo; + return 0; + } + + pInfo->handle = hndl; + + return hndl; +} + +static cell_t SMC_SetParseStart(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + ParseInfo *parse; + + if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err); + } + + parse->parse_start = pContext->GetFunctionById((funcid_t)params[2]); + + return 1; +} + +static cell_t SMC_SetParseEnd(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + ParseInfo *parse; + + if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err); + } + + parse->parse_end = pContext->GetFunctionById((funcid_t)params[2]); + + return 1; +} + +static cell_t SMC_SetReaders(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + ParseInfo *parse; + + if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err); + } + + parse->new_section = pContext->GetFunctionById((funcid_t)params[2]); + parse->key_value = pContext->GetFunctionById((funcid_t)params[3]); + parse->end_section = pContext->GetFunctionById((funcid_t)params[4]); + + return 1; +} + +static cell_t SMC_SetRawLine(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + ParseInfo *parse; + + if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err); + } + + parse->raw_line = pContext->GetFunctionById((funcid_t)params[2]); + + return 1; +} + +static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + ParseInfo *parse; + + if ((err=g_HandleSys.ReadHandle(hndl, g_TypeSMC, NULL, (void **)&parse)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid SMC Parse Handle %x (error %d)", hndl, err); + } + + char *file; + pContext->LocalToString(params[2], &file); + + char path[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file); + + unsigned int line = 0, col = 0; + SMCParseError p_err = g_TextParser.ParseFile_SMC(path, parse, &line, &col); + + cell_t *c_line, *c_col; + pContext->LocalToPhysAddr(params[3], &c_line); + pContext->LocalToPhysAddr(params[4], &c_col); + + return (cell_t)p_err; +} + +static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params) +{ + const char *str = g_TextParser.GetSMCErrorString((SMCParseError)params[1]); + + if (!str) + { + return 0; + } + + pContext->StringToLocal(params[2], params[3], str); + + return 1; +} + +REGISTER_NATIVES(textNatives) +{ + {"SMC_CreateParse", SMC_CreateParse}, + {"SMC_ParseFile", SMC_ParseFile}, + {"SMC_GetErrorString", SMC_GetErrorString}, + {"SMC_SetParseStart", SMC_SetParseStart}, + {"SMC_SetParseEnd", SMC_SetParseEnd}, + {"SMC_SetReaders", SMC_SetReaders}, + {"SMC_SetRawLine", SMC_SetRawLine}, + {NULL, NULL}, +}; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index b87b34eb..4b635679 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -8,6 +8,7 @@ #include "ShareSys.h" #include "CLogger.h" #include "ExtensionSys.h" +#include "AdminCache.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -169,6 +170,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_IsMapLoading = false; + g_Admins.DumpAdminCache(ADMIN_CACHE_GROUPS|ADMIN_CACHE_ADMINS|ADMIN_CACHE_OVERRIDES, true); + RETURN_META_VALUE(MRES_IGNORED, true); } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index c6f99289..2404a20b 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -238,7 +238,7 @@ void CPlugin::Call_OnPluginInit() m_status = Plugin_Running; cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginInit"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart"); if (!pFunction) { return; @@ -256,7 +256,7 @@ void CPlugin::Call_OnPluginUnload() } cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginUnload"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd"); if (!pFunction) { return; @@ -1369,8 +1369,12 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc assert(pl->GetStatus() != Plugin_Created); int len = 0; const sm_plugininfo_t *info = pl->GetPublicInfo(); - - len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus())); + if (pl->GetStatus() != Pl_Running) + { + len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus())); + } else { + len += UTIL_Format(buffer, sizeof(buffer), " %02d", id); + } len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); if (IS_STR_FILLED(info->version)) { From 8d7f5d8c05cf995c68e0078216a5f69ce15598fd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 02:40:14 +0000 Subject: [PATCH 0316/1664] configuration reorg --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40346 --- configs/admins_groups.cfg | 51 --------------------------------------- configs/admins_levels.cfg | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 51 deletions(-) create mode 100644 configs/admins_levels.cfg diff --git a/configs/admins_groups.cfg b/configs/admins_groups.cfg index 2f793528..d4505a72 100644 --- a/configs/admins_groups.cfg +++ b/configs/admins_groups.cfg @@ -1,54 +1,3 @@ -/** - * Use this section to tweak admin permission levels and groupings. - * You can also define admin roles in this section. - */ -Levels -{ - /** - * These are the default role flag mappings. - * You can assign new letters for custom purposes, however you should - * not change the default names, as SourceMod hardcodes these. - */ - Flags - { - "reservation" "a" - "kick" "b" - "ban" "c" - "unban" "d" - "slay" "e" - "changemap" "f" - "cvars" "g" - "configs" "h" - "chat" "i" - "vote" "j" - "password" "h" - "rcon" "i" - - //Custom flags START - //Custom flags END - - //Note - root is a magic access flag that grants all permissions. - "root" "z" - } - - /** - * By default, commands are registered with three pieces of information: - * 1)Command Name (for example, "csdm_enable") - * 2)Command Group Name (for example, "CSDM") - * 3)Command Level (for example, "changemap") - * You can override the default flags assigned to individual commands or command groups in this way. - * To override a group, use the ":" character before the name. Example: - * Examples: - * ":CSDM" "i" // Override the CSDM group - * "csdm_enable" "j" // Override the csdm_enable command - * Note that for overrides, order is important. In the above example, csdm_enable overwrites - * any setting that csdm_enable previously had. - */ - Overrides - { - } -} - Groups { /** diff --git a/configs/admins_levels.cfg b/configs/admins_levels.cfg new file mode 100644 index 00000000..253fcf43 --- /dev/null +++ b/configs/admins_levels.cfg @@ -0,0 +1,50 @@ +/** + * Use this section to tweak admin permission levels and groupings. + * You can also define admin roles in this section. + */ +Levels +{ + /** + * These are the default role flag mappings. + * You can assign new letters for custom purposes, however you should + * not change the default names, as SourceMod hardcodes these. + */ + Flags + { + "reservation" "a" + "kick" "b" + "ban" "c" + "unban" "d" + "slay" "e" + "changemap" "f" + "cvars" "g" + "configs" "h" + "chat" "i" + "vote" "j" + "password" "h" + "rcon" "i" + + //Custom flags START + //Custom flags END + + //Note - root is a magic access flag that grants all permissions. + "root" "z" + } + + /** + * By default, commands are registered with three pieces of information: + * 1)Command Name (for example, "csdm_enable") + * 2)Command Group Name (for example, "CSDM") + * 3)Command Level (for example, "changemap") + * You can override the default flags assigned to individual commands or command groups in this way. + * To override a group, use the ":" character before the name. Example: + * Examples: + * ":CSDM" "i" // Override the CSDM group + * "csdm_enable" "j" // Override the csdm_enable command + * Note that for overrides, order is important. In the above example, csdm_enable overwrites + * any setting that csdm_enable previously had. + */ + Overrides + { + } +} From c31ca9f0796f9056f68c62b026eeb414a3aacb1b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 02:40:47 +0000 Subject: [PATCH 0317/1664] removed plurality --HG-- rename : configs/admins_groups.cfg => configs/admin_groups.cfg rename : configs/admins_levels.cfg => configs/admin_levels.cfg extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40347 --- configs/{admins_groups.cfg => admin_groups.cfg} | 0 configs/{admins_levels.cfg => admin_levels.cfg} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename configs/{admins_groups.cfg => admin_groups.cfg} (100%) rename configs/{admins_levels.cfg => admin_levels.cfg} (100%) diff --git a/configs/admins_groups.cfg b/configs/admin_groups.cfg similarity index 100% rename from configs/admins_groups.cfg rename to configs/admin_groups.cfg diff --git a/configs/admins_levels.cfg b/configs/admin_levels.cfg similarity index 100% rename from configs/admins_levels.cfg rename to configs/admin_levels.cfg From dbf105cc718700bff7e531e749f14af8e98c785b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 04:25:40 +0000 Subject: [PATCH 0318/1664] addressed a very unfortunate issue, the compiler's multipass system is garbage --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40348 --- sourcepawn/compiler/pawncc.c | 3 +++ sourcepawn/compiler/sc1.c | 18 +++++++++++++++--- sourcepawn/compiler/sc3.c | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index f9c790a8..b5dc1bc3 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -39,6 +39,9 @@ jmp_buf brkout; int main(int argc, char *argv[]) { +#if defined _DEBUG + getchar(); +#endif if (pc_compile(argc,argv) == 0) { AMX_HEADER *hdr; diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index b80f3baf..9ecddcb5 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -3024,13 +3024,25 @@ static void dofuncenum(int listmode) memset(&func, 0, sizeof(func)); func.ret_tag = pc_addtag(NULL); /* Get the return tag */ l = lex(&val, &str); - if (l == tSTOCK) + /* :TODO: + * Right now, there is a problem. We can't pass non-public function pointer addresses around, + * because the address isn't known until the final reparse. Unfortunately, you can write code + * before the address is known, because Pawn's compiler isn't truly multipass. + * + * When you call a function, there's no problem, because it does not write the address. + * The assembly looks like this: + * call MyFunction + * Then, only at assembly time (once all passes are done), does it know the address. + * I do not see any solution to this because there is no way I know to inject the function name + * rather than the constant value. And even if we could, we'd have to change the assembler recognize that. + */ + /*if (l == tSTOCK) { func.type = uSTOCK; - } else if (l == tPUBLIC) { + } else */if (l == tPUBLIC) { func.type = uPUBLIC; } else { - error(1, "-stock,public-", str); + error(1, "-public-", str); } needtoken('('); do diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 74a879bc..5a8e0abf 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -2028,6 +2028,7 @@ restart: } lval1->tag=pc_addfunctag(faketag); oldsym->usage |= uREAD; + sym->usage |= uREAD; } else { error(76); /* invalid function call, or syntax error */ } /* if */ From aeb512c444491c8a3c7f5adde8c4967dfc5d17d2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 04:36:48 +0000 Subject: [PATCH 0319/1664] Non-public function addresses are no longer accepted Added a new VM function for pcode addresses (unused right now) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40349 --- core/vm/sp_vm_basecontext.cpp | 7 ++++ public/sourcepawn/sp_vm_api.h | 10 ++++++ sourcepawn/jit/x86/jit_x86.cpp | 43 +++++++++++++++++++++++-- sourcepawn/jit/x86/jit_x86.h | 2 ++ sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 12 ++++--- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index ac505533..8e132a4e 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -150,7 +150,11 @@ int BaseContext::Execute(funcid_t funcid, cell_t *result) } code_addr = pubfunc->code_offs; } else { +#if 0 code_addr = funcid >> 1; +#endif + assert(false); + return SP_ERROR_INVALID_ADDRESS; } PushCell(pushcount++); @@ -875,6 +879,7 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) pFunc = m_pub_funcs[func_id]; } } else { +#if 0 func_id >>= 1; unsigned int index; if (!g_pVM->FunctionLookup(ctx, func_id, &index)) @@ -887,6 +892,8 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) m_priv_funcs[func_id] = new CFunction(save, this); pFunc = m_priv_funcs[func_id]; } +#endif + assert(false); } return pFunc; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 21ff120d..a8232f6e 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -794,6 +794,16 @@ namespace SourcePawn * @return String describing CPU specific optimizations. */ virtual const char *GetCPUOptimizations() =0; + + /** + * @brief Given a context and a p-code address, returns the index of the function. + * + * @param ctx Context to search. + * @param code_addr Index into the p-code section. + * @param result Pointer to store result into. + * @return True if code index is valid, false otherwise. + */ + virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; }; }; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 346cacfb..2483aadf 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2161,10 +2161,12 @@ jit_rewind: functracker_t *fnc = new functracker_t; ctx->vm[JITVARS_FUNCINFO] = fnc; + ctx->vm[JITVARS_REBASE] = data->rebase; fnc->code_size = codemem; fnc->num_functions = data->func_idx; /* clean up relocation+compilation memory */ + data->rebase = NULL; AbortCompilation(co); *err = SP_ERROR_NONE; @@ -2194,6 +2196,7 @@ void JITX86::FreeContext(sp_context_t *ctx) delete [] ctx->publics; delete [] ctx->pubvars; delete [] ctx->symbols; + engine->BaseFree(ctx->vm[JITVARS_REBASE]); free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); delete ctx->vm[JITVARS_TRACKER]; delete ctx; @@ -2247,15 +2250,51 @@ unsigned int JITX86::GetAPIVersion() return SOURCEPAWN_VM_API_VERSION; } -bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) +bool JITX86::FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) { - functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + uint8_t *rebase = (uint8_t *)ctx->vm[JITVARS_REBASE]; + /* Is this within the pcode bounds? */ + if (code_addr >= ctx->plugin->pcode_size - sizeof(uint32_t)) + { + return false; + } + + /* Relocate this */ + code_addr = *(jitoffs_t *)(rebase + code_addr); + + /* Check if this is in the relocation bounds */ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; if (code_addr >= fnc->code_size) { return false; } + /* Get the function info and sanity check */ + funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t)); + if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions) + { + return false; + } + + if (result) + { + *result = f->index; + } + + return true; +} + +bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) +{ + /* Check if this is in the relocation bounds */ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + if (code_addr >= fnc->code_size) + { + return false; + } + + /* Get the function info and sanity check */ funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t)); if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions) { diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index fcdcbccf..51de2322 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -14,6 +14,7 @@ using namespace SourcePawn; #define JITVARS_TRACKER 0 //important: don't change this to avoid trouble #define JITVARS_FUNCINFO 1 //important: don't change this aWOAWOGJQG I LIKE HAM +#define JITVARS_REBASE 2 //important: hi, i'm bail typedef struct tracker_s { @@ -80,6 +81,7 @@ public: int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); unsigned int GetAPIVersion(); bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result); + bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result); unsigned int FunctionCount(const sp_context_t *ctx); const char *GetVersionString(); const char *GetCPUOptimizations(); diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index 537fd87b..f697686c 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -247,19 +247,23 @@ > + + From e5067458903c767ad610d8c6f35b07a1396d0c5e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 04:37:23 +0000 Subject: [PATCH 0320/1664] Added more path building stuff Addeed text parsing API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40350 --- core/AdminCache.cpp | 3 + core/msvc8/sourcemod_mm.vcproj | 2 +- core/smn_filesystem.cpp | 13 +++ core/sourcemod.cpp | 3 + core/sourcemod.h | 1 + core/systems/PluginSys.cpp | 2 +- plugins/include/admin.inc | 2 +- plugins/include/files.inc | 55 +++++++---- plugins/include/sourcemod.inc | 5 +- plugins/include/textparse.inc | 165 +++++++++++++++++++++++++++++++++ public/ISourceMod.h | 1 + 11 files changed, 228 insertions(+), 24 deletions(-) create mode 100644 plugins/include/textparse.inc diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index f98380d3..e1a15d4b 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -608,10 +608,13 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) { List::iterator iter; IAdminListener *pListener; + cell_t result; for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) { pListener = (*iter); pListener->OnRebuildAdminCache(cache_flags); } + m_pCacheFwd->PushCell(cache_flags); + m_pCacheFwd->Execute(&result); } } diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index e77b19dd..a6bfccfa 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -228,7 +228,7 @@ > LocalToString(params[2], &buffer); + pContext->LocalToString(params[4], &fmt); + + atcprintf(path, sizeof(path), fmt, pContext, params, &arg); + + return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path); +} + static FileNatives s_FileNatives; REGISTER_NATIVES(filesystem) @@ -446,5 +458,6 @@ REGISTER_NATIVES(filesystem) {"FileSize", sm_FileSize}, {"RemoveDir", sm_RemoveDir}, {"WriteFileLine", sm_WriteFileLine}, + {"BuildPath", sm_BuildPath}, {NULL, NULL}, }; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 4b635679..99dc5e26 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -48,6 +48,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) { g_BaseDir.assign(g_SMAPI->GetBaseDir()); g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); + g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod"); /* Attempt to load the JIT! */ char file[PLATFORM_MAX_PATH]; @@ -229,6 +230,8 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c base = GetModPath(); } else if (type == Path_SM) { base = GetSourceModPath(); + } else if (type == Path_SM_Rel) { + base = m_SMRelDir; } if (base) diff --git a/core/sourcemod.h b/core/sourcemod.h index b2c9c5d0..8b61c83b 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -56,6 +56,7 @@ private: void DoGlobalPluginLoads(); private: char m_SMBaseDir[PLATFORM_MAX_PATH+1]; + char m_SMRelDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; bool m_ExecPluginReload; }; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2404a20b..f0bc50e9 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1487,7 +1487,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.ConsolePrint(" Description: %s", info->description); } g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no"); - g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "yes" : "no"); + g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "no" : "yes"); } else { g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg); g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")", diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index a0206a31..99a8d04a 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -144,7 +144,7 @@ native bool:GetAdmGroupAddFlag(GroupId:id, AdminFlag:flag); * @param total Total number of flags that can be stored in the array (AdminFlags_TOTAL, usually). * @return Number of flags that were written to the array. */ -native GetAdmGroupAddFlagBits(GroupId:id, bool flags[], total); +native GetAdmGroupAddFlagBits(GroupId:id, bool:flags[], total); /** * Toggles a generic immunity type. diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 18052e96..7871acfd 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -22,13 +22,30 @@ enum FileType #define SEEK_CUR 1 #define SEEK_END 2 +enum PathType +{ + Path_SM, /* SourceMod root folder */ +}; + +/** + * @brief Builds a path relative to the SourceMod folder. + * + * @param type Type of path to build as the base. + * @param buffer Buffer to store the path. + * @param maxlength Maximum length of buffer. + * @param fmt Format string. + * @param ... Format arguments. + * @return Number of bytes written to buffer (not including null terminator). + */ +native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], ...); + /** * @brief Opens a directory/folder for contents enumeration. * @note Directories are closed with CloseHandle(). * @note Directories Handles can be cloned. * * @param path Path to open. - * @return A Handle to the directory, INVALID_HANDLE on open error. + * @return A Handle to the directory, INVALID_HANDLE on open error. */ native Handle:OpenDirectory(const String:path[]); @@ -41,7 +58,7 @@ native Handle:OpenDirectory(const String:path[]); * @param buffer String buffer to hold directory name. * @param maxlength Maximum size of string buffer. * @param type Optional variable to store the file type. - * @return True on success, false if there are no more files to read. + * @return True on success, false if there are no more files to read. * @error Invalid or corrupt Handle. */ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=FileType_Unknown); @@ -51,8 +68,8 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type= * @note Files are closed with CloseHandle(). * @note File Handles can be cloned. * - * @param file File to open. - * @param mode Open mode. + * @param file File to open. + * @param mode Open mode. * @return A Handle to the file, INVALID_HANDLE on open error. */ native Handle:OpenFile(const String:file[], const String:mode[]); @@ -60,7 +77,7 @@ native Handle:OpenFile(const String:file[], const String:mode[]); /** * @brief Deletes a file. * - * @param path Path of the file to delete. + * @param path Path of the file to delete. * @return True on success, false otherwise. */ native bool:DeleteFile(const String:path[]); @@ -71,14 +88,14 @@ native bool:DeleteFile(const String:path[]); * @param hndl Handle to the file. * @param buffer String buffer to hold the line. * @param maxlength Maximum size of string buffer. - * @return True on success, false otherwise. + * @return True on success, false otherwise. */ native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength); /** * @brief Tests if the end of file has been reached. * - * @param file Handle to the file. + * @param file Handle to the file. * @return True if end of file has been reached, false otherwise. */ native bool:IsEndOfFile(Handle:file); @@ -86,9 +103,9 @@ native bool:IsEndOfFile(Handle:file); /** * @brief Sets the file position indicator. * - * @param file Handle to the file. - * @param position Position relative to what is specified in whence. - * @param whence Look at the SEEK_* definitions. + * @param file Handle to the file. + * @param position Position relative to what is specified in whence. + * @param whence Look at the SEEK_* definitions. * @return True on success, false otherwise. */ native bool:FileSeek(Handle:file, position, whence); @@ -96,7 +113,7 @@ native bool:FileSeek(Handle:file, position, whence); /** * @brief Get current position in the file. * - * @param file Handle to the file. + * @param file Handle to the file. * @return Value for the file position indicator. */ native FilePosition(Handle:file); @@ -104,7 +121,7 @@ native FilePosition(Handle:file); /** * @brief Checks if a file exists. * - * @param path Path to the file. + * @param path Path to the file. * @return True if the file exists, false otherwise. */ native bool:FileExists(const String:path[]); @@ -114,14 +131,14 @@ native bool:FileExists(const String:path[]); * * @param newpath New path to the file. * @param oldpath Path to the existing file. - * @return True on success, false otherwise. + * @return True on success, false otherwise. */ native bool:RenameFile(const String:newpath[], const String:oldpath[]); /** * @brief Checks if a directory exists. * - * @param path Path to the directory. + * @param path Path to the directory. * @return True if the directory exists, false otherwise. */ native bool:DirExists(const String:path[]); @@ -129,7 +146,7 @@ native bool:DirExists(const String:path[]); /** * @brief Get the file size in bytes. * - * @param path Path to the file. + * @param path Path to the file. * @return File size in bytes, -1 if file not found. */ native FileSize(const String:path[]); @@ -138,7 +155,7 @@ native FileSize(const String:path[]); * @brief Removes a directory. * @note On most Operating Systems you cannot remove a directory which has files inside it. * - * @param path Path to the directory. + * @param path Path to the directory. * @return True on success, false otherwise. */ native bool:RemoveDir(const String:path[]); @@ -147,9 +164,9 @@ native bool:RemoveDir(const String:path[]); * @brief Writes a line of text in a file. * @note This native will append the newline character. * - * @param hndl Handle to the file. - * @param format Formatting rules. - * @param ... Variable number of format parameters. + * @param hndl Handle to the file. + * @param format Formatting rules. + * @param ... Variable number of format parameters. * @return True on success, false otherwise. */ native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,_}:...); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 78747cb0..8ee58bd6 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -21,6 +21,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -41,7 +42,7 @@ public Plugin:myinfo; * * @noreturn */ -forward OnPluginInit(Handle:myself); +forward OnPluginStart(Handle:myself); /** * Called before OnPluginInit, in case the plugin wants to check for load failure. @@ -65,7 +66,7 @@ forward bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max); * * @noreturn */ -forward OnPluginUnload(); +forward OnPluginEnd(); /** * Called when the plugin's pause status is changing. diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc new file mode 100644 index 00000000..823f60ef --- /dev/null +++ b/plugins/include/textparse.inc @@ -0,0 +1,165 @@ +#if defined _textparse_included + #endinput +#endif +#define _textparse_included + + +/******************************** + * Everything below describes the SMC Parse, or "SourceMod Configuration" format. + * This parser is entirely event based. You must hook events to receive data. + * The file format itself is nearly identical to Valve's KeyValues format. + ********************************/ + +enum SMCResult +{ + SMCParse_Continue, //continue parsing + SMCParse_Halt, //stop parsing here + SMCParse_HaltFail //stop parsing and return failure +}; + +enum SMCError +{ + SMCError_Okay = 0, //no error + SMCError_StreamOpen, //stream failed to open + SMCError_StreamError, //the stream died... somehow + SMCError_Custom, //a custom handler threw an error + SMCError_InvalidSection1, //a section was declared without quotes, and had extra tokens + SMCError_InvalidSection2, //a section was declared without any header + SMCError_InvalidSection3, //a section ending was declared with too many unknown tokens + SMCError_InvalidSection4, //a section ending has no matching beginning + SMCError_InvalidSection5, //a section beginning has no matching ending + SMCError_InvalidTokens, //there were too many unidentifiable strings on one line + SMCError_TokenOverflow, //the token buffer overflowed + SMCError_InvalidProperty1, //a property was declared outside of any section +}; + +/** + * Creates a new SMC file format parser. This is used to set parse hooks. + * + * @return A new Handle to an SMC Parse structure. + */ +native Handle:SMC_CreateParse(); + +/** + * Parses an SMC file. + * + * @param smc A Handle to an SMC Parse structure. + * @param file A string containing the file path. + * @param line An optional by reference cell to store the last line number read. + * @param col An optional by reference cell to store the last column number read. + * @return An SMCParseError result. + * @error Invalid or corrupt Handle. + */ +native SMCError:SMC_ParseFile(Handle:smc, const String:file[], &line=0, &col=0); + +/** + * Gets an error string for an SMCError code. + * @note SMCError_Okay returns false. + * @note SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false. + * + * @param error The SMCParseError code. + * @param buffer A string buffer for the error (contents undefined on failure). + * @param buf_max The maximum size of the buffer. + * @return True on success, false otherwise. + */ +native bool:SMC_GetErrorString(SMCError:error, String:buffer[], buf_max); + +/** + * Called when parsing is started. + * + * @param smc The SMC Parse Handle. + * @noreturn + */ +functag SMC_ParseStart public(Handle:smc); + +/** + * Sets the SMC_ParseStart function of a parse Handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseStart function. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SMC_SetParseStart(Handle:smc, SMC_ParseStart:func); + +/** + * Called when parsing is halted. + * + * @param smc The SMC Parse Handle. + * @param halted True if abnormally halted, false otherwise. + * @param failed True if parsing failed, false otherwise. + * @noreturn + */ +functag SMC_ParseEnd public(Handle:smc, bool:halted, bool:failed); + +/** + * Sets the SMC_ParseEnd of a parse handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseEnd function. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SMC_SetParseEnd(Handle:smc, SMC_ParseEnd:func); + +/** + * Called when the parser is entering a new section or sub-section. + * @note Enclosing quotes are always stripped. + * + * @param smc The SMC Parse Handle. + * @param name String containing section name. + * @param opt_quotes True if the section name was quote-enclosed in the file. + * @return An SMCResult action to take. + */ +functag SMC_NewSection SMCResult:public(Handle:smc, const String:name[], bool:opt_quotes); + +/** + * Called when the parser finds a new key/value pair. + * @note Enclosing quotes are always stripped. + * + * @param smc The SMC Parse Handle. + * @param key String containing key name. + * @param value String containing value name. + * @param key_quotes Whether or not the key was enclosed in quotes. + * @param value_quotes Whether or not the value was enclosed in quotes. + * @return An SMCResult action to take. + */ +functag SMC_KeyValue SMCResult:public(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes); + +/** + * Called when the parser finds the end of the current section. + * + * @param smc The SMC Parse Handle. + * @return An SMCResult action to take. + */ +functag SMC_EndSection SMCResult:public(Handle:smc); + +/** + * Sets the three main reader functions. + * + * @param smc An SMC parse Handle. + * @param ns An SMC_NewSection function pointer. + * @param kv An SMC_KeyValue function pointer. + * @param es An SMC_EndSection function pointer. + * @noreturn + */ +native SMC_SetReaders(Handle:smc, SMC_NewSection:ns, SMC_KeyValue:kv, SMC_EndSection:es); + +/** + * Called whenever a raw line is read. + * + * @param smc The SMC Parse Handle. + * @param line A string containing the raw line from the file. + * @param lineno The line number it occurs on. + * @return An SMCResult action to take. + */ +functag SMC_RawLine SMCResult:public(Handle:smc, const String:line[], lineno); + +/** + * Sets a raw line reader on an SMC parser Handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_RawLine function. + * @noreturn + */ +native SMC_SetRawLine(Handle:smc, SMC_Rawline:func); diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 444f2317..9161ffbb 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -13,6 +13,7 @@ namespace SourceMod Path_None = 0, Path_Game, Path_SM, + Path_SM_Rel, }; class ISourceMod : public SMInterface From 68ff0eb3282042a5c67edf2eb8ccd2ae3f9ffbff Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 06:18:22 +0000 Subject: [PATCH 0321/1664] fixed this file up a bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40351 --- configs/admin_levels.cfg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configs/admin_levels.cfg b/configs/admin_levels.cfg index 253fcf43..61732b94 100644 --- a/configs/admin_levels.cfg +++ b/configs/admin_levels.cfg @@ -11,18 +11,19 @@ Levels */ Flags { - "reservation" "a" + "reservation" "a" "kick" "b" "ban" "c" "unban" "d" "slay" "e" "changemap" "f" "cvars" "g" - "configs" "h" + "configs" "h" "chat" "i" "vote" "j" - "password" "h" - "rcon" "i" + "password" "k" + "rcon" "l" + "cheats" "m" //Custom flags START //Custom flags END From f9a5920e5b17651a62ffa627ef7bc178b4076589 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 06:19:17 +0000 Subject: [PATCH 0322/1664] added an easier format string Function changed normal log names to be more consistent added logging natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40352 --- core/CLogger.cpp | 14 +++++++---- core/smn_filesystem.cpp | 47 +++++++++++++++++++++++++++++++++++ core/sourcemod.cpp | 12 +++++++++ core/sourcemod.h | 1 + plugins/include/sourcemod.inc | 27 ++++++++++++++++++++ public/ISourceMod.h | 16 ++++++++++++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/core/CLogger.cpp b/core/CLogger.cpp index a420e1c2..3817a419 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -7,6 +7,10 @@ CLogger g_Logger; +/** + * :TODO: This should be creating the log folder if it doesn't exist + */ + void CLogger::OnSourceModStartup(bool late) { //:TODO: read these options from a file, dont hardcode them @@ -34,7 +38,7 @@ void CLogger::_NewMapFile() while (true) { - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i); FILE *fp = fopen(_filename, "r"); if (!fp) { @@ -54,7 +58,7 @@ void CLogger::_NewMapFile() } else { char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); - fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); + fprintf(fp, "L %s: SourceMod log file started (file \"logs_%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); fclose(fp); } } @@ -119,7 +123,7 @@ void CLogger::InitLogger(LoggingMode mode, bool startlogging) } case LoggingMode_Daily: { - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_DailyPrintHdr = true; break; @@ -183,7 +187,7 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_CurDay != curtime->tm_mday) { char _filename[256]; - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_CurDay = curtime->tm_mday; m_DailyPrintHdr = true; @@ -196,7 +200,7 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_DailyPrintHdr) { m_DailyPrintHdr = false; - fprintf(fp, "L %s: SourceMod log file session started (file \"L%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); + fprintf(fp, "L %s: SourceMod log file session started (file \"logs_%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); } fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index d7d7fc88..2777de27 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -3,6 +3,9 @@ #include "HandleSys.h" #include "LibrarySys.h" #include "sm_stringutil.h" +#include "CLogger.h" +#include "PluginSys.h" +#include "sourcemm_api.h" HandleType_t g_FileType; HandleType_t g_DirType; @@ -440,6 +443,47 @@ static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params) return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path); } +static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params) +{ + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + + if (len >= sizeof(buffer)-2) + { + buffer[1022] = '\n'; + buffer[1023] = '\0'; + } else { + buffer[len++] = '\n'; + buffer[len] = '\0'; + } + + engine->LogPrint(buffer); + + return 1; +} + +static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params) +{ + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer); + + return 1; +} + +static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params) +{ + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer); + + return 1; +} + static FileNatives s_FileNatives; REGISTER_NATIVES(filesystem) @@ -459,5 +503,8 @@ REGISTER_NATIVES(filesystem) {"RemoveDir", sm_RemoveDir}, {"WriteFileLine", sm_WriteFileLine}, {"BuildPath", sm_BuildPath}, + {"LogToGame", sm_LogToGame}, + {"LogMessage", sm_LogMessage}, + {"LogError", sm_LogError}, {NULL, NULL}, }; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 99dc5e26..a1adf21f 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -9,6 +9,7 @@ #include "CLogger.h" #include "ExtensionSys.h" #include "AdminCache.h" +#include "sm_stringutil.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -305,6 +306,17 @@ void SourceModBase::LogError(IExtension *pExt, const char *format, ...) } } +size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param) +{ + char *fmt; + + pContext->LocalToString(params[param], &fmt); + + int lparam = ++param; + + return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); +} + const char *SourceModBase::GetSourceModPath() { return m_SMBaseDir; diff --git a/core/sourcemod.h b/core/sourcemod.h index 8b61c83b..dcdf4148 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -49,6 +49,7 @@ public: //ISourceMod size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); void LogMessage(IExtension *pExt, const char *format, ...); void LogError(IExtension *pExt, const char *format, ...); + size_t FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param); private: /** * @brief Loading plugins diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 8ee58bd6..8095db0a 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -226,3 +226,30 @@ native PrintToServer(const String:format[], {Handle,Float,String,_}:...); * @error If the client is not connected an error will be thrown. */ native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a generic message to the HL2 logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogToGame(const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a plugin message to the SourceMod logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogMessage(const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a plugin error message to the SourceMod logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogError(const String:format[], {Handle,Float,String,_}:...); \ No newline at end of file diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 9161ffbb..fe2d2144 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -69,6 +69,22 @@ namespace SourceMod * @param ... Message format parameters. */ virtual void LogError(IExtension *pExt, const char *format, ...) =0; + + /** + * @brief Formats a string from a native. + * + * @param buffer Buffer to store message. + * @param maxlength Maximum length of buffer (inculding null terminator). + * @param pContext Pointer to the plugin's context. + * @param params Parameter array that was passed to the native. + * @param param Parameter index where format string and variable arguments begin. + * @return Number of bytes written, not including the null terminator. + */ + virtual size_t FormatString(char *buffer, + size_t maxlength, + IPluginContext *pContext, + const cell_t *params, + unsigned int param) =0; }; }; From 2129bb6d92168c73e468d6f7abc086c8a91db80b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 06:21:20 +0000 Subject: [PATCH 0323/1664] changed the API - funcid_t is now index only rather than a code address --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40353 --- core/vm/sp_vm_basecontext.cpp | 47 ++++------------------------------- core/vm/sp_vm_basecontext.h | 2 +- core/vm/sp_vm_function.cpp | 10 ++++---- core/vm/sp_vm_function.h | 6 ++--- plugins/include/admin.inc | 1 + public/IAdminSystem.h | 1 + public/sourcepawn/sp_vm_api.h | 5 ++-- 7 files changed, 18 insertions(+), 54 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 8e132a4e..ed6ca5c9 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -128,7 +128,7 @@ IPluginDebugInfo *BaseContext::GetDebugInfo() return this; } -int BaseContext::Execute(funcid_t funcid, cell_t *result) +int BaseContext::Execute(uint32_t code_addr, cell_t *result) { if (!m_Runnable) { @@ -138,25 +138,8 @@ int BaseContext::Execute(funcid_t funcid, cell_t *result) IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; uint32_t pushcount = ctx->pushcount; - uint32_t code_addr; int err; - if (funcid & 1) - { - sp_public_t *pubfunc; - if ((err=GetPublicByIndex((funcid>>1), &pubfunc)) != SP_ERROR_NONE) - { - return err; - } - code_addr = pubfunc->code_offs; - } else { -#if 0 - code_addr = funcid >> 1; -#endif - assert(false); - return SP_ERROR_INVALID_ADDRESS; - } - PushCell(pushcount++); ctx->pushcount = 0; @@ -331,25 +314,6 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) high = ctx->plugin->info.natives_num - 1; -#if 0 - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->natives[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } -#else for (uint32_t i=0; iplugin->info.natives_num; i++) { if (strcmp(ctx->natives[i].name, name) == 0) @@ -361,7 +325,6 @@ int BaseContext::FindNativeByName(const char *name, uint32_t *index) return SP_ERROR_NONE; } } -#endif return SP_ERROR_NOT_FOUND; } @@ -863,7 +826,6 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) { CFunction *pFunc = NULL; - funcid_t save = func_id; if (func_id & 1) { @@ -875,10 +837,11 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) pFunc = m_pub_funcs[func_id]; if (!pFunc) { - m_pub_funcs[func_id] = new CFunction(save, this); + m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); pFunc = m_pub_funcs[func_id]; } } else { + /* :TODO: currently not used */ #if 0 func_id >>= 1; unsigned int index; @@ -892,7 +855,7 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) m_priv_funcs[func_id] = new CFunction(save, this); pFunc = m_priv_funcs[func_id]; } -#endif +#endif 0 assert(false); } @@ -915,7 +878,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) GetPublicByIndex(index, &pub); if (pub) { - m_pub_funcs[index] = new CFunction(pub->funcid, this); + m_pub_funcs[index] = new CFunction(pub->code_offs, this); } pFunc = m_pub_funcs[index]; } diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index d2625686..8f9f1239 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -47,7 +47,7 @@ namespace SourcePawn virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite); virtual int BindNative(const sp_nativeinfo_t *native); virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); - virtual int Execute(funcid_t funcid, cell_t *result); + virtual int Execute(uint32_t code_addr, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); virtual IPluginFunction *GetFunctionByName(const char *public_name); diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 523a85a3..13b419b4 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -5,9 +5,9 @@ * FUNCTION CALLING * ********************/ -void CFunction::Set(funcid_t funcid, IPluginContext *plugin) +void CFunction::Set(uint32_t code_addr, IPluginContext *plugin) { - m_funcid = funcid; + m_codeaddr = code_addr; m_pContext = plugin; m_curparam = 0; m_errorstate = SP_ERROR_NONE; @@ -20,7 +20,7 @@ int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_ m_pContext->PushCell(params[num_params]); } - return m_pContext->Execute(m_funcid, result); + return m_pContext->Execute(m_codeaddr, result); } IPluginContext *CFunction::GetParentContext() @@ -28,8 +28,8 @@ IPluginContext *CFunction::GetParentContext() return m_pContext; } -CFunction::CFunction(funcid_t funcid, IPluginContext *plugin) : - m_funcid(funcid), m_pContext(plugin), m_curparam(0), +CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : + m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), m_errorstate(SP_ERROR_NONE) { } diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index ad688c1c..d94df739 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -19,7 +19,7 @@ class CFunction : public IPluginFunction { friend class SourcePawnEngine; public: - CFunction(funcid_t funcid, IPluginContext *pContext); + CFunction(uint32_t code_addr, IPluginContext *pContext); public: virtual int PushCell(cell_t cell); virtual int PushCellByRef(cell_t *cell, int flags); @@ -34,7 +34,7 @@ public: virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); virtual IPluginContext *GetParentContext(); public: - void Set(funcid_t funcid, IPluginContext *plugin); + void Set(uint32_t code_addr, IPluginContext *plugin); private: int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); inline int SetError(int err) @@ -43,7 +43,7 @@ private: return err; } private: - funcid_t m_funcid; + uint32_t m_codeaddr; IPluginContext *m_pContext; cell_t m_params[SP_MAX_EXEC_PARAMS]; ParamInfo m_info[SP_MAX_EXEC_PARAMS]; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 99a8d04a..df2d83d0 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -19,6 +19,7 @@ enum AdminFlag Admin_Password, /* Set a server password */ Admin_RCON, /* Use RCON */ Admin_Cheats, /* Change sv_cheats and use its commands */ + Admin_Root, /* Root access */ /* --- */ AdminFlags_TOTAL, }; diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index bbf02632..f2c80e8b 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -44,6 +44,7 @@ namespace SourceMod Admin_Password, /* Set a server password */ Admin_RCON, /* Use RCON */ Admin_Cheats, /* Change sv_cheats and use its commands */ + Admin_Root, /* All access by default */ /* --- */ AdminFlags_TOTAL, }; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index a8232f6e..41a7d09b 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -461,12 +461,11 @@ namespace SourcePawn /** * @brief Executes a function ID located in this context. * - * @param funcid Function id to execute. + * @param code_addr Address to execute at. * @param result Pointer to store the return value (required). * @return Error code (if any) from the VM. */ - virtual int Execute(uint32_t funcid, cell_t *result) =0; - + virtual int Execute(uint32_t code_addr, cell_t *result) =0; /** * @brief Throws a error and halts any current execution. From 0f3891a09800642fedfb5d4c80deb359a3b864c8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 06:22:03 +0000 Subject: [PATCH 0324/1664] started first admin plugin! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40354 --- plugins/admin-base.sma | 187 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 plugins/admin-base.sma diff --git a/plugins/admin-base.sma b/plugins/admin-base.sma new file mode 100644 index 00000000..c83d0bfb --- /dev/null +++ b/plugins/admin-base.sma @@ -0,0 +1,187 @@ +#include +#include + +public Plugin:myinfo = +{ + name = "Admin Base", + author = "AlliedModders LLC", + description = "Reads admin files", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +#define LEVEL_STATE_NONE 0 +#define LEVEL_STATE_LEVELS 1 +#define LEVEL_STATE_FLAGS 2 +#define LEVEL_STATE_OVERRIDES 3 + + +/** Parser handles */ +new Handle:g_hLevelParser = INVALID_HANDLE; + +/** Parser states */ +new g_LevelState = LEVEL_STATE_NONE; + +/** Globals for levels */ +new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ +new bool:g_ReadOverrides = false; /* Whether or not to read overrides */ +new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ + + +public OnPluginStart() +{ + g_hLevelParser = SMC_CreateParse(); + SMC_SetReaders(g_hLevelParser, + ReadLevels_NewSection, + ReadLevels_KeyValue, + ReadLevels_EndSection); +} + +LoadDefaultLetters() +{ + g_FlagLetters['a'-'a'] = Admin_Reservation; + g_FlagLetters['b'-'a'] = Admin_Kick; + g_FlagLetters['c'-'a'] = Admin_Ban; + g_FlagLetters['d'-'a'] = Admin_Unban; + g_FlagLetters['e'-'a'] = Admin_Slay; + g_FlagLetters['f'-'a'] = Admin_Changemap; + g_FlagLetters['g'-'a'] = Admin_Convars; + g_FlagLetters['h'-'a'] = Admin_Configs; + g_FlagLetters['i'-'a'] = Admin_Chat; + g_FlagLetters['j'-'a'] = Admin_Vote; + g_FlagLetters['h'-'a'] = Admin_Password; + g_FlagLetters['i'-'a'] = Admin_RCON; + g_FlagLetters['j'-'a'] = Admin_Cheats; + g_FlagLetters['z'-'a'] = Admin_Root; +} + +public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt_quotes) +{ + if (g_LevelState == LEVEL_STATE_NONE) + { + if (StrEqual(name, "Levels")) + { + g_LevelState = LEVEL_STATE_LEVELS; + } else { + /* :TODO: log error */ + } + } else if (g_LevelState == LEVEL_STATE_LEVELS) { + if (StrEqual(name, "Flags")) + { + g_LevelState = LEVEL_STATE_FLAGS; + } else if (StrEqual(name, "Overrides")) { + g_LevelState = LEVEL_STATE_OVERRIDES; + } else { + /* :TODO: log error */ + } + } else { + /* :TODO: Log error */ + } + + return SMCParse_Continue; +} + +public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes) +{ + if (g_LevelState == LEVEL_STATE_FLAGS) + { + new chr = value[0]; + + if (chr < 'a' || chr > 'z') + { + /* :TODO: log error */ + return SMCParse_Continue; + } + + chr -= 'a'; + + new AdminFlag:flag = Admin_None; + + if (StrEqual(key, "reservation")) + { + flag = Admin_Reservation; + } else if (StrEqual(key, "kick")) { + flag = Admin_Kick; + } else if (StrEqual(key, "ban")) { + flag = Admin_Ban; + } else if (StrEqual(key, "unban")) { + flag = Admin_Unban; + } else if (StrEqual(key, "slay")) { + flag = Admin_Slay; + } else if (StrEqual(key, "changemap")) { + flag = Admin_Changemap; + } else if (StrEqual(key, "cvars")) { + flag = Admin_Convars; + } else if (StrEqual(key, "configs")) { + flag = Admin_Configs; + } else if (StrEqual(key, "chat")) { + flag = Admin_Chat; + } else if (StrEqual(key, "vote")) { + flag = Admin_Vote; + } else if (StrEqual(key, "password")) { + flag = Admin_Password; + } else if (StrEqual(key, "rcon")) { + flag = Admin_RCON; + } else if (StrEqual(key, "cheats")) { + flag = Admin_Cheats; + } else if (StrEqual(key, "root")) { + flag = Admin_Root; + } else { + /* :TODO: log error */ + } + + g_FlagLetters[chr] = flag; + + + } else if (g_LevelState == LEVEL_STATE_OVERRIDES) { + if (!g_ReadOverrides) + { + return SMCParse_Continue; + } + } + + return SMCParse_Continue; +} + +public SMCResult:ReadLevels_EndSection(Handle:smc) +{ + if (g_LevelState == LEVEL_STATE_FLAGS) + { + g_LevelState = LEVEL_STATE_LEVELS; + } else if (g_LevelState == LEVEL_STATE_OVERRIDES) { + g_LevelState = LEVEL_STATE_OVERRIDES; + } else if (g_LevelState == LEVEL_STATE_LEVELS) { + g_LevelState = LEVEL_STATE_NONE; + } +} + +public OnRebuildAdminCache(cache_flags) +{ + if (cache_flags & ADMIN_CACHE_OVERRIDES) + { + g_ReadOverrides = true; + } else { + g_ReadOverrides = false; + } + + RefreshLevels(); +} + +RefreshLevels() +{ + new String:path[PLATFORM_MAX_PATH]; + + LoadDefaultLetters(); + + BuildPath(Path_SM, path, sizeof(path), "configs/admin_levels.cfg"); + + /* Set states */ + g_LevelState = LEVEL_STATE_NONE; + g_LoggedFileName = false; + + new SMCError:err = SMC_ParseFile(g_hLevelParser, path); + if (err != SMCError_Okay) + { + /* :TODO: log error */ + } +} From 25ed99ac60b2d75f92321bb2bda0b8ac0c43af76 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 08:31:52 +0000 Subject: [PATCH 0325/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40355 --- sourcepawn/jit/x86/Makefile | 65 +++++++++++++++++++++++++++ sourcepawn/jit/x86/dll_exports.cpp | 28 ++++++++++++ sourcepawn/jit/x86/jit_x86.cpp | 10 ++--- sourcepawn/jit/x86/jit_x86.h | 10 ++--- sourcepawn/jit/x86/opcode_helpers.cpp | 10 ++--- sourcepawn/jit/x86/opcode_helpers.h | 2 +- sourcepawn/jit/x86/opcode_switch.inc | 3 +- 7 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 sourcepawn/jit/x86/Makefile diff --git a/sourcepawn/jit/x86/Makefile b/sourcepawn/jit/x86/Makefile new file mode 100644 index 00000000..13bc56a1 --- /dev/null +++ b/sourcepawn/jit/x86/Makefile @@ -0,0 +1,65 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SRCDS = ~/srcds +SMSDK = ../../.. + +### EDIT BELOW FOR OTHER PROJECTS ### + +OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +DEBUG_FLAGS = -g -ggdb3 +CPP = gcc-4.1 +BINARY = sourcepawn.jit.x86.so + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk + +OBJECTS = dll_exports.cpp jit_x86.cpp opcode_helpers.cpp + +LINK = -static-libgcc + +INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS = $(DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS = $(OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) + +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse -DHAVE_STDINT_H + +ifeq "$(GCC_VERSION)" "4" + CFLAGS += $(GCC4_FLAGS) +endif + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) binary + rm -rf $(BINARY) + ln -sf $(BIN_DIR)/$(BINARY) $(BINARY) + +binary: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index 5df6e0b2..3e7ea3dd 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -1,4 +1,5 @@ #include +#include #include "jit_x86.h" #include "dll_exports.h" @@ -33,3 +34,30 @@ EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum) return &jit; } + +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 2483aadf..00a2276d 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1622,9 +1622,9 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) jitoffs_t call = IA32_Call_Imm32(jit, 0); if (!data->debug) { - IA32_Write_Jump32_Abs(jit, call, NativeCallback); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback); } else { - IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug); } /* check for errors */ @@ -1676,7 +1676,7 @@ inline void WriteOp_Tracker_Push_C(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); + IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker); /* Check for errors */ //cmp eax, 0 @@ -1722,7 +1722,7 @@ inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker); + IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyLowBoundTracker); /* Check for errors */ //cmp eax, 0 @@ -2198,7 +2198,7 @@ void JITX86::FreeContext(sp_context_t *ctx) delete [] ctx->symbols; engine->BaseFree(ctx->vm[JITVARS_REBASE]); free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); - delete ctx->vm[JITVARS_TRACKER]; + delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; delete ctx; } diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 51de2322..a3444a48 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -3,7 +3,7 @@ #include #include -#include "..\jit_helpers.h" +#include "../jit_helpers.h" using namespace SourcePawn; @@ -45,7 +45,11 @@ public: }; public: sp_plugin_t *plugin; /* plugin handle */ + bool debug; /* whether to compile debug mode */ + int inline_level; /* inline optimization level */ jitcode_t rebase; /* relocation map */ + int error_set; /* error code to halt process */ + unsigned int func_idx; /* current function index */ jitoffs_t jit_return; /* point in main call to return to */ jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; @@ -63,10 +67,6 @@ public: jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ - unsigned int func_idx; /* current function index */ - int inline_level; /* inline optimization level */ - int error_set; /* error code to halt process */ - bool debug; /* whether to compile debug mode */ }; class JITX86 : public IVirtualMachine diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index fda9a347..6552b3e2 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -429,9 +429,9 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit) jitoffs_t call = IA32_Call_Imm32(jit, 0); if (!data->debug) { - IA32_Write_Jump32_Abs(jit, call, NativeCallback); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback); } else { - IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug); } /* Test for error */ @@ -656,9 +656,9 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) jitoffs_t call = IA32_Call_Imm32(jit, 0); if (!data->debug) { - IA32_Write_Jump32_Abs(jit, call, NativeCallback); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback); } else { - IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug); } /* Test for error */ @@ -714,7 +714,7 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Push_Reg(jit, REG_EAX); jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); + IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker); /* Check for errors */ //cmp eax, 0 diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index 4ee72424..b19890d7 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -1,7 +1,7 @@ #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ -#include "..\jit_helpers.h" +#include "../jit_helpers.h" /** * This outputs the execution function for a plugin. diff --git a/sourcepawn/jit/x86/opcode_switch.inc b/sourcepawn/jit/x86/opcode_switch.inc index 69a3db23..51b8676b 100644 --- a/sourcepawn/jit/x86/opcode_switch.inc +++ b/sourcepawn/jit/x86/opcode_switch.inc @@ -686,4 +686,5 @@ data->error_set = SP_ERROR_INVALID_INSTRUCTION; break; } - \ No newline at end of file + + From 3e936bbd880e4bfae13068a07184f496a14e1218 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 09:19:38 +0000 Subject: [PATCH 0326/1664] initial import of linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40356 --- core/CDbgReporter.cpp | 3 +- core/CDbgReporter.h | 3 +- core/CLogger.cpp | 12 ++++- core/CTextParsers.cpp | 48 ++++++++--------- core/CTranslator.cpp | 3 +- core/Makefile | 90 +++++++++++++++++++++++++++++++ core/sm_stringutil.cpp | 3 +- core/smn_filesystem.cpp | 12 ++--- core/smn_float.cpp | 3 +- core/smn_player.cpp | 3 +- core/smn_string.cpp | 2 +- core/systems/ExtensionSys.cpp | 2 +- core/systems/ForwardSys.cpp | 10 ++-- core/systems/HandleSys.cpp | 4 +- core/systems/LibrarySys.cpp | 39 +++++++------- core/systems/LibrarySys.h | 4 +- core/systems/PluginInfoDatabase.h | 2 +- core/systems/PluginSys.cpp | 7 ++- core/vm/sp_vm_basecontext.cpp | 6 +-- core/vm/sp_vm_engine.cpp | 6 +-- core/vm/sp_vm_engine.h | 4 +- core/vm/sp_vm_function.cpp | 1 + public/ITextParsers.h | 4 +- public/sm_platform.h | 9 +++- public/sourcepawn/sp_typeutil.h | 3 +- public/sourcepawn/sp_vm_base.h | 3 +- 26 files changed, 203 insertions(+), 83 deletions(-) create mode 100644 core/Makefile diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp index 0a0d1dcf..29d81794 100644 --- a/core/CDbgReporter.cpp +++ b/core/CDbgReporter.cpp @@ -70,4 +70,5 @@ int CDbgReporter::_GetPluginIndex(IPluginContext *ctx) iter->Release(); return -1; -} \ No newline at end of file +} + diff --git a/core/CDbgReporter.h b/core/CDbgReporter.h index 7d296a46..650550e1 100644 --- a/core/CDbgReporter.h +++ b/core/CDbgReporter.h @@ -16,4 +16,5 @@ private: int _GetPluginIndex(IPluginContext *ctx); }; -#endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ \ No newline at end of file +#endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ + diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 3817a419..65354f49 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -2,7 +2,7 @@ #include "sourcemod.h" #include "sourcemm_api.h" #include "CLogger.h" -#include "systems/Librarysys.h" +#include "systems/LibrarySys.h" #include "sm_version.h" CLogger g_Logger; @@ -128,6 +128,11 @@ void CLogger::InitLogger(LoggingMode mode, bool startlogging) m_DailyPrintHdr = true; break; } + default: + { + /* do nothing... */ + break; + } } } @@ -280,6 +285,11 @@ void CLogger::MapChange(const char *mapname) _NewMapFile(); break; } + default: + { + /* Do nothing... */ + break; + } } if (m_ErrMapStart) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 296be553..48f630b6 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -14,20 +14,20 @@ static int g_ws_chartable[255] = {0}; CTextParsers::CTextParsers() { - g_ini_chartable1['_'] = 1; - g_ini_chartable1['-'] = 1; - g_ini_chartable1[','] = 1; - g_ini_chartable1['+'] = 1; - g_ini_chartable1['.'] = 1; - g_ini_chartable1['$'] = 1; - g_ini_chartable1['?'] = 1; - g_ini_chartable1['/'] = 1; - g_ws_chartable['\n'] = 1; - g_ws_chartable['\v'] = 1; - g_ws_chartable['\r'] = 1; - g_ws_chartable['\t'] = 1; - g_ws_chartable['\f'] = 1; - g_ws_chartable[' '] = 1; + g_ini_chartable1[(unsigned)'_'] = 1; + g_ini_chartable1[(unsigned)'-'] = 1; + g_ini_chartable1[(unsigned)','] = 1; + g_ini_chartable1[(unsigned)'+'] = 1; + g_ini_chartable1[(unsigned)'.'] = 1; + g_ini_chartable1[(unsigned)'$'] = 1; + g_ini_chartable1[(unsigned)'?'] = 1; + g_ini_chartable1[(unsigned)'/'] = 1; + g_ws_chartable[(unsigned)'\n'] = 1; + g_ws_chartable[(unsigned)'\v'] = 1; + g_ws_chartable[(unsigned)'\r'] = 1; + g_ws_chartable[(unsigned)'\t'] = 1; + g_ws_chartable[(unsigned)'\f'] = 1; + g_ws_chartable[(unsigned)' '] = 1; } void CTextParsers::OnSourceModAllInitialized() @@ -121,10 +121,10 @@ SMCParseError CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *s struct StringInfo { StringInfo() : quoted(false), ptr(NULL), end(NULL), special(false) { } + bool quoted; char *ptr; char *end; bool special; - bool quoted; }; const char *FixupString(StringInfo &data) @@ -366,13 +366,13 @@ SMCParseError CTextParsers::ParseStream_SMC(void *stream, } } else { /* Check if we're whitespace or not */ - if (!g_ws_chartable[c]) + if (!g_ws_chartable[(unsigned)c]) { bool restage = false; /* Check various special tokens: * ; * // - * /* + * / * * { * } */ @@ -402,7 +402,7 @@ SMCParseError CTextParsers::ParseStream_SMC(void *stream, ignoring = true; ml_comment = true; /* yes, we restage, meaning that: - * STR/*stuff* /ING (space because ml comments don't nest in C++) + * STR/ *stuff* /ING (space because ml comments don't nest in C++) * will not generate 'STRING', but rather 'STR' and 'ING'. * This should be a rare occurrence and is done here for convenience. */ @@ -656,7 +656,7 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen ***************************************************/ /* First strip beginning whitespace */ - while (*ptr != '\0' && g_ws_chartable[*ptr] != 0) + while (*ptr != '\0' && g_ws_chartable[(unsigned)*ptr] != 0) { ptr++; } @@ -709,7 +709,7 @@ bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listen /* Lastly, strip ending whitespace off */ for (size_t i=len-1; i>=0 && i #include +#include #include "CTranslator.h" #include "CLogger.h" #include "CTextParsers.h" @@ -336,7 +337,7 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value, *out_ptr++ = '%'; } /* Check length ... */ - if (out_ptr - fmt_buf >= sizeof(fmt_buf) - 1) + if ((unsigned)(out_ptr - fmt_buf) >= sizeof(fmt_buf) - 1) { ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.", m_CurLine); diff --git a/core/Makefile b/core/Makefile new file mode 100644 index 00000000..9c9c6b6e --- /dev/null +++ b/core/Makefile @@ -0,0 +1,90 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMM_BASE = ../../../sourcemm +SMM_TRUNK = $(SMM_BASE)/trunk +HL2SDK = $(SMM_BASE)/hl2sdk +SMSDK = .. +SRCDS = ~/srcds + +### EDIT BELOW FOR OTHER PROJECTS ### + +OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +DEBUG_FLAGS = -g -ggdb3 +CPP = gcc-4.1 +BINARY = sourcemod_mm.so + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk + +OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CDbgReporter.cpp CLogger.cpp \ + CPlayer.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ + sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ + sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ + smn_player.cpp smn_string.cpp smn_textparse.cpp \ + systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ + systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ + systems/PluginSys.cpp systems/ShareSys.cpp vm/sp_vm_basecontext.cpp \ + vm/sp_vm_engine.cpp vm/sp_vm_function.cpp +OBJECTS += zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \ + zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \ + zlib/uncompr.c zlib/zutil.c + +LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + -Isystems + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS = $(DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS = $(OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) + +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(GCC4_FLAGS) +endif + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/systems + mkdir -p $(BIN_DIR)/vm + mkdir -p $(BIN_DIR)/zlib + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) sourcemod + rm -rf $(BINARY) + ln -sf $(BIN_DIR)/$(BINARY) $(BINARY) + +sourcemod: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index c6798224..32e0fcfa 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -644,4 +644,5 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) va_end(ap); return (len >= maxlength) ? (maxlength - 1) : len; -} \ No newline at end of file +} + diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 2777de27..0eaa876c 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -268,7 +268,7 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) return 1; } return 0; -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { @@ -304,7 +304,7 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) #ifdef PLATFORM_WINDOWS return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX return (rename(old_realpath, new_realpath)) ? 0 : 1; #endif } @@ -332,7 +332,7 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) return 1; } return 0; -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { @@ -369,7 +369,7 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) return static_cast(s.st_size); } return -1; -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX struct stat s; if (stat(realpath, &s) != 0) { @@ -465,7 +465,7 @@ static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params) static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params) { char buffer[1024]; - size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer); @@ -476,7 +476,7 @@ static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params) static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params) { char buffer[1024]; - size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer); diff --git a/core/smn_float.cpp b/core/smn_float.cpp index baadc443..806349ff 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "sm_autonatives.h" #include "sp_vm_api.h" #include "sp_typeutil.h" @@ -255,4 +256,4 @@ REGISTER_NATIVES(floatnatives) {"ArcSine", sm_ArcSine}, {"ArcTangent2", sm_ArcTangent2}, {NULL, NULL} -}; \ No newline at end of file +}; diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 62f22cae..52a974e5 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -199,4 +199,5 @@ REGISTER_NATIVES(playernatives) {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, {NULL, NULL} -}; \ No newline at end of file +}; + diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 2fbfca82..eaa874ae 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -10,7 +10,7 @@ inline const char *_strstr(const char *str, const char *substr) { #ifdef PLATFORM_WINDOWS return strstr(str, substr); -#elif PLATFORM_LINUX +#elif defined PLATFORM_LINUX return (const char *)strstr(str, substr); #endif } diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index b459649a..ed97c5de 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -707,7 +707,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco if (argcount > 4 && pExt->unload_code) { const char *unload = g_RootMenu.GetArgument(4); - if (pExt->unload_code == atoi(unload)) + if (pExt->unload_code == (unsigned)atoi(unload)) { char filename[PLATFORM_MAX_PATH+1]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 70de62cf..124ac058 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "ForwardSys.h" #include "PluginSys.h" #include "ShareSys.h" @@ -179,7 +181,7 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu { for (unsigned int i=0; i +#include HandleSystem g_HandleSys; @@ -408,7 +409,6 @@ HandleError HandleSystem::GetHandle(Handle_t handle, } QHandle *pHandle = &m_Handles[index]; - QHandleType *pType = &m_Types[pHandle->type]; if (!pHandle->set || (pHandle->set == HandleSet_Freed && !ignoreFree)) @@ -694,7 +694,7 @@ void HandleSystem::ReleasePrimHandle(unsigned int index) if (set == HandleSet_Identity) { /* Extra work to do. We need to find everything connected to this identity and release it. */ - unsigned int ch_index, old_index = 0; + unsigned int ch_index; while ((ch_index = pHandle->ch_next) != 0) { pLocal = &m_Handles[ch_index]; diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index e43449c6..fa1df0dc 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include "LibrarySys.h" LibrarySystem g_LibSys; @@ -9,7 +12,7 @@ CLibrary::~CLibrary() { #if defined PLATFORM_WINDOWS FreeLibrary(m_lib); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX dlclose(m_lib); #endif m_lib = NULL; @@ -30,7 +33,7 @@ void *CLibrary::GetSymbolAddress(const char *symname) { #if defined PLATFORM_WINDOWS return GetProcAddress(m_lib, symname); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX return dlsym(m_lib, symname); #endif } @@ -51,12 +54,12 @@ CDirectory::CDirectory(const char *path) { m_fd.cFileName[0] = '\0'; } -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX m_dir = opendir(path); if (IsValid()) { /* :TODO: we need to read past "." and ".."! */ - ep = readdir(dp); + ep = readdir(m_dir); snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path); } else { ep = NULL; @@ -70,7 +73,7 @@ CDirectory::~CDirectory() { #if defined PLATFORM_WINDOWS FindClose(m_dir); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX closedir(m_dir); #endif } @@ -84,8 +87,8 @@ void CDirectory::NextEntry() FindClose(m_dir); m_dir = INVALID_HANDLE_VALUE; } -#else if defined PLATFORM_POSIX - if ((ep=readdir(m_dir) == NULL) +#elif defined PLATFORM_POSIX + if ((ep=readdir(m_dir)) == NULL) { closedir(m_dir); m_dir = NULL; @@ -102,10 +105,10 @@ bool CDirectory::IsEntryDirectory() { #if defined PLATFORM_WINDOWS return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_LINUX char temppath[PLATFORM_MAX_PATH]; snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); - return g_LibrarySys.IsPathDirectory(temppath); + return g_LibSys.IsPathDirectory(temppath); #endif } @@ -113,10 +116,10 @@ bool CDirectory::IsEntryFile() { #if defined PLATFORM_WINDOWS return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX char temppath[PLATFORM_MAX_PATH]; snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); - return g_LibrarySys.IsPathFile(temppath); + return g_LibSys.IsPathFile(temppath); #endif } @@ -124,7 +127,7 @@ const char *CDirectory::GetEntryName() { #if defined PLATFORM_WINDOWS return m_fd.cFileName; -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_LINUX return ep ? ep->d_name : ""; #endif } @@ -138,7 +141,7 @@ bool CDirectory::IsValid() { #if defined PLATFORM_WINDOWS return (m_dir != INVALID_HANDLE_VALUE); -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_LINUX return (m_dir != NULL); #endif } @@ -155,7 +158,7 @@ bool LibrarySystem::PathExists(const char *path) DWORD attr = GetFileAttributesA(path); return (attr != INVALID_FILE_ATTRIBUTES); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX struct stat s; return (stat(path, &s) == 0); @@ -178,7 +181,7 @@ bool LibrarySystem::IsPathFile(const char *path) } return true; -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_LINUX struct stat s; if (stat(path, &s) != 0) @@ -205,7 +208,7 @@ bool LibrarySystem::IsPathDirectory(const char *path) return true; } -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_LINUX struct stat s; if (stat(path, &s) != 0) @@ -249,7 +252,7 @@ void LibrarySystem::GetPlatformError(char *error, size_t err_max) (LPSTR)error, err_max, NULL); -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX snprintf(error, err_max, "%s", strerror(errno)); #endif } @@ -270,7 +273,7 @@ ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_m GetPlatformError(error, err_max); return false; } -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX lib = dlopen(path, RTLD_NOW); if (!lib) { diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index 352a6b9b..bea6b4df 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -8,7 +8,7 @@ using namespace SourceMod; #if defined PLATFORM_WINDOWS typedef HMODULE LibraryHandle; -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX typedef void * LibraryHandle; #endif @@ -30,7 +30,7 @@ private: #if defined PLATFORM_WINDOWS HANDLE m_dir; WIN32_FIND_DATAA m_fd; -#else if defined PLATFORM_LINUX +#elif defined PLATFORM_POSIX DIR *m_dir; struct dirent *ep; char m_origpath[PLATFORM_MAX_PATH]; diff --git a/core/systems/PluginInfoDatabase.h b/core/systems/PluginInfoDatabase.h index 572bb7b7..9c088e69 100644 --- a/core/systems/PluginInfoDatabase.h +++ b/core/systems/PluginInfoDatabase.h @@ -64,7 +64,7 @@ private: int m_errmsg; bool in_plugins; bool in_options; - unsigned int m_infodb; + int m_infodb; size_t m_infodb_count; size_t m_infodb_size; int cur_plugin; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index f0bc50e9..40850787 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -456,7 +456,7 @@ time_t CPlugin::GetFileTimeStamp() #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(path, &s) != 0) -#else if defined PLATFORM_POSIX +#elif defined PLATFORM_POSIX struct stat s; if (stat(path, &s) != 0) #endif @@ -1165,7 +1165,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) if (*aliasptr == '*') { /* First, see if this is the last character */ - if (aliasptr - alias == alias_len - 1) + if ((unsigned)(aliasptr - alias) == alias_len - 1) { /* If so, there's no need to match anything else */ return true; @@ -1369,7 +1369,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc assert(pl->GetStatus() != Plugin_Created); int len = 0; const sm_plugininfo_t *info = pl->GetPublicInfo(); - if (pl->GetStatus() != Pl_Running) + if (pl->GetStatus() != Plugin_Running) { len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus())); } else { @@ -1448,7 +1448,6 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc return; } - int id = 1; int num = atoi(g_RootMenu.GetArgument(3)); if (num < 1 || num > (int)GetPluginCount()) { diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index ed6ca5c9..f1c0fae5 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -285,7 +285,7 @@ int BaseContext::HeapPop(cell_t local_addr) addr = (cell_t *)(ctx->memory + local_addr); cellcount = (*addr) * sizeof(cell_t); /* check if this memory count looks valid */ - if (ctx->hp - cellcount - sizeof(cell_t) != local_addr) + if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr) { return SP_ERROR_INVALID_ADDRESS; } @@ -596,8 +596,6 @@ int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t ar int BaseContext::LocalToString(cell_t local_addr, char **addr) { - int len = 0; - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; @@ -855,7 +853,7 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) m_priv_funcs[func_id] = new CFunction(save, this); pFunc = m_priv_funcs[func_id]; } -#endif 0 +#endif assert(false); } diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index e39e0e52..fda2d009 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -10,7 +10,7 @@ #if defined WIN32 #define WIN32_LEAN_AND_MEAN #include -#else if defined __GNUC__ +#elif defined __GNUC__ #include #endif @@ -85,7 +85,7 @@ void *SourcePawnEngine::ExecAlloc(size_t size) { #if defined WIN32 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else if defined __GNUC__ +#elif defined __GNUC__ void *base = memalign(sysconf(_SC_PAGESIZE), size); if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) { @@ -100,7 +100,7 @@ void SourcePawnEngine::ExecFree(void *address) { #if defined WIN32 VirtualFree(address, 0, MEM_RELEASE); -#else if defined __GNUC__ +#elif defined __GNUC__ free(address); #endif } diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index 4ad0f715..f30d0b0e 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -27,10 +27,10 @@ public: virtual void ResetTrace(); virtual const char *GetLastNative(uint32_t *index); private: + int m_Error; + const char *m_pMsg; TracedCall *m_pStart; TracedCall *m_pIterator; - const char *m_pMsg; - int m_Error; uint32_t m_Native; }; diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 13b419b4..ceb78dc4 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -1,4 +1,5 @@ #include +#include #include "PluginSys.h" /******************** diff --git a/public/ITextParsers.h b/public/ITextParsers.h index 8a583a82..cae293a1 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -106,7 +106,7 @@ namespace SourceMod * * The SMC file format is defined as: * WHITESPACE: 0x20, \n, \t, \r - * IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, /*, or WHITESPACE. + * IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, / *, or WHITESPACE. * STRING: Any set of symbols enclosed in quotes. * Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER. * @@ -138,7 +138,7 @@ namespace SourceMod * unless they are inside literal strings: * ; * // - * /* */ + * / * */ enum SMCParseResult { diff --git a/public/sm_platform.h b/public/sm_platform.h index 05171cd8..8f672d37 100644 --- a/public/sm_platform.h +++ b/public/sm_platform.h @@ -24,11 +24,14 @@ #define PLATFORM_SEP_CHAR '\\' #define PLATFORM_SEP_ALTCHAR '/' #define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) -#else if defined __linux__ +#elif defined __linux__ #define PLATFORM_LINUX #define PLATFORM_POSIX +#include #include #include +#include +#include #define PLATFORM_MAX_PATH PATH_MAX #define PLATFORM_LIB_EXT "so" #define PLATFORM_SEP_CHAR '/' @@ -36,4 +39,8 @@ #define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) #endif +#if !defined SOURCEMOD_BUILD +#define SOURCEMOD_BUILD +#endif + #endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h index 921f9f74..f5146bb2 100644 --- a/public/sourcepawn/sp_typeutil.h +++ b/public/sourcepawn/sp_typeutil.h @@ -12,4 +12,5 @@ inline float sp_ctof(cell_t val) return *(float *)&val; } -#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ \ No newline at end of file +#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ + diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index 4fff0f4c..5d295d62 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -7,10 +7,11 @@ #if defined WIN32 #define EXPORT_LINK extern "C" __declspec(dllexport) -#else if defined __GNUC__ +#elif defined __GNUC__ #define EXPORT_LINK extern "C" __attribute__((visibility("default"))) #endif typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); #endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ + From 1b0475abb0168a6a344fd02c4e9cec05ac9e6d0d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 10:07:35 +0000 Subject: [PATCH 0327/1664] time to get rid of this little guy, you served us well --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40357 --- plugins/test.sma | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 plugins/test.sma diff --git a/plugins/test.sma b/plugins/test.sma deleted file mode 100644 index 30f93206..00000000 --- a/plugins/test.sma +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -public Plugin:myinfo = -{ - name = "Test Plugin", - author = "BAILOPAN", - description = "Tests Stuff", - version = "1.0.0.0", - url = "http://www.sourcemod.net/" -}; - -native PrintStuff(const String:buffer[]); - -DoItAll() -{ - new String:buffer[PLATFORM_MAX_PATH]; - new FileType:type; - - new Handle:dir = OpenDirectory("addons/stripper"); - while (ReadDirEntry(dir, buffer, sizeof(buffer), type)) - { - decl String:stuff[1024]; - Format(stuff, sizeof(stuff), "Type: %d Dir: %s", _:type, buffer) - PrintStuff(stuff); - } - new Handle:copy = CloneHandle(dir); - CloseHandle(copy); - CloseHandle(dir); -} - -public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) -{ - DoItAll(); - - return true; -} From a20cfbeb28ca5a781ce240a0982cbd323ca235b9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:08:00 +0000 Subject: [PATCH 0328/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40358 --- sourcepawn/compiler/Makefile | 65 +++ sourcepawn/compiler/amx.h | 4 +- sourcepawn/compiler/binreloc.c | 766 +++++++++++++++++++++++++++++++++ sourcepawn/compiler/binreloc.h | 80 ++++ sourcepawn/compiler/getch.h | 15 + sourcepawn/compiler/sclinux.h | 47 ++ 6 files changed, 976 insertions(+), 1 deletion(-) create mode 100644 sourcepawn/compiler/Makefile create mode 100644 sourcepawn/compiler/binreloc.c create mode 100644 sourcepawn/compiler/binreloc.h create mode 100644 sourcepawn/compiler/getch.h create mode 100644 sourcepawn/compiler/sclinux.h diff --git a/sourcepawn/compiler/Makefile b/sourcepawn/compiler/Makefile new file mode 100644 index 00000000..dfa35373 --- /dev/null +++ b/sourcepawn/compiler/Makefile @@ -0,0 +1,65 @@ +#(C)2004-2007 SourceMod Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. + +### EDIT BELOW FOR OTHER PROJECTS ### + +OPT_C_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing -fomit-frame-pointer +OPT_CPP_FLAGS = +DEBUG_C_FLAGS = -g -ggdb3 +CPP = gcc-4.1 +BINARY = spcomp + +OBJECTS = libpawnc.c lstring.c memfile.c pawncc.c sc1.c sc2.c sc3.c sc4.c sc5.c \ + sc6.c sc7.c scexpand.c sci18n.c sclist.c scmemfil.c scstate.c sctracker.c \ + scvars.c sp_file.c binreloc.c zlib/adler32.c zlib/crc32.c zlib/deflate.c \ + zlib/gzio.c zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c \ + zlib/trees.c zlib/uncompr.c zlib/zutil.c zlib/compress.c + +LINK = -lgcc -static-libgcc + +INCLUDE = -I. -I$(SMSDK)/public/sourcepawn + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) + +ifeq "$(GCC_VERSION)" "4" + OPT_CPP_FLAGS += -fvisibility=hidden -fvisibility-inlines-hidden +endif + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS = $(DEBUG_C_FLAGS) +else + BIN_DIR = Release + CFLAGS = $(OPT_C_FLAGS) + CPPFLAGS += $(OPT_CPP_FLAGS) +endif + +CFLAGS += -DLINUX -DNDEBUG -DHAVE_STDINT_H -DAMX_ANSIONLY +CPPFLAGS += -Wno-deprecated -fno-exceptions -fno-rtti + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/zlib + $(MAKE) spcomp + +spcomp: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -ldl -lm -o$(BIN_DIR)/$(BINARY) + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 057b4067..505932c4 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -36,7 +36,9 @@ #if defined __GNUC__ #include - #define HAVE_STDINT_H + #if !defined HAVE_STDINT_H + #define HAVE_STDINT_H + #endif #elif !defined HAVE_STDINT_H #if defined __LCC__ || defined __DMC__ || defined LINUX || (defined __WATCOMC__ && __WATCOMC__ >= 1200) #if defined HAVE_INTTYPES_H diff --git a/sourcepawn/compiler/binreloc.c b/sourcepawn/compiler/binreloc.c new file mode 100644 index 00000000..c6dc0ae7 --- /dev/null +++ b/sourcepawn/compiler/binreloc.c @@ -0,0 +1,766 @@ +/* + * BinReloc - a library for creating relocatable executables + * Written by: Hongli Lai + * http://autopackage.org/ + * + * This source code is public domain. You can relicense this code + * under whatever license you want. + * + * See http://autopackage.org/docs/binreloc/ for + * more information and how to use this. + */ + +#ifndef __BINRELOC_C__ +#define __BINRELOC_C__ + +#ifdef ENABLE_BINRELOC + #include + #include + #include +#endif /* ENABLE_BINRELOC */ +#include +#include +#include +#include +#include "binreloc.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** @internal + * Find the canonical filename of the executable. Returns the filename + * (which must be freed) or NULL on error. If the parameter 'error' is + * not NULL, the error code will be stored there, if an error occured. + */ +static char * +_br_find_exe (BrInitError *error) +{ +#ifndef ENABLE_BINRELOC + if (error) + *error = BR_INIT_ERROR_DISABLED; + return NULL; +#else + char *path, *path2, *line, *result; + size_t buf_size; + ssize_t size; + struct stat stat_buf; + FILE *f; + + /* Read from /proc/self/exe (symlink) */ + if (sizeof (path) > SSIZE_MAX) + buf_size = SSIZE_MAX - 1; + else + buf_size = PATH_MAX - 1; + path = (char *) malloc (buf_size); + if (path == NULL) { + /* Cannot allocate memory. */ + if (error) + *error = BR_INIT_ERROR_NOMEM; + return NULL; + } + path2 = (char *) malloc (buf_size); + if (path2 == NULL) { + /* Cannot allocate memory. */ + if (error) + *error = BR_INIT_ERROR_NOMEM; + free (path); + return NULL; + } + + strncpy (path2, "/proc/self/exe", buf_size - 1); + + while (1) { + int i; + + size = readlink (path2, path, buf_size - 1); + if (size == -1) { + /* Error. */ + free (path2); + break; + } + + /* readlink() success. */ + path[size] = '\0'; + + /* Check whether the symlink's target is also a symlink. + * We want to get the final target. */ + i = stat (path, &stat_buf); + if (i == -1) { + /* Error. */ + free (path2); + break; + } + + /* stat() success. */ + if (!S_ISLNK (stat_buf.st_mode)) { + /* path is not a symlink. Done. */ + free (path2); + return path; + } + + /* path is a symlink. Continue loop and resolve this. */ + strncpy (path, path2, buf_size - 1); + } + + + /* readlink() or stat() failed; this can happen when the program is + * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */ + + buf_size = PATH_MAX + 128; + line = (char *) realloc (path, buf_size); + if (line == NULL) { + /* Cannot allocate memory. */ + free (path); + if (error) + *error = BR_INIT_ERROR_NOMEM; + return NULL; + } + + f = fopen ("/proc/self/maps", "r"); + if (f == NULL) { + free (line); + if (error) + *error = BR_INIT_ERROR_OPEN_MAPS; + return NULL; + } + + /* The first entry should be the executable name. */ + result = fgets (line, (int) buf_size, f); + if (result == NULL) { + fclose (f); + free (line); + if (error) + *error = BR_INIT_ERROR_READ_MAPS; + return NULL; + } + + /* Get rid of newline character. */ + buf_size = strlen (line); + if (buf_size <= 0) { + /* Huh? An empty string? */ + fclose (f); + free (line); + if (error) + *error = BR_INIT_ERROR_INVALID_MAPS; + return NULL; + } + if (line[buf_size - 1] == 10) + line[buf_size - 1] = 0; + + /* Extract the filename; it is always an absolute path. */ + path = strchr (line, '/'); + + /* Sanity check. */ + if (strstr (line, " r-xp ") == NULL || path == NULL) { + fclose (f); + free (line); + if (error) + *error = BR_INIT_ERROR_INVALID_MAPS; + return NULL; + } + + path = strdup (path); + free (line); + fclose (f); + return path; +#endif /* ENABLE_BINRELOC */ +} + + +/** @internal + * Find the canonical filename of the executable which owns symbol. + * Returns a filename which must be freed, or NULL on error. + */ +static char * +_br_find_exe_for_symbol (const void *symbol, BrInitError *error) +{ +#ifndef ENABLE_BINRELOC + if (error) + *error = BR_INIT_ERROR_DISABLED; + return (char *) NULL; +#else + #define SIZE PATH_MAX + 100 + FILE *f; + size_t address_string_len; + char *address_string, line[SIZE], *found; + + if (symbol == NULL) + return (char *) NULL; + + f = fopen ("/proc/self/maps", "r"); + if (f == NULL) + return (char *) NULL; + + address_string_len = 4; + address_string = (char *) malloc (address_string_len); + found = (char *) NULL; + + while (!feof (f)) { + char *start_addr, *end_addr, *end_addr_end, *file; + void *start_addr_p, *end_addr_p; + size_t len; + + if (fgets (line, SIZE, f) == NULL) + break; + + /* Sanity check. */ + if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL) + continue; + + /* Parse line. */ + start_addr = line; + end_addr = strchr (line, '-'); + file = strchr (line, '/'); + + /* More sanity check. */ + if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-')) + continue; + + end_addr[0] = '\0'; + end_addr++; + end_addr_end = strchr (end_addr, ' '); + if (end_addr_end == NULL) + continue; + + end_addr_end[0] = '\0'; + len = strlen (file); + if (len == 0) + continue; + if (file[len - 1] == '\n') + file[len - 1] = '\0'; + + /* Get rid of "(deleted)" from the filename. */ + len = strlen (file); + if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0) + file[len - 10] = '\0'; + + /* I don't know whether this can happen but better safe than sorry. */ + len = strlen (start_addr); + if (len != strlen (end_addr)) + continue; + + + /* Transform the addresses into a string in the form of 0xdeadbeef, + * then transform that into a pointer. */ + if (address_string_len < len + 3) { + address_string_len = len + 3; + address_string = (char *) realloc (address_string, address_string_len); + } + + memcpy (address_string, "0x", 2); + memcpy (address_string + 2, start_addr, len); + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &start_addr_p); + + memcpy (address_string, "0x", 2); + memcpy (address_string + 2, end_addr, len); + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &end_addr_p); + + + if (symbol >= start_addr_p && symbol < end_addr_p) { + found = file; + break; + } + } + + free (address_string); + fclose (f); + + if (found == NULL) + return (char *) NULL; + else + return strdup (found); +#endif /* ENABLE_BINRELOC */ +} + + +#ifndef BINRELOC_RUNNING_DOXYGEN + #undef NULL + #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */ +#endif + +static char *exe = (char *) NULL; + + +/** Initialize the BinReloc library (for applications). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the application's canonical filename. + * + * @note If you want to use BinReloc for a library, then you should call + * br_init_lib() instead. + * + * @param error If BinReloc failed to initialize, then the error code will + * be stored in this variable. Set to NULL if you want to + * ignore this. See #BrInitError for a list of error codes. + * + * @returns 1 on success, 0 if BinReloc failed to initialize. + */ +int +br_init (BrInitError *error) +{ + exe = _br_find_exe (error); + return exe != NULL; +} + + +/** Initialize the BinReloc library (for libraries). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the calling library's canonical filename. + * + * @note The BinReloc source code MUST be included in your library, or this + * function won't work correctly. + * + * @param error If BinReloc failed to initialize, then the error code will + * be stored in this variable. Set to NULL if you want to + * ignore this. See #BrInitError for a list of error codes. + * + * @returns 1 on success, 0 if a filename cannot be found. + */ +int +br_init_lib (BrInitError *error) +{ + exe = _br_find_exe_for_symbol ((const void *) "", error); + return exe != NULL; +} + + +/** Find the canonical filename of the current application. + * + * @param default_exe A default filename which will be used as fallback. + * @returns A string containing the application's canonical filename, + * which must be freed when no longer necessary. If BinReloc is + * not initialized, or if br_init() failed, then a copy of + * default_exe will be returned. If default_exe is NULL, then + * NULL will be returned. + */ +char * +br_find_exe (const char *default_exe) +{ + if (exe == (char *) NULL) { + /* BinReloc is not initialized. */ + if (default_exe != (const char *) NULL) + return strdup (default_exe); + else + return (char *) NULL; + } + return strdup (exe); +} + + +/** Locate the directory in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(exename) + * \endcode + * + * @param default_dir A default directory which will used as fallback. + * @return A string containing the directory, which must be freed when no + * longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_dir + * will be returned. If default_dir is NULL, then NULL will be + * returned. + */ +char * +br_find_exe_dir (const char *default_dir) +{ + if (exe == NULL) { + /* BinReloc not initialized. */ + if (default_dir != NULL) + return strdup (default_dir); + else + return NULL; + } + + return br_dirname (exe); +} + + +/** Locate the prefix in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(dirname(exename)) + * \endcode + * + * @param default_prefix A default prefix which will used as fallback. + * @return A string containing the prefix, which must be freed when no + * longer necessary. If BinReloc is not initialized, or if + * the initialization function failed, then a copy of default_prefix + * will be returned. If default_prefix is NULL, then NULL will be returned. + */ +char * +br_find_prefix (const char *default_prefix) +{ + char *dir1, *dir2; + + if (exe == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_prefix != (const char *) NULL) + return strdup (default_prefix); + else + return (char *) NULL; + } + + dir1 = br_dirname (exe); + dir2 = br_dirname (dir1); + free (dir1); + return dir2; +} + + +/** Locate the application's binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/bin" + * \endcode + * + * @param default_bin_dir A default path which will used as fallback. + * @return A string containing the bin folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if + * the initialization function failed, then a copy of default_bin_dir will + * be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +char * +br_find_bin_dir (const char *default_bin_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_bin_dir != (const char *) NULL) + return strdup (default_bin_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "bin"); + free (prefix); + return dir; +} + + +/** Locate the application's superuser binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/sbin" + * \endcode + * + * @param default_sbin_dir A default path which will used as fallback. + * @return A string containing the sbin folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_sbin_dir will + * be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +char * +br_find_sbin_dir (const char *default_sbin_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_sbin_dir != (const char *) NULL) + return strdup (default_sbin_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "sbin"); + free (prefix); + return dir; +} + + +/** Locate the application's data folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share" + * \endcode + * + * @param default_data_dir A default path which will used as fallback. + * @return A string containing the data folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_data_dir + * will be returned. If default_data_dir is NULL, then NULL will be + * returned. + */ +char * +br_find_data_dir (const char *default_data_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_data_dir != (const char *) NULL) + return strdup (default_data_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "share"); + free (prefix); + return dir; +} + + +/** Locate the application's localization folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share/locale" + * \endcode + * + * @param default_locale_dir A default path which will used as fallback. + * @return A string containing the localization folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_locale_dir will be returned. + * If default_locale_dir is NULL, then NULL will be returned. + */ +char * +br_find_locale_dir (const char *default_locale_dir) +{ + char *data_dir, *dir; + + data_dir = br_find_data_dir ((const char *) NULL); + if (data_dir == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_locale_dir != (const char *) NULL) + return strdup (default_locale_dir); + else + return (char *) NULL; + } + + dir = br_build_path (data_dir, "locale"); + free (data_dir); + return dir; +} + + +/** Locate the application's library folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/lib" + * \endcode + * + * @param default_lib_dir A default path which will used as fallback. + * @return A string containing the library folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the initialization + * function failed, then a copy of default_lib_dir will be returned. + * If default_lib_dir is NULL, then NULL will be returned. + */ +char * +br_find_lib_dir (const char *default_lib_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_lib_dir != (const char *) NULL) + return strdup (default_lib_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "lib"); + free (prefix); + return dir; +} + + +/** Locate the application's libexec folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/libexec" + * \endcode + * + * @param default_libexec_dir A default path which will used as fallback. + * @return A string containing the libexec folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the initialization + * function failed, then a copy of default_libexec_dir will be returned. + * If default_libexec_dir is NULL, then NULL will be returned. + */ +char * +br_find_libexec_dir (const char *default_libexec_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_libexec_dir != (const char *) NULL) + return strdup (default_libexec_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "libexec"); + free (prefix); + return dir; +} + + +/** Locate the application's configuration files folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/etc" + * \endcode + * + * @param default_etc_dir A default path which will used as fallback. + * @return A string containing the etc folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the initialization + * function failed, then a copy of default_etc_dir will be returned. + * If default_etc_dir is NULL, then NULL will be returned. + */ +char * +br_find_etc_dir (const char *default_etc_dir) +{ + char *prefix, *dir; + + prefix = br_find_prefix ((const char *) NULL); + if (prefix == (char *) NULL) { + /* BinReloc not initialized. */ + if (default_etc_dir != (const char *) NULL) + return strdup (default_etc_dir); + else + return (char *) NULL; + } + + dir = br_build_path (prefix, "etc"); + free (prefix); + return dir; +} + + +/*********************** + * Utility functions + ***********************/ + +/** Concatenate str1 and str2 to a newly allocated string. + * + * @param str1 A string. + * @param str2 Another string. + * @returns A newly-allocated string. This string should be freed when no longer needed. + */ +char * +br_strcat (const char *str1, const char *str2) +{ + char *result; + size_t len1, len2; + + if (str1 == NULL) + str1 = ""; + if (str2 == NULL) + str2 = ""; + + len1 = strlen (str1); + len2 = strlen (str2); + + result = (char *) malloc (len1 + len2 + 1); + memcpy (result, str1, len1); + memcpy (result + len1, str2, len2); + result[len1 + len2] = '\0'; + + return result; +} + + +char * +br_build_path (const char *dir, const char *file) +{ + char *dir2, *result; + size_t len; + int must_free = 0; + + len = strlen (dir); + if (len > 0 && dir[len - 1] != '/') { + dir2 = br_strcat (dir, "/"); + must_free = 1; + } else + dir2 = (char *) dir; + + result = br_strcat (dir2, file); + if (must_free) + free (dir2); + return result; +} + + +/* Emulates glibc's strndup() */ +static char * +br_strndup (const char *str, size_t size) +{ + char *result = (char *) NULL; + size_t len; + + if (str == (const char *) NULL) + return (char *) NULL; + + len = strlen (str); + if (len == 0) + return strdup (""); + if (size > len) + size = len; + + result = (char *) malloc (len + 1); + memcpy (result, str, size); + result[size] = '\0'; + return result; +} + + +/** Extracts the directory component of a path. + * + * Similar to g_dirname() or the dirname commandline application. + * + * Example: + * \code + * br_dirname ("/usr/local/foobar"); --> Returns: "/usr/local" + * \endcode + * + * @param path A path. + * @returns A directory name. This string should be freed when no longer needed. + */ +char * +br_dirname (const char *path) +{ + char *end, *result; + + if (path == (const char *) NULL) + return (char *) NULL; + + end = strrchr (path, '/'); + if (end == (const char *) NULL) + return strdup ("."); + + while (end > path && *end == '/') + end--; + result = br_strndup (path, end - path + 1); + if (result[0] == 0) { + free (result); + return strdup ("/"); + } else + return result; +} + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __BINRELOC_C__ */ diff --git a/sourcepawn/compiler/binreloc.h b/sourcepawn/compiler/binreloc.h new file mode 100644 index 00000000..4ee25c29 --- /dev/null +++ b/sourcepawn/compiler/binreloc.h @@ -0,0 +1,80 @@ +/* + * BinReloc - a library for creating relocatable executables + * Written by: Hongli Lai + * http://autopackage.org/ + * + * This source code is public domain. You can relicense this code + * under whatever license you want. + * + * See http://autopackage.org/docs/binreloc/ for + * more information and how to use this. + */ + +#ifndef __BINRELOC_H__ +#define __BINRELOC_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** These error codes can be returned by br_init(), br_init_lib(), gbr_init() or gbr_init_lib(). */ +typedef enum { + /** Cannot allocate memory. */ + BR_INIT_ERROR_NOMEM, + /** Unable to open /proc/self/maps; see errno for details. */ + BR_INIT_ERROR_OPEN_MAPS, + /** Unable to read from /proc/self/maps; see errno for details. */ + BR_INIT_ERROR_READ_MAPS, + /** The file format of /proc/self/maps is invalid; kernel bug? */ + BR_INIT_ERROR_INVALID_MAPS, + /** BinReloc is disabled (the ENABLE_BINRELOC macro is not defined). */ + BR_INIT_ERROR_DISABLED +} BrInitError; + + +#ifndef BINRELOC_RUNNING_DOXYGEN +/* Mangle symbol names to avoid symbol collisions with other ELF objects. */ + #define br_init SbCJ22537442193159_br_init + #define br_init_lib SbCJ22537442193159_br_init_lib + #define br_find_exe SbCJ22537442193159_br_find_exe + #define br_find_exe_dir SbCJ22537442193159_br_find_exe_dir + #define br_find_prefix SbCJ22537442193159_br_find_prefix + #define br_find_bin_dir SbCJ22537442193159_br_find_bin_dir + #define br_find_sbin_dir SbCJ22537442193159_br_find_sbin_dir + #define br_find_data_dir SbCJ22537442193159_br_find_data_dir + #define br_find_locale_dir SbCJ22537442193159_br_find_locale_dir + #define br_find_lib_dir SbCJ22537442193159_br_find_lib_dir + #define br_find_libexec_dir SbCJ22537442193159_br_find_libexec_dir + #define br_find_etc_dir SbCJ22537442193159_br_find_etc_dir + #define br_strcat SbCJ22537442193159_br_strcat + #define br_build_path SbCJ22537442193159_br_build_path + #define br_dirname SbCJ22537442193159_br_dirname + + +#endif +int br_init (BrInitError *error); +int br_init_lib (BrInitError *error); + +char *br_find_exe (const char *default_exe); +char *br_find_exe_dir (const char *default_dir); +char *br_find_prefix (const char *default_prefix); +char *br_find_bin_dir (const char *default_bin_dir); +char *br_find_sbin_dir (const char *default_sbin_dir); +char *br_find_data_dir (const char *default_data_dir); +char *br_find_locale_dir (const char *default_locale_dir); +char *br_find_lib_dir (const char *default_lib_dir); +char *br_find_libexec_dir (const char *default_libexec_dir); +char *br_find_etc_dir (const char *default_etc_dir); + +/* Utility functions */ +char *br_strcat (const char *str1, const char *str2); +char *br_build_path (const char *dir, const char *file); +char *br_dirname (const char *path); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __BINRELOC_H__ */ diff --git a/sourcepawn/compiler/getch.h b/sourcepawn/compiler/getch.h new file mode 100644 index 00000000..71cdd83b --- /dev/null +++ b/sourcepawn/compiler/getch.h @@ -0,0 +1,15 @@ +/* Extremely inefficient but portable POSIX getch(), see getch.c */ +#ifndef GETCH_H +#define GETCH_H + +#if defined __cplusplus + extern "C" { +#endif +int getch(void); +int kbhit(void); + +#if defined __cplusplus +} +#endif + +#endif /* GETCH_H */ diff --git a/sourcepawn/compiler/sclinux.h b/sourcepawn/compiler/sclinux.h new file mode 100644 index 00000000..f22497a8 --- /dev/null +++ b/sourcepawn/compiler/sclinux.h @@ -0,0 +1,47 @@ +/* + * Things needed to compile under linux. + * + * Should be reworked totally to use GNU's 'configure' + */ +#ifndef SCLINUX_H +#define SCLINUX_H + +/* getchar() is not a 'cool' replacement for MSDOS getch: Linux/unix depends on the features activated or not about the + * controlling terminal's tty. This means that ioctl(2) calls must be performed, for instance to have the controlling + * terminal tty's in 'raw' mode, if we want to be able to fetch a single character. This also means that everything must + * be put back correctly when the function ends. See GETCH.C for an implementation. + * + * For interactive use of SRUN/SDBG if would be much better to use GNU's readline package: the user would be able to + * have a complete emacs/vi like line editing system. + */ +#include "getch.h" + +#define stricmp(a,b) strcasecmp(a,b) +#define strnicmp(a,b,c) strncasecmp(a,b,c) + +/* + * WinWorld wants '\'. Unices do not. + */ +#define DIRECTORY_SEP_CHAR '/' +#define DIRECTORY_SEP_STR "/" + +/* + * SC assumes that a computer is Little Endian unless told otherwise. It uses + * (and defines) the macros BYTE_ORDER and BIG_ENDIAN. + * For Linux, we must overrule these settings with those defined in glibc. + */ +#if !defined __BYTE_ORDER +# include +#endif + +#if defined __OpenBSD__ || defined __FreeBSD__ +# define __BYTE_ORDER BYTE_ORDER +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __BIG_ENDIAN BIG_ENDIAN +#endif + +#if !defined __BYTE_ORDER +# error "Can't figure computer byte order (__BYTE_ORDER macro not found)" +#endif + +#endif /* SCLINUX_H */ From 7c762262309e8058c80d6f5783b9dd84542e9eb2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:30:04 +0000 Subject: [PATCH 0329/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40359 --- public/sample_ext/Makefile | 91 +++++++++++++++++++++++++++++++++ public/sample_ext/smsdk_ext.cpp | 29 +++++++++++ 2 files changed, 120 insertions(+) create mode 100644 public/sample_ext/Makefile diff --git a/public/sample_ext/Makefile b/public/sample_ext/Makefile new file mode 100644 index 00000000..61e360ac --- /dev/null +++ b/public/sample_ext/Makefile @@ -0,0 +1,91 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = sample + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS = $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS = $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index ddd0cc5b..0dfcd408 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -1,4 +1,5 @@ #include +#include #include "smsdk_ext.h" IShareSys *g_pShareSys = NULL; @@ -279,3 +280,31 @@ bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err } #endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + From 4a0712545e76d1292c2c36b11b4274704cdfb7d9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:34:27 +0000 Subject: [PATCH 0330/1664] updated sdk added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40360 --- extensions/geoip/GeoIP.c | 2 + extensions/geoip/Makefile | 91 ++++++++++++++++++++++++++++++++++ extensions/geoip/extension.cpp | 3 +- extensions/geoip/smsdk_ext.cpp | 31 ++++++++++++ extensions/geoip/smsdk_ext.h | 2 + 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 extensions/geoip/Makefile diff --git a/extensions/geoip/GeoIP.c b/extensions/geoip/GeoIP.c index c5ee3217..8e60424f 100644 --- a/extensions/geoip/GeoIP.c +++ b/extensions/geoip/GeoIP.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define GEOIPDATADIR "" + #include "GeoIP.h" #ifndef _WIN32 diff --git a/extensions/geoip/Makefile b/extensions/geoip/Makefile new file mode 100644 index 00000000..1cf69223 --- /dev/null +++ b/extensions/geoip/Makefile @@ -0,0 +1,91 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = geoip + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp GeoIP.c + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS = $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS = $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp index ac9df7de..0212350d 100644 --- a/extensions/geoip/extension.cpp +++ b/extensions/geoip/extension.cpp @@ -93,4 +93,5 @@ const sp_nativeinfo_t geoip_natives[] = {"GeoipCode3", sm_Geoip_Code3}, {"GeoipCountry", sm_Geoip_Country}, {NULL, NULL}, -}; \ No newline at end of file +}; + diff --git a/extensions/geoip/smsdk_ext.cpp b/extensions/geoip/smsdk_ext.cpp index 01e3f42c..0dfcd408 100644 --- a/extensions/geoip/smsdk_ext.cpp +++ b/extensions/geoip/smsdk_ext.cpp @@ -1,10 +1,12 @@ #include +#include #include "smsdk_ext.h" IShareSys *g_pShareSys = NULL; IExtension *myself = NULL; IHandleSys *g_pHandleSys = NULL; ISourceMod *g_pSM = NULL; +IForwardManager *g_pForwards = NULL; PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { @@ -40,6 +42,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); if (SDK_OnLoad(error, err_max, late)) { @@ -277,3 +280,31 @@ bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err } #endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/extensions/geoip/smsdk_ext.h b/extensions/geoip/smsdk_ext.h index 07362c78..16d931bc 100644 --- a/extensions/geoip/smsdk_ext.h +++ b/extensions/geoip/smsdk_ext.h @@ -7,6 +7,7 @@ #include #include #include +#include #if defined SMEXT_CONF_METAMOD #include @@ -123,6 +124,7 @@ extern IShareSys *g_pShareSys; extern IExtension *myself; extern IHandleSys *g_pHandleSys; extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); From 8dfb783b14dfd5da99268acec49592f0a0fe5a1b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:42:07 +0000 Subject: [PATCH 0331/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40361 --- extensions/threader/Makefile | 92 +++++++++++++++++++++ extensions/threader/smsdk_ext.cpp | 31 +++++++ extensions/threader/smsdk_ext.h | 2 + extensions/threader/thread/PosixThreads.cpp | 16 ++++ extensions/threader/thread/PosixThreads.h | 16 ++-- 5 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 extensions/threader/Makefile diff --git a/extensions/threader/Makefile b/extensions/threader/Makefile new file mode 100644 index 00000000..a02f6076 --- /dev/null +++ b/extensions/threader/Makefile @@ -0,0 +1,92 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = threader + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp \ + thread/ThreadWorker.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -lpthread -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DSM_DEFAULT_THREADER +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/thread + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/extensions/threader/smsdk_ext.cpp b/extensions/threader/smsdk_ext.cpp index 01e3f42c..0dfcd408 100644 --- a/extensions/threader/smsdk_ext.cpp +++ b/extensions/threader/smsdk_ext.cpp @@ -1,10 +1,12 @@ #include +#include #include "smsdk_ext.h" IShareSys *g_pShareSys = NULL; IExtension *myself = NULL; IHandleSys *g_pHandleSys = NULL; ISourceMod *g_pSM = NULL; +IForwardManager *g_pForwards = NULL; PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { @@ -40,6 +42,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); if (SDK_OnLoad(error, err_max, late)) { @@ -277,3 +280,31 @@ bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err } #endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/extensions/threader/smsdk_ext.h b/extensions/threader/smsdk_ext.h index 07362c78..16d931bc 100644 --- a/extensions/threader/smsdk_ext.h +++ b/extensions/threader/smsdk_ext.h @@ -7,6 +7,7 @@ #include #include #include +#include #if defined SMEXT_CONF_METAMOD #include @@ -123,6 +124,7 @@ extern IShareSys *g_pShareSys; extern IExtension *myself; extern IHandleSys *g_pHandleSys; extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); diff --git a/extensions/threader/thread/PosixThreads.cpp b/extensions/threader/thread/PosixThreads.cpp index f08b9210..5c801e14 100644 --- a/extensions/threader/thread/PosixThreads.cpp +++ b/extensions/threader/thread/PosixThreads.cpp @@ -1,5 +1,21 @@ #include #include "PosixThreads.h" +#include "ThreadWorker.h" + +IThreadWorker *PosixThreader::MakeWorker(bool threaded) +{ + if (threaded) + { + return new ThreadWorker(this, DEFAULT_THINK_TIME_MS); + } else { + return new BaseWorker(); + } +} + +void PosixThreader::DestroyWorker(IThreadWorker *pWorker) +{ + delete pWorker; +} void PosixThreader::ThreadSleep(unsigned int ms) { diff --git a/extensions/threader/thread/PosixThreads.h b/extensions/threader/thread/PosixThreads.h index 30a5ee75..3a8eb9ed 100644 --- a/extensions/threader/thread/PosixThreads.h +++ b/extensions/threader/thread/PosixThreads.h @@ -65,13 +65,15 @@ public: pthread_mutex_t m_mutex; }; public: - virtual IMutex *MakeMutex(); - virtual void MakeThread(IThread *pThread); - virtual IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags); - virtual IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params); - virtual void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); - virtual void ThreadSleep(unsigned int ms); - virtual IEventSignal *MakeEventSignal(); + IMutex *MakeMutex(); + void MakeThread(IThread *pThread); + IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags); + IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params); + void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); + void ThreadSleep(unsigned int ms); + IEventSignal *MakeEventSignal(); + IThreadWorker *MakeWorker(bool threaded); + void DestroyWorker(IThreadWorker *pWorker); }; #if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER From ba1d7ae82fdd67df69d18169ffa57023503e28a7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:45:08 +0000 Subject: [PATCH 0332/1664] little fixes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40362 --- extensions/geoip/GeoIP.c | 4 +--- extensions/geoip/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/extensions/geoip/GeoIP.c b/extensions/geoip/GeoIP.c index 8e60424f..1090b893 100644 --- a/extensions/geoip/GeoIP.c +++ b/extensions/geoip/GeoIP.c @@ -611,8 +611,6 @@ unsigned long _GeoIP_lookupaddress (const char *host) { struct hostent phe2; struct hostent * phe = &phe2; char *buf = NULL; - int buflength = 16384; - int herr = 0; int result = 0; #ifdef HAVE_GETHOSTBYNAME_R buf = malloc(buflength); @@ -923,7 +921,7 @@ char *_get_name (GeoIP* gi, unsigned long ipnum) { org_buf = malloc(len); strncpy(org_buf, buf, len); } else { - buf_pointer = gi->cache + (long)record_pointer; + buf_pointer = (char *)(gi->cache + (long)record_pointer); len = sizeof(char) * (strlen(buf_pointer)+1); org_buf = malloc(len); strncpy(org_buf, buf_pointer, len); diff --git a/extensions/geoip/Makefile b/extensions/geoip/Makefile index 1cf69223..6323db70 100644 --- a/extensions/geoip/Makefile +++ b/extensions/geoip/Makefile @@ -45,10 +45,10 @@ CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti ifeq "$(DEBUG)" "true" BIN_DIR = Debug - CFLAGS = $(C_DEBUG_FLAGS) + CFLAGS += $(C_DEBUG_FLAGS) else BIN_DIR = Release - CFLAGS = $(C_OPT_FLAGS) + CFLAGS += $(C_OPT_FLAGS) endif From f5eab0e7779ea589b96c39ad947987935e00e4c2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:45:37 +0000 Subject: [PATCH 0333/1664] little makefile fix --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40363 --- public/sample_ext/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/sample_ext/Makefile b/public/sample_ext/Makefile index 61e360ac..537e149c 100644 --- a/public/sample_ext/Makefile +++ b/public/sample_ext/Makefile @@ -45,10 +45,10 @@ CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti ifeq "$(DEBUG)" "true" BIN_DIR = Debug - CFLAGS = $(C_DEBUG_FLAGS) + CFLAGS += $(C_DEBUG_FLAGS) else BIN_DIR = Release - CFLAGS = $(C_OPT_FLAGS) + CFLAGS += $(C_OPT_FLAGS) endif From 3b2f12622129023a54df88d071fd0295aa2c4e43 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 20:45:49 +0000 Subject: [PATCH 0334/1664] fixed a namespace collision --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40364 --- public/ISourceMod.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/ISourceMod.h b/public/ISourceMod.h index fe2d2144..43ec9cd5 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -2,6 +2,7 @@ #define _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ #include +#include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" #define SMINTERFACE_SOURCEMOD_VERSION 1 @@ -82,7 +83,7 @@ namespace SourceMod */ virtual size_t FormatString(char *buffer, size_t maxlength, - IPluginContext *pContext, + SourcePawn::IPluginContext *pContext, const cell_t *params, unsigned int param) =0; }; From f32af66596112a6a2678e4635188ac2383575349 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 21:10:27 +0000 Subject: [PATCH 0335/1664] finished linux builds i guess --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40365 --- TODO.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.txt b/TODO.txt index b2982988..fdf77b7f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -11,4 +11,4 @@ things to do for a release, in priority X add error messages to format routine X finish global unloading - add hex format specifier - - linux building (oh god) + X linux building (oh god) From 4e75204c77467849e24532f77a05fa56dacb693b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 21:14:30 +0000 Subject: [PATCH 0336/1664] reorganization --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40366 --- public/sample_ext/{ => msvc8}/sdk.sln | 0 public/sample_ext/{ => msvc8}/sdk.vcproj | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) rename public/sample_ext/{ => msvc8}/sdk.sln (100%) rename public/sample_ext/{ => msvc8}/sdk.vcproj (90%) diff --git a/public/sample_ext/sdk.sln b/public/sample_ext/msvc8/sdk.sln similarity index 100% rename from public/sample_ext/sdk.sln rename to public/sample_ext/msvc8/sdk.sln diff --git a/public/sample_ext/sdk.vcproj b/public/sample_ext/msvc8/sdk.vcproj similarity index 90% rename from public/sample_ext/sdk.vcproj rename to public/sample_ext/msvc8/sdk.vcproj index fb4199c5..e43f1cd9 100644 --- a/public/sample_ext/sdk.vcproj +++ b/public/sample_ext/msvc8/sdk.vcproj @@ -40,7 +40,7 @@ @@ -344,15 +344,15 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > From ea87f1977911c984c600edab73d62cfb10a52286 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 21:42:54 +0000 Subject: [PATCH 0337/1664] changed source extension to .sp added crimson editor binds --HG-- rename : plugins/admin-base.sma => plugins/admin-base.sp extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40367 --- editor/crimson/link/extension.sp | 2 + editor/crimson/sourcepawn.key | 48 +++++++++++++++++++++++ editor/crimson/sourcepawn.spc | 21 ++++++++++ editor/crimson/spec/sourcepawn.key | 48 +++++++++++++++++++++++ editor/crimson/spec/sourcepawn.spc | 21 ++++++++++ plugins/{admin-base.sma => admin-base.sp} | 0 6 files changed, 140 insertions(+) create mode 100644 editor/crimson/link/extension.sp create mode 100644 editor/crimson/sourcepawn.key create mode 100644 editor/crimson/sourcepawn.spc create mode 100644 editor/crimson/spec/sourcepawn.key create mode 100644 editor/crimson/spec/sourcepawn.spc rename plugins/{admin-base.sma => admin-base.sp} (100%) diff --git a/editor/crimson/link/extension.sp b/editor/crimson/link/extension.sp new file mode 100644 index 00000000..c2f792cf --- /dev/null +++ b/editor/crimson/link/extension.sp @@ -0,0 +1,2 @@ +LANGSPEC:SOURCEPAWN.SPC +KEYWORDS:SOURCEPAWN.KEY \ No newline at end of file diff --git a/editor/crimson/sourcepawn.key b/editor/crimson/sourcepawn.key new file mode 100644 index 00000000..86155320 --- /dev/null +++ b/editor/crimson/sourcepawn.key @@ -0,0 +1,48 @@ +[-COMMENT-:GLOBAL] +# =================================================================== +# "SourcePawn" LANGUAGE KEYWORD FILE FOR CRIMSON EDITOR +# Created by David Anderson +# =================================================================== + +[KEYWORDS0:GLOBAL] +# Statements +assert begin break case continue default defined do else enum exit for +forward funcenum functag if native new decl operator return struct switch while + +[KEYWORDS1:GLOBAL] +# Operators +cellsof chars sizeof tagof + +# Predefined constants +false true cellbits cellmax cellmin charbits charmax charmin myinfo INVALID_HANDLE +__version + +# Predefined tag names +bool Float Handle String + +[KEYWORDS2:GLOBAL] +# Directives + #assert #define #else #elseif #emit #endif #endinput #endscript #if #include + #pragma #error #tryinclude #undef + +# Extra information for #pragma +align ctrlchar dynamic library pack rational semicolon tabsize + +[KEYWORDS3:GLOBAL] +# Others +const public static stock + +[KEYWORDS4:GLOBAL] +#:TODO: + +[KEYWORDS5:GLOBAL] +#:TODO: + +[KEYWORDS6:GLOBAL] +#:TODO: + +[KEYWORDS6:GLOBAL] +#:TODO: + +[KEYWORDS8:GLOBAL] +#:TODO: diff --git a/editor/crimson/sourcepawn.spc b/editor/crimson/sourcepawn.spc new file mode 100644 index 00000000..4e76d299 --- /dev/null +++ b/editor/crimson/sourcepawn.spc @@ -0,0 +1,21 @@ +# =================================================================== +# "SourcePawn" LANGUAGE SPECIFICATION FILE FOR CRIMSON EDITOR +# Created by David Anderson +# +# =================================================================== + +$BLOCKCOMMENTON=/* +$BLOCKCOMMENTOFF=*/ +$CASESENSITIVE=YES +$DELIMITERS=~`!@#$%^&*()-+=|\{}[]:;"',.<>/? +$ESCAPECHAR=\ +$HEXADECIMALMARK=0x +$INDENTATIONON={ +$INDENTATIONOFF=} +$KEYWORDPREFIX=# +$LINECOMMENT=// +$PAIRS1=() +$PAIRS2=[] +$PAIRS3={} +$QUOTATIONMARK1=" +$QUOTATIONMARK2=' \ No newline at end of file diff --git a/editor/crimson/spec/sourcepawn.key b/editor/crimson/spec/sourcepawn.key new file mode 100644 index 00000000..86155320 --- /dev/null +++ b/editor/crimson/spec/sourcepawn.key @@ -0,0 +1,48 @@ +[-COMMENT-:GLOBAL] +# =================================================================== +# "SourcePawn" LANGUAGE KEYWORD FILE FOR CRIMSON EDITOR +# Created by David Anderson +# =================================================================== + +[KEYWORDS0:GLOBAL] +# Statements +assert begin break case continue default defined do else enum exit for +forward funcenum functag if native new decl operator return struct switch while + +[KEYWORDS1:GLOBAL] +# Operators +cellsof chars sizeof tagof + +# Predefined constants +false true cellbits cellmax cellmin charbits charmax charmin myinfo INVALID_HANDLE +__version + +# Predefined tag names +bool Float Handle String + +[KEYWORDS2:GLOBAL] +# Directives + #assert #define #else #elseif #emit #endif #endinput #endscript #if #include + #pragma #error #tryinclude #undef + +# Extra information for #pragma +align ctrlchar dynamic library pack rational semicolon tabsize + +[KEYWORDS3:GLOBAL] +# Others +const public static stock + +[KEYWORDS4:GLOBAL] +#:TODO: + +[KEYWORDS5:GLOBAL] +#:TODO: + +[KEYWORDS6:GLOBAL] +#:TODO: + +[KEYWORDS6:GLOBAL] +#:TODO: + +[KEYWORDS8:GLOBAL] +#:TODO: diff --git a/editor/crimson/spec/sourcepawn.spc b/editor/crimson/spec/sourcepawn.spc new file mode 100644 index 00000000..4e76d299 --- /dev/null +++ b/editor/crimson/spec/sourcepawn.spc @@ -0,0 +1,21 @@ +# =================================================================== +# "SourcePawn" LANGUAGE SPECIFICATION FILE FOR CRIMSON EDITOR +# Created by David Anderson +# +# =================================================================== + +$BLOCKCOMMENTON=/* +$BLOCKCOMMENTOFF=*/ +$CASESENSITIVE=YES +$DELIMITERS=~`!@#$%^&*()-+=|\{}[]:;"',.<>/? +$ESCAPECHAR=\ +$HEXADECIMALMARK=0x +$INDENTATIONON={ +$INDENTATIONOFF=} +$KEYWORDPREFIX=# +$LINECOMMENT=// +$PAIRS1=() +$PAIRS2=[] +$PAIRS3={} +$QUOTATIONMARK1=" +$QUOTATIONMARK2=' \ No newline at end of file diff --git a/plugins/admin-base.sma b/plugins/admin-base.sp similarity index 100% rename from plugins/admin-base.sma rename to plugins/admin-base.sp From 84d1627c6e3f21cb00dd14f7e4e2e0d51ae41d50 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 21:43:12 +0000 Subject: [PATCH 0338/1664] removed extra files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40368 --- editor/crimson/sourcepawn.key | 48 ----------------------------------- editor/crimson/sourcepawn.spc | 21 --------------- 2 files changed, 69 deletions(-) delete mode 100644 editor/crimson/sourcepawn.key delete mode 100644 editor/crimson/sourcepawn.spc diff --git a/editor/crimson/sourcepawn.key b/editor/crimson/sourcepawn.key deleted file mode 100644 index 86155320..00000000 --- a/editor/crimson/sourcepawn.key +++ /dev/null @@ -1,48 +0,0 @@ -[-COMMENT-:GLOBAL] -# =================================================================== -# "SourcePawn" LANGUAGE KEYWORD FILE FOR CRIMSON EDITOR -# Created by David Anderson -# =================================================================== - -[KEYWORDS0:GLOBAL] -# Statements -assert begin break case continue default defined do else enum exit for -forward funcenum functag if native new decl operator return struct switch while - -[KEYWORDS1:GLOBAL] -# Operators -cellsof chars sizeof tagof - -# Predefined constants -false true cellbits cellmax cellmin charbits charmax charmin myinfo INVALID_HANDLE -__version - -# Predefined tag names -bool Float Handle String - -[KEYWORDS2:GLOBAL] -# Directives - #assert #define #else #elseif #emit #endif #endinput #endscript #if #include - #pragma #error #tryinclude #undef - -# Extra information for #pragma -align ctrlchar dynamic library pack rational semicolon tabsize - -[KEYWORDS3:GLOBAL] -# Others -const public static stock - -[KEYWORDS4:GLOBAL] -#:TODO: - -[KEYWORDS5:GLOBAL] -#:TODO: - -[KEYWORDS6:GLOBAL] -#:TODO: - -[KEYWORDS6:GLOBAL] -#:TODO: - -[KEYWORDS8:GLOBAL] -#:TODO: diff --git a/editor/crimson/sourcepawn.spc b/editor/crimson/sourcepawn.spc deleted file mode 100644 index 4e76d299..00000000 --- a/editor/crimson/sourcepawn.spc +++ /dev/null @@ -1,21 +0,0 @@ -# =================================================================== -# "SourcePawn" LANGUAGE SPECIFICATION FILE FOR CRIMSON EDITOR -# Created by David Anderson -# -# =================================================================== - -$BLOCKCOMMENTON=/* -$BLOCKCOMMENTOFF=*/ -$CASESENSITIVE=YES -$DELIMITERS=~`!@#$%^&*()-+=|\{}[]:;"',.<>/? -$ESCAPECHAR=\ -$HEXADECIMALMARK=0x -$INDENTATIONON={ -$INDENTATIONOFF=} -$KEYWORDPREFIX=# -$LINECOMMENT=// -$PAIRS1=() -$PAIRS2=[] -$PAIRS3={} -$QUOTATIONMARK1=" -$QUOTATIONMARK2=' \ No newline at end of file From eaa989cb6be2336b843cca4c81d68b0c135c3210 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 21:50:45 +0000 Subject: [PATCH 0339/1664] fixed a build error renamed SMC_CreateParse to SMC_CreateParser --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40369 --- core/smn_textparse.cpp | 4 ++-- core/systems/HandleSys.cpp | 3 +++ plugins/include/textparse.inc | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index 7f1f1d5f..f1ef0340 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -142,7 +142,7 @@ public: TextParseGlobals g_TextParseGlobals; -static cell_t SMC_CreateParse(IPluginContext *pContext, const cell_t *params) +static cell_t SMC_CreateParser(IPluginContext *pContext, const cell_t *params) { ParseInfo *pInfo = new ParseInfo(); @@ -274,7 +274,7 @@ static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params) REGISTER_NATIVES(textNatives) { - {"SMC_CreateParse", SMC_CreateParse}, + {"SMC_CreateParser", SMC_CreateParser}, {"SMC_ParseFile", SMC_ParseFile}, {"SMC_GetErrorString", SMC_GetErrorString}, {"SMC_SetParseStart", SMC_SetParseStart}, diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 3a7634a9..6e80f5ce 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -695,6 +695,9 @@ void HandleSystem::ReleasePrimHandle(unsigned int index) { /* Extra work to do. We need to find everything connected to this identity and release it. */ unsigned int ch_index; +#if defined _DEBUG + unsigned int old_index = 0; +#endif while ((ch_index = pHandle->ch_next) != 0) { pLocal = &m_Handles[ch_index]; diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc index 823f60ef..51c96312 100644 --- a/plugins/include/textparse.inc +++ b/plugins/include/textparse.inc @@ -38,7 +38,7 @@ enum SMCError * * @return A new Handle to an SMC Parse structure. */ -native Handle:SMC_CreateParse(); +native Handle:SMC_CreateParser(); /** * Parses an SMC file. From 5a49f1d99b822e210c4052961cf1d7779eff2c92 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:00:15 +0000 Subject: [PATCH 0340/1664] added Id svn:keywords property --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40370 --- sourcepawn/compiler/amx.h | 2 +- sourcepawn/compiler/amxdbg.h | 2 +- sourcepawn/compiler/libpawnc.c | 2 +- sourcepawn/compiler/sc.h | 2 +- sourcepawn/compiler/sc1.c | 2 +- sourcepawn/compiler/sc2.c | 2 +- sourcepawn/compiler/sc3.c | 2 +- sourcepawn/compiler/sc4.c | 2 +- sourcepawn/compiler/sc5.c | 2 +- sourcepawn/compiler/sc5.scp | 2 +- sourcepawn/compiler/sc6.c | 2 +- sourcepawn/compiler/sc7.c | 2 +- sourcepawn/compiler/sc7.scp | 2 +- sourcepawn/compiler/sci18n.c | 2 +- sourcepawn/compiler/sclist.c | 2 +- sourcepawn/compiler/scmemfil.c | 2 +- sourcepawn/compiler/scstate.c | 2 +- sourcepawn/compiler/scvars.c | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sourcepawn/compiler/amx.h b/sourcepawn/compiler/amx.h index 505932c4..577afff8 100644 --- a/sourcepawn/compiler/amx.h +++ b/sourcepawn/compiler/amx.h @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: amx.h 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ #ifndef AMX_H_INCLUDED diff --git a/sourcepawn/compiler/amxdbg.h b/sourcepawn/compiler/amxdbg.h index 606b4806..cccd09ff 100644 --- a/sourcepawn/compiler/amxdbg.h +++ b/sourcepawn/compiler/amxdbg.h @@ -21,7 +21,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: amxdbg.h 3612 2006-07-22 09:59:46Z thiadmer $ + * Version: $Id$ */ #ifndef AMXDBG_H_INCLUDED diff --git a/sourcepawn/compiler/libpawnc.c b/sourcepawn/compiler/libpawnc.c index ddf84261..051895f2 100644 --- a/sourcepawn/compiler/libpawnc.c +++ b/sourcepawn/compiler/libpawnc.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: libpawnc.c 3612 2006-07-22 09:59:46Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index d314f0f6..95f61483 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -25,7 +25,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc.h 3636 2006-08-14 15:42:05Z thiadmer $ + * Version: $Id$ */ #ifndef SC_H_INCLUDED #define SC_H_INCLUDED diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 9ecddcb5..646a8161 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc1.c 3636 2006-08-14 15:42:05Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 536a3e8a..ea861e27 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc2.c 3636 2006-08-14 15:42:05Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 5a8e0abf..1828a47b 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc3.c 3635 2006-08-13 12:19:41Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index 2f2f51c4..b3e7fb86 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc4.c 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc5.c b/sourcepawn/compiler/sc5.c index d9d0298a..82d411c1 100644 --- a/sourcepawn/compiler/sc5.c +++ b/sourcepawn/compiler/sc5.c @@ -19,7 +19,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc5.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id$ */ #include #if defined __WIN32__ || defined _WIN32 || defined __MSDOS__ diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index e2988d75..1af2cd33 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc5.sch 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]); diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 011028e4..184116b5 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -18,7 +18,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc6.c 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc7.c b/sourcepawn/compiler/sc7.c index f5a52d5a..82096c25 100644 --- a/sourcepawn/compiler/sc7.c +++ b/sourcepawn/compiler/sc7.c @@ -45,7 +45,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc7.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sc7.scp b/sourcepawn/compiler/sc7.scp index 3210cb35..856994ca 100644 --- a/sourcepawn/compiler/sc7.scp +++ b/sourcepawn/compiler/sc7.scp @@ -19,7 +19,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sc7.sch 3577 2006-06-02 16:22:52Z thiadmer $ + * Version: $Id$ */ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]); diff --git a/sourcepawn/compiler/sci18n.c b/sourcepawn/compiler/sci18n.c index 68c94a77..0c34ecd5 100644 --- a/sourcepawn/compiler/sci18n.c +++ b/sourcepawn/compiler/sci18n.c @@ -30,7 +30,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sci18n.c 3612 2006-07-22 09:59:46Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/sclist.c b/sourcepawn/compiler/sclist.c index bf25550d..fd8ccf0e 100644 --- a/sourcepawn/compiler/sclist.c +++ b/sourcepawn/compiler/sclist.c @@ -24,7 +24,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: sclist.c 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/scmemfil.c b/sourcepawn/compiler/scmemfil.c index c33d2485..a8dd0aae 100644 --- a/sourcepawn/compiler/scmemfil.c +++ b/sourcepawn/compiler/scmemfil.c @@ -22,7 +22,7 @@ * * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: scmemfil.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id$ */ #include diff --git a/sourcepawn/compiler/scstate.c b/sourcepawn/compiler/scstate.c index f7b4d1d4..1d383e2b 100644 --- a/sourcepawn/compiler/scstate.c +++ b/sourcepawn/compiler/scstate.c @@ -43,7 +43,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: scstate.c 3579 2006-06-06 13:35:29Z thiadmer $ + * Version: $Id$ */ #include #include diff --git a/sourcepawn/compiler/scvars.c b/sourcepawn/compiler/scvars.c index c1419386..21e8c2b9 100644 --- a/sourcepawn/compiler/scvars.c +++ b/sourcepawn/compiler/scvars.c @@ -20,7 +20,7 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * Version: $Id: scvars.c 3633 2006-08-11 16:20:18Z thiadmer $ + * Version: $Id$ */ #include #include /* for _MAX_PATH */ From a9254e4b9a1b9704828b4fa71b4f819c2b29e53b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:17:20 +0000 Subject: [PATCH 0341/1664] added important notice about keywords --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40371 --- NOTICE.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 NOTICE.txt diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 00000000..c596b069 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,22 @@ +We now use svn:keywords "Id" on all .c/.cpp/.h/.sp/.inc files. Please make sure your client is configured properly. + +WINDOWS: + Open your Application Data folder. + Windows XP/2000: C:\Documents and Settings\\Application Data + Windows Vista: C:\Users\\Application Data + + Under Application Data, go to Subversion. Open the "config" file with a text editor. + +LINUX: + Open ~/.subversion/config with your favorite text editor. + +Under [miscellany], uncomment this line: +# enable-auto-props = yes + +Under [auto-props], add these lines: +*.c = svn:keywords=Id +*.cpp = svn:keywords=Id +*.h = svn:keywords=Id +*.sp = svn:keywords=Id +*.inc = svn:keywords=Id + From 25cdfb2c1bf200cf6dd1cf8ecc130f562977eb40 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:32:29 +0000 Subject: [PATCH 0342/1664] Added header license info --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40372 --- sourcepawn/jit/x86/dll_exports.cpp | 13 +++++++++++++ sourcepawn/jit/x86/dll_exports.h | 13 +++++++++++++ sourcepawn/jit/x86/jit_x86.cpp | 13 +++++++++++++ sourcepawn/jit/x86/jit_x86.h | 13 +++++++++++++ sourcepawn/jit/x86/opcode_helpers.cpp | 13 +++++++++++++ sourcepawn/jit/x86/opcode_helpers.h | 13 +++++++++++++ sourcepawn/jit/x86/ungen_opcodes.h | 13 +++++++++++++ sourcepawn/jit/x86/x86_macros.h | 13 +++++++++++++ 8 files changed, 104 insertions(+) diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index 3e7ea3dd..66a074db 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "jit_x86.h" diff --git a/sourcepawn/jit/x86/dll_exports.h b/sourcepawn/jit/x86/dll_exports.h index 653773f6..eeb4eaff 100644 --- a/sourcepawn/jit/x86/dll_exports.h +++ b/sourcepawn/jit/x86/dll_exports.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 00a2276d..9979f18c 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index a3444a48..134f7eed 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 6552b3e2..175a357e 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -1,3 +1,16 @@ +** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index b19890d7..85cfba45 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_ diff --git a/sourcepawn/jit/x86/ungen_opcodes.h b/sourcepawn/jit/x86/ungen_opcodes.h index abae1dba..63cebff4 100644 --- a/sourcepawn/jit/x86/ungen_opcodes.h +++ b/sourcepawn/jit/x86/ungen_opcodes.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_ #define _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_ diff --git a/sourcepawn/jit/x86/x86_macros.h b/sourcepawn/jit/x86/x86_macros.h index e623c6c8..0675fe33 100644 --- a/sourcepawn/jit/x86/x86_macros.h +++ b/sourcepawn/jit/x86/x86_macros.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_JIT_X86_MACROS_H #define _INCLUDE_JIT_X86_MACROS_H From 3f921621e8e9c0bd5e1f337476d49df42455649b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:33:01 +0000 Subject: [PATCH 0343/1664] oops, tee hee --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40373 --- sourcepawn/jit/x86/opcode_helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 175a357e..d31e7728 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -1,4 +1,4 @@ -** +/** * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== From 3f072e10979247179339b034a9d0b6c4eb978203 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:33:15 +0000 Subject: [PATCH 0344/1664] added license header --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40374 --- sourcepawn/jit/jit_helpers.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sourcepawn/jit/jit_helpers.h b/sourcepawn/jit/jit_helpers.h index d6b4b810..f2161e5c 100644 --- a/sourcepawn/jit/jit_helpers.h +++ b/sourcepawn/jit/jit_helpers.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ #define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_ From 21fb4856e0fad38ba4b7bbb600a291a84c2cebcf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:36:38 +0000 Subject: [PATCH 0345/1664] added license headers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40375 --- core/AdminCache.cpp | 13 +++++++++++++ core/AdminCache.h | 13 +++++++++++++ core/CDbgReporter.cpp | 13 +++++++++++++ core/CDbgReporter.h | 13 +++++++++++++ core/CLogger.cpp | 13 +++++++++++++ core/CLogger.h | 13 +++++++++++++ core/CPlayer.cpp | 13 +++++++++++++ core/CPlayer.h | 13 +++++++++++++ core/CPlayerManager.cpp | 13 +++++++++++++ core/CPlayerManager.h | 13 +++++++++++++ core/CTextParsers.cpp | 13 +++++++++++++ core/CTextParsers.h | 13 +++++++++++++ core/CTranslator.cpp | 13 +++++++++++++ core/CTranslator.h | 13 +++++++++++++ core/sm_autonatives.cpp | 13 +++++++++++++ core/sm_autonatives.h | 13 +++++++++++++ core/sm_globals.h | 13 +++++++++++++ core/sm_memtable.cpp | 13 +++++++++++++ core/sm_memtable.h | 13 +++++++++++++ core/sm_srvcmds.cpp | 13 +++++++++++++ core/sm_srvcmds.h | 13 +++++++++++++ core/sm_stringutil.cpp | 13 +++++++++++++ core/sm_stringutil.h | 13 +++++++++++++ core/sm_trie.cpp | 13 +++++++++++++ core/sm_trie.h | 13 +++++++++++++ core/sm_version.h | 13 +++++++++++++ core/smn_admin.cpp | 13 +++++++++++++ core/smn_filesystem.cpp | 13 +++++++++++++ core/smn_float.cpp | 13 +++++++++++++ core/smn_handles.cpp | 13 +++++++++++++ core/smn_player.cpp | 13 +++++++++++++ core/smn_string.cpp | 13 +++++++++++++ core/smn_textparse.cpp | 13 +++++++++++++ core/sourcemm_api.cpp | 13 +++++++++++++ core/sourcemm_api.h | 13 +++++++++++++ core/sourcemod.cpp | 13 +++++++++++++ core/sourcemod.h | 13 +++++++++++++ core/systems/ExtensionSys.cpp | 13 +++++++++++++ core/systems/ExtensionSys.h | 13 +++++++++++++ core/systems/ForwardSys.cpp | 13 +++++++++++++ core/systems/ForwardSys.h | 13 +++++++++++++ core/systems/HandleSys.cpp | 13 +++++++++++++ core/systems/HandleSys.h | 13 +++++++++++++ core/systems/LibrarySys.cpp | 13 +++++++++++++ core/systems/LibrarySys.h | 13 +++++++++++++ core/systems/PluginInfoDatabase.cpp | 13 +++++++++++++ core/systems/PluginInfoDatabase.h | 13 +++++++++++++ core/systems/PluginSys.cpp | 13 +++++++++++++ core/systems/PluginSys.h | 13 +++++++++++++ core/systems/ShareSys.cpp | 13 +++++++++++++ core/systems/ShareSys.h | 13 +++++++++++++ 51 files changed, 663 insertions(+) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index e1a15d4b..79d4a254 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "AdminCache.h" diff --git a/core/AdminCache.h b/core/AdminCache.h index 19382995..a4bb38d0 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_ #define _INCLUDE_SOURCEMOD_ADMINCACHE_H_ diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp index 29d81794..0833dbd7 100644 --- a/core/CDbgReporter.cpp +++ b/core/CDbgReporter.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "CDbgReporter.h" #include "CLogger.h" #include "PluginSys.h" diff --git a/core/CDbgReporter.h b/core/CDbgReporter.h index 650550e1..523f26f9 100644 --- a/core/CDbgReporter.h +++ b/core/CDbgReporter.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ #define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 65354f49..04962c68 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include "sourcemod.h" #include "sourcemm_api.h" diff --git a/core/CLogger.h b/core/CLogger.h index 89ad0175..df4d77a0 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_ #define _INCLUDE_SOURCEMOD_CLOGGER_H_ diff --git a/core/CPlayer.cpp b/core/CPlayer.cpp index fd4f9aef..1dc5de8c 100644 --- a/core/CPlayer.cpp +++ b/core/CPlayer.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "CPlayer.h" CPlayer::CPlayer() diff --git a/core/CPlayer.h b/core/CPlayer.h index 1fb23a2e..4324ad30 100644 --- a/core/CPlayer.h +++ b/core/CPlayer.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CPLAYER_H_ #define _INCLUDE_SOURCEMOD_CPLAYER_H_ diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 02952b24..c242ff5a 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "CPlayerManager.h" #include "ForwardSys.h" diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index 042476bf..98060a8e 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ #define _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index 48f630b6..c3180536 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/CTextParsers.h b/core/CTextParsers.h index f1e8c158..6150fccc 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index eeacd96f..515227ad 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/CTranslator.h b/core/CTranslator.h index cb0da51f..6899626e 100644 --- a/core/CTranslator.h +++ b/core/CTranslator.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_TRANSLATOR_H_ #define _INCLUDE_SOURCEMOD_TRANSLATOR_H_ diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp index 370386a6..a0740b2e 100644 --- a/core/sm_autonatives.cpp +++ b/core/sm_autonatives.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_autonatives.h" #include "PluginSys.h" diff --git a/core/sm_autonatives.h b/core/sm_autonatives.h index 8b3c06ad..170998c0 100644 --- a/core/sm_autonatives.h +++ b/core/sm_autonatives.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ #define _INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ diff --git a/core/sm_globals.h b/core/sm_globals.h index 00024b62..7d65b1f8 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_GLOBALS_H_ #define _INCLUDE_SOURCEMOD_GLOBALS_H_ diff --git a/core/sm_memtable.cpp b/core/sm_memtable.cpp index dc15dff2..fc8b1393 100644 --- a/core/sm_memtable.cpp +++ b/core/sm_memtable.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "sm_memtable.h" diff --git a/core/sm_memtable.h b/core/sm_memtable.h index 35066982..043e2618 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_ #define _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_ diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 3d307e15..c1347ea7 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_srvcmds.h" #include "sm_version.h" #include "sm_stringutil.h" diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index f381fc26..11b399ee 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ #define _INCLUDE_SOURCEMOD_SERVERCOMMANDS_H_ diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 32e0fcfa..133a2a87 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 8ef7336f..61fe0fce 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_STRINGUTIL_H_ #define _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index eaad3485..b87faed2 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/sm_trie.h b/core/sm_trie.h index 9c008081..38acd42d 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ #define _INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ diff --git a/core/sm_version.h b/core/sm_version.h index 6caa84d4..3b96e2aa 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_VERSION_H_ #define _INCLUDE_SOURCEMOD_VERSION_H_ diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index fc635445..ee327e5c 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_globals.h" #include "AdminCache.h" #include "ForwardSys.h" diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 0eaa876c..f875b0a1 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include "sm_globals.h" #include "HandleSys.h" diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 806349ff..bacbe516 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 875f8e4e..204c344f 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_globals.h" #include "HandleSys.h" #include "PluginSys.h" diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 52a974e5..aaa44932 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "CPlayerManager.h" #include "sm_stringutil.h" diff --git a/core/smn_string.cpp b/core/smn_string.cpp index eaa874ae..162ea4bd 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_platform.h" #include #include diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index f1ef0340..35e4c79a 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "sm_globals.h" #include "CTextParsers.h" #include "HandleSys.h" diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index e81cf40f..1bbd5f0b 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include "sourcemm_api.h" #include "sm_version.h" diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 7e753363..12e6cf3b 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_MM_API_H_ #define _INCLUDE_SOURCEMOD_MM_API_H_ diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index a1adf21f..d482506b 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include "sourcemod.h" #include "sourcemm_api.h" diff --git a/core/sourcemod.h b/core/sourcemod.h index dcdf4148..f2ce4961 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ #define _INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index ed97c5de..0b47740a 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "ExtensionSys.h" #include "LibrarySys.h" #include "ShareSys.h" diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index 91352ceb..e4d32375 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_ diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 124ac058..d627e5e3 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 617aaf03..73e58663 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ #define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 6e80f5ce..7ef9cc1d 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "HandleSys.h" #include "ShareSys.h" #include "PluginSys.h" diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 1b651ba8..46b56d7a 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index fa1df0dc..aa3b1d25 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index bea6b4df..83009bdf 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_ #define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_ diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index 47d04d8e..eb0705be 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "PluginInfoDatabase.h" diff --git a/core/systems/PluginInfoDatabase.h b/core/systems/PluginInfoDatabase.h index 9c088e69..f40724d9 100644 --- a/core/systems/PluginInfoDatabase.h +++ b/core/systems/PluginInfoDatabase.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_ #define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_ diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 40850787..b1818118 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include "PluginSys.h" #include "ShareSys.h" diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 721b94ba..f463dade 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index f72f1f99..95e7184d 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "ShareSys.h" #include "HandleSys.h" #include "ExtensionSys.h" diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index 21a09468..8c9fe6f3 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -1,3 +1,16 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ #define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ From e281a27c14704e82a1941ef040feb10ba4f49cd6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 25 Jan 2007 22:39:12 +0000 Subject: [PATCH 0346/1664] renamed relevant areas to SorucePawn --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40376 --- core/vm/sp_vm_basecontext.cpp | 13 +++++++++++++ core/vm/sp_vm_basecontext.h | 13 +++++++++++++ core/vm/sp_vm_engine.cpp | 13 +++++++++++++ core/vm/sp_vm_engine.h | 13 +++++++++++++ core/vm/sp_vm_function.cpp | 13 +++++++++++++ core/vm/sp_vm_function.h | 13 +++++++++++++ sourcepawn/jit/jit_helpers.h | 6 +++--- sourcepawn/jit/x86/dll_exports.cpp | 6 +++--- sourcepawn/jit/x86/dll_exports.h | 6 +++--- sourcepawn/jit/x86/jit_x86.cpp | 6 +++--- sourcepawn/jit/x86/jit_x86.h | 6 +++--- sourcepawn/jit/x86/opcode_helpers.cpp | 6 +++--- sourcepawn/jit/x86/opcode_helpers.h | 6 +++--- sourcepawn/jit/x86/ungen_opcodes.h | 6 +++--- sourcepawn/jit/x86/x86_macros.h | 6 +++--- 15 files changed, 105 insertions(+), 27 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index f1c0fae5..0107045b 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 8f9f1239..232a7967 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index fda2d009..ba1aa225 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index f30d0b0e..f43c6b91 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index ceb78dc4..04ce7a23 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "PluginSys.h" diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index d94df739..b61a51fa 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -1,3 +1,16 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ diff --git a/sourcepawn/jit/jit_helpers.h b/sourcepawn/jit/jit_helpers.h index f2161e5c..cdf257ce 100644 --- a/sourcepawn/jit/jit_helpers.h +++ b/sourcepawn/jit/jit_helpers.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index 66a074db..6ac0a56c 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/dll_exports.h b/sourcepawn/jit/x86/dll_exports.h index eeb4eaff..fa3859f9 100644 --- a/sourcepawn/jit/x86/dll_exports.h +++ b/sourcepawn/jit/x86/dll_exports.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 9979f18c..0e561626 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 134f7eed..4d65745a 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index d31e7728..dd63abef 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== +* ================================================================ +* SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. +* ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index 85cfba45..08f041f2 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/ungen_opcodes.h b/sourcepawn/jit/x86/ungen_opcodes.h index 63cebff4..60bd6a45 100644 --- a/sourcepawn/jit/x86/ungen_opcodes.h +++ b/sourcepawn/jit/x86/ungen_opcodes.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed diff --git a/sourcepawn/jit/x86/x86_macros.h b/sourcepawn/jit/x86/x86_macros.h index 0675fe33..256f6ce6 100644 --- a/sourcepawn/jit/x86/x86_macros.h +++ b/sourcepawn/jit/x86/x86_macros.h @@ -1,7 +1,7 @@ /** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ * * This file is not open source and may not be copied without explicit * written permission of AlliedModders LLC. This file may not be redistributed From 676a6ea7605b6a9661b09d95f45f4091e60c29eb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 01:55:06 +0000 Subject: [PATCH 0347/1664] Filled out more license headers Completed lots of missing documentation Fixed /** on one-liners, must be /**< --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40377 --- core/msvc8/sourcemod_mm.vcproj | 4 + core/vm/sp_vm_engine.cpp | 1 + public/IAdminSystem.h | 84 +++++--- public/IExtensionSys.h | 33 +++- public/IForwardSys.h | 95 +++++++--- public/IHandleSys.h | 128 +++++++++---- public/ILibrarySys.h | 22 ++- public/IPluginSys.h | 60 ++++-- public/IRootConsoleMenu.h | 30 ++- public/IShareSys.h | 30 ++- public/ISourceMod.h | 35 +++- public/ITextParsers.h | 69 +++++-- public/doxygen/SourceMod.doxyfile | 262 +++++++++++++++++++++++++ public/extensions/IThreader.h | 40 +++- public/sample_ext/extension.cpp | 7 +- public/sample_ext/extension.h | 7 + public/sample_ext/smsdk_config.h | 5 + public/sample_ext/smsdk_ext.cpp | 43 +++-- public/sample_ext/smsdk_ext.h | 50 +++++ public/sm_platform.h | 17 +- public/sourcepawn/sp_file_headers.h | 194 +++++++++++-------- public/sourcepawn/sp_typeutil.h | 32 ++++ public/sourcepawn/sp_vm_api.h | 44 +++-- public/sourcepawn/sp_vm_base.h | 20 ++ public/sourcepawn/sp_vm_types.h | 284 +++++++++++++++------------- 25 files changed, 1215 insertions(+), 381 deletions(-) create mode 100644 public/doxygen/SourceMod.doxyfile diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a6bfccfa..9095ead3 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -381,6 +381,10 @@ RelativePath="..\..\public\ITextParsers.h" > + + #include +/** + * @file IExtensionSys.h + * @brief Defines the interface for loading/unloading/managing extensions. + */ + namespace SourceMod { class IExtensionInterface; - typedef void * ITERATOR; + typedef void * ITERATOR; /**< Generic pointer for dependency iterators */ /** - * @brief Encapsulates an IExtension. + * @brief Encapsulates an IExtensionInterface and its dependencies. */ class IExtension { @@ -78,6 +97,9 @@ namespace SourceMod virtual bool IsRunning(char *error, size_t maxlength) =0; }; + /** + * @brief Version code of the IExtensionInterface API itself. + */ #define SMINTERFACE_EXTENSIONAPI_VERSION 1 /** @@ -86,6 +108,7 @@ namespace SourceMod class IExtensionInterface { public: + /** Returns the interface API version */ virtual unsigned int GetExtensionVersion() { return SMINTERFACE_EXTENSIONAPI_VERSION; @@ -172,12 +195,18 @@ namespace SourceMod #define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager" #define SMINTERFACE_EXTENSIONMANAGER_VERSION 1 + /** + * @brief Not currently used. + */ enum ExtensionLifetime { ExtLifetime_Forever, //Extension will never be unloaded automatically ExtLifetime_Map, //Extension will be unloaded at the end of the map }; + /** + * @brief Manages the loading/unloading of extensions. + */ class IExtensionManager : public SMInterface { public: diff --git a/public/IForwardSys.h b/public/IForwardSys.h index bd023adc..05608fef 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -1,6 +1,32 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ #define _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ +/** + * @file IForwardSys.h + * @brief Defines the interface for managing collections ("forwards") of plugin calls. + * + * The Forward System is responsible for managing automated collections of IPluginFunctions. + * It thus provides wrappers to calling many functions at once. There are two types of such + * wrappers: Managed and Unmanaged. Confusingly, these terms refer to whether the user manages + * the forwards, not Core. Managed forwards are completely managed by the user, and are custom + * editable collections. Unmanaged forwards are the opposite, and will only work on a single global + * function name in all plugins. + */ + #include #include #include @@ -10,31 +36,40 @@ using namespace SourcePawn; #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" #define SMINTERFACE_FORWARDMANAGER_VERSION 1 -/** +/* * There is some very important documentation at the bottom of this file. * Readers interested in knowing more about the forward system, scrolling down is a must! */ namespace SourceMod { + /** + * @brief Defines the event hook result types plugins can return. + */ enum ResultType { - Pl_Continue = 0, /* No result */ - Pl_Handled = 1, /* Result was handled, stop at the end */ - Pl_Stop = 2, /* Result was handled, stop now */ + Pl_Continue = 0, /**< No result */ + Pl_Handled = 1, /**< Result was handled, stop at the end */ + Pl_Stop = 2, /**< Result was handled, stop now */ }; + /** + * @brief Defines how a forward iterates through plugin functions. + */ enum ExecType { - ET_Ignore = 0, /* Ignore all return values, return 0 */ - ET_Single = 1, /* Only return the last exec, ignore all others */ - ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */ - ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */ - ET_Custom = 4, /* Ignored or handled by an IForwardFilter */ + ET_Ignore = 0, /**< Ignore all return values, return 0 */ + ET_Single = 1, /**< Only return the last exec, ignore all others */ + ET_Event = 2, /**< Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */ + ET_Hook = 3, /**< Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */ + ET_Custom = 4, /**< Ignored or handled by an IForwardFilter */ }; class IForward; + /** + * @brief Allows interception of how the Forward System executes functions. + */ class IForwardFilter { public: @@ -89,18 +124,16 @@ namespace SourceMod }; /** - * @brief Abstracts multiple function calling. + * @brief Unmanaged Forward, abstracts calling multiple functions as "forwards," or collections of functions. * - * NOTE: Parameters should be pushed in forward order, unlike - * the virtual machine/IPluginContext order. - * NOTE: Some functions are repeated in here because their - * documentation differs from their IPluginFunction equivalents. - * Missing are the Push functions, whose only doc change is that - * they throw SP_ERROR_PARAM on type mismatches. + * Parameters should be pushed in forward order, unlike the virtual machine/IPluginContext order. + * Some functions are repeated in here because their documentation differs from their IPluginFunction equivalents. + * Missing are the Push functions, whose only doc change is that they throw SP_ERROR_PARAM on type mismatches. */ class IForward : public ICallable { public: + /** Virtual Destructor */ virtual ~IForward() { } @@ -151,7 +184,9 @@ namespace SourceMod int flags=0) =0; }; - + /** + * @brief Managed Forward, same as IForward, except the collection can be modified. + */ class IChangeableForward : public IForward { public: @@ -189,7 +224,7 @@ namespace SourceMod * NOTE: If used during a call, function is temporarily queued until calls are over. * * @param ctx Context to use as a look-up. - * @param funcid Function id to add. + * @param index Function id to add. * @return True on success, otherwise false. */ virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; @@ -203,18 +238,24 @@ namespace SourceMod #define SP_PARAMTYPE_ARRAY (4<<1)|SP_PARAMFLAG_BYREF #define SP_PARAMTYPE_VARARG (5<<1) + /** + * @brief Describes the various ways to pass parameters to plugins. + */ enum ParamType { - Param_Any = SP_PARAMTYPE_ANY, - Param_Cell = SP_PARAMTYPE_CELL, - Param_Float = SP_PARAMTYPE_FLOAT, - Param_String = SP_PARAMTYPE_STRING, - Param_Array = SP_PARAMTYPE_ARRAY, - Param_VarArgs = SP_PARAMTYPE_VARARG, - Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF, - Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF, + Param_Any = SP_PARAMTYPE_ANY, /**< Any data type can be pushed */ + Param_Cell = SP_PARAMTYPE_CELL, /**< Only basic cells can be pushed */ + Param_Float = SP_PARAMTYPE_FLOAT, /**< Only floats can be pushed */ + Param_String = SP_PARAMTYPE_STRING, /**< Only strings can be pushed */ + Param_Array = SP_PARAMTYPE_ARRAY, /**< Only arrays can be pushed */ + Param_VarArgs = SP_PARAMTYPE_VARARG, /**< Same as "..." in plugins, anything can be pushed, but it will always be byref */ + Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF, /**< Only a cell by reference can be pushed */ + Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF, /**< Only a float by reference can be pushed */ }; + /** + * @brief Provides functions for creating/destroying managed and unmanaged forwards. + */ class IForwardManager : public SMInterface { public: @@ -287,7 +328,7 @@ namespace SourceMod }; }; -/** +/* * In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing * a function ID and an AMX structure. The forward structure itself did very little but hold parameter types. * An execution call worked like this: diff --git a/public/IHandleSys.h b/public/IHandleSys.h index ba56bb43..e9631892 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -1,24 +1,63 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ +/** + * @file IHandleSys.h + * @brief Defines the interface for creating, reading, and removing Handles. + * + * The Handle system abstracts generic pointers into typed objects represented by + * 32bit codes. This is extremely useful for verifying data integrity and cross-platform + * support in SourcePawn scripts. When a Plugin unloads, all its Handles are freed, ensuring + * that no memory leaks are present, They have reference counts and thus can be duplicated, + * or cloned, and are safe to pass between Plugins even if one is unloaded. + * + * Handles are created with a given type (custom types may be created). They can have + * per-Identity permissions for deletion, reading, and cloning. They also support generic + * operations. For example, deleting a Handle will call that type's destructor on the generic + * pointer, making cleanup easier for users and eliminating memory leaks. + */ + #include #include #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" #define SMINTERFACE_HANDLESYSTEM_VERSION 1 +/** Specifies no Identity */ #define DEFAULT_IDENTITY NULL +/** Specifies no Type. This is invalid for everything but reading a Handle. */ +#define NO_HANDLE_TYPE 0 +/** Specifies an invalid/NULL Handle */ +#define BAD_HANDLE 0 namespace SourceMod { /** - * Both of these types have invalid values of '0' for error checking. + * @brief Represents a Handle Type ID. */ typedef unsigned int HandleType_t; + + /** + * @brief Represents a Handle ID. + */ typedef unsigned int Handle_t; - /** + /* * About type checking: * Types can be inherited - a Parent type ("Supertype") can have child types. * When accessing handles, type checking is done. This table shows how this is resolved: @@ -31,88 +70,100 @@ namespace SourceMod * Child Child Success */ + /** + * @brief Lists the possible handle error codes. + */ enum HandleError { - HandleError_None = 0, /* No error */ - HandleError_Changed, /* The handle has been freed and reassigned */ - HandleError_Type, /* The handle has a different type registered */ - HandleError_Freed, /* The handle has been freed */ - HandleError_Index, /* generic internal indexing error */ - HandleError_Access, /* No access permitted to free this handle */ - HandleError_Limit, /* The limited number of handles has been reached */ - HandleError_Identity, /* The identity token was not usable */ - HandleError_Owner, /* Owners do not match for this operation */ - HandleError_Version, /* Unrecognized security structure version */ - HandleError_Parameter, /* An invalid parameter was passed */ - HandleError_NoInherit, /* This type cannot be inherited */ + HandleError_None = 0, /**< No error */ + HandleError_Changed, /**< The handle has been freed and reassigned */ + HandleError_Type, /**< The handle has a different type registered */ + HandleError_Freed, /**< The handle has been freed */ + HandleError_Index, /**< generic internal indexing error */ + HandleError_Access, /**< No access permitted to free this handle */ + HandleError_Limit, /**< The limited number of handles has been reached */ + HandleError_Identity, /**< The identity token was not usable */ + HandleError_Owner, /**< Owners do not match for this operation */ + HandleError_Version, /**< Unrecognized security structure version */ + HandleError_Parameter, /**< An invalid parameter was passed */ + HandleError_NoInherit, /**< This type cannot be inherited */ }; /** - * Access rights specific to a type + * @brief Lists access rights specific to a type. */ enum HTypeAccessRight { - HTypeAccess_Create = 0, /* Handles of this type can be created (DEFAULT=false) */ - HTypeAccess_Inherit, /* Sub-types can inherit this type (DEFAULT=false) */ + HTypeAccess_Create = 0, /**< Handles of this type can be created (DEFAULT=false) */ + HTypeAccess_Inherit, /**< Sub-types can inherit this type (DEFAULT=false) */ /* -------------- */ - HTypeAccess_TOTAL, /* Total number of type access rights */ + HTypeAccess_TOTAL, /**< Total number of type access rights */ }; /** - * Access rights specific to a Handle. These rights are exclusive. - * For example, you do not need "read" access to delete or clone. + * @brief Lists access rights specific to a Handle. + * + * These rights are exclusive. For example, you do not need "read" access to delete or clone. */ enum HandleAccessRight { - HandleAccess_Read, /* Can be read (DEFAULT=ident only) */ - HandleAccess_Delete, /* Can be deleted (DEFAULT=owner only) */ - HandleAccess_Clone, /* Can be cloned (DEFAULT=any) */ + HandleAccess_Read, /**< Can be read (DEFAULT=ident only) */ + HandleAccess_Delete, /**< Can be deleted (DEFAULT=owner only) */ + HandleAccess_Clone, /**< Can be cloned (DEFAULT=any) */ /* ------------- */ - HandleAccess_TOTAL, /* Total number of access rights */ + HandleAccess_TOTAL, /**< Total number of access rights */ }; - #define HANDLE_RESTRICT_IDENTITY (1<<0) /* Access is restricted to the identity */ - #define HANDLE_RESTRICT_OWNER (1<<1) /* Access is restricted to the owner */ + /** Access is restricted to the identity */ + #define HANDLE_RESTRICT_IDENTITY (1<<0) + /** Access is restricted to the owner */ + #define HANDLE_RESTRICT_OWNER (1<<1) /** - * This is used to define per-type access rights. + * @brief This is used to define per-type access rights. */ struct TypeAccess { + /** Constructor */ TypeAccess() { hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; } - unsigned int hsVersion; - IdentityToken_t *ident; - bool access[HTypeAccess_TOTAL]; + unsigned int hsVersion; /**< Handle API version */ + IdentityToken_t *ident; /**< Identity owning this type */ + bool access[HTypeAccess_TOTAL]; /**< Access array */ }; /** - * This is used to define per-Handle access rights. + * @brief This is used to define per-Handle access rights. */ struct HandleAccess { + /** Constructor */ HandleAccess() { hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; } - unsigned int hsVersion; - unsigned int access[HandleAccess_TOTAL]; + unsigned int hsVersion; /**< Handle API version */ + unsigned int access[HandleAccess_TOTAL]; /**< Access array */ }; /** - * This pair of tokens is used for identification. + * @brief This pair of tokens is used for identification. */ struct HandleSecurity { - IdentityToken_t *pOwner; /* Owner of the Handle */ - IdentityToken_t *pIdentity; /* Owner of the Type */ + IdentityToken_t *pOwner; /**< Owner of the Handle */ + IdentityToken_t *pIdentity; /**< Owner of the Type */ }; + /** + * @brief Hooks type-specific Handle operations. + */ class IHandleTypeDispatch { public: + /** Returns the Handle API version */ virtual unsigned int GetDispatchVersion() { return SMINTERFACE_HANDLESYSTEM_VERSION; @@ -124,6 +175,9 @@ namespace SourceMod virtual void OnHandleDestroy(HandleType_t type, void *object) =0; }; + /** + * @brief Provides functions for managing Handles. + */ class IHandleSys : public SMInterface { public: @@ -202,7 +256,7 @@ namespace SourceMod * NOTE: This function will decrement the internal reference counter. It will * only perform any further action if the counter hits 0. * - * @param type Handle_t identifier to destroy. + * @param handle Handle_t identifier to destroy. * @param pSecurity Security information struct (may be NULL). * @return A HandleError error code. */ diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index 000668d6..a8bafacf 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -1,6 +1,25 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ #define _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ +/** + * @file ILibrarySys.h + * @brief Defines platform-dependent operations, such as opening libraries and files. + */ + #include namespace SourceMod @@ -11,9 +30,9 @@ namespace SourceMod class ILibrary { public: + /** Virtual destructor (calls CloseLibrary) */ virtual ~ILibrary() { - /* Calling delete will call CloseLibrary! */ }; public: /** @@ -36,6 +55,7 @@ namespace SourceMod class IDirectory { public: + /** Virtual destructor */ virtual ~IDirectory() { } diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 589b788f..6f4846fb 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -1,12 +1,32 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ #define _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ +/** + * @file IPluginSys.h + * @brief Defines the interface for the Plugin System, which manages loaded plugins. + */ + #include #include #define SMINTERFACE_PLUGINSYSTEM_NAME "IPluginManager" #define SMINTERFACE_PLUGINSYSTEM_VERSION 1 +/** Context user slot 3 is used Core for holding an IPluginContext pointer. */ #define SM_CONTEXTVAR_USER 3 namespace SourceMod @@ -14,35 +34,33 @@ namespace SourceMod class IPlugin; /** - * @brief Encapsulates plugin public information. + * @brief Encapsulates plugin public information exposed through "myinfo." */ typedef struct sm_plugininfo_s { - const char *name; - const char *author; - const char *description; - const char *version; - const char *url; + const char *name; /**< Plugin name */ + const char *author; /**< Plugin author */ + const char *description; /**< Plugin description */ + const char *version; /**< Plugin version string */ + const char *url; /**< Plugin URL */ } sm_plugininfo_t; /** * @brief Describes the usability status of a plugin. - * Note: The status "Loaded" and "Created" are only reachable - * during map load. */ enum PluginStatus { - Plugin_Running=0, /* Plugin is running */ + Plugin_Running=0, /**< Plugin is running */ /* All states below are unexecutable */ - Plugin_Paused, /* Plugin is loaded but paused */ - Plugin_Error, /* Plugin is loaded but errored/locked */ + Plugin_Paused, /**< Plugin is loaded but paused */ + Plugin_Error, /**< Plugin is loaded but errored/locked */ /* All states below do not have all natives */ - Plugin_Loaded, /* Plugin has passed loading and can be finalized */ - Plugin_Failed, /* Plugin has a fatal failure */ - Plugin_Created, /* Plugin is created but not initialized */ - Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */ - Plugin_BadLoad, /* Plugin failed to load */ + Plugin_Loaded, /**< Plugin has passed loading and can be finalized */ + Plugin_Failed, /**< Plugin has a fatal failure */ + Plugin_Created, /**< Plugin is created but not initialized */ + Plugin_Uncompiled, /**< Plugin is not yet compiled by the JIT */ + Plugin_BadLoad, /**< Plugin failed to load */ }; @@ -51,10 +69,10 @@ namespace SourceMod */ enum PluginType { - PluginType_Private, /* Plugin is privately managed and receives no forwards */ - PluginType_MapUpdated, /* Plugin will never be unloaded unless for updates on mapchange */ - PluginType_MapOnly, /* Plugin will be removed at mapchange */ - PluginType_Global, /* Plugin will never be unloaded or updated */ + PluginType_Private, /**< Plugin is privately managed and receives no forwards */ + PluginType_MapUpdated, /**< Plugin will never be unloaded unless for updates on mapchange */ + PluginType_MapOnly, /**< Plugin will be removed at mapchange */ + PluginType_Global, /**< Plugin will never be unloaded or updated */ }; /** @@ -63,6 +81,7 @@ namespace SourceMod class IPlugin { public: + /** Virtual destructor */ virtual ~IPlugin() { } @@ -140,6 +159,7 @@ namespace SourceMod class IPluginIterator { public: + /** Virtual destructor */ virtual ~IPluginIterator() { }; diff --git a/public/IRootConsoleMenu.h b/public/IRootConsoleMenu.h index fc389b5a..01b5d4f3 100644 --- a/public/IRootConsoleMenu.h +++ b/public/IRootConsoleMenu.h @@ -1,11 +1,29 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ #define _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ /** - * @brief Note: This interface is not exposed. - * The reason should be obvious: we do not want users touching the "root" console menu. - * If we exposed this, every little plugin would be dropping down a silly set of user commands, - * whereas this menu is explicitly provided for stuff that only Core itself is capable of managing. + * @file IRootConsoleMenu.h + * @brief Defines the interface for adding options to the "sm" console command. + * + * This interface is not yet exported. It will be eventually. The initial reason should + * be obvious: we do not want users actually touching it. If we exposed this, every little + * plugin would be dropping down a silly set of user commands, and exploiting/cluttering the menu. + * Since this menu is explicitly provided for stuff that only Core itself is capable of managing, + * we won't expose it until a legitimate reason comes up. */ namespace SourceMod @@ -80,8 +98,8 @@ namespace SourceMod * N being the length of the command name. This is subject to change in case we * account for Valve's font choices. * - * @param option String containing the command option. - * @param description String containing the command description. + * @param cmd String containing the command option. + * @param text String containing the command description. */ virtual void DrawGenericOption(const char *cmd, const char *text) =0; }; diff --git a/public/IShareSys.h b/public/IShareSys.h index ab8f4525..528e4233 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -1,16 +1,42 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ #define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ +/** + * @file IShareSys.h + * @brief Defines the Share System, responsible for shared resources and dependencies. + * + * The Share System also manages the Identity_t data type, although this is internally + * implemented with the Handle System. + */ + #include -#define NO_IDENTITY 0 namespace SourceMod { class IExtension; struct IdentityToken_t; + + /** Forward declaration from IHandleSys.h */ typedef unsigned int HandleType_t; + + /** Forward declaration from IHandleSys.h */ typedef HandleType_t IdentityType_t; + /** * @brief Defines the base functionality required by a shared interface. */ @@ -79,7 +105,7 @@ namespace SourceMod * NOTE: Adding natives currently does not bind them to any loaded plugins. * You must manually bind late natives. * - * @param token Identity token of parent object. + * @param myself Identity token of parent object. * @param natives Array of natives to add. The last entry must have NULL members. */ virtual void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0; diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 43ec9cd5..bfdf4897 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -1,6 +1,25 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ #define _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ +/** + * @file ISourceMod.h + * @brief Defines miscellanious helper functions useful to extensions. + */ + #include #include @@ -9,14 +28,20 @@ namespace SourceMod { + /** + * @brief Describes various ways of formatting a base path. + */ enum PathType { - Path_None = 0, - Path_Game, - Path_SM, - Path_SM_Rel, + Path_None = 0, /**< No base path */ + Path_Game, /**< Base path is absolute mod folder */ + Path_SM, /**< Base path is absolute to SourceMod */ + Path_SM_Rel, /**< Base path is relative to SourceMod */ }; + /** + * @brief Contains miscellanious helper functions. + */ class ISourceMod : public SMInterface { public: @@ -58,6 +83,7 @@ namespace SourceMod /** * @brief Logs a message to the SourceMod logs. * + * @param pExt Extension calling this function. * @param format Message format. * @param ... Message format parameters. */ @@ -66,6 +92,7 @@ namespace SourceMod /** * @brief Logs a message to the SourceMod error logs. * + * @param pExt Extension calling this function. * @param format Message format. * @param ... Message format parameters. */ diff --git a/public/ITextParsers.h b/public/ITextParsers.h index cae293a1..d7723cd9 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -1,6 +1,25 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ +/** + * @file ITextParsers.h + * @brief Defines various text/file parsing functions, as well as UTF-8 support code. + */ + #include namespace SourceMod @@ -43,6 +62,10 @@ namespace SourceMod * maintain * products */ + + /** + * @brief Contains parse events for INI files. + */ class ITextListener_INI { public: @@ -74,7 +97,7 @@ namespace SourceMod * @param invalid_tokens Whether or not the key contained invalid tokens. * @param equal_token There was an '=' sign present (in case the value is missing). * @param quotes Whether value was enclosed in quotes. - * @param curtoken Contains the token index of the start of the value string. + * @param curtok Contains the token index of the start of the value string. * This can be changed when returning false. * @return True to keep parsing, false otherwise. */ @@ -95,7 +118,7 @@ namespace SourceMod * @param curtok Pointer to optionally store failed position in string. * @return True to keep parsing, false otherwise. */ - virtual bool ReadINI_RawLine(const char *line, unsigned int *cutok) + virtual bool ReadINI_RawLine(const char *line, unsigned int *curtok) { return true; } @@ -140,29 +163,38 @@ namespace SourceMod * // * / * */ + /** + * @brief Lists actions to take when an SMC parse hook is done. + */ enum SMCParseResult { - SMCParse_Continue, //continue parsing - SMCParse_Halt, //stop parsing here - SMCParse_HaltFail //stop parsing and return failure + SMCParse_Continue, /**< Continue parsing */ + SMCParse_Halt, /**< Stop parsing here */ + SMCParse_HaltFail /**< Stop parsing and return SMCParseError_Custom */ }; + /** + * @brief Lists error codes possible from parsing an SMC file. + */ enum SMCParseError { - SMCParse_Okay = 0, //no error - SMCParse_StreamOpen, //stream failed to open - SMCParse_StreamError, //the stream died... somehow - SMCParse_Custom, //a custom handler threw an error - SMCParse_InvalidSection1, //a section was declared without quotes, and had extra tokens - SMCParse_InvalidSection2, //a section was declared without any header - SMCParse_InvalidSection3, //a section ending was declared with too many unknown tokens - SMCParse_InvalidSection4, //a section ending has no matching beginning - SMCParse_InvalidSection5, //a section beginning has no matching ending - SMCParse_InvalidTokens, //there were too many unidentifiable strings on one line - SMCParse_TokenOverflow, //the token buffer overflowed - SMCParse_InvalidProperty1, //a property was declared outside of any section + SMCParse_Okay = 0, /**< No error */ + SMCParse_StreamOpen, /**< Stream failed to open */ + SMCParse_StreamError, /**< The stream died... somehow */ + SMCParse_Custom, /**< A custom handler threw an error */ + SMCParse_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ + SMCParse_InvalidSection2, /**< A section was declared without any header */ + SMCParse_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ + SMCParse_InvalidSection4, /**< A section ending has no matching beginning */ + SMCParse_InvalidSection5, /**< A section beginning has no matching ending */ + SMCParse_InvalidTokens, /**< There were too many unidentifiable strings on one line */ + SMCParse_TokenOverflow, /**< The token buffer overflowed */ + SMCParse_InvalidProperty1, /**< A property was declared outside of any section */ }; + /** + * @brief Describes the events available for reading an SMC stream. + */ class ITextListener_SMC { public: @@ -250,6 +282,9 @@ namespace SourceMod #define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers" #define SMINTERFACE_TEXTPARSERS_VERSION 1 + /** + * @brief Contains various text stream parsing functions. + */ class ITextParsers : public SMInterface { public: diff --git a/public/doxygen/SourceMod.doxyfile b/public/doxygen/SourceMod.doxyfile new file mode 100644 index 00000000..857703d9 --- /dev/null +++ b/public/doxygen/SourceMod.doxyfile @@ -0,0 +1,262 @@ +# Doxyfile 1.5.1-p1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "SourceMod SDK" +PROJECT_NUMBER = 376 +OUTPUT_DIRECTORY = c:\temp\sm-dox +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = r:\sourcemod\ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 10 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = r:\sourcemod\trunk\public +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = YES +CHM_FILE = SourceMod-SDK.chm +HHC_LOCATION = C:/temp/sm-dox/html/index.hhc +GENERATE_CHI = NO +BINARY_TOC = YES +TOC_EXPAND = YES +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = SOURCEMOD_BUILD \ + SMEXT_CONF_METAMOD +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = "C:/Program Files/ATT/Graphviz/bin" +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = YES diff --git a/public/extensions/IThreader.h b/public/extensions/IThreader.h index 90e401fe..6e934010 100644 --- a/public/extensions/IThreader.h +++ b/public/extensions/IThreader.h @@ -1,6 +1,25 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_THREADER_H #define _INCLUDE_SOURCEMOD_THREADER_H +/** + * @file IThreader.h + * @brief Contains platform independent routines for threading. + */ + #include #define SMINTERFACE_THREADER_NAME "IThreader" @@ -15,13 +34,14 @@ namespace SourceMod { Thread_Default = 0, /** - * Auto-release handle on finish + * @brief Auto-release handle on finish + * * You are not guaranteed the handle for this is valid after * calling MakeThread(), so never use it until OnTerminate is called. */ Thread_AutoRelease = 1, /** - * Thread is created "suspended", meaning it is inactive until unpaused. + * @brief Thread is created "suspended", meaning it is inactive until unpaused. */ Thread_CreateSuspended = 2, }; @@ -53,13 +73,14 @@ namespace SourceMod */ struct ThreadParams { + /** Constructor */ ThreadParams() : flags(Thread_Default), prio(ThreadPrio_Normal) { }; - ThreadFlags flags; - ThreadPriority prio; + ThreadFlags flags; /**< Flags to set on the thread */ + ThreadPriority prio; /**< Priority to set on the thread */ }; class IThreadCreator; @@ -70,6 +91,7 @@ namespace SourceMod class IThreadHandle { public: + /** Virtual destructor */ virtual ~IThreadHandle() { }; public: /** @@ -94,7 +116,7 @@ namespace SourceMod /** * @brief Returns the thread states. * - * @param ptparmas Pointer to a ThreadParams buffer. + * @param ptparams Pointer to a ThreadParams buffer. */ virtual void GetParams(ThreadParams *ptparams) =0; @@ -135,6 +157,7 @@ namespace SourceMod class IThread { public: + /** Virtual destructor */ virtual ~IThread() { }; public: /** @@ -145,8 +168,7 @@ namespace SourceMod virtual void RunThread(IThreadHandle *pHandle) =0; /** - * @param Called when the thread terminates. - * Note: This occurs inside the thread as well. + * @brief Called when the thread terminates. This occurs inside the thread as well. * * @param pHandle Pointer to the thread's handle. * @param cancel True if the thread did not finish, false otherwise. @@ -161,6 +183,7 @@ namespace SourceMod class IThreadCreator { public: + /** Virtual Destructor */ virtual ~IThreadCreator() { }; public: /** @@ -204,6 +227,7 @@ namespace SourceMod class IMutex { public: + /** Virtual Destructor */ virtual ~IMutex() { }; public: /** @@ -235,6 +259,7 @@ namespace SourceMod class IEventSignal { public: + /** Virtual Destructor */ virtual ~IEventSignal() { }; public: /** @@ -271,6 +296,7 @@ namespace SourceMod class IThreadWorker : public IThreadCreator { public: + /** Virtual Destructor */ virtual ~IThreadWorker() { }; diff --git a/public/sample_ext/extension.cpp b/public/sample_ext/extension.cpp index 9065e47d..dcdc0211 100644 --- a/public/sample_ext/extension.cpp +++ b/public/sample_ext/extension.cpp @@ -1,5 +1,10 @@ #include "extension.h" -Sample g_Sample; +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + +Sample g_Sample; /**< Global singleton for your extension's main interface */ SMEXT_LINK(&g_Sample); diff --git a/public/sample_ext/extension.h b/public/sample_ext/extension.h index 7d0fc767..cd40740e 100644 --- a/public/sample_ext/extension.h +++ b/public/sample_ext/extension.h @@ -1,8 +1,15 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +/** + * @file extension.h + * @brief Sample extension code header. + */ + + #include "smsdk_ext.h" + /** * @brief Sample implementation of the SDK Extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. diff --git a/public/sample_ext/smsdk_config.h b/public/sample_ext/smsdk_config.h index 488dedf1..80cf4b6a 100644 --- a/public/sample_ext/smsdk_config.h +++ b/public/sample_ext/smsdk_config.h @@ -1,6 +1,11 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + /* Basic information exposed publically */ #define SMEXT_CONF_NAME "Sample Extension" #define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index 0dfcd408..493cf7f3 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -1,13 +1,33 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "smsdk_ext.h" -IShareSys *g_pShareSys = NULL; -IExtension *myself = NULL; -IHandleSys *g_pHandleSys = NULL; -ISourceMod *g_pSM = NULL; -IForwardManager *g_pForwards = NULL; +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { return g_pExtensionIface; @@ -139,14 +159,15 @@ void SDKExtension::SDK_OnAllLoaded() #if defined SMEXT_CONF_METAMOD -PluginId g_PLID = 0; -ISmmPlugin *g_PLAPI = NULL; -SourceHook::ISourceHook *g_SHPtr = NULL; -ISmmAPI *g_SMAPI = NULL; +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ -IVEngineServer *engine = NULL; -IServerGameDLL *gamedll = NULL; +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ +/** Exposes the extension to Metamod */ SMM_API void *PL_EXPOSURE(const char *name, int *code) { if (name && !strcmp(name, PLAPI_NAME)) diff --git a/public/sample_ext/smsdk_ext.h b/public/sample_ext/smsdk_ext.h index 16d931bc..85c70011 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/public/sample_ext/smsdk_ext.h @@ -1,6 +1,25 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + #include "smsdk_config.h" #include #include @@ -24,6 +43,7 @@ class SDKExtension : public IExtensionInterface { public: + /** Constructor */ SDKExtension(); public: /** @@ -88,28 +108,56 @@ public: //IExtensionInterface virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); virtual void OnExtensionUnload(); virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ virtual const char *GetExtensionName(); + /** Returns URL */ virtual const char *GetExtensionURL(); + /** Returns log tag */ virtual const char *GetExtensionTag(); + /** Returns author */ virtual const char *GetExtensionAuthor(); + /** Returns version string */ virtual const char *GetExtensionVerString(); + /** Returns description string */ virtual const char *GetExtensionDescription(); + /** Returns date string */ virtual const char *GetExtensionDateString(); #if defined SMEXT_CONF_METAMOD public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ virtual const char *GetAuthor(); + /** Returns the name to MM */ virtual const char *GetName(); + /** Returns the description to MM */ virtual const char *GetDescription(); + /** Returns the URL to MM */ virtual const char *GetURL(); + /** Returns the license to MM */ virtual const char *GetLicense(); + /** Returns the version string to MM */ virtual const char *GetVersion(); + /** Returns the date string to MM */ virtual const char *GetDate(); + /** Returns the logtag to MM */ virtual const char *GetLogTag(); + /** Called on unload */ virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ virtual bool Unpause(char *error, size_t maxlen); private: bool m_SourceMMLoaded; @@ -132,7 +180,9 @@ extern IVEngineServer *engine; extern IServerGameDLL *gamedll; #endif +/** Creates a SourceMod interface macro pair */ #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ #define SM_GET_IFACE(prefix,addr) \ if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ if (error) { \ diff --git a/public/sm_platform.h b/public/sm_platform.h index 8f672d37..062b08c8 100644 --- a/public/sm_platform.h +++ b/public/sm_platform.h @@ -1,8 +1,23 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ #define _INCLUDE_SOURCEMOD_PLATFORM_H_ /** - * @file Contains platform-specific macros for abstraction. + * @file sm_platform.h + * @brief Contains platform-specific macros for abstraction. */ #if defined WIN32 || defined WIN64 diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index d3f41e7e..5f925bb2 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -1,26 +1,46 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SPFILE_HEADERS_H #define _INCLUDE_SPFILE_HEADERS_H +/** + * @file sp_file_headers.h + * @brief Defines the structure present in a SourcePawn compiled binary. + * + * Note: These structures should be 1-byte packed to match the file format. + */ + #include #if defined __GNUC__ || defined HAVE_STDINT_ #include #else #if !defined HAVE_STDINT_H - typedef unsigned __int64 uint64_t; - typedef __int64 int64_t; - typedef unsigned __int32 uint32_t; - typedef __int32 int32_t; - typedef unsigned __int16 uint16_t; - typedef __int16 int16_t; - typedef unsigned __int8 uint8_t; - typedef __int8 int8_t; + typedef unsigned __int64 uint64_t; /**< 64bit unsigned integer */ + typedef __int64 int64_t; /**< 64bit signed integer */ + typedef unsigned __int32 uint32_t; /**< 32bit unsigned integer */ + typedef __int32 int32_t; /**< 32bit signed integer */ + typedef unsigned __int16 uint16_t; /**< 16bit unsigned integer */ + typedef __int16 int16_t; /**< 16bit signed integer */ + typedef unsigned __int8 uint8_t; /**< 8bit unsigned integer */ + typedef __int8 int8_t; /**< 8bit signed integer */ #define HAVE_STDINT_H #endif #endif -#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ -//#define SPFILE_VERSION 0x0100 -#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */ +#define SPFILE_MAGIC 0x53504646 /**< Source Pawn File Format (SPFF) */ +#define SPFILE_VERSION 0x0101 /**< Uncompressed bytecode */ //:TODO: better compiler/nix support #if defined __linux__ @@ -30,78 +50,92 @@ #pragma pack(1) /* structures must be packed (byte-aligned) */ #endif -#define SPFILE_COMPRESSION_NONE 0 -#define SPFILE_COMPRESSION_GZ 1 +#define SPFILE_COMPRESSION_NONE 0 /**< No compression in file */ +#define SPFILE_COMPRESSION_GZ 1 /**< GZ compression */ +/** + * @brief File section header format. + */ typedef struct sp_file_section_s { - uint32_t nameoffs; /* rel offset into global string table */ - uint32_t dataoffs; - uint32_t size; + uint32_t nameoffs; /**< Relative offset into global string table */ + uint32_t dataoffs; /**< Offset into the data section of the file */ + uint32_t size; /**< Size of the section's entry in the data section */ } sp_file_section_t; /** - * If compression is 0, then - * disksize may be 0 to mean that - * only the imagesize is needed. + * @brief File header format. If compression is 0, then disksize may be 0 + * to mean that only the imagesize is needed. */ typedef struct sp_file_hdr_s { - uint32_t magic; /* magic number */ - uint16_t version; /* version code */ - uint8_t compression;/* compression algorithm */ - uint32_t disksize; /* size on disk */ - uint32_t imagesize; /* size in memory */ - uint8_t sections; /* number of sections */ - uint32_t stringtab; /* offset to string table */ - uint32_t dataoffs; /* offset to file proper (any compression starts here) */ + uint32_t magic; /**< Magic number */ + uint16_t version; /**< Version code */ + uint8_t compression;/**< Compression algorithm */ + uint32_t disksize; /**< Size on disk */ + uint32_t imagesize; /**< Size in memory */ + uint8_t sections; /**< Number of sections */ + uint32_t stringtab; /**< Offset to string table */ + uint32_t dataoffs; /**< Offset to file proper (any compression starts here) */ } sp_file_hdr_t; -#define SP_FLAG_DEBUG (1<<0) +#define SP_FLAG_DEBUG (1<<0) /**< Debug information is present in the file */ -/* section is ".code" */ +/** + * @brief File-encoded format of the ".code" section. + */ typedef struct sp_file_code_s { - uint32_t codesize; /* codesize in bytes */ - uint8_t cellsize; /* cellsize in bytes */ - uint8_t codeversion; /* version of opcodes supported */ - uint16_t flags; /* flags */ - uint32_t main; /* address to "main" if any */ - uint32_t code; /* rel offset to code */ + uint32_t codesize; /**< Codesize in bytes */ + uint8_t cellsize; /**< Cellsize in bytes */ + uint8_t codeversion; /**< Version of opcodes supported */ + uint16_t flags; /**< Flags */ + uint32_t main; /**< Address to "main," if any */ + uint32_t code; /**< Relative offset to code */ } sp_file_code_t; -/* section is .data */ +/** + * @brief File-encoded format of the ".data" section. + */ typedef struct sp_file_data_s { - uint32_t datasize; /* size of data section in memory */ - uint32_t memsize; /* total mem required (includes data) */ - uint32_t data; /* file offset to data (helper) */ + uint32_t datasize; /**< Size of data section in memory */ + uint32_t memsize; /**< Total mem required (includes data) */ + uint32_t data; /**< File offset to data (helper) */ } sp_file_data_t; -/* section is .publics */ +/** + * @brief File-encoded format of the ".publics" section. + */ typedef struct sp_file_publics_s { - uint32_t address; /* address rel to code section */ - uint32_t name; /* index into nametable */ + uint32_t address; /**< Address relative to code section */ + uint32_t name; /**< Index into nametable */ } sp_file_publics_t; -/* section is .natives */ +/** + * @brief File-encoded format of the ".natives" section. + */ typedef struct sp_file_natives_s { - uint32_t name; /* name of native at index */ + uint32_t name; /**< Index into nametable */ } sp_file_natives_t; -/* section is .libraries */ +/** + * @brief File-encoded format of the ".libraries" section (UNUSED). + */ typedef struct sp_file_libraries_s { - uint32_t name; /* index into nametable */ + uint32_t name; /**< Index into nametable */ } sp_file_libraries_t; -/* section is .pubvars */ +/** + * @brief File-encoded format of the ".pubvars" section. + */ typedef struct sp_file_pubvars_s { - uint32_t address; /* address rel to dat section */ - uint32_t name; /* index into nametable */ + uint32_t address; /**< Address relative to the DAT section */ + uint32_t name; /**< Index into nametable */ } sp_file_pubvars_t; #if defined __linux__ @@ -110,54 +144,66 @@ typedef struct sp_file_pubvars_s #pragma pack(pop) /* reset previous packing */ #endif +/** + * @brief File-encoded debug information table. + */ typedef struct sp_fdbg_info_s { - uint32_t num_files; /* number of files */ - uint32_t num_lines; /* number of lines */ - uint32_t num_syms; /* number of symbols */ - uint32_t num_arrays; /* number of symbols which are arrays */ + uint32_t num_files; /**< number of files */ + uint32_t num_lines; /**< number of lines */ + uint32_t num_syms; /**< number of symbols */ + uint32_t num_arrays; /**< number of symbols which are arrays */ } sp_fdbg_info_t; /** - * Debug information structures + * @brief File-encoded debug file table. */ typedef struct sp_fdbg_file_s { - uint32_t addr; /* address into code */ - uint32_t name; /* offset into debug nametable */ + uint32_t addr; /**< Address into code */ + uint32_t name; /**< Offset into debug nametable */ } sp_fdbg_file_t; +/** + * @brief File-encoded debug line table. + */ typedef struct sp_fdbg_line_s { - uint32_t addr; /* address into code */ - uint32_t line; /* line number */ + uint32_t addr; /**< Address into code */ + uint32_t line; /**< Line number */ } sp_fdbg_line_t; -#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ -#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */ -#define SP_SYM_ARRAY 3 -#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */ -#define SP_SYM_FUNCTION 9 +#define SP_SYM_VARIABLE 1 /**< Cell that has an address and that can be fetched directly (lvalue) */ +#define SP_SYM_REFERENCE 2 /**< VARIABLE, but must be dereferenced */ +#define SP_SYM_ARRAY 3 /**< Symbol is an array */ +#define SP_SYM_REFARRAY 4 /**< An array passed by reference (i.e. a pointer) */ +#define SP_SYM_FUNCTION 9 /**< Symbol is a function */ +/** + * @brief File-encoded debug symbol information. + */ typedef struct sp_fdbg_symbol_s { - int32_t addr; /* address rel to DAT or stack frame */ - int16_t tagid; /* tag id */ - uint32_t codestart; /* start scope validity in code */ - uint32_t codeend; /* end scope validity in code */ - uint8_t ident; /* variable type */ - uint8_t vclass; /* scope class (local vs global) */ - uint16_t dimcount; /* dimension count (for arrays) */ - uint32_t name; /* offset into debug nametable */ + int32_t addr; /**< Address rel to DAT or stack frame */ + int16_t tagid; /**< Tag id */ + uint32_t codestart; /**< Start scope validity in code */ + uint32_t codeend; /**< End scope validity in code */ + uint8_t ident; /**< Variable type */ + uint8_t vclass; /**< Scope class (local vs global) */ + uint16_t dimcount; /**< Dimension count (for arrays) */ + uint32_t name; /**< Offset into debug nametable */ } sp_fdbg_symbol_t; +/** + * @brief File-encoded debug symbol array dimension info. + */ typedef struct sp_fdbg_arraydim_s { - int16_t tagid; /* tag id */ - uint32_t size; /* size of dimension */ + int16_t tagid; /**< Tag id */ + uint32_t size; /**< Size of dimension */ } sp_fdbg_arraydim_t; -/* section is .names */ +/** Typedef for .names table */ typedef char * sp_file_nametab_t; #endif //_INCLUDE_SPFILE_HEADERS_H diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h index f5146bb2..b0dd39eb 100644 --- a/public/sourcepawn/sp_typeutil.h +++ b/public/sourcepawn/sp_typeutil.h @@ -1,12 +1,44 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ #define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ +/** + * @file sp_typeutil.h + * @brief Defines type utility functions. + */ + #include "sp_vm_types.h" +/** + * @brief Reinterpret-casts a float to a cell (requires -fno-strict-aliasing for GCC). + * + * @param val Float value. + * @return Cell typed version. + */ inline cell_t sp_ftoc(float val) { return *(cell_t *)&val; } + +/** + * @brief Reinterpret-casts a cell to a float (requires -fno-strict-aliasing for GCC). + * + * @param val Cell-packed float value. + * @return Float typed version. + */ inline float sp_ctof(cell_t val) { return *(float *)&val; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 41a7d09b..86bedccb 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -1,9 +1,29 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_VM_API_H_ #define _INCLUDE_SOURCEPAWN_VM_API_H_ +/** + * @file sp_vm_api.h + * @brief Contains all of the object structures used in the SourcePawn API. + */ + #include #include "sp_vm_types.h" +/** SourcePawn VM API Version */ #define SOURCEPAWN_VM_API_VERSION 1 #if defined SOURCEMOD_BUILD @@ -17,10 +37,9 @@ namespace SourcePawn { class IVirtualMachine; - #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ - - #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ - #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ + #define SM_PARAM_COPYBACK (1<<0) /**< Copy an array/reference back after call */ + #define SM_PARAM_STRING_UTF8 (1<<0) /**< String should be UTF-8 handled */ + #define SM_PARAM_STRING_COPY (1<<1) /**< String should be copied into the plugin */ /** * @brief Represents what a function needs to implement in order to be callable. @@ -52,7 +71,7 @@ namespace SourcePawn /** * @brief Pushes a float onto the current call. * - * @param float Parameter value to push. + * @param number Parameter value to push. * @return Error code, if any. */ virtual int PushFloat(float number) =0; @@ -64,7 +83,7 @@ namespace SourcePawn * This means you cannot push a pointer, change it, and push it again and expect * two different values to come out. * - * @param float Parameter value to push. + * @param number Parameter value to push. & @param flags Copy-back flags. * @return Error code, if any. */ @@ -119,6 +138,7 @@ namespace SourcePawn /** * @brief Encapsulates a function call in a plugin. + * * NOTE: Function calls must be atomic to one execution context. * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. */ @@ -139,7 +159,7 @@ namespace SourcePawn * NOTE: You will get an error if you attempt to use CallFunction() with * previously pushed parameters. * - * @param param Array of cell parameters. + * @param params Array of cell parameters. * @param num_params Number of parameters to push. * @param result Pointer to store result of function on return. * @return SourcePawn error code (if any). @@ -156,7 +176,7 @@ namespace SourcePawn /** * @brief Returns the physical address of a by-reference parameter. * - * @param Parameter index to read (beginning at 0). + * @param param Parameter index to read (beginning at 0). * @return Address, or NULL if invalid parameter specified. */ virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; @@ -200,6 +220,7 @@ namespace SourcePawn class IPluginContext { public: + /** Virtual destructr */ virtual ~IPluginContext() { }; public: /** @@ -525,9 +546,9 @@ namespace SourcePawn */ struct CallStackInfo { - const char *filename; /* NULL if not found */ - unsigned int line; /* 0 if not found */ - const char *function; /* NULL if not found */ + const char *filename; /**< NULL if not found */ + unsigned int line; /**< 0 if not found */ + const char *function; /**< NULL if not found */ }; /** @@ -690,6 +711,7 @@ namespace SourcePawn class ICompilation { public: + /** Virtual destructor */ virtual ~ICompilation() { }; }; diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index 5d295d62..0d1b7136 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -1,6 +1,25 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_ #define _INCLUDE_SOURCEPAWN_VM_BASE_H_ +/** + * @file sp_vm_base.h + * @brief Contains JIT export/linkage macros. + */ + #include /* :TODO: rename this to sp_vm_linkage.h */ @@ -11,6 +30,7 @@ #define EXPORT_LINK extern "C" __attribute__((visibility("default"))) #endif +/** No longer used */ typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); #endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 74e47434..94a02f58 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -1,45 +1,64 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H #define _INCLUDE_SOURCEPAWN_VM_TYPES_H +/** + * @file sp_vm_types.h + * @brief Contains all run-time SourcePawn structures. + */ + #include "sp_file_headers.h" -typedef uint32_t ucell_t; -typedef int32_t cell_t; -typedef uint32_t funcid_t; +typedef uint32_t ucell_t; /**< Unsigned 32bit integer */ +typedef int32_t cell_t; /**< Basic 32bit signed integer type for plugins */ +typedef uint32_t funcid_t; /**< Function index code */ #include "sp_typeutil.h" -#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ +#define SP_MAX_EXEC_PARAMS 32 /**< Maximum number of parameters in a function */ /** - * Error codes - * NOTE: Be sure to update the error string table when changing these + * @brief Error codes for SourcePawn routines. */ -#define SP_ERROR_NONE 0 -#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ -#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ -#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ -#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */ -#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ -#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ -#define SP_ERROR_INDEX 7 /* Invalid index parameter */ -#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */ -#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */ -#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */ -#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */ -#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */ -#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */ -#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */ -#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */ -#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */ -#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */ -#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */ -#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ -#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ -#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ -#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ -#define SP_ERROR_NATIVE 23 /* Error originates from a native */ -#define SP_ERROR_NOT_RUNNABLE 24 /* Function or plugin is not runnable */ +#define SP_ERROR_NONE 0 /**< No error occurred */ +#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */ +#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */ +#define SP_ERROR_INDEX 7 /**< Invalid index parameter */ +#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /**< Error originates from a native */ +#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ +//Hey you! Update the string table if you add to the end of me! */ /********************************************** *** The following structures are reference structures. @@ -49,60 +68,56 @@ typedef uint32_t funcid_t; **********************************************/ /** - * Information about the core plugin tables. - * These may or may not be present! + * @brief Information about the core plugin tables. These may or may not be present! */ typedef struct sp_plugin_infotab_s { - const char *stringbase; /* base of string table */ - uint32_t publics_num; /* number of publics */ - sp_file_publics_t *publics; /* public table */ - uint32_t natives_num; /* number of natives */ - sp_file_natives_t *natives; /* native table */ - uint32_t pubvars_num; /* number of pubvars */ - sp_file_pubvars_t *pubvars; /* pubvars table */ - uint32_t libraries_num; /* number of libraries */ - sp_file_libraries_t *lib; /* library table */ + const char *stringbase; /**< base of string table */ + uint32_t publics_num; /**< number of publics */ + sp_file_publics_t *publics; /**< public table */ + uint32_t natives_num; /**< number of natives */ + sp_file_natives_t *natives; /**< native table */ + uint32_t pubvars_num; /**< number of pubvars */ + sp_file_pubvars_t *pubvars; /**< pubvars table */ + uint32_t libraries_num; /**< number of libraries */ + sp_file_libraries_t *lib; /**< library table */ } sp_plugin_infotab_t; /** - * Information about the plugin's debug tables. - * These are all present if one is present. + * @brief Information about the plugin's debug tables. These are all present if one is present. */ typedef struct sp_plugin_debug_s { - const char *stringbase; /* base of string table */ - uint32_t files_num; /* number of files */ - sp_fdbg_file_t *files; /* files table */ - uint32_t lines_num; /* number of lines */ - sp_fdbg_line_t *lines; /* lines table */ - uint32_t syms_num; /* number of symbols */ - sp_fdbg_symbol_t *symbols; /* symbol table */ + const char *stringbase; /**< base of string table */ + uint32_t files_num; /**< number of files */ + sp_fdbg_file_t *files; /**< files table */ + uint32_t lines_num; /**< number of lines */ + sp_fdbg_line_t *lines; /**< lines table */ + uint32_t syms_num; /**< number of symbols */ + sp_fdbg_symbol_t *symbols; /**< symbol table */ } sp_plugin_debug_t; -#define SP_FA_SELF_EXTERNAL (1<<0) -#define SP_FA_BASE_EXTERNAL (1<<1) +#define SP_FA_SELF_EXTERNAL (1<<0) /**< Allocation of structure is external */ +#define SP_FA_BASE_EXTERNAL (1<<1) /**< Allocation of base is external */ /** - * The rebased, in-memory format of a plugin. - * This differs from the on-disk structure to ensure - * that the format is properly read. + * @brief The rebased memory format of a plugin. This differs from the on-disk structure + * to ensure that the format is properly read. */ typedef struct sp_plugin_s { - uint8_t *base; /* base of memory */ - uint8_t *pcode; /* p-code */ - uint32_t pcode_size; /* size of p-code */ - uint8_t *data; /* data size */ - uint32_t data_size; /* size of data */ - uint32_t memory; /* required memory */ - uint16_t flags; /* code flags */ - uint32_t allocflags; /* allocation flags */ - sp_plugin_infotab_t info; /* base info table */ - sp_plugin_debug_t debug; /* debug info table */ + uint8_t *base; /**< Base of memory for this plugin. */ + uint8_t *pcode; /**< P-Code of plugin */ + uint32_t pcode_size; /**< Size of p-code */ + uint8_t *data; /**< Data/memory layout */ + uint32_t data_size; /**< Size of data */ + uint32_t memory; /**< Required memory space */ + uint16_t flags; /**< Code flags */ + uint32_t allocflags; /**< Allocation flags */ + sp_plugin_infotab_t info; /**< Base info table */ + sp_plugin_debug_t debug; /**< Debug info table */ } sp_plugin_t; -/** Forward declarations */ namespace SourcePawn { @@ -112,6 +127,10 @@ namespace SourcePawn struct sp_context_s; +/** + * @brief Native callback prototype, passed a context and a parameter stack (0=count, 1+=args). + * A cell must be returned. + */ typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); /********************************************** @@ -120,84 +139,82 @@ typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *) **********************************************/ /** - * Offsets and names to a public function. - * By default, these point back to the string table - * in the sp_plugin_infotab_t structure. + * @brief Offsets and names to a public function. */ typedef struct sp_public_s { - funcid_t funcid; /* encoded function id */ - uint32_t code_offs; /* code offset */ - const char *name; /* name */ + funcid_t funcid; /**< Encoded function id */ + uint32_t code_offs; /**< Relocated code offset */ + const char *name; /**< Name of function */ } sp_public_t; /** - * Offsets and names to public variables. - * The offset is relocated and the name by default - * points back to the sp_plugin_infotab_t structure. + * @brief Offsets and names to public variables. + * + * The offset is relocated and the name by default points back to the sp_plugin_infotab_t structure. */ typedef struct sp_pubvar_s { - cell_t *offs; /* pointer to data */ - const char *name; /* name */ + cell_t *offs; /**< Pointer to data */ + const char *name; /**< Name */ } sp_pubvar_t; -#define SP_NATIVE_UNBOUND (0) /* Native is undefined */ -#define SP_NATIVE_BOUND (1) /* Native is bound */ +#define SP_NATIVE_UNBOUND (0) /**< Native is undefined */ +#define SP_NATIVE_BOUND (1) /**< Native is bound */ /** - * Native lookup table, by default names - * point back to the sp_plugin_infotab_t structure. - * A native is NULL if unit + * @brief Native lookup table, by default names point back to the sp_plugin_infotab_t structure. */ typedef struct sp_native_s { - SPVM_NATIVE_FUNC pfn; /* function pointer */ - const char * name; /* name of function */ - uint32_t status; /* status flags */ + SPVM_NATIVE_FUNC pfn; /**< Function pointer */ + const char * name; /**< Name of function */ + uint32_t status; /**< Status flags */ } sp_native_t; /** - * Used for setting natives from modules/host apps. + * @brief Used for setting natives from modules/host apps. */ typedef struct sp_nativeinfo_s { - const char *name; - SPVM_NATIVE_FUNC func; + const char *name; /**< Name of the native */ + SPVM_NATIVE_FUNC func; /**< Address of native implementation */ } sp_nativeinfo_t; /** - * Debug file table + * @brief Run-time debug file table */ typedef struct sp_debug_file_s { - uint32_t addr; /* address into code */ - const char * name; /* name of file */ + uint32_t addr; /**< Address into code */ + const char * name; /**< Name of file */ } sp_debug_file_t; /** - * Note that line is missing. It is not necessary since - * this can be retrieved from the base plugin info. + * @brief Contains run-time debug line table. */ typedef struct sp_debug_line_s { - uint32_t addr; /* address into code */ - uint32_t line; /* line no. */ + uint32_t addr; /**< Address into code */ + uint32_t line; /**< Line number */ } sp_debug_line_t; +/** + * @brief These structures are equivalent. + */ typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; /** - * The majority of this struct is already located in the parent - * block. Thus, only the relocated portions are required. + * @brief The majority of this struct is already located in the parent + * block. Thus, only the relocated portions are required. */ typedef struct sp_debug_symbol_s { - uint32_t codestart; /* relocated code address */ - uint32_t codeend; /* relocated code end address */ - const char * name; /* relocated name */ - sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */ - sp_fdbg_symbol_t *sym; /* pointer to original symbol */ + uint32_t codestart; /**< Relocated code address */ + uint32_t codeend; /**< relocated code end address */ + const char * name; /**< Relocated name */ + sp_debug_arraydim_t *dims; /**< Relocated dimension struct, if any */ + sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */ } sp_debug_symbol_t; /** @@ -209,44 +226,39 @@ typedef struct sp_debug_symbol_s */ typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); -#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ +#define SPFLAG_PLUGIN_DEBUG (1<<0) /**< plugin is in debug mode */ /** - * This is the heart of the VM. It contains all of the runtime - * information about a plugin context. - * Note that user[0..3] can be used for any user based pointers. - * vm[0..3] should not be touched, as it is reserved for the VM. + * @brief This is the heart of the VM. It contains all of the runtime + * information about a plugin context. Note that user[0..3] can be used for any user based pointers. + * However, vm[0..3] should not be touched, as it is reserved for the VM. */ typedef struct sp_context_s { - /* general/parent information */ - void *codebase; /* base of generated code and memory */ - sp_plugin_t *plugin; /* pointer back to parent information */ - SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ - SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ - void *user[4]; /* user specific pointers */ - void *vm[4]; /* VM specific pointers */ - uint32_t flags; /* compilation flags */ - SPVM_DEBUGBREAK dbreak; /* debug break function */ - /* context runtime information */ - uint8_t *memory; /* data chunk */ - ucell_t mem_size; /* total memory size; */ - cell_t data_size; /* data chunk size, always starts at 0 */ - cell_t heap_base; /* where the heap starts */ - /* execution specific data */ - cell_t hp; /* heap pointer */ - cell_t sp; /* stack pointer */ - cell_t frm; /* frame pointer */ - uint32_t pushcount; /* push count */ - int32_t n_err; /* error code set by a native */ - uint32_t n_idx; /* current native index being executed */ - /* context rebased database */ - sp_public_t *publics; /* public functions table */ - sp_pubvar_t *pubvars; /* public variables table */ - sp_native_t *natives; /* natives table */ - sp_debug_file_t *files; /* files */ - sp_debug_line_t *lines; /* lines */ - sp_debug_symbol_t *symbols; /* symbols */ + void *codebase; /**< Base of generated code and memory */ + sp_plugin_t *plugin; /**< Pointer back to parent information */ + SourcePawn::IPluginContext *context; /**< Pointer to IPluginContext */ + SourcePawn::IVirtualMachine *vmbase; /**< Pointer to IVirtualMachine */ + void *user[4]; /**< User specific pointers */ + void *vm[4]; /**< VM specific pointers */ + uint32_t flags; /**< Compilation flags */ + SPVM_DEBUGBREAK dbreak; /**< Debug break function */ + uint8_t *memory; /**< Data chunk */ + ucell_t mem_size; /**< Total memory size; */ + cell_t data_size; /**< Data chunk size, always starts at 0 */ + cell_t heap_base; /**< Where the heap starts */ + cell_t hp; /**< Heap pointer */ + cell_t sp; /**< Stack pointer */ + cell_t frm; /**< Frame pointer */ + uint32_t pushcount; /**< Push count */ + int32_t n_err; /**< Error code set by a native */ + uint32_t n_idx; /**< Current native index being executed */ + sp_public_t *publics; /**< Public functions table */ + sp_pubvar_t *pubvars; /**< Public variables table */ + sp_native_t *natives; /**< Natives table */ + sp_debug_file_t *files; /**< Files */ + sp_debug_line_t *lines; /**< Lines */ + sp_debug_symbol_t *symbols; /**< Symbols */ } sp_context_t; #endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H From 52727c6f216960a2dfec3800d46243992cf5894e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 02:04:07 +0000 Subject: [PATCH 0348/1664] added license headers to extensions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40378 --- extensions/geoip/extension.cpp | 19 +++++++++++++++++++ extensions/geoip/extension.h | 19 +++++++++++++++++++ extensions/geoip/smsdk_config.h | 19 +++++++++++++++++++ extensions/geoip/smsdk_ext.cpp | 14 ++++++++++++++ extensions/geoip/smsdk_ext.h | 14 ++++++++++++++ extensions/threader/extension.cpp | 19 +++++++++++++++++++ extensions/threader/extension.h | 19 +++++++++++++++++++ extensions/threader/msvc8/threader.vcproj | 4 ---- extensions/threader/smsdk_config.h | 18 ++++++++++++++++++ extensions/threader/smsdk_ext.cpp | 14 ++++++++++++++ extensions/threader/smsdk_ext.h | 14 ++++++++++++++ extensions/threader/thread/BaseWorker.cpp | 19 +++++++++++++++++++ extensions/threader/thread/BaseWorker.h | 19 +++++++++++++++++++ extensions/threader/thread/PosixThreads.cpp | 19 +++++++++++++++++++ extensions/threader/thread/PosixThreads.h | 19 +++++++++++++++++++ extensions/threader/thread/ThreadSupport.h | 19 +++++++++++++++++++ extensions/threader/thread/ThreadWorker.cpp | 19 +++++++++++++++++++ extensions/threader/thread/ThreadWorker.h | 19 +++++++++++++++++++ extensions/threader/thread/WinThreads.cpp | 19 +++++++++++++++++++ extensions/threader/thread/WinThreads.h | 19 +++++++++++++++++++ 20 files changed, 340 insertions(+), 4 deletions(-) diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp index 0212350d..0fb7b4a0 100644 --- a/extensions/geoip/extension.cpp +++ b/extensions/geoip/extension.cpp @@ -1,3 +1,22 @@ +/** + * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "extension.h" #include "GeoIP.h" diff --git a/extensions/geoip/extension.h b/extensions/geoip/extension.h index 2a4f7ad7..79e313d4 100644 --- a/extensions/geoip/extension.h +++ b/extensions/geoip/extension.h @@ -1,3 +1,22 @@ +/** + * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/geoip/smsdk_config.h b/extensions/geoip/smsdk_config.h index 64d78400..3356afb2 100644 --- a/extensions/geoip/smsdk_config.h +++ b/extensions/geoip/smsdk_config.h @@ -1,3 +1,22 @@ +/** + * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/geoip/smsdk_ext.cpp b/extensions/geoip/smsdk_ext.cpp index 0dfcd408..8dfd6db6 100644 --- a/extensions/geoip/smsdk_ext.cpp +++ b/extensions/geoip/smsdk_ext.cpp @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "smsdk_ext.h" diff --git a/extensions/geoip/smsdk_ext.h b/extensions/geoip/smsdk_ext.h index 16d931bc..ce82828a 100644 --- a/extensions/geoip/smsdk_ext.h +++ b/extensions/geoip/smsdk_ext.h @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/threader/extension.cpp b/extensions/threader/extension.cpp index 2d1cc3f6..b8907529 100644 --- a/extensions/threader/extension.cpp +++ b/extensions/threader/extension.cpp @@ -1,3 +1,22 @@ +/** + * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "extension.h" #include "thread/ThreadSupport.h" diff --git a/extensions/threader/extension.h b/extensions/threader/extension.h index 584dbdc1..f43a8ea1 100644 --- a/extensions/threader/extension.h +++ b/extensions/threader/extension.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/threader/msvc8/threader.vcproj b/extensions/threader/msvc8/threader.vcproj index d76a6ad7..02ef88dc 100644 --- a/extensions/threader/msvc8/threader.vcproj +++ b/extensions/threader/msvc8/threader.vcproj @@ -239,10 +239,6 @@ RelativePath="..\thread\BaseWorker.h" > - - diff --git a/extensions/threader/smsdk_config.h b/extensions/threader/smsdk_config.h index 13ebf9c3..9f6f3525 100644 --- a/extensions/threader/smsdk_config.h +++ b/extensions/threader/smsdk_config.h @@ -1,3 +1,21 @@ +/** + * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/threader/smsdk_ext.cpp b/extensions/threader/smsdk_ext.cpp index 0dfcd408..8dfd6db6 100644 --- a/extensions/threader/smsdk_ext.cpp +++ b/extensions/threader/smsdk_ext.cpp @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include #include #include "smsdk_ext.h" diff --git a/extensions/threader/smsdk_ext.h b/extensions/threader/smsdk_ext.h index 16d931bc..ce82828a 100644 --- a/extensions/threader/smsdk_ext.h +++ b/extensions/threader/smsdk_ext.h @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/threader/thread/BaseWorker.cpp b/extensions/threader/thread/BaseWorker.cpp index 819c5d02..e2881c9e 100644 --- a/extensions/threader/thread/BaseWorker.cpp +++ b/extensions/threader/thread/BaseWorker.cpp @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "BaseWorker.h" BaseWorker::BaseWorker() : diff --git a/extensions/threader/thread/BaseWorker.h b/extensions/threader/thread/BaseWorker.h index 5e91c28b..127e8259 100644 --- a/extensions/threader/thread/BaseWorker.h +++ b/extensions/threader/thread/BaseWorker.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_BASEWORKER_H #define _INCLUDE_SOURCEMOD_BASEWORKER_H diff --git a/extensions/threader/thread/PosixThreads.cpp b/extensions/threader/thread/PosixThreads.cpp index 5c801e14..24e8e5ef 100644 --- a/extensions/threader/thread/PosixThreads.cpp +++ b/extensions/threader/thread/PosixThreads.cpp @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include #include "PosixThreads.h" #include "ThreadWorker.h" diff --git a/extensions/threader/thread/PosixThreads.h b/extensions/threader/thread/PosixThreads.h index 3a8eb9ed..f27b4f27 100644 --- a/extensions/threader/thread/PosixThreads.h +++ b/extensions/threader/thread/PosixThreads.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_POSIXTHREADS_H_ #define _INCLUDE_POSIXTHREADS_H_ diff --git a/extensions/threader/thread/ThreadSupport.h b/extensions/threader/thread/ThreadSupport.h index f948e6ce..f36f6e57 100644 --- a/extensions/threader/thread/ThreadSupport.h +++ b/extensions/threader/thread/ThreadSupport.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H #define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H diff --git a/extensions/threader/thread/ThreadWorker.cpp b/extensions/threader/thread/ThreadWorker.cpp index fb298185..7e745e91 100644 --- a/extensions/threader/thread/ThreadWorker.cpp +++ b/extensions/threader/thread/ThreadWorker.cpp @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "ThreadWorker.h" ThreadWorker::ThreadWorker() : diff --git a/extensions/threader/thread/ThreadWorker.h b/extensions/threader/thread/ThreadWorker.h index 6afd64f4..c01a9f39 100644 --- a/extensions/threader/thread/ThreadWorker.h +++ b/extensions/threader/thread/ThreadWorker.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_THREADWORKER_H #define _INCLUDE_SOURCEMOD_THREADWORKER_H diff --git a/extensions/threader/thread/WinThreads.cpp b/extensions/threader/thread/WinThreads.cpp index be444a69..25c335b2 100644 --- a/extensions/threader/thread/WinThreads.cpp +++ b/extensions/threader/thread/WinThreads.cpp @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "WinThreads.h" #include "ThreadWorker.h" diff --git a/extensions/threader/thread/WinThreads.h b/extensions/threader/thread/WinThreads.h index 89a640fc..fd11b932 100644 --- a/extensions/threader/thread/WinThreads.h +++ b/extensions/threader/thread/WinThreads.h @@ -1,3 +1,22 @@ +/** + * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_WINTHREADS_H_ #define _INCLUDE_WINTHREADS_H_ From 6abb60a908b5d28644b8270c37fcb4209bb527df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 02:07:24 +0000 Subject: [PATCH 0349/1664] added license info to include files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40379 --- plugins/include/admin.inc | 14 ++++++++++++++ plugins/include/core.inc | 14 ++++++++++++++ plugins/include/files.inc | 12 +++++++++++- plugins/include/float.inc | 14 ++++++++++++-- plugins/include/geoip.inc | 12 +++++++++++- plugins/include/handles.inc | 13 +++++++++++-- plugins/include/sourcemod.inc | 12 +++++++++++- plugins/include/string.inc | 14 ++++++++++++-- plugins/include/textparse.inc | 14 ++++++++++++++ 9 files changed, 110 insertions(+), 9 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index df2d83d0..23a9217b 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #if defined _admin_included #endinput #endif diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 03678840..c520295d 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #if defined _core_included #endinput #endif diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 7871acfd..677a0681 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -1,5 +1,15 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ #if defined _files_included diff --git a/plugins/include/float.inc b/plugins/include/float.inc index ca9588cf..a1bf2034 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -1,7 +1,17 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ - + #if defined _float_included #endinput #endif diff --git a/plugins/include/geoip.inc b/plugins/include/geoip.inc index 3ba6f227..66271799 100644 --- a/plugins/include/geoip.inc +++ b/plugins/include/geoip.inc @@ -1,5 +1,15 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ #if defined _geoip_included diff --git a/plugins/include/handles.inc b/plugins/include/handles.inc index be3640b8..554dd632 100644 --- a/plugins/include/handles.inc +++ b/plugins/include/handles.inc @@ -1,8 +1,17 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ - #if defined _handles_included #endinput #endif diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 8095db0a..4a168f60 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -1,5 +1,15 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ #if defined _sourcemod_included diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 639dd8b7..b1ad0268 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -1,7 +1,17 @@ /** - * :TODO: license info + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ */ - + #if defined _string_included #endinput #endif diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc index 51c96312..394bae43 100644 --- a/plugins/include/textparse.inc +++ b/plugins/include/textparse.inc @@ -1,3 +1,17 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #if defined _textparse_included #endinput #endif From cf866e544689706a42747064a09de48c94f3a86f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 02:27:34 +0000 Subject: [PATCH 0350/1664] Added vim settings to SDK files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40380 --- public/IAdminSystem.h | 1 + public/IExtensionSys.h | 1 + public/IForwardSys.h | 1 + public/IHandleSys.h | 1 + public/ILibrarySys.h | 1 + public/IPluginSys.h | 1 + public/IRootConsoleMenu.h | 1 + public/IShareSys.h | 1 + public/ITextParsers.h | 1 + public/extensions/IThreader.h | 1 + public/sample_ext/extension.cpp | 1 + public/sample_ext/extension.h | 1 + public/sample_ext/smsdk_config.h | 1 + public/sample_ext/smsdk_ext.cpp | 1 + public/sample_ext/smsdk_ext.h | 1 + public/sm_platform.h | 1 + public/sourcepawn/sp_file_headers.h | 1 + public/sourcepawn/sp_typeutil.h | 1 + public/sourcepawn/sp_vm_api.h | 1 + public/sourcepawn/sp_vm_types.h | 1 + 20 files changed, 20 insertions(+) diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 382dc63d..c335e453 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index 2c03606e..dc434b96 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 05608fef..37ecfe27 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IHandleSys.h b/public/IHandleSys.h index e9631892..71e0b42d 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index a8bafacf..51ba46ee 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 6f4846fb..1f5526ec 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IRootConsoleMenu.h b/public/IRootConsoleMenu.h index 01b5d4f3..ccb7877d 100644 --- a/public/IRootConsoleMenu.h +++ b/public/IRootConsoleMenu.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/IShareSys.h b/public/IShareSys.h index 528e4233..8fa8ec63 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/ITextParsers.h b/public/ITextParsers.h index d7723cd9..995ac278 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/extensions/IThreader.h b/public/extensions/IThreader.h index 6e934010..be47c9d7 100644 --- a/public/extensions/IThreader.h +++ b/public/extensions/IThreader.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/sample_ext/extension.cpp b/public/sample_ext/extension.cpp index dcdc0211..112d06ca 100644 --- a/public/sample_ext/extension.cpp +++ b/public/sample_ext/extension.cpp @@ -1,3 +1,4 @@ +// vim: set ts=4 : #include "extension.h" /** diff --git a/public/sample_ext/extension.h b/public/sample_ext/extension.h index cd40740e..4851c32c 100644 --- a/public/sample_ext/extension.h +++ b/public/sample_ext/extension.h @@ -1,3 +1,4 @@ +// vim: set ts=4 : #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/public/sample_ext/smsdk_config.h b/public/sample_ext/smsdk_config.h index 80cf4b6a..dfc8a925 100644 --- a/public/sample_ext/smsdk_config.h +++ b/public/sample_ext/smsdk_config.h @@ -1,3 +1,4 @@ +// vim: set ts=4 : #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index 493cf7f3..33476c97 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/sample_ext/smsdk_ext.h b/public/sample_ext/smsdk_ext.h index 85c70011..99706bbc 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/public/sample_ext/smsdk_ext.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/sm_platform.h b/public/sm_platform.h index 062b08c8..b980ece5 100644 --- a/public/sm_platform.h +++ b/public/sm_platform.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index 5f925bb2..63a0d1ab 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h index b0dd39eb..e2282284 100644 --- a/public/sourcepawn/sp_typeutil.h +++ b/public/sourcepawn/sp_typeutil.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 86bedccb..f04dff14 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 94a02f58..7218bc95 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ From 51d1aa70acb49f845ecb9ecad84d829e2f478373 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 02:50:48 +0000 Subject: [PATCH 0351/1664] changed license header again --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40381 --- public/IAdminSystem.h | 3 ++- public/IExtensionSys.h | 3 ++- public/IForwardSys.h | 3 ++- public/IHandleSys.h | 3 ++- public/ILibrarySys.h | 3 ++- public/IPluginSys.h | 3 ++- public/IRootConsoleMenu.h | 3 ++- public/IShareSys.h | 3 ++- public/ITextParsers.h | 3 ++- public/extensions/IThreader.h | 3 ++- public/sample_ext/smsdk_ext.cpp | 3 ++- public/sample_ext/smsdk_ext.h | 3 ++- public/sm_platform.h | 3 ++- public/sourcepawn/sp_file_headers.h | 3 ++- public/sourcepawn/sp_typeutil.h | 3 ++- public/sourcepawn/sp_vm_api.h | 3 ++- public/sourcepawn/sp_vm_base.h | 3 ++- public/sourcepawn/sp_vm_types.h | 3 ++- 18 files changed, 36 insertions(+), 18 deletions(-) diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index c335e453..1f53185c 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index dc434b96..4632d398 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 37ecfe27..ee5eaf1f 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 71e0b42d..4f59294f 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index 51ba46ee..7a0ac074 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 1f5526ec..afc71ed9 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IRootConsoleMenu.h b/public/IRootConsoleMenu.h index ccb7877d..b753494c 100644 --- a/public/IRootConsoleMenu.h +++ b/public/IRootConsoleMenu.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/IShareSys.h b/public/IShareSys.h index 8fa8ec63..7f334444 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/ITextParsers.h b/public/ITextParsers.h index 995ac278..d0d71253 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/extensions/IThreader.h b/public/extensions/IThreader.h index be47c9d7..6bcb5aa9 100644 --- a/public/extensions/IThreader.h +++ b/public/extensions/IThreader.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index 33476c97..2e060a7f 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sample_ext/smsdk_ext.h b/public/sample_ext/smsdk_ext.h index 99706bbc..8d23c32e 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/public/sample_ext/smsdk_ext.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sm_platform.h b/public/sm_platform.h index b980ece5..499050f3 100644 --- a/public/sm_platform.h +++ b/public/sm_platform.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index 63a0d1ab..305df2e9 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * ================================================================ * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h index e2282284..c1802a5a 100644 --- a/public/sourcepawn/sp_typeutil.h +++ b/public/sourcepawn/sp_typeutil.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * ================================================================ * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index f04dff14..8fd7846e 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * ================================================================ * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index 0d1b7136..8c40f607 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -1,6 +1,7 @@ /** * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * ================================================================ * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 7218bc95..13bc7107 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -1,7 +1,8 @@ /** * vim: set ts=4 : * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * ================================================================ * * This file is part of the SourceMod/SourcePawn SDK. This file may only be used From f5b969c5511d3242839f3bffe462b5af28a32d95 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 04:25:59 +0000 Subject: [PATCH 0352/1664] added license --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40382 --- public/licenses/GPL.txt | 339 ++++++++++++++++++++++++++++++++++++ public/licenses/LICENSE.txt | 150 ++++++++++++++++ 2 files changed, 489 insertions(+) create mode 100644 public/licenses/GPL.txt create mode 100644 public/licenses/LICENSE.txt diff --git a/public/licenses/GPL.txt b/public/licenses/GPL.txt new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/public/licenses/GPL.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/public/licenses/LICENSE.txt b/public/licenses/LICENSE.txt new file mode 100644 index 00000000..5bf1061d --- /dev/null +++ b/public/licenses/LICENSE.txt @@ -0,0 +1,150 @@ +0. Preamble + + This license is designed to address various issues that came up with AMX Mod X. +SourceMod is Freeware and has fairly unrestrictive terms for redistribution. You +may use it commercially, but you may not sell SourceMod redistributions or +derivatives. + + Derivative works created with the SourceMod SDK are required to be licensed +under the GNU General Public License (GPL), unless with explicit written permission +of AlliedModders LLC. This affects both Extensions and Plugins. A copy of the GPL +is distributed in GPL.txt. + + While there are sections of this license that restrict your usage, there are +many entries to explicitly grant rights that were ambiguous with prior products. + +1. COPYRIGHT INFORMATION + + SourceMod is Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + SourcePawn is Copyright (C) 2006-2007 AlliedModders LLC. All rights reserved. + Pawn and SMALL are Copyright (C) 1997-2007 ITB CompuPhase. + Source is Copyright (C) Valve Corporation. + All trademarks are property of their respective in the US and other countries. + +2. LICENSE AGREEMENT + + The copyright owner and Licensor of SourceMod is "AlliedModders LLC." + SourceMod is Freeware, and does not require payment of any license fee. + This license is a binding legal agreement between the individual who downloads + SourceMod ("you") and the Licensor. AlliedModders hereby grants you a + non-exclusive, transferable license to use SourceMod and its accompanying + documentation and source code. As a condition for granting You a license to + download or use SourceMod, you agree to all of the Terms and Conditions. + If you fail to adhere to the Terms and Conditions, your license to use SourceMod + is automatically revoked without any action on behalf of the Licensor. + + This License may be updated at any time. Each revision is differentiated by a + date version. This License was created on Jan-25-2007. + + With this License, you may: + + a. Use SourceMod on any number of computers; + + b. Redistribute or copy SourceMod (subject to requirements in Section 3); + + c. Alter SourceMod files (both binary and text) for personal use; + + d. Disassemble, decompile, reverse engineer, or otherwise reduce SourceMod + to human readable form for personal use, documentation, research, or to + report bugs or security issues. + + e. Create derivate works using the provided SDK, subject to the SDK Terms + and Conditions (Section 4). + +3. LIMITATIONS ON DISTRIBUTION. + + Redistribution granted in Section 2.b is subject to the following restrictions: + + a. You may alter certain files under the following restrictions: + + (i) You may not alter any binary object file for redistribution. + + (ii) You may alter any text, configuration, or database file, if you + mark the files explicitly as altered from their original. + + (iii) SourceMod may come with files under their own licenses (for example, + the GeoIP database by MaxMind). You must obey the licenses for + third-party files. + + b. You may not sell SourceMod, alter its License, or sell/rent licenses to + third parties (by payment of money or otherwise). + + (i) You may charge for the media transfer of its files only. + + (ii) You may not sell individual files derived from or directly from SourceMod + without explicit written permission of AlliedModders LLC. + + (iii) You may sell or offer services related to installing, configuring, + servicing, coding for, or troubleshooting SourceMod. + + (iv) You may sell or offer services where SourceMod is offered, permitted, or + pre-installed on game servers you provide. You may charge a nominal fee + for such services in relation to SourceMod. However, it must be clear + that you are not charging for a SourceMod License itself, but a service + related to it. + + (v) You may sell or charge for the service of using SourceMod in-game or + remotely. Such services are considered not to be related to SourceMod, + but to the VALVe (R) Source Engine, and thus are not related to this + License or its Terms and Conditions. + + c. You may not remove this or any copyright notice from SourceMod, or any files + distributed with SourceMod. + + d. You may remove files or otherwise reorganize the SourceMod distribution + as long as you explicitly mark it as altered from the original, and maintain + all Copyright and License information. + +4. SDK TERMS AND CONDITIONS. + + You may create derivative works using the + provided SourceMod SDK. In order to create such works, you must agree to the + terms and conditions below. Failure to adhere to these conditions + automatically revokes your License to use the SourceMod SDK. + + a. You may redistribute the SourceMod SDK or any derivative works in object + or source code form, provided you use one of the following open source + licenses. In this case, "use" means "adhere to the terms and conditions of." + The alternate license does not replace the SourceMod SDK License, but + applies to your redistribution of the SourceMod SDK in altered form. + + (i) GNU General Public License ("GPL") Version 2 or higher. A copy of the + GPL is provided in GPL.txt. You are granted explicit permission to link + your GPL SourceMod SDK code against both SourceMod and the Source SDK + from VALVe (R). + + b. Usage of alternate licenses, terms, or conditions specified in Section 4.a + is not allowed unless given explicit written permission from AlliedModders + LLC. You may, however, use more than one of the alternate licenses under a + multi-license scheme. + + c. You may alter any file in the SourceMod SDK and redistribute as long as it + is explicitly marked as altered, and all License or Copyright information + remains unaltered. + + d. You may use the SourceMod SDK freely to write competing works, to reverse + engineer SourceMod, or to otherwise write works unrelated to SourceMod, + under the normal conditions specified by Section 4.a. + +5. NO WARRANTY + + BECAUSE SOURCEMOD IS LICENSED FREE OF CHARGE, THERE IS NO WARRANT, TO THE + EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING + ALLIEDMODDERS LLC AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS + WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL + ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE + THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY + GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA + OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES + OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH + HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + + \ No newline at end of file From cb8829b009dac3ed6dd4f97b96bc26e6a1589943 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 04:26:47 +0000 Subject: [PATCH 0353/1664] corrected line endings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40383 --- public/licenses/GPL.txt | 678 ++++++++++++++++++++-------------------- 1 file changed, 339 insertions(+), 339 deletions(-) diff --git a/public/licenses/GPL.txt b/public/licenses/GPL.txt index d511905c..82fa1daa 100644 --- a/public/licenses/GPL.txt +++ b/public/licenses/GPL.txt @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. From fcc5f00a2bd7e97b6169aadf010c7c71082445b1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 04:35:08 +0000 Subject: [PATCH 0354/1664] changed license header once again --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40384 --- public/IAdminSystem.h | 12 +++++++----- public/IExtensionSys.h | 12 +++++++----- public/IForwardSys.h | 12 +++++++----- public/IHandleSys.h | 12 +++++++----- public/ILibrarySys.h | 12 +++++++----- public/IPluginSys.h | 12 +++++++----- public/IRootConsoleMenu.h | 12 +++++++----- public/IShareSys.h | 12 +++++++----- public/ISourceMod.h | 12 +++++++----- public/ITextParsers.h | 12 +++++++----- public/extensions/IThreader.h | 12 +++++++----- public/sourcepawn/sp_file_headers.h | 12 +++++++----- public/sourcepawn/sp_typeutil.h | 12 +++++++----- public/sourcepawn/sp_vm_api.h | 12 +++++++----- public/sourcepawn/sp_vm_base.h | 12 +++++++----- public/sourcepawn/sp_vm_types.h | 12 +++++++----- 16 files changed, 112 insertions(+), 80 deletions(-) diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 1f53185c..ceb4188c 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index 4632d398..0d0eed87 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IForwardSys.h b/public/IForwardSys.h index ee5eaf1f..6d467e1d 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 4f59294f..9d2d283b 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index 7a0ac074..bac0ede2 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IPluginSys.h b/public/IPluginSys.h index afc71ed9..ea63795b 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IRootConsoleMenu.h b/public/IRootConsoleMenu.h index b753494c..e3fcb97d 100644 --- a/public/IRootConsoleMenu.h +++ b/public/IRootConsoleMenu.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/IShareSys.h b/public/IShareSys.h index 7f334444..559f5583 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/ISourceMod.h b/public/ISourceMod.h index bfdf4897..bd8f2547 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -3,11 +3,13 @@ * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/ITextParsers.h b/public/ITextParsers.h index d0d71253..4f8654c7 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/extensions/IThreader.h b/public/extensions/IThreader.h index 6bcb5aa9..369f8dfd 100644 --- a/public/extensions/IThreader.h +++ b/public/extensions/IThreader.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index 305df2e9..526d764c 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -5,11 +5,13 @@ * All rights reserved. * ================================================================ * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h index c1802a5a..43497929 100644 --- a/public/sourcepawn/sp_typeutil.h +++ b/public/sourcepawn/sp_typeutil.h @@ -5,11 +5,13 @@ * All rights reserved. * ================================================================ * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 8fd7846e..eefe6201 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -5,11 +5,13 @@ * All rights reserved. * ================================================================ * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index 8c40f607..ad9e0095 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -4,11 +4,13 @@ * All rights reserved. * ================================================================ * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 13bc7107..b8f94324 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -5,11 +5,13 @@ * All rights reserved. * ================================================================ * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ From 4bea89f6e7252f05d66964c7640a7fb1861a89f1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 04:35:38 +0000 Subject: [PATCH 0355/1664] removed IThreader.h from the project file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40385 --- core/msvc8/sourcemod_mm.vcproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 9095ead3..a6bfccfa 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -381,10 +381,6 @@ RelativePath="..\..\public\ITextParsers.h" > - - Date: Fri, 26 Jan 2007 19:35:33 +0000 Subject: [PATCH 0356/1664] nearly finished my exams!!! :D library table is no longer needed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40387 --- core/vm/sp_vm_engine.cpp | 5 ----- public/sourcepawn/sp_file_headers.h | 8 -------- public/sourcepawn/sp_vm_types.h | 4 +--- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index c2c81bfe..d59b70b3 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -182,11 +182,6 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t); plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs); } - else if (!(plugin->info.lib) && !strcmp(nameptr, ".libraries")) - { - plugin->info.libraries_num = secptr->size / sizeof(sp_file_libraries_t); - plugin->info.lib = (sp_file_libraries_t *)(base + secptr->dataoffs); - } else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names")) { plugin->info.stringbase = (const char *)(base + secptr->dataoffs); diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index 526d764c..eb0bab53 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -125,14 +125,6 @@ typedef struct sp_file_natives_s uint32_t name; /**< Index into nametable */ } sp_file_natives_t; -/** - * @brief File-encoded format of the ".libraries" section (UNUSED). - */ -typedef struct sp_file_libraries_s -{ - uint32_t name; /**< Index into nametable */ -} sp_file_libraries_t; - /** * @brief File-encoded format of the ".pubvars" section. */ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index b8f94324..3440aa8a 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -82,9 +82,7 @@ typedef struct sp_plugin_infotab_s uint32_t natives_num; /**< number of natives */ sp_file_natives_t *natives; /**< native table */ uint32_t pubvars_num; /**< number of pubvars */ - sp_file_pubvars_t *pubvars; /**< pubvars table */ - uint32_t libraries_num; /**< number of libraries */ - sp_file_libraries_t *lib; /**< library table */ + sp_file_pubvars_t *pubvars; /**< pubvars table */ } sp_plugin_infotab_t; /** From 326ac67c68d3d71eec6294596e34714ab7031b35 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Jan 2007 22:37:54 +0000 Subject: [PATCH 0357/1664] changed around translation API a bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40388 --- core/CTranslator.cpp | 47 ++++++++++++++++---------------------------- core/CTranslator.h | 20 +++++++++++++------ 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 515227ad..bf4369df 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -538,33 +538,35 @@ void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed) } } -const char *CPhraseFile::GetTranslation(const Translation *pTrans, int **fmt_order, unsigned int *fmt_count) +TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans) { - if (pTrans->lang_id >= m_LangCount) + if (lang_id >= m_LangCount) { - return NULL; + return Trans_BadLanguage; } void *object; - if (!sm_trie_retrieve(m_pPhraseLookup, pTrans->szPhrase, &object)) + if (!sm_trie_retrieve(m_pPhraseLookup, szPhrase, &object)) { - return NULL; + return Trans_BadPhrase; } phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(reinterpret_cast(object)); trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); - trans = &trans[pTrans->lang_id]; + trans = &trans[lang_id]; if (trans->stridx == -1) { - return NULL; + return Trans_BadPhraseLanguage; } - *fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order); - *fmt_count = pPhrase->fmt_count; + pTrans->fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order); + pTrans->fmt_count = pPhrase->fmt_count; - return m_pStringTab->GetString(trans->stridx); + pTrans->szPhrase = m_pStringTab->GetString(trans->stridx); + + return Trans_Okay; } const char *CPhraseFile::GetFilename() @@ -735,30 +737,15 @@ SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, return SMCParse_Continue; } -size_t CTranslator::Translate(char *buffer, size_t maxlength, const Translation *pTrans) +size_t CTranslator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans) { - if (pTrans->file_id >= m_Files.size()) - { - return 0; - } - - CPhraseFile *pFile = m_Files[pTrans->file_id]; - unsigned int count; - int *order_table; - const char *str; - - if ((str=pFile->GetTranslation(pTrans, &order_table, &count)) == NULL) - { - return 0; - } - - void *params[MAX_TRANSLATE_PARAMS]; + void *new_params[MAX_TRANSLATE_PARAMS]; /* Rewrite the parameter order */ - for (unsigned int i=0; ifmt_count; i++) { - params[i] = pTrans->params[order_table[i]]; + new_params[i] = params[pTrans->fmt_order[i]]; } - return gnprintf(buffer, maxlength, str, params); + return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params); } diff --git a/core/CTranslator.h b/core/CTranslator.h index 6899626e..a77e7405 100644 --- a/core/CTranslator.h +++ b/core/CTranslator.h @@ -43,10 +43,17 @@ struct Language struct Translation { - const char *szPhrase; - unsigned int lang_id; - unsigned int file_id; - void **params; + const char *szPhrase; /**< Translated phrase. */ + unsigned int fmt_count; /**< Number of format parameters. */ + int *fmt_order; /**< Format phrase order. */ +}; + +enum TransError +{ + Trans_Okay = 0, + Trans_BadLanguage = 1, + Trans_BadPhrase = 2, + Trans_BadPhraseLanguage = 3 }; class CPhraseFile : public ITextListener_SMC @@ -57,7 +64,7 @@ public: public: void ReparseFile(); const char *GetFilename(); - const char *GetTranslation(const Translation *pTrans, int **fmt_order, unsigned int *fmt_count); + TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans); public: //ITextListener_SMC void ReadSMC_ParseStart(); void ReadSMC_ParseEnd(bool halted, bool failed); @@ -99,7 +106,8 @@ public: BaseStringTable *GetStringTable(); unsigned int GetLanguageCount(); bool GetLanguageByCode(const char *code, unsigned int *index); - size_t Translate(char *buffer, size_t maxlength, const Translation *pTrans); + size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans); + CPhraseFile *GetFileByIndex(unsigned int index); private: CVector m_Languages; CVector m_Files; From 21123f4c741c65f0d2fc336d00cf06bf79d509e6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 27 Jan 2007 00:03:34 +0000 Subject: [PATCH 0358/1664] fixed plugins being loaded twice if they were loaded previously --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40389 --- core/systems/PluginSys.cpp | 46 ++++++++++++++++++++++++++------------ core/systems/PluginSys.h | 12 ++++++++-- public/IPluginSys.h | 4 +++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index b1818118..c75fd680 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -634,7 +634,7 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa } //well i have discovered that gabe newell is very fat, so i wrote this comment now -bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max) +LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max) { /** * Does this plugin already exist? @@ -642,19 +642,18 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug CPlugin *pPlugin; if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin)) { - /* First check the type */ - PluginType type = pPlugin->GetType(); - if (type == PluginType_Private - || type == PluginType_Global) - { - return true; - } /* Check to see if we should try reloading it */ if (pPlugin->GetStatus() == Plugin_BadLoad || pPlugin->GetStatus() == Plugin_Error || pPlugin->GetStatus() == Plugin_Failed) { UnloadPlugin(pPlugin); + } else { + if (_plugin) + { + *_plugin = pPlugin; + } + return LoadRes_AlreadyLoaded; } } @@ -732,19 +731,27 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug *_plugin = pPlugin; } - return (pPlugin->GetStatus() == Plugin_Loaded); + return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure; } -IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) +IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max, bool *wasloaded) { CPlugin *pl; + LoadRes res; - if (!_LoadPlugin(&pl, path, debug, type, error, err_max)) + *wasloaded = false; + if ((res=_LoadPlugin(&pl, path, debug, type, error, err_max)) == LoadRes_Failure) { delete pl; return NULL; } + if (res == LoadRes_AlreadyLoaded) + { + *wasloaded = true; + return pl; + } + AddPlugin(pl); /* Run second pass if we need to */ @@ -763,15 +770,19 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ void CPluginManager::LoadAutoPlugin(const char *plugin) { CPlugin *pl; + LoadRes res; char error[255] = "Unknown error"; - if (!_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) + if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure) { g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error); pl->SetErrorState(Plugin_Failed, "%s", error); } - AddPlugin(pl); + if (res == LoadRes_Successful) + { + AddPlugin(pl); + } } void CPluginManager::AddPlugin(CPlugin *pPlugin) @@ -1410,8 +1421,15 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc } char error[128]; + bool wasloaded; const char *filename = g_RootMenu.GetArgument(3); - IPlugin *pl = LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error)); + IPlugin *pl = LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded); + + if (wasloaded) + { + g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", filename); + return; + } if (pl) { diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index f463dade..1cbb05cf 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -89,6 +89,13 @@ struct ContextPair IVirtualMachine *vm; }; +enum LoadRes +{ + LoadRes_Successful, + LoadRes_AlreadyLoaded, + LoadRes_Failure +}; + class CPlugin : public IPlugin { friend class CPluginManager; @@ -235,7 +242,8 @@ public: //IPluginManager bool debug, PluginType type, char error[], - size_t err_max); + size_t err_max, + bool *wasloaded); bool UnloadPlugin(IPlugin *plugin); IPlugin *FindPluginByContext(const sp_context_t *ctx); unsigned int GetPluginCount(); @@ -302,7 +310,7 @@ public: void ReloadOrUnloadPlugins(); private: - bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); + LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); void LoadAutoPlugin(const char *plugin); diff --git a/public/IPluginSys.h b/public/IPluginSys.h index ea63795b..1feb5858 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -251,13 +251,15 @@ namespace SourceMod * @param type Lifetime of the plugin. * @param error Buffer to hold any error message. * @param err_max Maximum length of error message buffer. + * @param wasloaded Stores if the plugin is already loaded. * @return A new plugin pointer on success, false otherwise. */ virtual IPlugin *LoadPlugin(const char *path, bool debug, PluginType type, char error[], - size_t err_max) =0; + size_t err_max, + bool *wasloaded) =0; /** * @brief Attempts to unload a plugin. From d72eef61961d0deffe4fcf7170e5f667f87fb146 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 00:06:21 +0000 Subject: [PATCH 0359/1664] changed how versioning is done --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40390 --- core/msvc8/sourcemod_mm.vcproj | 4 ++++ core/sm_version.h | 5 +++-- core/svn_version.h | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 core/svn_version.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a6bfccfa..d79f849e 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -337,6 +337,10 @@ RelativePath="..\sourcemod.h" > + + Date: Sat, 27 Jan 2007 00:50:59 +0000 Subject: [PATCH 0360/1664] turned /W64 off --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40391 --- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index f697686c..5d64372f 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -122,7 +122,7 @@ RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" - Detect64BitPortabilityProblems="true" + Detect64BitPortabilityProblems="false" DebugInformationFormat="3" /> Date: Sat, 27 Jan 2007 02:25:23 +0000 Subject: [PATCH 0361/1664] added version info --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40392 --- core/msvc8/sourcemod_mm.vcproj | 8 ++ core/sm_version.h | 1 + core/svn_version.h | 6 +- core/version.rc | 104 ++++++++++++++++++++++++ sourcepawn/compiler/libpawnc.rc | 10 +-- sourcepawn/compiler/msvc8/spcomp.vcproj | 2 +- sourcepawn/compiler/pawncc.c | 25 ------ sourcepawn/compiler/sc1.c | 6 +- sourcepawn/compiler/svnrev.h | 9 -- sourcepawn/jit/x86/jit_x86.cpp | 3 +- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 12 +++ sourcepawn/jit/x86/svn_version.h | 11 +++ sourcepawn/jit/x86/version.rc | 103 +++++++++++++++++++++++ 13 files changed, 254 insertions(+), 46 deletions(-) create mode 100644 core/version.rc delete mode 100644 sourcepawn/compiler/svnrev.h create mode 100644 sourcepawn/jit/x86/svn_version.h create mode 100644 sourcepawn/jit/x86/version.rc diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d79f849e..913534d3 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -614,6 +614,14 @@ + + + + diff --git a/core/sm_version.h b/core/sm_version.h index 774818cf..ca273dd3 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -25,5 +25,6 @@ #define SOURCEMOD_V_REV 0 #define SOURCEMOD_VERSION "1.0.0." SVN_REVISION_STRING +#define SOURCEMOD_FILEVERS 1,0,0,0 #endif //_INCLUDE_SOURCEMOD_VERSION_H_ diff --git a/core/svn_version.h b/core/svn_version.h index 74cf8f5b..95cf2d96 100644 --- a/core/svn_version.h +++ b/core/svn_version.h @@ -3,7 +3,9 @@ #ifndef _INCLUDE_SVN_VERSION_H_ #define _INCLUDE_SVN_VERSION_H_ -#define SVN_REVISION 0 -#define SVN_REVISION_STRING "$trunk" +#define SVN_REVISION 390 +#define SVN_REVISION_STRING "390" +#define SVN_FILE_VERSION 1,0,0,390 #endif //_INCLUDE_SVN_VERSION_H_ + diff --git a/core/version.rc b/core/version.rc new file mode 100644 index 00000000..5e6c1bfe --- /dev/null +++ b/core/version.rc @@ -0,0 +1,104 @@ +// Microsoft Visual C++ generated resource script. +// +//#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +#include "sm_version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION SVN_FILE_VERSION + PRODUCTVERSION SVN_FILE_VERSION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "SourceMod" + VALUE "FileDescription", "SourceMod Core" + VALUE "FileVersion", SVN_REVISION_STRING + VALUE "InternalName", "sourcemod" + VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" + VALUE "OriginalFilename", "sourcemod_mm.dll" + VALUE "ProductName", "SourceMod" + VALUE "ProductVersion", SOURCEMOD_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/sourcepawn/compiler/libpawnc.rc b/sourcepawn/compiler/libpawnc.rc index df89015a..d486738d 100644 --- a/sourcepawn/compiler/libpawnc.rc +++ b/sourcepawn/compiler/libpawnc.rc @@ -4,7 +4,7 @@ #else # include #endif -#include "svnrev.h" +#include "svn_version.h" AppIcon ICON "pawn.ico" @@ -13,10 +13,10 @@ AppIcon ICON "pawn.ico" * All strings MUST have an explicit \0. See the Windows SDK documentation * for details on version information and the VERSIONINFO structure. */ -#define VERSION SMC_VERSION -#define REVISION SMC_REVISION -#define BUILD SMC_BUILD -#define VERSIONSTR SMC_VERSTRING +#define VERSION 1 +#define REVISION 0 +#define BUILD SVN_REVISION +#define VERSIONSTR SVN_REVISION_STRING #define VERSIONNAME "smcomp.exe\0" #define VERSIONDESCRIPTION "SourcePawn Compiler\0" #define VERSIONPRODUCTNAME "smcomp\0" diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index bc6dacc2..c18d258b 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -309,7 +309,7 @@ > diff --git a/sourcepawn/compiler/pawncc.c b/sourcepawn/compiler/pawncc.c index b5dc1bc3..8a35a40f 100644 --- a/sourcepawn/compiler/pawncc.c +++ b/sourcepawn/compiler/pawncc.c @@ -260,31 +260,6 @@ int main(int argc, char *argv[]) spfw_next_section(spf); } - if (sections[FS_Libraries]) - { - sp_file_libraries_t *libtbl; - AMX_FUNCSTUBNT *stub; - unsigned char *stubptr; - uint32_t libraries = sections[FS_Libraries]; - - libtbl = (sp_file_libraries_t *)malloc(sizeof(sp_file_libraries_t) * libraries); - stubptr = (unsigned char *)hdr + hdr->libraries; - - for (i=0; inameofs - (hdr->nametable + sizeof(uint16_t)); - - stubptr += hdr->defsize; - } - if (libraries) - { - sfwrite(libtbl, sizeof(sp_file_libraries_t), libraries, spf); - } - free(libtbl); - spfw_next_section(spf); - } - if (sections[FS_Nametable]) { unsigned char *base; diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 646a8161..d605a8c8 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -65,9 +65,9 @@ #include "lstring.h" #include "sc.h" -#include "svnrev.h" +#include "svn_version.h" #include "sctracker.h" -#define VERSION_STR "3.2." SVN_REVSTR +#define VERSION_STR "3.2.3636" #define VERSION_INT 0x0302 int pc_functag = 0; @@ -1179,7 +1179,7 @@ static void setconfig(char *root) static void setcaption(void) { - pc_printf("SourcePawn Compiler " SMC_VERSTRING "\n"); + pc_printf("SourcePawn Compiler 1.0.0." SVN_REVISION_STRING "\n"); pc_printf("Copyright (c) 1997-2006, ITB CompuPhase, (C)2004-2006 AlliedModders, LLC\n\n"); } diff --git a/sourcepawn/compiler/svnrev.h b/sourcepawn/compiler/svnrev.h deleted file mode 100644 index 3843eb5b..00000000 --- a/sourcepawn/compiler/svnrev.h +++ /dev/null @@ -1,9 +0,0 @@ -#define SMC_VERSION 1 -#define SMC_REVISION 0 -#define SMC_BUILD 1 -#define SMC_VERSTRING "1.0.1.3636" - -#define SVN_REV 3636 -#define SVN_REVSTR "3636" -#define SVN_REVDATE "2006-08-14" -#define SVN_REVSTAMP 20060814L diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 0e561626..35da47a2 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -17,6 +17,7 @@ #include "jit_x86.h" #include "opcode_helpers.h" #include "x86_macros.h" +#include "jit_version.h" #if defined USE_UNGEN_OPCODES #include "ungen_opcodes.h" @@ -2331,7 +2332,7 @@ unsigned int JITX86::FunctionCount(const sp_context_t *ctx) const char *JITX86::GetVersionString() { - return "1.0.0.0"; + return JIT_VERSION; } const char *JITX86::GetCPUOptimizations() diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index 5d64372f..a9d943e3 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -208,6 +208,10 @@ RelativePath="..\dll_exports.h" > + + @@ -216,6 +220,10 @@ RelativePath="..\opcode_helpers.h" > + + @@ -238,6 +246,10 @@ RelativePath="..\ungen_opcode_switch.inc" > + + Date: Sat, 27 Jan 2007 02:58:24 +0000 Subject: [PATCH 0362/1664] fixed directory structure --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40393 --- extensions/geoip/{ => msvc8}/geoip.sln | 0 extensions/geoip/{ => msvc8}/geoip.vcproj | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) rename extensions/geoip/{ => msvc8}/geoip.sln (100%) rename extensions/geoip/{ => msvc8}/geoip.vcproj (92%) diff --git a/extensions/geoip/geoip.sln b/extensions/geoip/msvc8/geoip.sln similarity index 100% rename from extensions/geoip/geoip.sln rename to extensions/geoip/msvc8/geoip.sln diff --git a/extensions/geoip/geoip.vcproj b/extensions/geoip/msvc8/geoip.vcproj similarity index 92% rename from extensions/geoip/geoip.vcproj rename to extensions/geoip/msvc8/geoip.vcproj index 5128b8af..392724b7 100644 --- a/extensions/geoip/geoip.vcproj +++ b/extensions/geoip/msvc8/geoip.vcproj @@ -1,7 +1,7 @@ @@ -351,19 +351,19 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > From 7f44c014ae1f85c42a7fc490777541dac2be42ec Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:10:31 +0000 Subject: [PATCH 0363/1664] added build tool --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40394 --- core/svn_version.h | 6 +- sourcepawn/jit/x86/svn_version.h | 6 +- tools/builder/ABuilder.cs | 165 +++++++++++++++++++++++++++++++ tools/builder/AssemblyInfo.cs | 58 +++++++++++ tools/builder/Config.cs | 120 ++++++++++++++++++++++ tools/builder/LinuxBuilder.cs | 93 +++++++++++++++++ tools/builder/Main.cs | 39 ++++++++ tools/builder/Package.cs | 51 ++++++++++ tools/builder/PkgCore.cs | 96 ++++++++++++++++++ tools/builder/Win32Builder.cs | 65 ++++++++++++ tools/builder/build-win32.cfg | 0 tools/builder/builder.csproj | 130 ++++++++++++++++++++++++ tools/builder/builder.sln | 23 +++++ 13 files changed, 846 insertions(+), 6 deletions(-) create mode 100644 tools/builder/ABuilder.cs create mode 100644 tools/builder/AssemblyInfo.cs create mode 100644 tools/builder/Config.cs create mode 100644 tools/builder/LinuxBuilder.cs create mode 100644 tools/builder/Main.cs create mode 100644 tools/builder/Package.cs create mode 100644 tools/builder/PkgCore.cs create mode 100644 tools/builder/Win32Builder.cs create mode 100644 tools/builder/build-win32.cfg create mode 100644 tools/builder/builder.csproj create mode 100644 tools/builder/builder.sln diff --git a/core/svn_version.h b/core/svn_version.h index 95cf2d96..c4478d50 100644 --- a/core/svn_version.h +++ b/core/svn_version.h @@ -3,9 +3,9 @@ #ifndef _INCLUDE_SVN_VERSION_H_ #define _INCLUDE_SVN_VERSION_H_ -#define SVN_REVISION 390 -#define SVN_REVISION_STRING "390" -#define SVN_FILE_VERSION 1,0,0,390 +#define SVN_REVISION 392 +#define SVN_REVISION_STRING "392" +#define SVN_FILE_VERSION 1,0,0,392 #endif //_INCLUDE_SVN_VERSION_H_ diff --git a/sourcepawn/jit/x86/svn_version.h b/sourcepawn/jit/x86/svn_version.h index 46a4d57a..c4478d50 100644 --- a/sourcepawn/jit/x86/svn_version.h +++ b/sourcepawn/jit/x86/svn_version.h @@ -3,9 +3,9 @@ #ifndef _INCLUDE_SVN_VERSION_H_ #define _INCLUDE_SVN_VERSION_H_ -#define SVN_REVISION 390 -#define SVN_REVISION_STRING "390" -#define SVN_FILE_VERSION 1,0,0,390 +#define SVN_REVISION 392 +#define SVN_REVISION_STRING "392" +#define SVN_FILE_VERSION 1,0,0,392 #endif //_INCLUDE_SVN_VERSION_H_ diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs new file mode 100644 index 00000000..5400f846 --- /dev/null +++ b/tools/builder/ABuilder.cs @@ -0,0 +1,165 @@ +using System; +using System.IO; +using System.Diagnostics; + +namespace builder +{ + public abstract class ABuilder + { + public Config cfg; + + public ABuilder() + { + } + + public abstract bool BuildLibrary(Package pkg, Library lib, ref string _binName, ref string _binPath); + + public void UpdateRevisionInfo(Package pkg, Library lib) + { + string path = Config.PathFormat("{0}/{1}", cfg.SourceBase, lib.LocalPath); + string file = Config.PathFormat("{0}/svn_version.h", path); + + if (File.Exists(file)) + { + UpdateRevisionInfo(path, file); + } + } + + public void CopyFolder(Package pkg, string source, string dest, string [] omits) + { + string from_base = Config.PathFormat("{0}/{1}", cfg.SourceBase, source); + string to_base = Config.PathFormat("{0}/{1}/{2}", + cfg.OutputBase, + pkg.GetBaseFolder(), + dest); + + string [] files = Directory.GetFiles(from_base); + string file; + + for (int i=0; i. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/tools/builder/Config.cs b/tools/builder/Config.cs new file mode 100644 index 00000000..bb52ad95 --- /dev/null +++ b/tools/builder/Config.cs @@ -0,0 +1,120 @@ +using System; +using System.IO; +using System.Text; + +namespace builder +{ + public enum BasePlatform + { + Platform_Windows, + Platform_Linux + }; + + public class Config + { + public string SourceBase; + public string OutputBase; + public string BuilderPath; + public string CompressPath; + public string CompressOptions; + public string SVNVersion; + public string ProductVersion; + public builder.BasePlatform Platform; + + public Config() + { + if ((int)System.Environment.OSVersion.Platform == 128) + { + Platform = BasePlatform.Platform_Linux; + } + else + { + Platform = BasePlatform.Platform_Windows; + } + } + + public static string PathFormat(string format, params string [] args) + { + string temp = string.Format(format, args); + return temp.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + } + + public bool ReadFromFile(string file) + { + bool read = true; + StreamReader sr = null; + try + { + sr = new StreamReader(file); + + string line; + string delim = "\t \n\r\v"; + string split = "="; + + while ( (line = sr.ReadLine()) != null ) + { + line = line.Trim(delim.ToCharArray()); + if (line.Length < 1 || line[0] == ';') + { + continue; + } + string [] s = line.Split(split.ToCharArray()); + string key, val = ""; + if (s.GetLength(0) >= 1) + { + key = s[0]; + if (s.GetLength(0) >= 2) + { + for (int i=1; i"); + return; + } + + Config cfg = new Config(); + if (!cfg.ReadFromFile(args[0])) + { + return; + } + + /* :TODO: Add path validation */ + + ABuilder bld = null; + + if (cfg.Platform == BasePlatform.Platform_Linux) + { + bld = new LinuxBuilder(cfg); + } + else if (cfg.Platform == BasePlatform.Platform_Windows) + { + bld = new Win32Builder(cfg); + } + + bld.BuildPackage(new PkgCore()); + } + } +} diff --git a/tools/builder/Package.cs b/tools/builder/Package.cs new file mode 100644 index 00000000..a9965d52 --- /dev/null +++ b/tools/builder/Package.cs @@ -0,0 +1,51 @@ +using System; + +namespace builder +{ + public class Library + { + public Library() + { + PlatformExt = false; + ProjectFile = null; + IsExecutable = false; + ReleaseBuild = "Release"; + } + public string Name; /* Name of binary */ + public string LocalPath; /* Local path to library build scripts */ + public string ReleaseBuild; /* Release build name */ + public string Destination; /* Final relative path */ + public bool PlatformExt; /* Extra platform extension */ + public string ProjectFile; /* Project file, NULL for standard */ + public bool IsExecutable; /* If this is an EXE instead of a DLL */ + //string DebugBuild; /* Debug build name */ + }; + + public abstract class Package + { + /** + * Must return the base package folder. + */ + public abstract string GetBaseFolder(); + + /** + * Must return the list of folders to create. + */ + public abstract string [] GetFolders(); + + /** + * Called when file to file copies must be performed + */ + public abstract void OnCopyFiles(); + + /** + * Called when dir to dir copies must be performed + */ + public abstract void OnCopyFolders(ABuilder builder); + + /** + * Called to build libraries + */ + public abstract Library [] GetLibraries(); + } +} diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs new file mode 100644 index 00000000..35cd3e28 --- /dev/null +++ b/tools/builder/PkgCore.cs @@ -0,0 +1,96 @@ +using System; + +namespace builder +{ + public class PkgCore : Package + { + public PkgCore() + { + } + + public override string GetBaseFolder() + { + return "base/addons/sourcemod"; + } + + /** + * Must return the list of folders to create. + */ + public override string [] GetFolders() + { + string [] folders = new string[7]; + + folders[0] = "bin"; + folders[1] = "plugins/disabled"; + folders[2] = "configs"; + folders[3] = "translations"; + folders[4] = "logs"; + folders[5] = "extensions"; + folders[6] = "scripting/include"; + + return folders; + } + + /** + * Called when file to file copies must be performed + */ + public override void OnCopyFiles() + { + } + + /** + * Called when dir to dir copies must be performed + */ + public override void OnCopyFolders(ABuilder builder) + { + builder.CopyFolder(this, "configs", "configs", null); + + string [] plugin_omits = new string[1]; + plugin_omits[0] = "spcomp.exe"; + + builder.CopyFolder(this, "plugins", "scripting", plugin_omits); + builder.CopyFolder(this, "plugins/include", "scripting/include", null); + builder.CopyFolder(this, "translations", "translations", null); + } + + /** + * Called to build libraries + */ + public override Library [] GetLibraries() + { + Library [] libs = new Library[5]; + + for (int i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/builder/builder.sln b/tools/builder/builder.sln new file mode 100644 index 00000000..a621b833 --- /dev/null +++ b/tools/builder/builder.sln @@ -0,0 +1,23 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "builder", "builder.csproj", "{BFC4EB78-4C3E-4C81-8EAD-5A1A2F126512}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BFC4EB78-4C3E-4C81-8EAD-5A1A2F126512}.Debug.ActiveCfg = Debug|.NET + {BFC4EB78-4C3E-4C81-8EAD-5A1A2F126512}.Debug.Build.0 = Debug|.NET + {BFC4EB78-4C3E-4C81-8EAD-5A1A2F126512}.Release.ActiveCfg = Release|.NET + {BFC4EB78-4C3E-4C81-8EAD-5A1A2F126512}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal From aa8bf86dc15c2b841ebdf31572058f0dadcc6dc7 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 27 Jan 2007 03:25:34 +0000 Subject: [PATCH 0364/1664] added %T format support added a new lang native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40395 --- core/msvc8/sourcemod_mm.vcproj | 6 +++- core/sm_stringutil.cpp | 53 ++++++++++++++++++++++++++++++++++ core/sm_stringutil.h | 2 ++ core/smn_lang.cpp | 29 +++++++++++++++++++ core/smn_textparse.cpp | 3 ++ core/systems/PluginSys.cpp | 15 ++++++++++ core/systems/PluginSys.h | 17 +++++++++++ plugins/include/lang.inc | 26 +++++++++++++++++ 8 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 core/smn_lang.cpp create mode 100644 plugins/include/lang.inc diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 913534d3..7fdd69da 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 133a2a87..1dda1ab9 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -16,6 +16,8 @@ #include #include "sm_stringutil.h" #include "CLogger.h" +#include "PluginSys.h" +#include "CTranslator.h" #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ @@ -28,6 +30,47 @@ return 0; \ } +size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg) +{ + unsigned int langid; + CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); + size_t langcount = pl->GetLangFileCount(); + + if (!g_Translator.GetLanguageByCode("en", &langid)) //:TODO: hardcoded this just for testing + { + //:TODO: error out something + } + + CPhraseFile *phrfl; + TransError err = Trans_Okay; + Translation pTrans; + + for (size_t i=0; iGetFileByIndex(i)); + err = phrfl->GetTranslation(key, langid, &pTrans); + } + + if (err != Trans_Okay) + { + //:TODO: we didnt find our translation in any file :o + } + + void *new_params[MAX_TRANSLATE_PARAMS]; + unsigned int max_params = pTrans.fmt_count; + for (size_t i=0; iLocalToPhysAddr(params[*arg], reinterpret_cast(&new_params[i])); + (*arg)++; + if ((*arg) + i > (size_t)params[0]) + { + //:TODO: we are missing arguments zOMG + } + } + + return g_Translator.Translate(buffer, maxlen, new_params, &pTrans); +} + //:TODO: review this code before we choose a license void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) @@ -564,6 +607,16 @@ reswitch: arg++; break; } + case 'T': + { + CHECK_ARGS(0); + char *key; + cell_t target = params[arg++]; + pCtx->LocalToString(params[arg++], &key); + llen -= Translate(buf_p, llen, pCtx, key, target, params, &arg); + buf_p += llen; + break; + } case '%': { if (!llen) diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 61fe0fce..d47b4b7b 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -20,6 +20,8 @@ using namespace SourcePawn; +#define LANG_SERVER 0 + size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); diff --git a/core/smn_lang.cpp b/core/smn_lang.cpp new file mode 100644 index 00000000..f6d3728f --- /dev/null +++ b/core/smn_lang.cpp @@ -0,0 +1,29 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "PluginSys.h" +#include "CTranslator.h" + +static cell_t sm_LoadTranslations(IPluginContext *pCtx, const cell_t *params) +{ + char *filename; + unsigned int index; + CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); + + pCtx->LocalToString(params[1], &filename); + + index = g_Translator.FindOrAddPhraseFile(filename); + pl->AddLangFile(index); + + return 1; +} diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index 35e4c79a..b61f90de 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -268,6 +268,9 @@ static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[3], &c_line); pContext->LocalToPhysAddr(params[4], &c_col); + *c_line = line; + *c_col = col; + return (cell_t)p_err; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index c75fd680..15284a06 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -491,6 +491,21 @@ void CPlugin::SetTimeStamp(time_t t) m_LastAccess = t; } +void CPlugin::AddLangFile(unsigned int index) +{ + m_PhraseFiles.push_back(index); +} + +size_t CPlugin::GetLangFileCount() const +{ + return m_PhraseFiles.size(); +} + +unsigned int CPlugin::GetFileByIndex(unsigned int index) const +{ + return m_PhraseFiles.at(index); +} + /******************* * PLUGIN ITERATOR * *******************/ diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 1cbb05cf..fe5dc201 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "sm_globals.h" #include "vm/sp_vm_basecontext.h" #include "PluginInfoDatabase.h" @@ -176,6 +177,21 @@ public: * Returns true if a plugin is usable. */ bool IsRunnable() const; + + /** + * Adds a language file index to the plugin's list. + */ + void AddLangFile(unsigned int index); + + /** + * Get language file count for this plugin. + */ + size_t GetLangFileCount() const; + + /** + * Get language file index based on the vector index. + */ + unsigned int GetFileByIndex(unsigned int index) const; public: /** * Returns the modification time during last plugin load. @@ -207,6 +223,7 @@ private: IdentityToken_t *m_ident; Handle_t m_handle; bool m_WasRunning; + CVector m_PhraseFiles; }; class CPluginManager : diff --git a/plugins/include/lang.inc b/plugins/include/lang.inc new file mode 100644 index 00000000..66fff159 --- /dev/null +++ b/plugins/include/lang.inc @@ -0,0 +1,26 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _lang_included + #endinput +#endif +#define _lang_included + +/** + * @brief Loads a translation file for the plugin calling this native. + * + * @param path Translation file. + * @noreturn + */ +native LoadTranslations(const String:file[]); \ No newline at end of file From 49c6e38ffa15a06d518277f1d424a1f67c357688 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:35:42 +0000 Subject: [PATCH 0365/1664] added version file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40396 --- sourcepawn/jit/x86/jit_version.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 sourcepawn/jit/x86/jit_version.h diff --git a/sourcepawn/jit/x86/jit_version.h b/sourcepawn/jit/x86/jit_version.h new file mode 100644 index 00000000..2f86e017 --- /dev/null +++ b/sourcepawn/jit/x86/jit_version.h @@ -0,0 +1,22 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + + +#ifndef _INCLUDE_JIT_VERSION_H_ +#define _INCLUDE_JIT_VERSION_H_ + +#include "svn_version.h" + +#define JIT_VERSION "1.0.0" SVN_REVISION_STRING + +#endif //_INCLUDE_JIT_VERSION_H_ From 8434c25bd801aad636c934df6916ba70d9fc8e97 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:38:52 +0000 Subject: [PATCH 0366/1664] added compiler's version file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40397 --- sourcepawn/compiler/svn_version.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 sourcepawn/compiler/svn_version.h diff --git a/sourcepawn/compiler/svn_version.h b/sourcepawn/compiler/svn_version.h new file mode 100644 index 00000000..c4478d50 --- /dev/null +++ b/sourcepawn/compiler/svn_version.h @@ -0,0 +1,11 @@ +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 392 +#define SVN_REVISION_STRING "392" +#define SVN_FILE_VERSION 1,0,0,392 + +#endif //_INCLUDE_SVN_VERSION_H_ + From 7d33bf009896def34164b1b55523e8f4464010d1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:40:05 +0000 Subject: [PATCH 0367/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40398 --- tools/builder/LinuxBuilder.cs | 18 +----------------- tools/builder/PkgCore.cs | 1 + tools/builder/build-linux.cfg | 5 +++++ tools/builder/build-win32.cfg | 5 +++++ 4 files changed, 12 insertions(+), 17 deletions(-) create mode 100644 tools/builder/build-linux.cfg diff --git a/tools/builder/LinuxBuilder.cs b/tools/builder/LinuxBuilder.cs index 9aeea04a..35ee9063 100644 --- a/tools/builder/LinuxBuilder.cs +++ b/tools/builder/LinuxBuilder.cs @@ -57,7 +57,7 @@ namespace builder /* Now build it */ info.WorkingDirectory = path; info.FileName = cfg.BuilderPath; - info.Arguments = "Release"; + info.Arguments = ""; info.UseShellExecute = false; p = Process.Start(info); p.WaitForExit(); @@ -68,22 +68,6 @@ namespace builder return false; } - /* Now verify the binary */ - info.WorkingDirectory = "/bin"; /* :TODO: Fix this */ - info.FileName = "dlsym"; - info.Arguments = binpath; - info.UseShellExecute = false; - info.RedirectStandardOutput = true; - p = Process.Start(info); - string output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); - p.Close(); - - if (output.IndexOf("Handle:") == -1) - { - return false; - } - _binName = binName; _binPath = binpath; diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 35cd3e28..1976c1b1 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -94,3 +94,4 @@ namespace builder } } } + diff --git a/tools/builder/build-linux.cfg b/tools/builder/build-linux.cfg new file mode 100644 index 00000000..2ac4b5b6 --- /dev/null +++ b/tools/builder/build-linux.cfg @@ -0,0 +1,5 @@ +OutputBase = /home/users/dvander/done +SourceBase = /home/users/dvander/sourcemod/trunk +BuilderPath = /usr/bin/make +SVNVersion = /usr/bin/svnversion +ProductVersion = 1.0.0 diff --git a/tools/builder/build-win32.cfg b/tools/builder/build-win32.cfg index e69de29b..15b722bd 100644 --- a/tools/builder/build-win32.cfg +++ b/tools/builder/build-win32.cfg @@ -0,0 +1,5 @@ +OutputBase = c:\real\done\sourcemod +SourceBase = r:\sourcemod\trunk +BuilderPath = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.com +SVNVersion = C:\Program Files\Subversion\bin\svnversion.exe +ProductVersion = 1.0.0 From 8f64370954d48012c46b4406f1d293d48d250985 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:46:48 +0000 Subject: [PATCH 0368/1664] updated core's makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40399 --- core/Makefile | 2 +- core/svn_version.h | 22 +++++++++++----------- sourcepawn/compiler/svn_version.h | 22 +++++++++++----------- sourcepawn/jit/x86/svn_version.h | 22 +++++++++++----------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/core/Makefile b/core/Makefile index 9c9c6b6e..beb6bb34 100644 --- a/core/Makefile +++ b/core/Makefile @@ -13,7 +13,7 @@ OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden DEBUG_FLAGS = -g -ggdb3 CPP = gcc-4.1 -BINARY = sourcemod_mm.so +BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk diff --git a/core/svn_version.h b/core/svn_version.h index c4478d50..4aee5738 100644 --- a/core/svn_version.h +++ b/core/svn_version.h @@ -1,11 +1,11 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 392 -#define SVN_REVISION_STRING "392" -#define SVN_FILE_VERSION 1,0,0,392 - -#endif //_INCLUDE_SVN_VERSION_H_ - +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 395 +#define SVN_REVISION_STRING "395" +#define SVN_FILE_VERSION 1,0,0,395 + +#endif //_INCLUDE_SVN_VERSION_H_ + diff --git a/sourcepawn/compiler/svn_version.h b/sourcepawn/compiler/svn_version.h index c4478d50..53b1673c 100644 --- a/sourcepawn/compiler/svn_version.h +++ b/sourcepawn/compiler/svn_version.h @@ -1,11 +1,11 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 392 -#define SVN_REVISION_STRING "392" -#define SVN_FILE_VERSION 1,0,0,392 - -#endif //_INCLUDE_SVN_VERSION_H_ - +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 397 +#define SVN_REVISION_STRING "397" +#define SVN_FILE_VERSION 1,0,0,397 + +#endif //_INCLUDE_SVN_VERSION_H_ + diff --git a/sourcepawn/jit/x86/svn_version.h b/sourcepawn/jit/x86/svn_version.h index c4478d50..66c0227f 100644 --- a/sourcepawn/jit/x86/svn_version.h +++ b/sourcepawn/jit/x86/svn_version.h @@ -1,11 +1,11 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 392 -#define SVN_REVISION_STRING "392" -#define SVN_FILE_VERSION 1,0,0,392 - -#endif //_INCLUDE_SVN_VERSION_H_ - +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 396 +#define SVN_REVISION_STRING "396" +#define SVN_FILE_VERSION 1,0,0,396 + +#endif //_INCLUDE_SVN_VERSION_H_ + From 8cea528978cbb2d09917f7b4e5d0993858346e21 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:55:33 +0000 Subject: [PATCH 0369/1664] fixed compiler not getting includes right on linux --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40400 --- sourcepawn/compiler/sc1.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index d605a8c8..6ab861a4 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1118,12 +1118,6 @@ static void setconfig(char *root) /* add the default "include" directory */ #if defined __WIN32__ || defined _WIN32 GetModuleFileNameA(NULL,path,_MAX_PATH); - #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ - /* see www.autopackage.org for the BinReloc module */ - br_init_lib(NULL); - ptr=br_find_exe("spcomp"); - strlcpy(path,ptr,sizeof path); - free(ptr); #else if (root!=NULL) strlcpy(path,root,sizeof path); /* path + filename (hopefully) */ From ad403d62a217b940c3367e2f6865489b48ac7589 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 03:55:59 +0000 Subject: [PATCH 0370/1664] changed .psrc to .sp --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40401 --- sourcepawn/compiler/sc1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 6ab861a4..2af527c9 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -990,8 +990,8 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam i=atoi(ptr+1); add_constant(str,i,sGLOBAL,0); } else { - strlcpy(str,argv[arg],sizeof(str)-5); /* -5 because default extension is ".psrc" */ - set_extension(str,".psrc",FALSE); + strlcpy(str,argv[arg],sizeof(str)-5); /* -5 because default extension is ".sp" */ + set_extension(str,".sp",FALSE); insert_sourcefile(str); /* The output name is the first input name with a different extension, * but it is stored in a different directory From b3b1978d102301a677faea606a84342c6e28c6d6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 04:21:11 +0000 Subject: [PATCH 0371/1664] exposed translation natives and fixed build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40402 --- core/CTranslator.cpp | 10 ++++++++++ core/smn_lang.cpp | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index bf4369df..059f1366 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -737,6 +737,16 @@ SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, return SMCParse_Continue; } +CPhraseFile *CTranslator::GetFileByIndex(unsigned int index) +{ + if (index >= m_Files.size()) + { + return NULL; + } + + return m_Files[index]; +} + size_t CTranslator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans) { void *new_params[MAX_TRANSLATE_PARAMS]; diff --git a/core/smn_lang.cpp b/core/smn_lang.cpp index f6d3728f..a0eefde3 100644 --- a/core/smn_lang.cpp +++ b/core/smn_lang.cpp @@ -27,3 +27,9 @@ static cell_t sm_LoadTranslations(IPluginContext *pCtx, const cell_t *params) return 1; } + +REGISTER_NATIVES(langNativeS) +{ + {"LoadTranslations", sm_LoadTranslations}, + {NULL, NULL}, +}; From aea1073d1391b9d53ec66709cde990195941e07a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 04:50:33 +0000 Subject: [PATCH 0372/1664] added autoloading of extensions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40403 --- core/sourcemod.cpp | 3 +++ core/systems/ExtensionSys.cpp | 49 ++++++++++++++++++++++++++++++++++- core/systems/ExtensionSys.h | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index d482506b..76bbe06d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -216,6 +216,9 @@ void SourceModBase::DoGlobalPluginLoads() sizeof(plugins_path), "plugins"); + /* Load any auto extensions */ + g_Extensions.TryAutoload(); + /* Run the first pass */ g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 0b47740a..066f616b 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -11,6 +11,7 @@ * Version: $Id$ */ +#include #include "ExtensionSys.h" #include "LibrarySys.h" #include "ShareSys.h" @@ -18,7 +19,7 @@ #include "sourcemm_api.h" #include "PluginSys.h" #include "sm_srvcmds.h" -#include +#include "sm_stringutil.h" CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -267,6 +268,52 @@ void CExtensionManager::OnSourceModShutdown() g_ShareSys.DestroyIdentType(g_ExtType); } +void CExtensionManager::TryAutoload() +{ + char path[PLATFORM_MAX_PATH]; + + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions"); + + IDirectory *pDir = g_LibSys.OpenDirectory(path); + if (!pDir) + { + return; + } + + const char *lfile; + size_t len; + while (pDir->MoreFiles()) + { + if (pDir->IsEntryDirectory()) + { + pDir->NextEntry(); + continue; + } + + lfile = pDir->GetEntryName(); + len = strlen(lfile); + if (len <= 9) /* size of ".autoload" */ + { + pDir->NextEntry(); + continue; + } + + if (strcmp(&lfile[len - 9], ".autoload") != 0) + { + pDir->NextEntry(); + continue; + } + + char file[PLATFORM_MAX_PATH]; + len = UTIL_Format(file, sizeof(file), "%s", lfile); + strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT); + + LoadAutoExtension(file); + + pDir->NextEntry(); + } +} + IExtension *CExtensionManager::LoadAutoExtension(const char *path) { if (!strstr(path, "." PLATFORM_LIB_EXT)) diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index e4d32375..a0202c74 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -94,6 +94,7 @@ public: void BindAllNativesToPlugin(IPlugin *pPlugin); void MarkAllLoaded(); void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload); + void TryAutoload(); private: CExtension *FindByOrder(unsigned int num); private: From 9b88f80d0e303c670602b173c29c405aa7e1adb0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 04:50:48 +0000 Subject: [PATCH 0373/1664] fixed a bug in the admin plugin --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40404 --- plugins/admin-base.sp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/admin-base.sp b/plugins/admin-base.sp index c83d0bfb..f196c6eb 100644 --- a/plugins/admin-base.sp +++ b/plugins/admin-base.sp @@ -30,7 +30,7 @@ new bool:g_LoggedFileName = false; /* Whether or not the file name has been lo public OnPluginStart() { - g_hLevelParser = SMC_CreateParse(); + g_hLevelParser = SMC_CreateParser(); SMC_SetReaders(g_hLevelParser, ReadLevels_NewSection, ReadLevels_KeyValue, From cb1e84781dadb062d5787ce9b2f376400c550670 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 05:25:47 +0000 Subject: [PATCH 0374/1664] fixed line endings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40405 --- tools/builder/build-win32.cfg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/builder/build-win32.cfg b/tools/builder/build-win32.cfg index 15b722bd..0a4a86a9 100644 --- a/tools/builder/build-win32.cfg +++ b/tools/builder/build-win32.cfg @@ -1,5 +1,5 @@ -OutputBase = c:\real\done\sourcemod -SourceBase = r:\sourcemod\trunk -BuilderPath = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.com -SVNVersion = C:\Program Files\Subversion\bin\svnversion.exe -ProductVersion = 1.0.0 +OutputBase = c:\real\done\sourcemod +SourceBase = r:\sourcemod\trunk +BuilderPath = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.com +SVNVersion = C:\Program Files\Subversion\bin\svnversion.exe +ProductVersion = 1.0.0 From 32679b7d48f36dd4bd6cae441c0d8e7028b64a17 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 05:38:23 +0000 Subject: [PATCH 0375/1664] fixed license mistakes (greentryst) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40406 --- public/licenses/LICENSE.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/licenses/LICENSE.txt b/public/licenses/LICENSE.txt index 5bf1061d..679fc157 100644 --- a/public/licenses/LICENSE.txt +++ b/public/licenses/LICENSE.txt @@ -19,7 +19,7 @@ many entries to explicitly grant rights that were ambiguous with prior products. SourcePawn is Copyright (C) 2006-2007 AlliedModders LLC. All rights reserved. Pawn and SMALL are Copyright (C) 1997-2007 ITB CompuPhase. Source is Copyright (C) Valve Corporation. - All trademarks are property of their respective in the US and other countries. + All trademarks are property of their respective owners in the US and other countries. 2. LICENSE AGREEMENT @@ -28,13 +28,13 @@ many entries to explicitly grant rights that were ambiguous with prior products. This license is a binding legal agreement between the individual who downloads SourceMod ("you") and the Licensor. AlliedModders hereby grants you a non-exclusive, transferable license to use SourceMod and its accompanying - documentation and source code. As a condition for granting You a license to + documentation and source code. As a condition for granting you a license to download or use SourceMod, you agree to all of the Terms and Conditions. If you fail to adhere to the Terms and Conditions, your license to use SourceMod is automatically revoked without any action on behalf of the Licensor. - This License may be updated at any time. Each revision is differentiated by a - date version. This License was created on Jan-25-2007. + This License may be updated at any time, without prior notice.. Each revision + is differentiated by a date version. This License was created on Jan-27-2007. With this License, you may: @@ -128,11 +128,11 @@ many entries to explicitly grant rights that were ambiguous with prior products. 5. NO WARRANTY - BECAUSE SOURCEMOD IS LICENSED FREE OF CHARGE, THERE IS NO WARRANT, TO THE - EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING + BECAUSE SOURCEMOD IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY, TO THE + EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING, ALLIEDMODDERS LLC AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. From d9742cb67d06c7b8f26ed127e5dafb8561ab77ea Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 09:25:07 +0000 Subject: [PATCH 0376/1664] fixed this using /MD in release mode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40407 --- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 2 +- sourcepawn/jit/x86/svn_version.h | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index a9d943e3..e5f32bf7 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -119,7 +119,7 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\..\include" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;JITX86_EXPORTS" - RuntimeLibrary="2" + RuntimeLibrary="0" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="false" diff --git a/sourcepawn/jit/x86/svn_version.h b/sourcepawn/jit/x86/svn_version.h index 66c0227f..132938e8 100644 --- a/sourcepawn/jit/x86/svn_version.h +++ b/sourcepawn/jit/x86/svn_version.h @@ -1,11 +1,11 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 396 -#define SVN_REVISION_STRING "396" -#define SVN_FILE_VERSION 1,0,0,396 - -#endif //_INCLUDE_SVN_VERSION_H_ - +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 399 +#define SVN_REVISION_STRING "399" +#define SVN_FILE_VERSION 1,0,0,399 + +#endif //_INCLUDE_SVN_VERSION_H_ + From 0234b51a9f0748c100cbf11559dbee6e37be76c2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 27 Jan 2007 09:28:48 +0000 Subject: [PATCH 0377/1664] fixed error in JIT version header --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40408 --- sourcepawn/jit/x86/jit_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/jit_version.h b/sourcepawn/jit/x86/jit_version.h index 2f86e017..01b7f602 100644 --- a/sourcepawn/jit/x86/jit_version.h +++ b/sourcepawn/jit/x86/jit_version.h @@ -17,6 +17,6 @@ #include "svn_version.h" -#define JIT_VERSION "1.0.0" SVN_REVISION_STRING +#define JIT_VERSION "1.0.0." SVN_REVISION_STRING #endif //_INCLUDE_JIT_VERSION_H_ From 7a8d164b25f3e9ba93deadbb4ab090cf4a7ee8cd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 28 Jan 2007 04:19:46 +0000 Subject: [PATCH 0378/1664] Added compression support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40409 --- tools/builder/ABuilder.cs | 181 +++++++++++++++++++++++----------- tools/builder/Config.cs | 10 +- tools/builder/LinuxBuilder.cs | 32 ++++++ tools/builder/Package.cs | 14 ++- tools/builder/PkgCore.cs | 14 ++- tools/builder/Win32Builder.cs | 31 ++++++ tools/builder/build-linux.cfg | 1 + tools/builder/build-win32.cfg | 1 + 8 files changed, 219 insertions(+), 65 deletions(-) diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs index 5400f846..4259da00 100644 --- a/tools/builder/ABuilder.cs +++ b/tools/builder/ABuilder.cs @@ -12,8 +12,48 @@ namespace builder { } + public abstract string CompressPackage(Package pkg); + public abstract bool BuildLibrary(Package pkg, Library lib, ref string _binName, ref string _binPath); + public string GetRevsionOfPath(string path) + { + ProcessStartInfo info = new ProcessStartInfo(); + + info.WorkingDirectory = path; + info.FileName = cfg.SVNVersion; + info.Arguments = "--committed " + path; + info.UseShellExecute = false; + info.RedirectStandardOutput = true; + + Process p = Process.Start(info); + string output = p.StandardOutput.ReadToEnd(); + p.WaitForExit(); + p.Close(); + + string [] revs = output.Split(":".ToCharArray(), 2); + if (revs.Length < 1) + { + return null; + } + + string rev = null; + if (revs.Length == 1) + { + rev = revs[0]; + } + else + { + rev = revs[1]; + } + + rev = rev.Trim(); + rev = rev.Replace("M", ""); + rev = rev.Replace("S", ""); + + return rev; + } + public void UpdateRevisionInfo(Package pkg, Library lib) { string path = Config.PathFormat("{0}/{1}", cfg.SourceBase, lib.LocalPath); @@ -25,13 +65,63 @@ namespace builder } } + public void UpdateRevisionInfo(string path, string file) + { + string vers = cfg.ProductVersion.Replace(".", ","); + string rev = GetRevsionOfPath(path); + + File.Delete(file); + StreamWriter sw = File.CreateText(file); + + sw.WriteLine("/** This file is autogenerated by build scripts */"); + sw.WriteLine(""); + sw.WriteLine("#ifndef _INCLUDE_SVN_VERSION_H_"); + sw.WriteLine("#define _INCLUDE_SVN_VERSION_H_"); + sw.WriteLine(""); + sw.WriteLine("#define SVN_REVISION {0}", rev); + sw.WriteLine("#define SVN_REVISION_STRING \"{0}\"", rev); + sw.WriteLine("#define SVN_FILE_VERSION {0},{1}", vers, rev); + sw.WriteLine(""); + sw.WriteLine("#endif //_INCLUDE_SVN_VERSION_H_"); + sw.WriteLine(""); + + sw.Close(); + } + + public bool CopyFile(Package pkg, string source, string dest) + { + string from = Config.PathFormat("{0}/{1}", + cfg.SourceBase, + source); + string to = Config.PathFormat("{0}/{1}/{2}", + cfg.OutputBase, + pkg.GetBaseFolder(), + dest); + + File.Copy(from, to, true); + + return true; + } + + /** dest can be null to mean root base folder */ public void CopyFolder(Package pkg, string source, string dest, string [] omits) { string from_base = Config.PathFormat("{0}/{1}", cfg.SourceBase, source); - string to_base = Config.PathFormat("{0}/{1}/{2}", - cfg.OutputBase, - pkg.GetBaseFolder(), - dest); + string to_base = null; + + if (dest == null) + { + to_base = Config.PathFormat("{0}/{1}", + cfg.OutputBase, + pkg.GetBaseFolder()); + } + else + { + to_base = Config.PathFormat("{0}/{1}/{2}", + cfg.OutputBase, + pkg.GetBaseFolder(), + dest); + } string [] files = Directory.GetFiles(from_base); string file; @@ -61,59 +151,15 @@ namespace builder } } - public void UpdateRevisionInfo(string path, string file) + public string PackageBuildName(Package pkg) { - ProcessStartInfo info = new ProcessStartInfo(); - - info.WorkingDirectory = path; - info.FileName = cfg.SVNVersion; - info.Arguments = "--committed " + path; - info.UseShellExecute = false; - info.RedirectStandardOutput = true; - - Process p = Process.Start(info); - string output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); - p.Close(); - - string [] revs = output.Split(":".ToCharArray(), 2); - if (revs.Length < 1) - { - return; - } - - string rev = null; - if (revs.Length == 1) - { - rev = revs[0]; - } - else - { - rev = revs[1]; - } - - rev = rev.Trim(); - rev = rev.Replace("M", ""); - rev = rev.Replace("S", ""); - - string vers = cfg.ProductVersion.Replace(".", ","); - - File.Delete(file); - StreamWriter sw = File.CreateText(file); - - sw.WriteLine("/** This file is autogenerated by build scripts */"); - sw.WriteLine(""); - sw.WriteLine("#ifndef _INCLUDE_SVN_VERSION_H_"); - sw.WriteLine("#define _INCLUDE_SVN_VERSION_H_"); - sw.WriteLine(""); - sw.WriteLine("#define SVN_REVISION {0}", rev); - sw.WriteLine("#define SVN_REVISION_STRING \"{0}\"", rev); - sw.WriteLine("#define SVN_FILE_VERSION {0},{1}", vers, rev); - sw.WriteLine(""); - sw.WriteLine("#endif //_INCLUDE_SVN_VERSION_H_"); - sw.WriteLine(""); - - sw.Close(); + return pkg.GetPackageName() + + "-" + + DateTime.Now.Day.ToString("00") + + DateTime.Now.Month.ToString("00") + + DateTime.Now.Year + + "-r" + + GetRevsionOfPath(cfg.SourceBase); } public void BuildPackage(Package pkg) @@ -138,7 +184,7 @@ namespace builder /* Do primitive copies */ pkg.OnCopyFolders(this); - pkg.OnCopyFiles(); + pkg.OnCopyFiles(this); /* Do libraries */ Library [] libs = pkg.GetLibraries(); @@ -160,6 +206,27 @@ namespace builder throw new System.Exception("Failed to compile library: " + libs[i].Name); } } + + string pkg_file = null; + if ((pkg_file=CompressPackage(pkg)) == null) + { + throw new System.Exception("Failed to compress package: " + pkg.GetPackageName()); + } + + string lpath = null, ltarget = null; + pkg.GetCompressBases(ref lpath, ref ltarget); + lpath = Config.PathFormat("{0}/{1}/{2}", + cfg.OutputBase, + lpath, + pkg_file); + ltarget = Config.PathFormat("{0}/{1}", cfg.OutputBase, pkg_file); + + if (File.Exists(ltarget)) + { + File.Delete(ltarget); + } + + File.Move(lpath, ltarget); } } } diff --git a/tools/builder/Config.cs b/tools/builder/Config.cs index bb52ad95..4f7700e7 100644 --- a/tools/builder/Config.cs +++ b/tools/builder/Config.cs @@ -15,10 +15,10 @@ namespace builder public string SourceBase; public string OutputBase; public string BuilderPath; - public string CompressPath; public string CompressOptions; public string SVNVersion; public string ProductVersion; + public string Compressor; public builder.BasePlatform Platform; public Config() @@ -84,10 +84,6 @@ namespace builder { BuilderPath = val; } - else if (key.CompareTo("CompressPath") == 0) - { - CompressPath = val; - } else if (key.CompareTo("CompressOptions") == 0) { CompressOptions = val; @@ -99,6 +95,10 @@ namespace builder else if (key.CompareTo("ProductVersion") == 0) { ProductVersion = val; + } + else if (key.CompareTo("Compressor") == 0) + { + Compressor = val; } } } diff --git a/tools/builder/LinuxBuilder.cs b/tools/builder/LinuxBuilder.cs index 35ee9063..ccda2027 100644 --- a/tools/builder/LinuxBuilder.cs +++ b/tools/builder/LinuxBuilder.cs @@ -11,6 +11,38 @@ namespace builder cfg = _cfg; } + public override string CompressPackage(Package pkg) + { + string lpath = null, ltarget = null; + + pkg.GetCompressBases(ref lpath, ref ltarget); + + string local_dir = Config.PathFormat("{0}/{1}", + cfg.OutputBase, + lpath); + + string name = PackageBuildName(pkg) + ".tar.gz"; + + ProcessStartInfo info = new ProcessStartInfo(); + info.FileName = cfg.Compressor; + info.WorkingDirectory = local_dir; + info.Arguments = "zcvf \"" + name + "\" \"" + ltarget + "\""; + info.UseShellExecute = false; + + Process p = Process.Start(info); + p.WaitForExit(); + + local_dir = Config.PathFormat("{0}/{1}", local_dir, name); + + if (!File.Exists(local_dir)) + { + return null; + } + + return name; + } + + public override bool BuildLibrary(Package pkg, Library lib, ref string _binName, ref string _binPath) { ProcessStartInfo info = new ProcessStartInfo(); diff --git a/tools/builder/Package.cs b/tools/builder/Package.cs index a9965d52..481f2f6c 100644 --- a/tools/builder/Package.cs +++ b/tools/builder/Package.cs @@ -24,7 +24,12 @@ namespace builder public abstract class Package { /** - * Must return the base package folder. + * Must return the root compression point. + */ + public abstract void GetCompressBases(ref string path, ref string folder); + + /** + * Must return the base package output folder. */ public abstract string GetBaseFolder(); @@ -36,7 +41,7 @@ namespace builder /** * Called when file to file copies must be performed */ - public abstract void OnCopyFiles(); + public abstract void OnCopyFiles(ABuilder builder); /** * Called when dir to dir copies must be performed @@ -47,5 +52,10 @@ namespace builder * Called to build libraries */ public abstract Library [] GetLibraries(); + + /** + * Called to get package name + */ + public abstract string GetPackageName(); } } diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 1976c1b1..0c54e565 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -13,6 +13,17 @@ namespace builder return "base/addons/sourcemod"; } + public override void GetCompressBases(ref string path, ref string folder) + { + path = "base"; + folder = "addons"; + } + + public override string GetPackageName() + { + return "sourcemod-core"; + } + /** * Must return the list of folders to create. */ @@ -34,7 +45,7 @@ namespace builder /** * Called when file to file copies must be performed */ - public override void OnCopyFiles() + public override void OnCopyFiles(ABuilder builder) { } @@ -51,6 +62,7 @@ namespace builder builder.CopyFolder(this, "plugins", "scripting", plugin_omits); builder.CopyFolder(this, "plugins/include", "scripting/include", null); builder.CopyFolder(this, "translations", "translations", null); + builder.CopyFolder(this, "public/licenses", null, null); } /** diff --git a/tools/builder/Win32Builder.cs b/tools/builder/Win32Builder.cs index efa0e9cf..fda67bb2 100644 --- a/tools/builder/Win32Builder.cs +++ b/tools/builder/Win32Builder.cs @@ -11,6 +11,37 @@ namespace builder cfg = _cfg; } + public override string CompressPackage(Package pkg) + { + string lpath = null, ltarget = null; + + pkg.GetCompressBases(ref lpath, ref ltarget); + + string local_dir = Config.PathFormat("{0}/{1}", + cfg.OutputBase, + lpath); + + string name = PackageBuildName(pkg) + ".zip"; + + ProcessStartInfo info = new ProcessStartInfo(); + info.FileName = cfg.Compressor; + info.WorkingDirectory = local_dir; + info.Arguments = "-r \"" + name + "\" \"" + ltarget + "\""; + info.UseShellExecute = false; + + Process p = Process.Start(info); + p.WaitForExit(); + + local_dir = Config.PathFormat("{0}/{1}", local_dir, name); + + if (!File.Exists(local_dir)) + { + return null; + } + + return name; + } + public override bool BuildLibrary(Package pkg, Library lib, ref string _binName, ref string _binPath) { ProcessStartInfo info = new ProcessStartInfo(); diff --git a/tools/builder/build-linux.cfg b/tools/builder/build-linux.cfg index 2ac4b5b6..918abd32 100644 --- a/tools/builder/build-linux.cfg +++ b/tools/builder/build-linux.cfg @@ -3,3 +3,4 @@ SourceBase = /home/users/dvander/sourcemod/trunk BuilderPath = /usr/bin/make SVNVersion = /usr/bin/svnversion ProductVersion = 1.0.0 +Compressor = /bin/tar \ No newline at end of file diff --git a/tools/builder/build-win32.cfg b/tools/builder/build-win32.cfg index 0a4a86a9..586d44e2 100644 --- a/tools/builder/build-win32.cfg +++ b/tools/builder/build-win32.cfg @@ -3,3 +3,4 @@ SourceBase = r:\sourcemod\trunk BuilderPath = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.com SVNVersion = C:\Program Files\Subversion\bin\svnversion.exe ProductVersion = 1.0.0 +Compressor = c:\Windows\zip.exe From c66632776f27e5617f89e922910a1e908c8e8148 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 04:19:14 +0000 Subject: [PATCH 0379/1664] initial import of finished admin api --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40410 --- core/AdminCache.cpp | 456 +++++++++++++++++++++++++++++++++++++++++- core/AdminCache.h | 55 +++++ core/sm_memtable.h | 2 + public/IAdminSystem.h | 155 ++++++++++++++ 4 files changed, 657 insertions(+), 11 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 79d4a254..0f05e49f 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -26,8 +26,10 @@ AdminCache::AdminCache() m_pStrings = new BaseStringTable(1024); m_pMemory = m_pStrings->GetMemTable(); m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID; + m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID; m_pGroups = sm_trie_create(); m_pCacheFwd = NULL; + m_FirstGroup = -1; } AdminCache::~AdminCache() @@ -52,6 +54,13 @@ AdminCache::~AdminCache() delete m_pStrings; } +void AdminCache::OnSourceModStartup(bool late) +{ + RegisterAuthIdentType("steam"); + RegisterAuthIdentType("name"); + RegisterAuthIdentType("ip"); +} + void AdminCache::OnSourceModAllInitialized() { m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell); @@ -196,6 +205,51 @@ void AdminCache::DumpCommandOverrideCache(OverrideType type) } } +AdminId AdminCache::CreateAdmin(const char *name) +{ + AdminId id; + AdminUser *pUser; + + if (m_FreeUserList != INVALID_ADMIN_ID) + { + pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList); + assert(pUser->magic == USR_MAGIC_UNSET); + id = m_FreeUserList; + m_FreeUserList = pUser->next_user; + } else { + id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser); + pUser->grp_size = 0; + pUser->grp_table = -1; + pUser->auth_size = 0; + pUser->auth_table = -1; + } + + memset(pUser->flags, 0, sizeof(pUser->flags)); + memset(pUser->eflags, 0, sizeof(pUser->flags)); + pUser->grp_count = 0; + pUser->auth_count = 0; + pUser->password = -1; + pUser->magic = USR_MAGIC_SET; + + if (m_FirstUser == INVALID_ADMIN_ID) + { + m_FirstUser = id; + m_LastUser = id; + } else { + AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser); + pPrev->next_user = id; + pUser->prev_user = m_LastUser; + m_LastUser = id; + } + + if (name && name[0] != '\0') + { + pUser->nameidx = m_pStrings->AddString(name); + } + + return id; +} + GroupId AdminCache::AddGroup(const char *group_name) { if (sm_trie_retrieve(m_pGroups, group_name, NULL)) @@ -222,7 +276,6 @@ GroupId AdminCache::AddGroup(const char *group_name) pGroup->next_grp = INVALID_GROUP_ID; pGroup->pCmdGrpTable = NULL; pGroup->pCmdTable = NULL; - pGroup->nameidx = m_pStrings->AddString(group_name); memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL); if (m_FirstGroup == INVALID_GROUP_ID) @@ -238,6 +291,8 @@ GroupId AdminCache::AddGroup(const char *group_name) m_LastGroup = id; } + pGroup->nameidx = m_pStrings->AddString(group_name); + sm_trie_insert(m_pGroups, group_name, (void *)id); return id; @@ -498,6 +553,80 @@ bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideT return true; } +Trie *AdminCache::GetMethodByIndex(unsigned int index) +{ + List::iterator iter; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++) + { + if (index-- == 0) + { + return (*iter).table; + } + } + + return NULL; +} + +bool AdminCache::InvalidateAdmin(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + AdminUser *pOther; + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + /* Unlink from the dbl link list */ + if (id == m_FirstUser && id == m_LastUser) + { + m_FirstUser = INVALID_ADMIN_ID; + m_LastUser = INVALID_ADMIN_ID; + } else if (id == m_FirstUser) { + m_FirstUser = pUser->next_user; + pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser); + pOther->prev_user = INVALID_ADMIN_ID; + } else if (id == m_LastUser) { + m_LastUser = pUser->prev_user; + pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser); + pOther->next_user = INVALID_ADMIN_ID; + } else { + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user); + pOther->next_user = pUser->next_user; + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user); + pOther->prev_user = pUser->prev_user; + } + + /* Unlink from auth tables */ + if (pUser->auth_count > 0) + { + UserAuth *pAuth = (UserAuth *)m_pMemory->GetAddress(pUser->auth_table); + Trie *pTrie; + for (unsigned int i=0; iauth_count; i++) + { + pTrie = GetMethodByIndex(pAuth[i].index); + if (!pTrie) + { + continue; + } + sm_trie_delete(pTrie, m_pStrings->GetString(pAuth->identidx)); + } + } + + /* Clear table counts */ + pUser->grp_count = 0; + pUser->auth_count = 0; + + /* Link into free list */ + pUser->magic = USR_MAGIC_UNSET; + pUser->next_user = m_FreeUserList; + m_FreeUserList = id; + + return true; +} + + void AdminCache::InvalidateGroup(GroupId id) { AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); @@ -548,7 +677,44 @@ void AdminCache::InvalidateGroup(GroupId id) pGroup->next_grp = m_FreeGroupList; m_FreeGroupList = id; - /* :TODO: remove this group from any users */ + int idx = m_FirstUser; + AdminUser *pUser; + int *table; + while (idx != INVALID_ADMIN_ID) + { + pUser = (AdminUser *)m_pMemory->GetAddress(idx); + if (pUser->grp_count > 0) + { + table = (int *)m_pMemory->GetAddress(pUser->grp_table); + for (unsigned int i=0; igrp_count; i++) + { + if (table[i] == id) + { + /* We have to remove this entry */ + for (unsigned int j=i+1; jgrp_count; j++) + { + /* Move everything down by one */ + table[j-1] = table[j]; + } + /* Decrease count */ + pUser->grp_count--; + /* Recalculate effective flags */ + memset(pUser->eflags, 0, sizeof(pUser->eflags)); + for (unsigned int j=0; jgrp_count; j++) + { + pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]); + for (unsigned int k=0; keflags[k] = (pUser->flags[k] || pOther->addflags[k]); + } + } + /* Break now, duplicates aren't allowed */ + break; + } + } + } + idx = pUser->next_user; + } } void AdminCache::InvalidateGroupCache() @@ -580,7 +746,7 @@ void AdminCache::InvalidateGroupCache() m_FirstGroup = INVALID_GROUP_ID; m_LastGroup = INVALID_GROUP_ID; - /* :TODO: dump the admin cache */ + InvalidateAdminCache(false); /* Reset the memory table */ m_pMemory->Reset(); @@ -596,6 +762,41 @@ void AdminCache::RemoveAdminListener(IAdminListener *pListener) m_hooks.remove(pListener); } +void AdminCache::RegisterAuthIdentType(const char *name) +{ + if (sm_trie_retrieve(m_pAuthTables, name, NULL)) + { + return; + } + + Trie *pAuth = sm_trie_create(); + + AuthMethod method; + method.name.assign(name); + method.table = pAuth; + + m_AuthMethods.push_back(method); + + sm_trie_insert(m_pAuthTables, name, pAuth); +} + +void AdminCache::InvalidateAdminCache(bool unlink_admins) +{ + /* Wipe the identity cache first */ + List::iterator iter; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++) + { + sm_trie_clear((*iter).table); + } + + while (m_FirstUser != INVALID_ADMIN_ID) + { + InvalidateAdmin(m_FirstUser); + } +} + void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) { if (cache_flags & ADMIN_CACHE_OVERRIDES) @@ -604,19 +805,19 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) DumpCommandOverrideCache(Override_CommandGroup); } - if ((cache_flags & ADMIN_CACHE_ADMINS) || - (cache_flags & ADMIN_CACHE_GROUPS)) - { - /* Make sure the flag is set */ - cache_flags |= ADMIN_CACHE_ADMINS; - /* :TODO: Dump admin cache */ - } - + /* This will auto-invalidate the admin cache */ if (cache_flags & ADMIN_CACHE_GROUPS) { InvalidateGroupCache(); } + /* If we only requested an admin rebuild, re-use the internal memory */ + if ((cache_flags & ADMIN_CACHE_ADMINS) && + !(cache_flags & ADMIN_CACHE_GROUPS)) + { + InvalidateAdminCache(true); + } + if (rebuild) { List::iterator iter; @@ -631,3 +832,236 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) m_pCacheFwd->Execute(&result); } } + +const char *AdminCache::GetAdminName(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return NULL; + } + + return m_pStrings->GetString(pUser->nameidx); +} + +bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + Trie *pTable; + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable)) + { + return false; + } + + if (sm_trie_retrieve(pTable, ident, NULL)) + { + return false; + } + + return sm_trie_insert(pTable, ident, (void **)id); +} + +AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity) +{ + Trie *pTable; + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable)) + { + return INVALID_ADMIN_ID; + } + + void *object; + if (!sm_trie_retrieve(pTable, identity, &object)) + { + return INVALID_ADMIN_ID; + } + + return (AdminId)object; +} + +void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + if (flag < Admin_None + || flag >= AdminFlags_TOTAL) + { + return; + } + + pUser->flags[enabled] = false; +} + +bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + if (flag < Admin_None + || flag >= AdminFlags_TOTAL) + { + return false; + } + + if (mode == Access_Real) + { + return pUser->flags[flag]; + } else if (mode == Access_Effective) { + return (pUser->flags[flag] || pUser->eflags[flag]); + } + + return false; +} + +unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return 0; + } + + unsigned int i = 0; + if (mode == Access_Real) + { + for (i=0; iflags[i]; + } + } else if (mode == Access_Effective) { + for (i=0; iflags[i] || pUser->eflags[i]); + } + } + + return i; +} + +bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid); + if (!pGroup || pGroup->magic != USR_MAGIC_SET) + { + return false; + } + + int *table; + if (pUser->grp_count + 1 > pUser->grp_size) + { + int new_size = 0; + int tblidx; + + if (pUser->grp_size == 0) + { + new_size = 2; + } else { + new_size = pUser->grp_size * 2; + } + + /* Create and refresh pointers */ + tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table); + pUser = (AdminUser *)m_pMemory->GetAddress(id); + pGroup = (AdminGroup *)m_pMemory->GetAddress(gid); + + /* Copy old data if necessary */ + if (pUser->grp_table != -1) + { + int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table); + memcpy(table, old_table, sizeof(int) * pUser->grp_count); + } + pUser->grp_table = tblidx; + pUser->grp_size = new_size; + } else { + table = (int *)m_pMemory->GetAddress(pUser->grp_table); + } + + for (unsigned int i=0; igrp_count; i++) + { + if (table[i] == gid) + { + return false; + } + } + + table[pUser->grp_count] = gid; + pUser->grp_count++; + + /* Compute new effective flags */ + for (unsigned int i=Admin_None; + ieflags[i]) + { + pUser->eflags[i] = pGroup->addflags[i]; + } + } + + return true; +} + +unsigned int AdminCache::GetAdminGroupCount(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return 0; + } + + return pUser->grp_count; +} + +GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count) + { + return INVALID_GROUP_ID; + } + + int *table = (int *)m_pMemory->GetAddress(pUser->grp_table); + + return table[index]; +} + +const char *AdminCache::GetAdminPassword(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return NULL; + } + + return m_pStrings->GetString(pUser->password); +} + +void AdminCache::SetAdminPassword(AdminId id, const char *password) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + pUser->password = m_pStrings->AddString(password); +} + diff --git a/core/AdminCache.h b/core/AdminCache.h index a4bb38d0..07681a14 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -17,6 +17,7 @@ #include "sm_memtable.h" #include #include +#include #include #include "sm_globals.h" #include @@ -25,6 +26,8 @@ using namespace SourceHook; #define GRP_MAGIC_SET 0xDEADFADE #define GRP_MAGIC_UNSET 0xFACEFACE +#define USR_MAGIC_SET 0xDEADFACE +#define USR_MAGIC_UNSET 0xFADEDEAD struct AdminGroup { @@ -44,6 +47,35 @@ struct AdminGroup bool addflags[AdminFlags_TOTAL]; /* Additive flags */ }; +struct AuthMethod +{ + String name; + Trie *table; +}; + +struct UserAuth +{ + unsigned int index; /* Index into auth table */ + int identidx; /* Index into the string table */ +}; + +struct AdminUser +{ + int magic; /* Magic flag, for memory validation */ + bool flags[AdminFlags_TOTAL]; /* Base flags */ + bool eflags[AdminFlags_TOTAL]; /* Effective flags */ + int nameidx; /* Name index */ + int password; /* Password index */ + unsigned int grp_count; /* Number of groups */ + unsigned int grp_size; /* Size of groups table */ + int grp_table; /* Group table itself */ + int next_user; /* Next user in ze list */ + int prev_user; /* Prev user in the list */ + unsigned int auth_count; /* Number of auth methods */ + unsigned int auth_size; /* Size of auth table */ + int auth_table; /* Auth table itself */ +}; + class AdminCache : public IAdminSystem, public SMGlobalClass @@ -52,6 +84,7 @@ public: AdminCache(); ~AdminCache(); public: //SMGlobalClass + void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: //IAdminSystem @@ -76,6 +109,21 @@ public: //IAdminSystem void DumpAdminCache(int cache_flags, bool rebuild); void AddAdminListener(IAdminListener *pListener); void RemoveAdminListener(IAdminListener *pListener); + /** User stuff */ + void RegisterAuthIdentType(const char *name); + AdminId CreateAdmin(const char *name); + const char *GetAdminName(AdminId id); + bool BindAdminIdentity(AdminId id, const char *auth, const char *ident); + virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled); + bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode); + unsigned int GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode); + bool AdminInheritGroup(AdminId id, GroupId gid); + unsigned int GetAdminGroupCount(AdminId id); + GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name); + void SetAdminPassword(AdminId id, const char *password); + const char *GetAdminPassword(AdminId id); + AdminId FindAdminByIdentity(const char *auth, const char *identity); + bool InvalidateAdmin(AdminId id); private: void _AddCommandOverride(const char *cmd, AdminFlag flag); void _AddCommandGroupOverride(const char *group, AdminFlag flag); @@ -84,7 +132,9 @@ private: void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); void InvalidateGroupCache(); + void InvalidateAdminCache(bool unlink_admins); void DumpCommandOverrideCache(OverrideType type); + Trie *GetMethodByIndex(unsigned int index); public: BaseStringTable *m_pStrings; BaseMemTable *m_pMemory; @@ -95,7 +145,12 @@ public: int m_FreeGroupList; Trie *m_pGroups; List m_hooks; + List m_AuthMethods; + Trie *m_pAuthTables; IForward *m_pCacheFwd; + int m_FirstUser; + int m_LastUser; + int m_FreeUserList; }; extern AdminCache g_Admins; diff --git a/core/sm_memtable.h b/core/sm_memtable.h index 043e2618..e77eeb88 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -39,6 +39,8 @@ public: * begin at the first index again. */ void Reset(); + + private: unsigned char *membase; unsigned int size; diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index ceb4188c..83e7b646 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -43,6 +43,8 @@ * 3] An override table - insertion and retrieval only. * Individual groups can be invalidated entirely. It should be considered an expensive * operation, since each admin needs to be patched up to not reference the group. + * + * For more information, see the SourceMod Development wiki. */ namespace SourceMod @@ -98,11 +100,25 @@ namespace SourceMod Immunity_Global, /**< Immune from everyone (except root admins) */ }; + /** + * @brief Defines user access modes. + */ + enum AccessMode + { + Access_Real, /**< Access the user has inherently */ + Access_Effective, /**< Access the user has from their groups */ + }; + /** * @brief Represents an index to one group. */ typedef int GroupId; + /** + * @brief Represents an index to one user entry. + */ + typedef int AdminId; + #define ADMIN_CACHE_OVERRIDES (1<<0) #define ADMIN_CACHE_ADMINS (1<<1) #define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) @@ -112,6 +128,11 @@ namespace SourceMod */ #define INVALID_GROUP_ID -1 + /** + * @brief Represents an invalid/nonexistant user or an erroneous operation. + */ + #define INVALID_ADMIN_ID -1 + /** * @brief Provides callbacks for admin cache operations. */ @@ -315,6 +336,140 @@ namespace SourceMod * @param pListener Pointer to an IAdminListener to remove. */ virtual void RemoveAdminListener(IAdminListener *pListener) =0; + + /** + * @brief Registers an authentication identity type. + * Note: Default types are "steam," "name," and "ip." + * + * @param name String containing the type name. + */ + virtual void RegisterAuthIdentType(const char *name) =0; + + /** + * @brief Creates a new user entry. + * + * @param name Name for this entry (does not have to be unique). + * Specify NULL for an anonymous admin. + * @return A new AdminId index. + */ + virtual AdminId CreateAdmin(const char *name) =0; + + /** + * @brief Gets an admin's user name. + * + * @param id AdminId index for this admin. + * @return A string containing the admin's name, or NULL + * if the admin was created anonymously. + */ + virtual const char *GetAdminName(AdminId id) =0; + + /** + * @brief Binds a user entry to a particular auth method. + * This bind must be unique. + * + * @param id AdminId index of the admin. + * @param auth Auth method to use. + * @param ident Identity string to bind to. + * @return True on success, false if auth method was not found, + * id was invalid, or ident was already taken. + */ + virtual bool BindAdminIdentity(AdminId id, const char *auth, const char *ident) =0; + + /** + * @brief Sets whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param enabled True to enable, false to disable. + */ + virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) =0; + + /** + * @brief Returns whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param mode Access mode to check. + * @return True if enabled, false otherwise. + */ + virtual bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) =0; + + /** + * @brief Returns a bitarray of flags enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Array to store flag bits in. + * @param total Maximum size of the flag array. + * @param mode Access mode to use. + * @return Number of flags written to the array. + */ + virtual unsigned int GetAdminFlags(AdminId id, + bool flags[], + unsigned int total, + AccessMode mode) =0; + + /** + * @brief Adds a group to an admin's inherited group list. + * Any flags the group has will be added to the admin's effective flags. + * + * @param id AdminId index of the admin. + * @param gid GroupId index of the group. + * @return True on success, false on invalid input or duplicate membership. + */ + virtual bool AdminInheritGroup(AdminId id, GroupId gid) =0; + + /** + * @brief Returns the number of groups this admin is a member of. + * + * @param id AdminId index of the admin. + * @return Number of groups this admin is a member of. + */ + virtual unsigned int GetAdminGroupCount(AdminId id) =0; + + /** + * @brief Returns group information from an admin. + * + * @param id AdminId index of the admin. + * @param index Group number to retrieve, from 0 to N-1, where N + * is the value of GetAdminGroupCount(id). + * @param name Optional pointer to store the group's name. + * @return A GroupId index and a name pointer, or + * INVALID_GROUP_ID and NULL if an error occurred. + */ + virtual GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name) =0; + + /** + * @brief Sets a password on an admin. + * + * @param id AdminId index of the admin. + * @param passwd String containing the password. + */ + virtual void SetAdminPassword(AdminId id, const char *password) =0; + + /** + * @brief Gets an admin's password. + * + * @param id AdminId index of the admin. + * @return Password of the admin, or NULL if none. + */ + virtual const char *GetAdminPassword(AdminId id) =0; + + /** + * @brief Attempts to find an admin by an auth method and an identity. + * + * @param auth Auth method to try. + * @param identity Identity string to look up. + * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. + */ + virtual AdminId FindAdminByIdentity(const char *auth, const char *identity) =0; + + /** + * @brief Invalidates an admin from the cache so its resources can be re-used. + * + * @param id AdminId index to invalidate. + * @return True on success, false otherwise. + */ + virtual bool InvalidateAdmin(AdminId id) =0; }; }; From af651e15f3495c6f2702752dcc80995b0d7eeee9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 05:02:44 +0000 Subject: [PATCH 0380/1664] finished implementing admin interface --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40411 --- core/AdminCache.cpp | 69 ++++++++++++++++++++++++++++++++------------- core/AdminCache.h | 5 ++-- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 0f05e49f..2555f552 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -30,6 +30,7 @@ AdminCache::AdminCache() m_pGroups = sm_trie_create(); m_pCacheFwd = NULL; m_FirstGroup = -1; + m_pAuthTables = sm_trie_create(); } AdminCache::~AdminCache() @@ -44,13 +45,23 @@ AdminCache::~AdminCache() sm_trie_destroy(m_pCmdOverrides); } - InvalidateGroupCache(); + DumpAdminCache(0xFFFFFFFF, false); if (m_pGroups) { sm_trie_destroy(m_pGroups); } + List::iterator iter; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++) + { + sm_trie_destroy((*iter).table); + } + + sm_trie_destroy(m_pAuthTables); + delete m_pStrings; } @@ -220,16 +231,15 @@ AdminId AdminCache::CreateAdmin(const char *name) id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser); pUser->grp_size = 0; pUser->grp_table = -1; - pUser->auth_size = 0; - pUser->auth_table = -1; } memset(pUser->flags, 0, sizeof(pUser->flags)); memset(pUser->eflags, 0, sizeof(pUser->flags)); pUser->grp_count = 0; - pUser->auth_count = 0; pUser->password = -1; pUser->magic = USR_MAGIC_SET; + pUser->auth.identidx = -1; + pUser->auth.index = 0; if (m_FirstUser == INVALID_ADMIN_ID) { @@ -599,25 +609,18 @@ bool AdminCache::InvalidateAdmin(AdminId id) } /* Unlink from auth tables */ - if (pUser->auth_count > 0) + if (pUser->auth.identidx != -1) { - UserAuth *pAuth = (UserAuth *)m_pMemory->GetAddress(pUser->auth_table); - Trie *pTrie; - for (unsigned int i=0; iauth_count; i++) + Trie *pTrie = GetMethodByIndex(pUser->auth.index); + if (pTrie) { - pTrie = GetMethodByIndex(pAuth[i].index); - if (!pTrie) - { - continue; - } - sm_trie_delete(pTrie, m_pStrings->GetString(pAuth->identidx)); + sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx)); } } /* Clear table counts */ pUser->grp_count = 0; - pUser->auth_count = 0; - + /* Link into free list */ pUser->magic = USR_MAGIC_UNSET; pUser->next_user = m_FreeUserList; @@ -791,9 +794,16 @@ void AdminCache::InvalidateAdminCache(bool unlink_admins) sm_trie_clear((*iter).table); } - while (m_FirstUser != INVALID_ADMIN_ID) + if (unlink_admins) { - InvalidateAdmin(m_FirstUser); + while (m_FirstUser != INVALID_ADMIN_ID) + { + InvalidateAdmin(m_FirstUser); + } + } else { + m_FirstUser = -1; + m_LastUser = -1; + m_FreeUserList = -1; } } @@ -844,6 +854,24 @@ const char *AdminCache::GetAdminName(AdminId id) return m_pStrings->GetString(pUser->nameidx); } +bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index) +{ + List::iterator iter; + unsigned int index = 0; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++,index++) + { + if ((*iter).name.compare(name) == 0) + { + *_index = index; + return true; + } + } + + return false; +} + bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); @@ -863,6 +891,9 @@ bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ide return false; } + pUser->auth.identidx = m_pStrings->AddString(ident); + GetMethodIndex(auth, &pUser->auth.index); + return sm_trie_insert(pTable, ident, (void **)id); } @@ -958,7 +989,7 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) } AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid); - if (!pGroup || pGroup->magic != USR_MAGIC_SET) + if (!pGroup || pGroup->magic != GRP_MAGIC_SET) { return false; } diff --git a/core/AdminCache.h b/core/AdminCache.h index 07681a14..704250b5 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -71,9 +71,7 @@ struct AdminUser int grp_table; /* Group table itself */ int next_user; /* Next user in ze list */ int prev_user; /* Prev user in the list */ - unsigned int auth_count; /* Number of auth methods */ - unsigned int auth_size; /* Size of auth table */ - int auth_table; /* Auth table itself */ + UserAuth auth; /* Auth method for this user */ }; class AdminCache : @@ -135,6 +133,7 @@ private: void InvalidateAdminCache(bool unlink_admins); void DumpCommandOverrideCache(OverrideType type); Trie *GetMethodByIndex(unsigned int index); + bool GetMethodIndex(const char *name, unsigned int *_index); public: BaseStringTable *m_pStrings; BaseMemTable *m_pMemory; From 52b45354e8be1c638d48d29c96552d50641665e5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 06:43:27 +0000 Subject: [PATCH 0381/1664] multiple input files feature now works again --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40412 --- sourcepawn/compiler/sc1.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 2af527c9..b46f3457 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -170,6 +170,8 @@ static int *wqptr; /* pointer to next entry */ static HWND hwndFinish = 0; #endif +char g_tmpfile[_MAX_PATH] = {0}; + /* "main" of the compiler */ #if defined __cplusplus @@ -263,20 +265,22 @@ int pc_compile(int argc, char *argv[]) unsigned char tstring[128]; fsrc=(FILE*)pc_opensrc(sname); if (fsrc==NULL) { + pc_closesrc(ftmp); + remove(tname); strcpy(inpfname,sname); /* avoid invalid filename */ error(100,sname); } /* if */ - pc_writesrc(ftmp,(unsigned char*)"#file "); + pc_writesrc(ftmp,(unsigned char*)"#file \""); pc_writesrc(ftmp,(unsigned char*)sname); - pc_writesrc(ftmp,(unsigned char*)"\n"); - while (!pc_eofsrc(fsrc)) { - pc_readsrc(fsrc,tstring,sizeof tstring); + pc_writesrc(ftmp,(unsigned char*)"\"\n"); + while (!pc_eofsrc(fsrc) && pc_readsrc(fsrc,tstring,sizeof tstring)) { pc_writesrc(ftmp,tstring); } /* while */ pc_closesrc(fsrc); } /* for */ pc_closesrc(ftmp); strcpy(inpfname,tname); + strcpy(g_tmpfile,tname); free(tname); } else { strcpy(inpfname,get_sourcefile(0)); @@ -481,9 +485,10 @@ cleanup: } /* if */ #endif + if (g_tmpfile[0] != '\0') { + remove(g_tmpfile); + } if (inpfname!=NULL) { - if (get_sourcefile(1)!=NULL) - remove(inpfname); /* the "input file" was in fact a temporary file */ free(inpfname); } /* if */ if (litq!=NULL) From 4299828211e9d48c6b28843da9a164e8df24e514 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 07:01:26 +0000 Subject: [PATCH 0382/1664] whoot, broke the build >:\ --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40413 --- core/AdminCache.cpp | 4 ++-- core/AdminCache.h | 3 ++- core/svn_version.h | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 2555f552..58478ad0 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -822,8 +822,8 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) } /* If we only requested an admin rebuild, re-use the internal memory */ - if ((cache_flags & ADMIN_CACHE_ADMINS) && - !(cache_flags & ADMIN_CACHE_GROUPS)) + if (((cache_flags & ADMIN_CACHE_ADMINS) == ADMIN_CACHE_ADMINS) + && (cache_flags & (1<<2) != (1<<2))) { InvalidateAdminCache(true); } diff --git a/core/AdminCache.h b/core/AdminCache.h index 704250b5..5170463d 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -61,7 +62,7 @@ struct UserAuth struct AdminUser { - int magic; /* Magic flag, for memory validation */ + uint32_t magic; /* Magic flag, for memory validation */ bool flags[AdminFlags_TOTAL]; /* Base flags */ bool eflags[AdminFlags_TOTAL]; /* Effective flags */ int nameidx; /* Name index */ diff --git a/core/svn_version.h b/core/svn_version.h index 4aee5738..d16af69f 100644 --- a/core/svn_version.h +++ b/core/svn_version.h @@ -3,9 +3,9 @@ #ifndef _INCLUDE_SVN_VERSION_H_ #define _INCLUDE_SVN_VERSION_H_ -#define SVN_REVISION 395 -#define SVN_REVISION_STRING "395" -#define SVN_FILE_VERSION 1,0,0,395 +#define SVN_REVISION 403 +#define SVN_REVISION_STRING "403" +#define SVN_FILE_VERSION 1,0,0,403 #endif //_INCLUDE_SVN_VERSION_H_ From 831344d353956d3e5bb71955bf41557241326887 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 19:34:28 +0000 Subject: [PATCH 0383/1664] fixed a bug where line numbers were not reset --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40414 --- sourcepawn/compiler/sc2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index ea861e27..2894e14c 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1005,6 +1005,7 @@ static int command(void) inpfname=duplicatestring(pathname); if (inpfname==NULL) error(103); /* insufficient memory */ + fline=0; } /* if */ } /* if */ check_empty(lptr); From 701cda8f0b4d937863ce7a1e8cd5434a7ab46782 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 19:36:02 +0000 Subject: [PATCH 0384/1664] split this baby up --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40415 --- plugins/admin-base/admin-base.sp | 20 ++++++ .../admin-levels.sp} | 62 +++---------------- 2 files changed, 30 insertions(+), 52 deletions(-) create mode 100644 plugins/admin-base/admin-base.sp rename plugins/{admin-base.sp => admin-base/admin-levels.sp} (69%) diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-base/admin-base.sp new file mode 100644 index 00000000..13f10a25 --- /dev/null +++ b/plugins/admin-base/admin-base.sp @@ -0,0 +1,20 @@ +#include +#include + +public Plugin:myinfo = +{ + name = "Admin Base", + author = "AlliedModders LLC", + description = "Reads admin files", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +/** Various globals */ +new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ +new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ + +public OnRebuildAdminCache(cache_flags) +{ + RefreshLevels(); +} diff --git a/plugins/admin-base.sp b/plugins/admin-base/admin-levels.sp similarity index 69% rename from plugins/admin-base.sp rename to plugins/admin-base/admin-levels.sp index f196c6eb..0a49a835 100644 --- a/plugins/admin-base.sp +++ b/plugins/admin-base/admin-levels.sp @@ -1,40 +1,20 @@ -#include -#include - -public Plugin:myinfo = -{ - name = "Admin Base", - author = "AlliedModders LLC", - description = "Reads admin files", - version = "1.0.0.0", - url = "http://www.sourcemod.net/" -}; - #define LEVEL_STATE_NONE 0 #define LEVEL_STATE_LEVELS 1 #define LEVEL_STATE_FLAGS 2 -#define LEVEL_STATE_OVERRIDES 3 - -/** Parser handles */ new Handle:g_hLevelParser = INVALID_HANDLE; - -/** Parser states */ new g_LevelState = LEVEL_STATE_NONE; -/** Globals for levels */ -new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ -new bool:g_ReadOverrides = false; /* Whether or not to read overrides */ -new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ - - -public OnPluginStart() +InitializeLevelParser() { - g_hLevelParser = SMC_CreateParser(); - SMC_SetReaders(g_hLevelParser, - ReadLevels_NewSection, - ReadLevels_KeyValue, - ReadLevels_EndSection); + if (g_hLevelParser == INVALID_HANDLE) + { + g_hLevelParser = SMC_CreateParser(); + SMC_SetReaders(g_hLevelParser, + ReadLevels_NewSection, + ReadLevels_KeyValue, + ReadLevels_EndSection); + } } LoadDefaultLetters() @@ -69,8 +49,6 @@ public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt if (StrEqual(name, "Flags")) { g_LevelState = LEVEL_STATE_FLAGS; - } else if (StrEqual(name, "Overrides")) { - g_LevelState = LEVEL_STATE_OVERRIDES; } else { /* :TODO: log error */ } @@ -131,13 +109,6 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin } g_FlagLetters[chr] = flag; - - - } else if (g_LevelState == LEVEL_STATE_OVERRIDES) { - if (!g_ReadOverrides) - { - return SMCParse_Continue; - } } return SMCParse_Continue; @@ -148,30 +119,17 @@ public SMCResult:ReadLevels_EndSection(Handle:smc) if (g_LevelState == LEVEL_STATE_FLAGS) { g_LevelState = LEVEL_STATE_LEVELS; - } else if (g_LevelState == LEVEL_STATE_OVERRIDES) { - g_LevelState = LEVEL_STATE_OVERRIDES; } else if (g_LevelState == LEVEL_STATE_LEVELS) { g_LevelState = LEVEL_STATE_NONE; } } -public OnRebuildAdminCache(cache_flags) -{ - if (cache_flags & ADMIN_CACHE_OVERRIDES) - { - g_ReadOverrides = true; - } else { - g_ReadOverrides = false; - } - - RefreshLevels(); -} - RefreshLevels() { new String:path[PLATFORM_MAX_PATH]; LoadDefaultLetters(); + InitializeLevelParser(); BuildPath(Path_SM, path, sizeof(path), "configs/admin_levels.cfg"); From 726498833e5ca5e21c73d6491eaac0602a0f821b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 22:33:57 +0000 Subject: [PATCH 0385/1664] Fixed a bug where decl was essentially broken when using arrays --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40416 --- sourcepawn/compiler/sc1.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index b46f3457..e5fbc32b 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2510,10 +2510,6 @@ static void initials(int ident,int tag,cell *size,int dim[],int numdim, int curlit=litidx; int err=0; - if (!autozero) { - return; - } - if (!matchtoken('=')) { assert(ident!=iARRAY || numdim>0); if (ident==iARRAY && dim[numdim-1]==0) { From 8db394c85dfef19f15a7b78a2b8e611c53176fc4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 22:34:53 +0000 Subject: [PATCH 0386/1664] Added VFormat() native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40417 --- core/smn_string.cpp | 53 ++++++++++++++++++++++++++++++++++++++++ core/vm/sp_vm_engine.cpp | 2 -- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 162ea4bd..0d746722 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -170,6 +170,58 @@ static cell_t sm_format(IPluginContext *pCtx, const cell_t *params) return static_cast(res); } +static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params) +{ + int vargPos = static_cast(params[4]); + + /* Get the parent parameter array */ + sp_context_t *ctx = pContext->GetContext(); + cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t))); + + cell_t max = local_params[0]; + if (vargPos > (int)max + 1) + { + return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos); + } + + cell_t addr_start = params[1]; + cell_t addr_end = addr_start + params[2]; + bool copy = false; + for (int i=vargPos; i<=max; i++) + { + /* Does this clip bounds? */ + if ((local_params[i] >= addr_start) + && (local_params[i] <= addr_end)) + { + copy = true; + break; + } + } + + /* Get destination info */ + char *format, *destination; + size_t maxlen = static_cast(params[2]); + + if (copy) + { + destination = g_formatbuf; + } else { + pContext->LocalToString(params[1], &destination); + } + + pContext->LocalToString(params[3], &format); + + size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos); + + /* Perform copy-on-write if we need to */ + if (copy) + { + pContext->StringToLocal(params[1], maxlen, g_formatbuf); + } + + return total; +} + REGISTER_NATIVES(basicstrings) { {"strlen", sm_strlen}, @@ -182,5 +234,6 @@ REGISTER_NATIVES(basicstrings) {"FloatToString", sm_floattostr}, {"Format", sm_format}, {"FormatEx", sm_formatex}, + {"VFormat", sm_vformat}, {NULL, NULL}, }; diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index d59b70b3..49d6fa25 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -74,8 +74,6 @@ SourcePawnEngine::SourcePawnEngine() SourcePawnEngine::~SourcePawnEngine() { - assert(m_CallStack == NULL); - TracedCall *pTemp; while (m_FreedCalls) { From 003fa1371ecc442986cbcaabbd7b5fd8f0ca8031 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 22:35:06 +0000 Subject: [PATCH 0387/1664] exposed VFormat() native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40418 --- plugins/include/string.inc | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index b1ad0268..6c715484 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -64,8 +64,8 @@ native StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=t * @param str1 First string (left). * @param str2 Second string (right). * @param caseSensitive If true (default), comparison is case sensitive. - * If false, comparison is case insensitive. - * @return True if equal, false otherwise. + * If false, comparison is case insensitive. + * @return True if equal, false otherwise. */ stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive=true) { @@ -80,7 +80,7 @@ stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive * @param dest Destination string buffer to copy to. * @param destlen Destination buffer length (includes null terminator). * @param source Source string buffer to copy from. - * @return Number of cells written. + * @return Number of cells written. */ native StrCopy(String:dest[], destLen, const String:source[]); @@ -91,7 +91,7 @@ native StrCopy(String:dest[], destLen, const String:source[]); * @param maxlength Maximum length of output string buffer. * @param format Formatting rules. * @param ... Variable number of format parameters. - * @return Number of cells written. + * @return Number of cells written. */ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); @@ -104,16 +104,31 @@ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,S * @param maxlength Maximum length of output string buffer. * @param format Formatting rules. * @param ... Variable number of format parameters. - * @return Number of cells written. + * @return Number of cells written. */ native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); +/** + * Formats a string according to the SourceMod format rules (see documentation). + * @note This is the same as Format(), except it grabs parameters from a parent parameter + * stack, rather than a local. This is useful for implementing your own variable argument + * functions. + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param varpos Argument number which contains the '...' symbol. + * Note: Arguments start at 1. + * @return Number of bytes written. + */ +native VFormat(String:buffer[], maxlength, const String:format[], varpos); + /** * Converts a string to an integer. * * @param str String to convert. - * @param nBase Numerical base to use. 10 is default. - * @return Integer conversion of string, or 0 on failure. + * @param nBase Numerical base to use. 10 is default. + * @return Integer conversion of string, or 0 on failure. */ native StringToInt(const String:str[], nBase=10); @@ -123,7 +138,7 @@ native StringToInt(const String:str[], nBase=10); * @param str Buffer to store string in. * @param maxlength Maximum length of string buffer. * @param num Integer to convert. - * @return Number of cells written to buffer. + * @return Number of cells written to buffer. */ native IntToString(String:str[], maxlength, num); @@ -131,7 +146,7 @@ native IntToString(String:str[], maxlength, num); * Converts a string to a floating point number. * * @param str String to convert to a foat. - * @return Floating point result, or 0.0 on error. + * @return Floating point result, or 0.0 on error. */ native Float:StringToFloat(const String:str[]); @@ -141,6 +156,6 @@ native Float:StringToFloat(const String:str[]); * @param str Buffer to store string in. * @param maxlength Maximum length of string buffer. * @param num Floating point number to convert. - * @return Number of cells written to buffer. + * @return Number of cells written to buffer. */ native FloatToString(String:str[], maxlength, Float:num); From afd52e161186769a6bdbbad722d11a728b4964fa Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 22:37:37 +0000 Subject: [PATCH 0388/1664] fixed a crash bug from not initializing properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40419 --- core/systems/PluginSys.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 15284a06..3be86aa4 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -213,6 +213,8 @@ void CPlugin::UpdateInfo() IPluginContext *base = GetBaseContext(); int err = base->FindPubvarByName("myinfo", &idx); + memset(&m_info, 0, sizeof(m_info)); + if (err == SP_ERROR_NONE) { struct sm_plugininfo_c_t From 221de124e92c6c7a3b628e4e3a116dcf9e006f5b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 23:09:11 +0000 Subject: [PATCH 0389/1664] finished level reading --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40420 --- plugins/admin-base/admin-base.sp | 1 + plugins/admin-base/admin-levels.sp | 36 ++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-base/admin-base.sp index 13f10a25..88083aa7 100644 --- a/plugins/admin-base/admin-base.sp +++ b/plugins/admin-base/admin-base.sp @@ -13,6 +13,7 @@ public Plugin:myinfo = /** Various globals */ new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ +new g_ErrorCount = 0; public OnRebuildAdminCache(cache_flags) { diff --git a/plugins/admin-base/admin-levels.sp b/plugins/admin-base/admin-levels.sp index 0a49a835..996cf38c 100644 --- a/plugins/admin-base/admin-levels.sp +++ b/plugins/admin-base/admin-levels.sp @@ -5,6 +5,8 @@ new Handle:g_hLevelParser = INVALID_HANDLE; new g_LevelState = LEVEL_STATE_NONE; +/* :TODO: log line numbers? */ + InitializeLevelParser() { if (g_hLevelParser == INVALID_HANDLE) @@ -35,6 +37,21 @@ LoadDefaultLetters() g_FlagLetters['z'-'a'] = Admin_Root; } +stock LogLevelError(const String:format[], {Handle,String,Float,_}:...) +{ + decl String:buffer[512]; + + if (!g_LoggedFileName) + { + LogError("Error(s) detected parsing admin_level.cfg:"); + g_LoggedFileName = true; + } + + VFormat(buffer, sizeof(buffer), format, 2); + + LogError(" (%d) %s", ++g_ErrorCount, buffer); +} + public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt_quotes) { if (g_LevelState == LEVEL_STATE_NONE) @@ -42,18 +59,12 @@ public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt if (StrEqual(name, "Levels")) { g_LevelState = LEVEL_STATE_LEVELS; - } else { - /* :TODO: log error */ } } else if (g_LevelState == LEVEL_STATE_LEVELS) { if (StrEqual(name, "Flags")) { g_LevelState = LEVEL_STATE_FLAGS; - } else { - /* :TODO: log error */ } - } else { - /* :TODO: Log error */ } return SMCParse_Continue; @@ -67,7 +78,7 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin if (chr < 'a' || chr > 'z') { - /* :TODO: log error */ + LogLevelError("Unrecognized character: \"%s\"", value); return SMCParse_Continue; } @@ -105,7 +116,7 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin } else if (StrEqual(key, "root")) { flag = Admin_Root; } else { - /* :TODO: log error */ + LogLevelError("Unrecognized flag type: %s", key); } g_FlagLetters[chr] = flag; @@ -136,10 +147,17 @@ RefreshLevels() /* Set states */ g_LevelState = LEVEL_STATE_NONE; g_LoggedFileName = false; + g_ErrorCount = 0; new SMCError:err = SMC_ParseFile(g_hLevelParser, path); if (err != SMCError_Okay) { - /* :TODO: log error */ + decl String:buffer[64]; + if (SMC_GetErrorString(err, buffer, sizeof(buffer))) + { + LogLevelError("%s", buffer); + } else { + LogLevelError("Fatal parse error"); + } } } From 3f0de65cc6d8add8851b4cb06887d605520f8491 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 23:54:04 +0000 Subject: [PATCH 0390/1664] added override parser --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40421 --- configs/admin_levels.cfg | 6 +- plugins/admin-base/admin-base.sp | 4 + plugins/admin-base/admin-levels.sp | 42 +++++---- plugins/admin-base/admin-overrides.sp | 121 ++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 plugins/admin-base/admin-overrides.sp diff --git a/configs/admin_levels.cfg b/configs/admin_levels.cfg index 61732b94..0ddb0248 100644 --- a/configs/admin_levels.cfg +++ b/configs/admin_levels.cfg @@ -38,10 +38,10 @@ Levels * 2)Command Group Name (for example, "CSDM") * 3)Command Level (for example, "changemap") * You can override the default flags assigned to individual commands or command groups in this way. - * To override a group, use the ":" character before the name. Example: + * To override a group, use the "@" character before the name. Example: * Examples: - * ":CSDM" "i" // Override the CSDM group - * "csdm_enable" "j" // Override the csdm_enable command + * "@CSDM" "i" // Override the CSDM group + * "csdm_enable" "j" // Override the csdm_enable command * Note that for overrides, order is important. In the above example, csdm_enable overwrites * any setting that csdm_enable previously had. */ diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-base/admin-base.sp index 88083aa7..e1df3784 100644 --- a/plugins/admin-base/admin-base.sp +++ b/plugins/admin-base/admin-base.sp @@ -18,4 +18,8 @@ new g_ErrorCount = 0; public OnRebuildAdminCache(cache_flags) { RefreshLevels(); + if (cache_flags & ADMIN_CACHE_OVERRIDES) + { + ReadOverrides(); + } } diff --git a/plugins/admin-base/admin-levels.sp b/plugins/admin-base/admin-levels.sp index 996cf38c..ed23529c 100644 --- a/plugins/admin-base/admin-levels.sp +++ b/plugins/admin-base/admin-levels.sp @@ -2,25 +2,19 @@ #define LEVEL_STATE_LEVELS 1 #define LEVEL_STATE_FLAGS 2 -new Handle:g_hLevelParser = INVALID_HANDLE; -new g_LevelState = LEVEL_STATE_NONE; +static Handle:g_hLevelParser = INVALID_HANDLE; +static g_LevelState = LEVEL_STATE_NONE; /* :TODO: log line numbers? */ -InitializeLevelParser() -{ - if (g_hLevelParser == INVALID_HANDLE) - { - g_hLevelParser = SMC_CreateParser(); - SMC_SetReaders(g_hLevelParser, - ReadLevels_NewSection, - ReadLevels_KeyValue, - ReadLevels_EndSection); - } -} - LoadDefaultLetters() { + /* Clear letters first */ + for (new i='a'; i<='z'; i++) + { + g_FlagLetters[i-'a'] = Admin_None; + } + g_FlagLetters['a'-'a'] = Admin_Reservation; g_FlagLetters['b'-'a'] = Admin_Kick; g_FlagLetters['c'-'a'] = Admin_Ban; @@ -37,13 +31,13 @@ LoadDefaultLetters() g_FlagLetters['z'-'a'] = Admin_Root; } -stock LogLevelError(const String:format[], {Handle,String,Float,_}:...) +static LogLevelError(const String:format[], {Handle,String,Float,_}:...) { decl String:buffer[512]; if (!g_LoggedFileName) { - LogError("Error(s) detected parsing admin_level.cfg:"); + LogError("Error(s) detected parsing admin_levels.cfg:"); g_LoggedFileName = true; } @@ -129,10 +123,26 @@ public SMCResult:ReadLevels_EndSection(Handle:smc) { if (g_LevelState == LEVEL_STATE_FLAGS) { + /* We're totally done parsing */ g_LevelState = LEVEL_STATE_LEVELS; + return SMCParse_Halt; } else if (g_LevelState == LEVEL_STATE_LEVELS) { g_LevelState = LEVEL_STATE_NONE; } + + return SMCParse_Continue; +} + +static InitializeLevelParser() +{ + if (g_hLevelParser == INVALID_HANDLE) + { + g_hLevelParser = SMC_CreateParser(); + SMC_SetReaders(g_hLevelParser, + ReadLevels_NewSection, + ReadLevels_KeyValue, + ReadLevels_EndSection); + } } RefreshLevels() diff --git a/plugins/admin-base/admin-overrides.sp b/plugins/admin-base/admin-overrides.sp new file mode 100644 index 00000000..a56b18cc --- /dev/null +++ b/plugins/admin-base/admin-overrides.sp @@ -0,0 +1,121 @@ +#define OVERRIDE_STATE_NONE 0 +#define OVERRIDE_STATE_LEVELS 1 +#define OVERRIDE_STATE_OVERRIDES 2 + +static Handle:g_hOverrideParser = INVALID_HANDLE; +static g_OverrideState = OVERRIDE_STATE_NONE; + +LogOverrideError(const String:format[], {Handle,String,Float,_}:...) +{ + decl String:buffer[512]; + + if (!g_LoggedFileName) + { + LogError("Error(s) detected parsing admin_levels.cfg:"); + g_LoggedFileName = true; + } + + VFormat(buffer, sizeof(buffer), format, 2); + + LogError(" (%d) %s", ++g_ErrorCount, buffer); +} + + +public SMCResult:ReadOverrides_NewSection(Handle:smc, const String:name[], bool:opt_quotes) +{ + if (g_OverrideState == OVERRIDE_STATE_NONE) + { + if (StrEqual(name, "Levels")) + { + g_OverrideState = OVERRIDE_STATE_LEVELS; + } + } else if (g_OverrideState == OVERRIDE_STATE_LEVELS) { + if (StrEqual(name, "Overrides")) + { + g_OverrideState = OVERRIDE_STATE_OVERRIDES; + } + } + + return SMCParse_Continue; +} + +public SMCResult:ReadOverrides_KeyValue(Handle:smc, + const String:key[], + const String:value[], + bool:key_quotes, + bool:value_quotes) +{ + if (g_OverrideState != OVERRIDE_STATE_OVERRIDES) + { + return SMCParse_Continue; + } + + new AdminFlag:flag = Admin_None; + + if (value[0] >= 'a' && value[0] <= 'z') + { + flag = g_FlagLetters[value[0] - 'a']; + } + + if (key[0] == '@') + { + AddCommandOverride(key[1], Override_CommandGroup, flag); + } else { + AddCommandOverride(key, Override_Command, flag); + } + + return SMCParse_Continue; +} + +public SMCResult:ReadOverrides_EndSection(Handle:smc) +{ + if (g_OverrideState == OVERRIDE_STATE_LEVELS) + { + g_OverrideState = OVERRIDE_STATE_NONE; + } else if (g_OverrideState == OVERRIDE_STATE_OVERRIDES) { + /* We're totally done parsing */ + g_OverrideState = OVERRIDE_STATE_LEVELS; + return SMCParse_Halt; + } + + return SMCParse_Continue; +} + +static InitializeOverrideParser() +{ + if (g_hOverrideParser == INVALID_HANDLE) + { + g_hOverrideParser = SMC_CreateParser(); + SMC_SetReaders(g_hOverrideParser, + ReadOverrides_NewSection, + ReadOverrides_KeyValue, + ReadOverrides_EndSection); + } +} + +ReadOverrides() +{ + new String:path[PLATFORM_MAX_PATH]; + + InitializeOverrideParser(); + + BuildPath(Path_SM, path, sizeof(path), "configs/admin_levels.cfg"); + + /* Set states */ + g_OverrideState = OVERRIDE_STATE_NONE; + g_LoggedFileName = false; + g_ErrorCount = 0; + + new SMCError:err = SMC_ParseFile(g_hOverrideParser, path); + if (err != SMCError_Okay) + { + decl String:buffer[64]; + if (SMC_GetErrorString(err, buffer, sizeof(buffer))) + { + LogOverrideError("%s", buffer); + } else { + LogOverrideError("Fatal parse error"); + } + } +} + From 3091462dff9bd026b5e9ae8414db6cf1371ae045 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 23:54:46 +0000 Subject: [PATCH 0391/1664] clarified parameter indexing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40422 --- public/ISourceMod.h | 1 + 1 file changed, 1 insertion(+) diff --git a/public/ISourceMod.h b/public/ISourceMod.h index bd8f2547..154cfa4b 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -108,6 +108,7 @@ namespace SourceMod * @param pContext Pointer to the plugin's context. * @param params Parameter array that was passed to the native. * @param param Parameter index where format string and variable arguments begin. + * Note: parameter indexes start at 1. * @return Number of bytes written, not including the null terminator. */ virtual size_t FormatString(char *buffer, From 619c15cac98604016509404eb00cfa516d403a93 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 00:38:15 +0000 Subject: [PATCH 0392/1664] moved these to includes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40423 --- plugins/admin-base/admin-base.sp | 3 +++ plugins/admin-base/admin-overrides.sp | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-base/admin-base.sp index e1df3784..a4f1a48a 100644 --- a/plugins/admin-base/admin-base.sp +++ b/plugins/admin-base/admin-base.sp @@ -15,6 +15,9 @@ new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ new g_ErrorCount = 0; +#include "admin-levels.sp" +#include "admin-overrides.sp" + public OnRebuildAdminCache(cache_flags) { RefreshLevels(); diff --git a/plugins/admin-base/admin-overrides.sp b/plugins/admin-base/admin-overrides.sp index a56b18cc..14ccaa95 100644 --- a/plugins/admin-base/admin-overrides.sp +++ b/plugins/admin-base/admin-overrides.sp @@ -52,6 +52,12 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, new AdminFlag:flag = Admin_None; + if (strlen(value) > 1) + { + LogOverrideError("Unrecognized access level: %s", value); + return SMCParse_Continue; + } + if (value[0] >= 'a' && value[0] <= 'z') { flag = g_FlagLetters[value[0] - 'a']; From 7b5886d511a90acb1f987dfc122664a516c77bf6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 00:38:56 +0000 Subject: [PATCH 0393/1664] updated todo list --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40424 --- TODO.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.txt b/TODO.txt index fdf77b7f..c504cadc 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,9 +3,9 @@ things to do for a release, in priority X URGENT: fix compiler's sizeof(), add cellsof X do module api X finish plugin pausing/unpausing, forwards must block execution - - do admin api + X do admin api - finish cross extension dependencies (ShareSys::AddDepency) - - make "mapupdated" plugins work as intended (reload on mapchange if newer) + X make "mapupdated" plugins work as intended (reload on mapchange if newer) X add debugging output to logger - finish ML api, expose through interface X add error messages to format routine From d52aaa81d92fc5a443a8aa65d276c5a1e5827693 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 02:38:12 +0000 Subject: [PATCH 0394/1664] oh god I hate GNU make so much hate hate hate yes I hate HATE what a sucky system who designed this anyway, a squirrel a radioactive squirrel? I tihnk it was a dead radioactive squirrel --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40425 --- core/Makefile | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/core/Makefile b/core/Makefile index beb6bb34..ea716188 100644 --- a/core/Makefile +++ b/core/Makefile @@ -10,7 +10,8 @@ SRCDS = ~/srcds ### EDIT BELOW FOR OTHER PROJECTS ### OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing -GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +GCC4_FLAGS = -fvisibility=hidden +GCC4_CPP_FLAGS = -fvisibility-inlines-hidden DEBUG_FLAGS = -g -ggdb3 CPP = gcc-4.1 BINARY = sourcemod_mm_i486.so @@ -27,7 +28,7 @@ OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CDbgReporter.cpp CLogger systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ systems/PluginSys.cpp systems/ShareSys.cpp vm/sp_vm_basecontext.cpp \ vm/sp_vm_engine.cpp vm/sp_vm_function.cpp -OBJECTS += zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \ +OBJECTS_C = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \ zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \ zlib/uncompr.c zlib/zutil.c @@ -52,16 +53,17 @@ CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnic CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti ifeq "$(GCC_VERSION)" "4" - CPPFLAGS += $(GCC4_FLAGS) + CFLAGS += $(GCC4_FLAGS) + CPPFLAGS += $(GCC4_CPP_FLAGS) endif -OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) -OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.ox) +OBJ_LINUX_C := $(OBJECTS_C:%.c=$(BIN_DIR)/%.oc) -$(BIN_DIR)/%.o: %.cpp +$(BIN_DIR)/%.ox: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -$(BIN_DIR)/%.o: %.c +$(BIN_DIR)/%.oc: %.c $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< all: @@ -74,8 +76,8 @@ all: rm -rf $(BINARY) ln -sf $(BIN_DIR)/$(BINARY) $(BINARY) -sourcemod: $(OBJ_LINUX) - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) +sourcemod: $(OBJ_LINUX) $(OBJ_LINUX_C) + $(CPP) $(INCLUDE) $(OBJ_LINUX) $(OBJ_LINUX_C) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) debug: $(MAKE) all DEBUG=true @@ -83,8 +85,12 @@ debug: default: all clean: - rm -rf Release/*.o + rm -rf Release/*.ox + rm -rf Release/systems/*.ox + rm -rf Release/zlib/*.oc rm -rf Release/$(BINARY) - rm -rf Debug/*.o + rm -rf Debug/*.ox + rm -rf DEbug/systems/*.ox + rm -rf Debug/zlib/*.oc rm -rf Debug/$(BINARY) From 5085521b548d9aa703d70ccd86e25bc204a9cc90 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 05:42:57 +0000 Subject: [PATCH 0395/1664] initial import of group reader (unfinished) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40426 --- configs/admin_groups.cfg | 6 +- plugins/admin-base/admin-groups.sp | 147 ++++++++++++++++++++++++++ plugins/admin-base/admin-overrides.sp | 2 +- plugins/include/admin.inc | 6 ++ 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 plugins/admin-base/admin-groups.sp diff --git a/configs/admin_groups.cfg b/configs/admin_groups.cfg index d4505a72..d450c5c2 100644 --- a/configs/admin_groups.cfg +++ b/configs/admin_groups.cfg @@ -4,9 +4,9 @@ Groups * Allowed properties for a group: * * "flags" - Flag string. - * "inherit" - Inherits permissions from another group. + * "inherit" - Inherits permissions from another group. Use one group per instance of this key. * "immunity" - Specifies a group to be immune to. Use "*" for all or "$" for users with no group. - * NOTE: No one, even a root user, is immune from other root users. + * This key may be used multiple times. */ "Full Admins" { @@ -14,7 +14,7 @@ Groups * You can override commands and command groups here. * Specify a command name or group and either "allow" or "deny" * Examples: - * ":CSDM" "allow" + * ":CSDM" "allow" * "csdm_enable" "deny" */ Commands diff --git a/plugins/admin-base/admin-groups.sp b/plugins/admin-base/admin-groups.sp new file mode 100644 index 00000000..7f63c663 --- /dev/null +++ b/plugins/admin-base/admin-groups.sp @@ -0,0 +1,147 @@ +#define GROUP_STATE_NONE 0 +#define GROUP_STATE_GROUPS 1 +#define GROUP_STATE_INGROUP 2 +#define GROUP_STATE_OVERRIDES 3 +#define GROUP_PASS_FIRST 1 +#define GROUP_PASS_SECOND 2 + +static Handle:g_hGroupParser = INVALID_HANDLE; +static GroupId:g_CurGrp = INVALID_GROUP_ID; +static g_GroupState = GROUP_STATE_NONE; +static g_GroupPass = 0 + +static LevelGroupError(const String:buffer[], {Handle,String,Float,_}:...) +{ + decl String:buffer[512]; + + if (!g_LoggedFileName) + { + LogError("Error(s) detected parsing admin_groups.cfg:"); + g_LoggedFileName = true; + } + + VFormat(buffer, sizeof(buffer), format, 2); + + LogError(" (%d) %s", ++g_ErrorCount, buffer); +} + +public SMCResult:ReadGroups_NewSection(Handle:smc, const String:name[], bool:opt_quotes) +{ + if (g_GroupState == GROUP_STATE_NONE) + { + if (StrEqual(name, "Groups")) + { + g_GroupState = GROUP_STATE_GROUPS; + } + } else if (g_GroupState == GROUP_STATE_GROUPS) { + if ((g_CurGrp = CreateAdmGroup(name)) == INVALID_GROUP_ID) + { + g_CurGrp = FindAdmGroup(name); + } + g_GroupState = GROUP_STATE_INGROUP; + } else if (g_GroupState == GROUP_STATE_INGROUP) { + if (StrEqual(name, "Overrides")) + { + g_GroupState = GROUP_STATE_OVERRIDES; + } + } + + return SMCParse_Continue; +} + +public SMCResult:ReadGroups_KeyValue(Handle:smc, + const String:key[], + const String:value[], + bool:key_quotes, + bool:value_quotes) +{ + if (g_CurGrp == INVALID_GROUP_ID) + { + return SMCParse_Continue; + } + + new AdminFlag:flag; + + if (StrEqual(key, "flags")) + { + new len = strlen(value); + for (new i=0; i 'z') + { + continue; + } + flag = g_FlagLetters[value[i] - 'a']; + if (flag == Admin_None) + { + continue; + } + SetAdmGroupAddFlag(g_CurGrp, flag, true); + } + } else if (StrEqual(key, "immunity")) { + if (StrEqual(value, "*")) + { + SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true); + } else if (StrEqual(value, "$")) { + SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true); + } + } + + return SMCParse_Continue; +} + +public SMCResult:ReadGroups_EndSection(Handle:smc) +{ + if (g_GroupState == GROUP_STATE_OVERRIDES) + { + g_GroupState = GROUP_STATE_INGROUP; + } else if (g_GroupState == GROUP_STATE_INGROUP) { + g_GroupState = GROUP_STATE_GROUPS; + g_CurGrp = INVALID_GROUP_ID; + } else if (g_GroupState == GROUP_STATE_GROUPS) { + g_GroupState = GROUP_STATE_NONE; + } + + return SMCParse_Continue; +} + +static InitializeGroupParser() +{ + if (g_hGroupParser == INVALID_HANDLE) + { + g_hGroupParser = SMC_CreateParser(); + SMC_SetReaders(g_hGroupParser, + ReadGroup_NewSection, + ReadGroup_KeyValue, + ReadGroup_EndSection); + } +} + +ReadGroups() +{ + new String:path[PLATFORM_MAX_PATH]; + + InitializeGroupParser(); + + BuildPath(Path_SM, path, sizeof(path), "configs/admin_groups.cfg"); + + /* Set states */ + g_GroupState = GROUP_STATE_NONE; + g_LoggedFileName = false; + g_ErrorCount = 0; + g_CurGrp = INVALID_GROUP_ID; + g_GroupPass = GROUP_PASS_FIRST; + + new SMCError:err = SMC_ParseFile(g_hGroupParser, path); + if (err != SMCError_Okay) + { + decl String:buffer[64]; + if (SMC_GetErrorString(err, buffer, sizeof(buffer))) + { + LogGroupError("%s", buffer); + } else { + LogGroupError("Fatal parse error"); + } + } +} + diff --git a/plugins/admin-base/admin-overrides.sp b/plugins/admin-base/admin-overrides.sp index 14ccaa95..cd3a522f 100644 --- a/plugins/admin-base/admin-overrides.sp +++ b/plugins/admin-base/admin-overrides.sp @@ -5,7 +5,7 @@ static Handle:g_hOverrideParser = INVALID_HANDLE; static g_OverrideState = OVERRIDE_STATE_NONE; -LogOverrideError(const String:format[], {Handle,String,Float,_}:...) +static LogOverrideError(const String:format[], {Handle,String,Float,_}:...) { decl String:buffer[512]; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 23a9217b..bb184c74 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -62,6 +62,12 @@ enum GroupId INVALID_GROUP_ID = -1, }; +/** Note: These are not Handles */ +enum AdminId +{ + INVALID_ADMIN_ID = -1, +}; + #define ADMIN_CACHE_OVERRIDES (1<<0) #define ADMIN_CACHE_ADMINS (1<<1) #define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) From bf145be82655fe0463f351df04f2def3fe40ce88 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 06:43:34 +0000 Subject: [PATCH 0396/1664] implemented more of the group reader eliminated the pointless "inherit" directive --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40427 --- configs/admin_groups.cfg | 1 - plugins/admin-base/admin-base.sp | 5 ++ plugins/admin-base/admin-groups.sp | 87 +++++++++++++++++++++++------- plugins/include/admin.inc | 2 +- 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/configs/admin_groups.cfg b/configs/admin_groups.cfg index d450c5c2..ed4c4142 100644 --- a/configs/admin_groups.cfg +++ b/configs/admin_groups.cfg @@ -4,7 +4,6 @@ Groups * Allowed properties for a group: * * "flags" - Flag string. - * "inherit" - Inherits permissions from another group. Use one group per instance of this key. * "immunity" - Specifies a group to be immune to. Use "*" for all or "$" for users with no group. * This key may be used multiple times. */ diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-base/admin-base.sp index a4f1a48a..af9ffb5e 100644 --- a/plugins/admin-base/admin-base.sp +++ b/plugins/admin-base/admin-base.sp @@ -17,6 +17,7 @@ new g_ErrorCount = 0; #include "admin-levels.sp" #include "admin-overrides.sp" +#include "admin-groups.sp" public OnRebuildAdminCache(cache_flags) { @@ -25,4 +26,8 @@ public OnRebuildAdminCache(cache_flags) { ReadOverrides(); } + if (cache_flags & ADMIN_CACHE_GROUPS) + { + ReadGroups(); + } } diff --git a/plugins/admin-base/admin-groups.sp b/plugins/admin-base/admin-groups.sp index 7f63c663..22e27f59 100644 --- a/plugins/admin-base/admin-groups.sp +++ b/plugins/admin-base/admin-groups.sp @@ -9,8 +9,13 @@ static Handle:g_hGroupParser = INVALID_HANDLE; static GroupId:g_CurGrp = INVALID_GROUP_ID; static g_GroupState = GROUP_STATE_NONE; static g_GroupPass = 0 +static bool:g_NeedReparse = false; -static LevelGroupError(const String:buffer[], {Handle,String,Float,_}:...) +//:TODO: immunity needs to self-check itself for redundancy in core +//:TODO: invalidating groups internally needs to check immunities +//:TODO: reparsing + +static LogGroupError(const String:fmt[], {Handle,String,Float,_}:...) { decl String:buffer[512]; @@ -20,7 +25,7 @@ static LevelGroupError(const String:buffer[], {Handle,String,Float,_}:...) g_LoggedFileName = true; } - VFormat(buffer, sizeof(buffer), format, 2); + VFormat(buffer, sizeof(buffer), fmt, 2); LogError(" (%d) %s", ++g_ErrorCount, buffer); } @@ -62,28 +67,71 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, new AdminFlag:flag; - if (StrEqual(key, "flags")) + if (g_GroupPass == GROUP_PASS_FIRST) { - new len = strlen(value); - for (new i=0; i 'z') + if (StrEqual(key, "flags")) { - continue; + new len = strlen(value); + for (new i=0; i 'z') + { + continue; + } + flag = g_FlagLetters[value[i] - 'a']; + if (flag == Admin_None) + { + continue; + } + SetAdmGroupAddFlag(g_CurGrp, flag, true); + } + } else if (StrEqual(key, "immunity")) { + /* If it's a value we know about, use it */ + if (StrEqual(value, "*")) + { + SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true); + } else if (StrEqual(value, "$")) { + SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true); + } else { + /* If we can't find the group, we'll need to schedule a reparse */ + new GroupId:id = FindAdmGroup(value); + if (id == INVALID_GROUP_ID) + { + SetAdmGroupImmuneFrom(g_CurGrp, id); + } else { + g_NeedReparse = true; + } + } } - flag = g_FlagLetters[value[i] - 'a']; - if (flag == Admin_None) + } else if (g_GroupState == GROUP_STATE_OVERRIDES) { + new OverrideRule:rule = Command_Deny; + + if (StrEqual(value, "allow", false)) { - continue; + rule = Command_Allow; + } + + if (key[0] == '@') + { + AddAdmGroupCmdOverride(g_CurGrp, key[1], Override_CommandGroup, rule); + } else { + AddAdmGroupCmdOverride(g_CurGrp, key, Override_Command, rule); } - SetAdmGroupAddFlag(g_CurGrp, flag, true); } - } else if (StrEqual(key, "immunity")) { - if (StrEqual(value, "*")) + } else if (g_GroupPass == GROUP_PASS_SECOND + && g_GroupState == GROUP_STATE_INGROUP) { + /* Check for immunity again, core should handle double inserts */ + if (StrEqual(key, "immunity")) { - SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true); - } else if (StrEqual(value, "$")) { - SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true); + new GroupId:id = FindAdmGroup(value); + if (id != INVALID_GROUP_ID) + { + SetAdmGroupImmuneFrom(g_CurGrp, id); + } else { + LogGroupError("Unable to find group: \"%s\"", value); + } } } @@ -111,9 +159,9 @@ static InitializeGroupParser() { g_hGroupParser = SMC_CreateParser(); SMC_SetReaders(g_hGroupParser, - ReadGroup_NewSection, - ReadGroup_KeyValue, - ReadGroup_EndSection); + ReadGroups_NewSection, + ReadGroups_KeyValue, + ReadGroups_EndSection); } } @@ -131,6 +179,7 @@ ReadGroups() g_ErrorCount = 0; g_CurGrp = INVALID_GROUP_ID; g_GroupPass = GROUP_PASS_FIRST; + g_NeedReparse = false; new SMCError:err = SMC_ParseFile(g_hGroupParser, path); if (err != SMCError_Okay) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index bb184c74..465c35a8 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -133,7 +133,7 @@ native GroupId:CreateAdmGroup(const String:group_name[]); * @param group_name String containing the group name. * @return A group id, or INVALID_GROUP_ID if not found. */ -native FindAdmGroup(const String:group_name[]); +native GroupId:FindAdmGroup(const String:group_name[]); /** * Adds or removes a flag from a group's flag set. From 5c90acd7bea0e08782b0bd4eb7e595798149fbfe Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 30 Jan 2007 18:04:53 +0000 Subject: [PATCH 0397/1664] finalized translation routines and formatting --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40428 --- core/sm_stringutil.cpp | 113 +++++++++++++++++++++++++++++++++++------ core/sourcemod.cpp | 10 ++++ core/sourcemod.h | 11 ++++ 3 files changed, 118 insertions(+), 16 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 1dda1ab9..83d2b40d 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -18,6 +18,7 @@ #include "CLogger.h" #include "PluginSys.h" #include "CTranslator.h" +#include "CPlayerManager.h" #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ @@ -26,34 +27,86 @@ #define CHECK_ARGS(x) \ if ((arg+x) > args) { \ - g_Logger.LogError("String formatted incorrectly - parameter %d (total %d)", arg, args); \ + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ return 0; \ } -size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg) +inline bool TryServerLanguage(const char *serverlang, unsigned int *langid) { - unsigned int langid; - CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); - size_t langcount = pl->GetLangFileCount(); - - if (!g_Translator.GetLanguageByCode("en", &langid)) //:TODO: hardcoded this just for testing + if (!g_Translator.GetLanguageByCode(serverlang, langid)) { - //:TODO: error out something + if (!g_Translator.GetLanguageByCode("en", langid)) + { + return false; + } } + return true; +} +inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans) +{ + TransError err = Trans_BadLanguage; CPhraseFile *phrfl; - TransError err = Trans_Okay; - Translation pTrans; for (size_t i=0; iGetFileByIndex(i)); - err = phrfl->GetTranslation(key, langid, &pTrans); + err = phrfl->GetTranslation(key, langid, pTrans); } - if (err != Trans_Okay) + return (err == Trans_Okay) ? true : false; +} + +size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error) +{ + unsigned int langid; + char *langname = NULL; + *error = false; + +try_serverlang: + if (target == LANG_SERVER) { - //:TODO: we didnt find our translation in any file :o + langname = "en"; //:TODO: read serverlang + if (!TryServerLanguage(langname ? langname : "en", &langid)) + { + pCtx->ThrowNativeError("Translation failure: English language not found."); + goto error_out; + } + } else if ((target >= 1) && (target <= g_PlayerManager.GetMaxClients())) { + langname = "en"; //:TODO: read player's lang + if (!langname || !g_Translator.GetLanguageByCode(langname, &langid)) + { + if (langname && !strcmp(langname, "en")) + { + pCtx->ThrowNativeError("Translation failure: English language not found."); + goto error_out; + } + target = LANG_SERVER; + goto try_serverlang; + } + } else { + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target); + goto error_out; + } + + Translation pTrans; + CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); + size_t langcount = pl->GetLangFileCount(); + + if (!TryTranslation(pl, key, langid, langcount, &pTrans)) + { + if (target != LANG_SERVER) + { + target = LANG_SERVER; + goto try_serverlang; + } else { + if (!g_Translator.GetLanguageByCode("en", &langid) + || !TryTranslation(pl, key, langid, langcount, &pTrans)) + { + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); + goto error_out; + } + } } void *new_params[MAX_TRANSLATE_PARAMS]; @@ -64,11 +117,15 @@ size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char * (*arg)++; if ((*arg) + i > (size_t)params[0]) { - //:TODO: we are missing arguments zOMG + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "Translation string formatted incorrectly - parameter %d (total %d)", (*arg) + i, params[0]); + goto error_out; } } return g_Translator.Translate(buffer, maxlen, new_params, &pTrans); +error_out: + *error = true; + return 0; } //:TODO: review this code before we choose a license @@ -611,10 +668,34 @@ reswitch: { CHECK_ARGS(0); char *key; + bool error; + size_t res; cell_t target = params[arg++]; pCtx->LocalToString(params[arg++], &key); - llen -= Translate(buf_p, llen, pCtx, key, target, params, &arg); - buf_p += llen; + res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error); + if (error) + { + return 0; + } + buf_p += res; + llen -= res; + break; + } + case 't': + { + CHECK_ARGS(0); + char *key; + bool error; + size_t res; + cell_t target = g_SourceMod.GetGlobalTarget(); + pCtx->LocalToString(params[arg++], &key); + res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error); + if (error) + { + return 0; + } + buf_p += res; + llen -= res; break; } case '%': diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 76bbe06d..016f325a 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -343,6 +343,16 @@ const char *SourceModBase::GetModPath() return g_BaseDir.c_str(); } +void SourceModBase::SetGlobalTarget(unsigned int index) +{ + m_target = index; +} + +unsigned int SourceModBase::GetGlobalTarget() const +{ + return m_target; +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index f2ce4961..bbe290a2 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -56,6 +56,16 @@ public: */ bool IsMapLoading(); + /** + * @brief Stores the global target index. + */ + void SetGlobalTarget(unsigned int index); + + /** + * @brief Returns the global target index. + */ + unsigned int GetGlobalTarget() const; + public: //ISourceMod const char *GetModPath(); const char *GetSourceModPath(); @@ -73,6 +83,7 @@ private: char m_SMRelDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; bool m_ExecPluginReload; + unsigned int m_target; }; extern SourceModBase g_SourceMod; From 66e9205ab54cbeb1ac044fd46044b53c2f7abd38 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 30 Jan 2007 18:34:43 +0000 Subject: [PATCH 0398/1664] fixed typo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40429 --- core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Makefile b/core/Makefile index ea716188..625c7b0b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -90,7 +90,7 @@ clean: rm -rf Release/zlib/*.oc rm -rf Release/$(BINARY) rm -rf Debug/*.ox - rm -rf DEbug/systems/*.ox + rm -rf Debug/systems/*.ox rm -rf Debug/zlib/*.oc rm -rf Debug/$(BINARY) From 54a574c104856e051d96ae263a6d103591ab74c7 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 2 Feb 2007 11:08:51 +0000 Subject: [PATCH 0399/1664] Fixed annoying bug in builder where executing svnversion command on a path containing spaces would cause a crash --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40430 --- tools/builder/ABuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs index 4259da00..f1a95b19 100644 --- a/tools/builder/ABuilder.cs +++ b/tools/builder/ABuilder.cs @@ -22,7 +22,7 @@ namespace builder info.WorkingDirectory = path; info.FileName = cfg.SVNVersion; - info.Arguments = "--committed " + path; + info.Arguments = "--committed \"" + path + "\""; info.UseShellExecute = false; info.RedirectStandardOutput = true; From 3efb1587549e82a25610bc96208d42f40f49fd4b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 2 Feb 2007 11:27:22 +0000 Subject: [PATCH 0400/1664] Code clean-up on aisle nana! Well, barely any code was touched here actually... 1) Fixed a few minor warnings 2) Removed MM build configs from geoip 3) Made sure that every project and build config had its Character Set set to Multi-Byte and that Detect 64-Bit Portability Issues was set to No. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40431 --- core/AdminCache.cpp | 2 +- core/msvc8/sourcemod_mm.vcproj | 6 +- core/svn_version.h | 22 +-- extensions/geoip/msvc8/geoip.sln | 6 - extensions/geoip/msvc8/geoip.vcproj | 162 +--------------------- extensions/threader/msvc8/threader.vcproj | 10 +- public/sample_ext/msvc8/sdk.vcproj | 16 ++- sourcepawn/compiler/msvc8/spcomp.vcproj | 8 +- sourcepawn/compiler/sc1.c | 3 +- sourcepawn/compiler/svn_version.h | 22 +-- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 6 +- sourcepawn/jit/x86/svn_version.h | 6 +- 12 files changed, 59 insertions(+), 210 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 58478ad0..fa6bcc9d 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -823,7 +823,7 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) /* If we only requested an admin rebuild, re-use the internal memory */ if (((cache_flags & ADMIN_CACHE_ADMINS) == ADMIN_CACHE_ADMINS) - && (cache_flags & (1<<2) != (1<<2))) + && ((cache_flags & (1<<2)) != (1<<2))) { InvalidateAdminCache(true); } diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7fdd69da..a5e95c10 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Date: Fri, 2 Feb 2007 22:47:14 +0000 Subject: [PATCH 0401/1664] Oi, consistency... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40432 --- core/systems/PluginSys.cpp | 8 ++++---- core/systems/PluginSys.h | 10 +++++----- plugins/include/sourcemod.inc | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 3be86aa4..6eb5941e 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -243,7 +243,7 @@ void CPlugin::UpdateInfo() m_info.version = m_info.version ? m_info.version : ""; } -void CPlugin::Call_OnPluginInit() +void CPlugin::Call_OnPluginStart() { if (m_status != Plugin_Loaded) { @@ -263,7 +263,7 @@ void CPlugin::Call_OnPluginInit() pFunction->Execute(&result); } -void CPlugin::Call_OnPluginUnload() +void CPlugin::Call_OnPluginEnd() { if (m_status < Plugin_Paused) { @@ -959,7 +959,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng } /* Tell this plugin to finish initializing itself */ - pPlugin->Call_OnPluginInit(); + pPlugin->Call_OnPluginStart(); return true; } @@ -1003,7 +1003,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener->OnPluginUnloaded(pPlugin); } /* Notify plugin */ - pPlugin->Call_OnPluginUnload(); + pPlugin->Call_OnPluginEnd(); } for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index fe5dc201..b46bd356 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -74,7 +74,7 @@ using namespace SourceHook; * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped. * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran. * PASS THREE (not a real pass): - * 7. Once all plugins are deemed to be loaded, OnPluginInit() is called + * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called */ #define SM_CONTEXTVAR_MYSELF 0 @@ -157,16 +157,16 @@ public: bool Call_AskPluginLoad(char *error, size_t maxlength); /** - * Calls the OnPluginInit function. + * Calls the OnPluginStart function. * NOTE: Valid pre-states are: Plugin_Created * NOTE: Post-state will be Plugin_Running */ - void Call_OnPluginInit(); + void Call_OnPluginStart(); /** - * Calls the OnPluginUnload function. + * Calls the OnPluginEnd function. */ - void Call_OnPluginUnload(); + void Call_OnPluginEnd(); /** * Toggles debug mode in the plugin diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 4a168f60..936fc2f5 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -55,12 +55,12 @@ public Plugin:myinfo; forward OnPluginStart(Handle:myself); /** - * Called before OnPluginInit, in case the plugin wants to check for load failure. + * Called before OnPluginStart, in case the plugin wants to check for load failure. * This is called even if the plugin type is "private." Any natives from modules are * not available at this point. Thus, this forward should only be used for explicit * pre-emptive things, such as adding dynamic natives, or setting certain types of load filters. * - * NOTE: It is not safe to call externally resolved natives until OnPluginInit(). + * NOTE: It is not safe to call externally resolved natives until OnPluginStart(). * NOTE: Any sort of RTE in this function will cause the plugin to fail loading. * * @param myself Handle to the plugin. From 485692e6a421bb37c3cb0d1217048558b5cccd22 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 3 Feb 2007 14:33:43 +0000 Subject: [PATCH 0402/1664] fixed type reported at am50751 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40433 --- plugins/include/textparse.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc index 394bae43..c39dc6f7 100644 --- a/plugins/include/textparse.inc +++ b/plugins/include/textparse.inc @@ -176,4 +176,4 @@ functag SMC_RawLine SMCResult:public(Handle:smc, const String:line[], lineno); * @param func SMC_RawLine function. * @noreturn */ -native SMC_SetRawLine(Handle:smc, SMC_Rawline:func); +native SMC_SetRawLine(Handle:smc, SMC_RawLine:func); From 8649e57ebc007cce4030322d4842cd4087af251a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 4 Feb 2007 08:00:44 +0000 Subject: [PATCH 0403/1664] added API spec sample for data packs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40434 --- plugins/include/datapack.inc | 72 +++++++++ plugins/include/sourcemod.inc | 265 ---------------------------------- 2 files changed, 72 insertions(+), 265 deletions(-) create mode 100644 plugins/include/datapack.inc delete mode 100644 plugins/include/sourcemod.inc diff --git a/plugins/include/datapack.inc b/plugins/include/datapack.inc new file mode 100644 index 00000000..3f40df8d --- /dev/null +++ b/plugins/include/datapack.inc @@ -0,0 +1,72 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _datapack_included + #endinput +#endif +#define _datapack_included + + +/** + * Creates a new data pack. + * + * @return A Handle to the data pack. Must be closed with CloseHandle(). + */ +native Handle:CreateDataPack(); + +/** + * Packs a normal cell into a data pack. + * + * @param pack Handle to the data pack. + * @param cell Cell to add. + * @noreturn + * @error Invalid handle. + */ +native WritePackCell(Handle:pack, cell); + +/** + * Reads a cell from a data pack. + * + * @param pack Handle to the data pack. + * @return Cell value. + * @error Invalid handle, or bounds error. + */ +native ReadPackCell(Handle:pack); + +/** + * Resets the position in a data pack. + * + * @param pack Handle to the data pack. + * @param clear If true, clears the contained data. + * @noreturn + */ +native ResetPack(Handle:pack, bool:clear=false); + +/** + * Returns the read or write position in a data pack. + * + * @param pack Handle to the data pack. + * @return Numerical position in the data pack. + */ +native GetPackPosition(Handle:pack); + +/** + * Sets the read/write position in a data pack. + * + * @param pack Handle to the data pack. + * @param position New position to set. + * @noreturn + * @error Position is beyond the pack bounds. + */ +native SetPackPosition(Handle:pack, position); \ No newline at end of file diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc deleted file mode 100644 index 936fc2f5..00000000 --- a/plugins/include/sourcemod.inc +++ /dev/null @@ -1,265 +0,0 @@ -/** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== - * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#if defined _sourcemod_included - #endinput -#endif -#define _sourcemod_included - -struct Plugin -{ - const String:name[], /* Plugin Name */ - const String:description[], /* Plugin Description */ - const String:author[], /* Plugin Author */ - const String:version[], /* Plugin Version */ - const String:url[], /* Plugin URL */ -}; - -#include -#include -#include -#include -#include -#include - -/** - * Declare this as a struct in your plugin to expose its information. - * Example: - * - * public Plugin:myinfo = - * { - * name = "My Plugin", - * //etc - * }; - */ -public Plugin:myinfo; - -/** - * Called when the plugin is fully initialized and all known external references are resolved. - * This is called even if the plugin type is "private." - * NOTE: Errors in this function will cause the plugin to stop running. - * - * @noreturn - */ -forward OnPluginStart(Handle:myself); - -/** - * Called before OnPluginStart, in case the plugin wants to check for load failure. - * This is called even if the plugin type is "private." Any natives from modules are - * not available at this point. Thus, this forward should only be used for explicit - * pre-emptive things, such as adding dynamic natives, or setting certain types of load filters. - * - * NOTE: It is not safe to call externally resolved natives until OnPluginStart(). - * NOTE: Any sort of RTE in this function will cause the plugin to fail loading. - * - * @param myself Handle to the plugin. - * @param late Whether or not the plugin was loaded "late" (after map load). - * @param error Error message buffer in case load failed. - * @param err_max Maximum number of characters for error message buffer. - * @return True if load success, false otherwise. - */ -forward bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max); - -/** - * Called when the plugin is about to be unloaded. - * - * @noreturn - */ -forward OnPluginEnd(); - -/** - * Called when the plugin's pause status is changing. - * - * @param pause True if the plugin is being paused, false otherwise. - * @noreturn - */ -forward OnPluginPauseChange(bool:pause); - -/** - * Called on client connection. - * - * @param client Player index. - * @param rejectmsg Buffer to store the rejection message when the connection is refused. - * @param maxlen Maximum number of characters for rejection buffer. - * @return True to validate client's connection, false to refuse it. - */ -forward bool:OnClientConnect(client, String:rejectmsg[], maxlen); - -/** - * Called when a client is entering to the game. - * - * @param client Player index. - * @noreturn - */ -forward OnClientPutInServer(client); - -/** - * Called when a client is disconnecting from the server. - * - * @param client Player index. - * @noreturn - */ -forward OnClientDisconnect(client); - -/** - * Called when a client is disconnected from the server. - * - * @param client Player index. - * @noreturn - */ -forward OnClientDisconnect_Post(client); - -/** - * Called when a client is sending a command. - * - * @param client Player index. - * @noreturn - */ -forward OnClientCommand(client); - -/** - * Called whenever the client's settings are changed. - * - * @param client Player index. - * @noreturn - */ -forward OnClientSettingsChanged(client); - -/** - * Returns the maximum number of clients allowed on the server. - * - * @return Maximum number of clients allowed. - */ -native GetMaxClients(); - -/** - * Returns the client count put in the server. - * - * @param inGameOnly If false connecting players are also counted. - * @return Client count in the server. - */ -native GetClientCount(bool:inGameOnly=true); - -/** - * Returns the client's name. - * - * @param client Player index. - * @param name Buffer to store the client's name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. - */ -native bool:GetClientName(client, String:name[], maxlen); - -/** - * Retrieves a client's IP address. - * - * @param client Player index. - * @param name Buffer to store the client's ip address. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param remport Remove client's port from the ip string (true by default). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. - */ -native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); - -/** - * Retrieves a client's authentication string (SteamID). - * - * @param client Player index. - * @param auth Buffer to store the client's auth string. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. - */ -native bool:GetClientAuthString(client, String:auth[], maxlen); - -/** - * Returns if a certain player is connected. - * - * @param client Player index. - * @return True if player is connected to the server, false otherwise. - */ -native bool:IsPlayerConnected(client); - -/** - * Returns if a certain player has entered the game. - * - * @param client Player index. - * @return True if player has entered the game, false otherwise. - */ -native bool:IsPlayerInGame(client); - -/** - * Returns if a certain player has been authenticated. - * - * @param client Player index. - * @return True if player has been authenticated, false otherwise. - */ -native bool:IsPlayerAuthorized(client); - -/** - * Returns if a certain player is a fake client. - * - * @param client Player index. - * @return True if player is a fake client, false otherwise. - */ -native bool:IsPlayerFakeClient(client); - -/** - * Sends a message to the server console. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @noreturn - */ -native PrintToServer(const String:format[], {Handle,Float,String,_}:...); - -/** - * Sends a message to a client's console. - * - * @param client Player index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @noreturn - * @error If the client is not connected an error will be thrown. - */ -native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); - -/** - * Logs a generic message to the HL2 logs. - * - * @param format String format. - * @param ... Format arguments. - * @noreturn - */ -native LogToGame(const String:format[], {Handle,Float,String,_}:...); - -/** - * Logs a plugin message to the SourceMod logs. - * - * @param format String format. - * @param ... Format arguments. - * @noreturn - */ -native LogMessage(const String:format[], {Handle,Float,String,_}:...); - -/** - * Logs a plugin error message to the SourceMod logs. - * - * @param format String format. - * @param ... Format arguments. - * @noreturn - */ -native LogError(const String:format[], {Handle,Float,String,_}:...); \ No newline at end of file From 4f5edf7b1f456e109249e24f5fda6e0cf4000e28 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 4 Feb 2007 08:01:07 +0000 Subject: [PATCH 0404/1664] what --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40435 --- plugins/include/sourcemod.inc | 265 ++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 plugins/include/sourcemod.inc diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc new file mode 100644 index 00000000..33876e00 --- /dev/null +++ b/plugins/include/sourcemod.inc @@ -0,0 +1,265 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id: sourcemod.inc 432 2007-02-02 22:47:14Z damagedsoul $ + */ + +#if defined _sourcemod_included + #endinput +#endif +#define _sourcemod_included + +struct Plugin +{ + const String:name[], /* Plugin Name */ + const String:description[], /* Plugin Description */ + const String:author[], /* Plugin Author */ + const String:version[], /* Plugin Version */ + const String:url[], /* Plugin URL */ +}; + +#include +#include +#include +#include +#include +#include + +/** + * Declare this as a struct in your plugin to expose its information. + * Example: + * + * public Plugin:myinfo = + * { + * name = "My Plugin", + * //etc + * }; + */ +public Plugin:myinfo; + +/** + * Called when the plugin is fully initialized and all known external references are resolved. + * This is called even if the plugin type is "private." + * NOTE: Errors in this function will cause the plugin to stop running. + * + * @noreturn + */ +forward OnPluginStart(Handle:myself); + +/** + * Called before OnPluginStart, in case the plugin wants to check for load failure. + * This is called even if the plugin type is "private." Any natives from modules are + * not available at this point. Thus, this forward should only be used for explicit + * pre-emptive things, such as adding dynamic natives, or setting certain types of load filters. + * + * NOTE: It is not safe to call externally resolved natives until OnPluginStart(). + * NOTE: Any sort of RTE in this function will cause the plugin to fail loading. + * + * @param myself Handle to the plugin. + * @param late Whether or not the plugin was loaded "late" (after map load). + * @param error Error message buffer in case load failed. + * @param err_max Maximum number of characters for error message buffer. + * @return True if load success, false otherwise. + */ +forward bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max); + +/** + * Called when the plugin is about to be unloaded. + * + * @noreturn + */ +forward OnPluginEnd(); + +/** + * Called when the plugin's pause status is changing. + * + * @param pause True if the plugin is being paused, false otherwise. + * @noreturn + */ +forward OnPluginPauseChange(bool:pause); + +/** + * Called on client connection. + * + * @param client Player index. + * @param rejectmsg Buffer to store the rejection message when the connection is refused. + * @param maxlen Maximum number of characters for rejection buffer. + * @return True to validate client's connection, false to refuse it. + */ +forward bool:OnClientConnect(client, String:rejectmsg[], maxlen); + +/** + * Called when a client is entering to the game. + * + * @param client Player index. + * @noreturn + */ +forward OnClientPutInServer(client); + +/** + * Called when a client is disconnecting from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect(client); + +/** + * Called when a client is disconnected from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect_Post(client); + +/** + * Called when a client is sending a command. + * + * @param client Player index. + * @noreturn + */ +forward OnClientCommand(client); + +/** + * Called whenever the client's settings are changed. + * + * @param client Player index. + * @noreturn + */ +forward OnClientSettingsChanged(client); + +/** + * Returns the maximum number of clients allowed on the server. + * + * @return Maximum number of clients allowed. + */ +native GetMaxClients(); + +/** + * Returns the client count put in the server. + * + * @param inGameOnly If false connecting players are also counted. + * @return Client count in the server. + */ +native GetClientCount(bool:inGameOnly=true); + +/** + * Returns the client's name. + * + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. + */ +native bool:GetClientName(client, String:name[], maxlen); + +/** + * Retrieves a client's IP address. + * + * @param client Player index. + * @param name Buffer to store the client's ip address. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param remport Remove client's port from the ip string (true by default). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. + */ +native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); + +/** + * Retrieves a client's authentication string (SteamID). + * + * @param client Player index. + * @param auth Buffer to store the client's auth string. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. + */ +native bool:GetClientAuthString(client, String:auth[], maxlen); + +/** + * Returns if a certain player is connected. + * + * @param client Player index. + * @return True if player is connected to the server, false otherwise. + */ +native bool:IsPlayerConnected(client); + +/** + * Returns if a certain player has entered the game. + * + * @param client Player index. + * @return True if player has entered the game, false otherwise. + */ +native bool:IsPlayerInGame(client); + +/** + * Returns if a certain player has been authenticated. + * + * @param client Player index. + * @return True if player has been authenticated, false otherwise. + */ +native bool:IsPlayerAuthorized(client); + +/** + * Returns if a certain player is a fake client. + * + * @param client Player index. + * @return True if player is a fake client, false otherwise. + */ +native bool:IsPlayerFakeClient(client); + +/** + * Sends a message to the server console. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native PrintToServer(const String:format[], {Handle,Float,String,_}:...); + +/** + * Sends a message to a client's console. + * + * @param client Player index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error If the client is not connected an error will be thrown. + */ +native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a generic message to the HL2 logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogToGame(const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a plugin message to the SourceMod logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogMessage(const String:format[], {Handle,Float,String,_}:...); + +/** + * Logs a plugin error message to the SourceMod logs. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + */ +native LogError(const String:format[], {Handle,Float,String,_}:...); \ No newline at end of file From c21bfe57c1308cec839ea6f38bd4785e1f60c88d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 4 Feb 2007 22:41:44 +0000 Subject: [PATCH 0405/1664] Optimized forwards, now paused functions are stored in a temp list so we dont have to check if they're runnable on each function execution. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40436 --- core/CPlayerManager.h | 4 +- core/systems/ForwardSys.cpp | 103 +++++++++++++++++++++++++++++++----- core/systems/ForwardSys.h | 26 +++++---- core/systems/PluginSys.cpp | 13 +++++ core/systems/PluginSys.h | 2 + public/IForwardSys.h | 7 ++- public/IPluginSys.h | 7 +++ 7 files changed, 131 insertions(+), 31 deletions(-) diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index 98060a8e..c2dc1dd7 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -27,8 +27,8 @@ class CPlayerManager : public SMGlobalClass public: CPlayerManager() : m_FirstPass(true) {} public: //SMGlobalClass - virtual void OnSourceModAllInitialized(); - virtual void OnSourceModShutdown(); + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); public: int GetMaxClients() const; CPlayer *GetPlayerByIndex(int client) const; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index d627e5e3..95fd06c6 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -177,6 +177,37 @@ CForward *CForwardManager::ForwardMake() return fwd; } +void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused) +{ + List::iterator iter; + CForward *fwd; + + if (paused) + { + for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) + { + fwd = (*iter); + fwd->PushPausedFunctions(plugin); + } + for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) + { + fwd = (*iter); + fwd->PushPausedFunctions(plugin); + } + } else { + for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) + { + fwd = (*iter); + fwd->PopPausedFunctions(plugin); + } + for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) + { + fwd = (*iter); + fwd->PopPausedFunctions(plugin); + } + } +} + /************************************* * ACTUAL FORWARD API IMPLEMENTATION * *************************************/ @@ -272,11 +303,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); - /* Ugh... */ - if (!func->GetParentContext()->IsRunnable()) - { - continue; - } for (unsigned int i=0; i *lst; - for (iter=m_functions.begin(); iter!=m_functions.end();) + if (func->GetParentContext()->IsRunnable()) + { + lst = &m_functions; + } else { + lst = &m_paused; + } + + for (iter=lst->begin(); iter!=lst->end(); iter++) { if ((*iter) == func) { found = true; - /* If this iterator is being used, swap in a new one !*/ - iter = m_functions.erase(iter); - } else { - iter++; + lst->erase(iter); + break; } } @@ -653,22 +685,65 @@ bool CForward::AddFunction(IPluginFunction *func) } //:IDEA: eventually we will tell the plugin we're using it [?] - m_functions.push_back(func); + if (func->GetParentContext()->IsRunnable()) + { + m_functions.push_back(func); + } else { + m_paused.push_back(func); + } return true; } -const char *CForward::GetForwardName() +const char *CForward::GetForwardName() const { return m_name; } -unsigned int CForward::GetFunctionCount() +unsigned int CForward::GetFunctionCount() const { return m_functions.size(); } -ExecType CForward::GetExecType() +ExecType CForward::GetExecType() const { return m_ExecType; } + +void CForward::PushPausedFunctions(IPlugin *plugin) +{ + FuncIter iter; + IPluginFunction *func; + IPluginContext *pContext = plugin->GetBaseContext(); + + for (iter=m_functions.begin(); iter!=m_functions.end();) + { + func = (*iter); + if (func->GetParentContext() == pContext) + { + m_paused.push_back(func); + iter = m_functions.erase(iter); + } else { + iter++; + } + } +} + +void CForward::PopPausedFunctions(IPlugin *plugin) +{ + FuncIter iter; + IPluginFunction *func; + IPluginContext *pContext = plugin->GetBaseContext(); + + for (iter=m_paused.begin(); iter!=m_paused.end();) + { + func = (*iter); + if (func->GetParentContext() == pContext) + { + m_functions.push_back(func); + iter = m_paused.erase(iter); + } else { + iter++; + } + } +} diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 73e58663..e8e16ae7 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -55,9 +55,9 @@ public: //ICallable virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual void Cancel(); public: //IForward - virtual const char *GetForwardName(); - virtual unsigned int GetFunctionCount(); - virtual ExecType GetExecType(); + virtual const char *GetForwardName() const; + virtual unsigned int GetFunctionCount() const; + virtual ExecType GetExecType() const; virtual int Execute(cell_t *result, IForwardFilter *filter); public: //IChangeableForward virtual bool RemoveFunction(IPluginFunction *func); @@ -70,6 +70,8 @@ public: unsigned int num_params, ParamType *types, va_list ap); + void PushPausedFunctions(IPlugin *plugin); + void PopPausedFunctions(IPlugin *plugin); private: void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags); @@ -83,6 +85,7 @@ protected: * Destroying these things and using new/delete for their members feels bad. */ List m_functions; + List m_paused; /* Type and name information */ FwdParamInfo m_params[SP_MAX_EXEC_PARAMS]; @@ -104,24 +107,25 @@ class CForwardManager : { friend class CForward; public: //IForwardManager - virtual IForward *CreateForward(const char *name, + IForward *CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...); - virtual IChangeableForward *CreateForwardEx(const char *name, + IChangeableForward *CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...); - virtual IForward *FindForward(const char *name, IChangeableForward **ifchng); - virtual void ReleaseForward(IForward *forward); + IForward *FindForward(const char *name, IChangeableForward **ifchng); + void ReleaseForward(IForward *forward); public: //IPluginsListener - virtual void OnPluginLoaded(IPlugin *plugin); - virtual void OnPluginUnloaded(IPlugin *plugin); + void OnPluginLoaded(IPlugin *plugin); + void OnPluginUnloaded(IPlugin *plugin); + void OnPluginPauseChange(IPlugin *plugin, bool paused); public: //SMGlobalClass - virtual void OnSourceModAllInitialized(); - virtual void OnSourceModShutdown(); + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); protected: CForward *ForwardMake(); void ForwardFree(CForward *fwd); diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6eb5941e..95cded30 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -385,6 +385,8 @@ bool CPlugin::SetPauseState(bool paused) pFunction->Execute(&result); } + g_PluginSys._SetPauseState(this, paused); + return true; } @@ -1636,3 +1638,14 @@ void CPluginManager::ReloadOrUnloadPlugins() } } } + +void CPluginManager::_SetPauseState(CPlugin *pl, bool paused) +{ + List::iterator iter; + IPluginsListener *pListener; + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) + { + pListener = (*iter); + pListener->OnPluginPauseChange(pl, paused); + } +} \ No newline at end of file diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index b46bd356..4954fe40 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -355,6 +355,8 @@ private: * Runs an extension pass on a plugin. */ bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength); + + void _SetPauseState(CPlugin *pPlugin, bool pause); protected: /** * Caching internal objects diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 6d467e1d..9139ef02 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -31,7 +31,6 @@ * function name in all plugins. */ -#include #include #include @@ -147,21 +146,21 @@ namespace SourceMod * * @return Forward name. */ - virtual const char *GetForwardName() =0; + virtual const char *GetForwardName() const =0; /** * @brief Returns the number of functions in this forward. * * @return Number of functions in forward. */ - virtual unsigned int GetFunctionCount() =0; + virtual unsigned int GetFunctionCount() const =0; /** * @brief Returns the method of multi-calling this forward has. * * @return ExecType of the forward. */ - virtual ExecType GetExecType() =0; + virtual ExecType GetExecType() const =0; /** * @brief Executes the forward. diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 1feb5858..45e9a78d 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -210,6 +210,13 @@ namespace SourceMod { } + /** + * @brief Called when a plugin is paused or unpaused. + */ + virtual void OnPluginPauseChange(IPlugin *plugin, bool paused) + { + } + /** * @brief Called when a plugin is unloaded (only if fully loaded). */ From fcb8c35eecddc07a9837e9000fbaba587a63552b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Feb 2007 02:16:33 +0000 Subject: [PATCH 0406/1664] removed InvalidateGroup() - it was a bad idea --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40437 --- public/IAdminSystem.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 83e7b646..3c87681e 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -307,13 +307,6 @@ namespace SourceMod OverrideType type, OverrideRule *pRule) =0; - /** - * @brief Invalidates and removes a group from the group cache. - * - * @param id Group id. - */ - virtual void InvalidateGroup(GroupId id) =0; - /** * @brief Tells the admin system to dump a portion of the cache. * This calls into plugin forwards to rebuild the cache. From 6a7f216615c1796cf95c0d28b300a1468e0b0f68 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 5 Feb 2007 08:58:03 +0000 Subject: [PATCH 0407/1664] Worst commit ever, but I have removed some unnecessary things --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40438 --- core/smn_float.cpp | 8 +------- core/smn_string.cpp | 3 --- public/IAdminSystem.h | 2 +- public/IExtensionSys.h | 2 +- public/IForwardSys.h | 4 ++-- public/IHandleSys.h | 2 +- public/ILibrarySys.h | 2 +- public/IPluginSys.h | 2 +- public/IRootConsoleMenu.h | 2 +- public/IShareSys.h | 2 +- public/ISourceMod.h | 2 +- public/ITextParsers.h | 2 +- 12 files changed, 12 insertions(+), 21 deletions(-) diff --git a/core/smn_float.cpp b/core/smn_float.cpp index bacbe516..e54fd80b 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -12,13 +12,7 @@ */ #include -#include -#include -#include "sm_autonatives.h" -#include "sp_vm_api.h" -#include "sp_typeutil.h" - -using namespace SourcePawn; +#include "sm_globals.h" /**************************************** * * diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 0d746722..e864cb99 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -11,14 +11,11 @@ * Version: $Id$ */ -#include "sm_platform.h" #include #include #include "sm_globals.h" #include "sm_stringutil.h" -using namespace SourcePawn; - inline const char *_strstr(const char *str, const char *substr) { #ifdef PLATFORM_WINDOWS diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 3c87681e..9877b893 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -464,6 +464,6 @@ namespace SourceMod */ virtual bool InvalidateAdmin(AdminId id) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_ADMINISTRATION_SYSTEM_H_ diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index 0d0eed87..b3e76250 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -245,6 +245,6 @@ namespace SourceMod */ virtual bool UnloadExtension(IExtension *pExt) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 9139ef02..4fddf472 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -329,7 +329,7 @@ namespace SourceMod */ virtual void ReleaseForward(IForward *forward) =0; }; -}; +} /* * In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing @@ -387,7 +387,7 @@ namespace SourceMod * be immediately resolved. Unfortunately, this became extremely burdensome on the API and exposed many problems, * the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same * plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order - * and become impossible to re-arrange without some global heap tracking mechanis. It also made iterative copy backs + * and become impossible to re-arrange without some global heap tracking mechanism. It also made iterative copy backs * for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy. * Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X * uses. It is both faster and works better. diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 9d2d283b..92cf5a72 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -304,6 +304,6 @@ namespace SourceMod */ virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index bac0ede2..18dfbc1a 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -174,6 +174,6 @@ namespace SourceMod */ virtual size_t PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_ diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 45e9a78d..6bafd2e7 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -312,6 +312,6 @@ namespace SourceMod */ virtual void RemovePluginsListener(IPluginsListener *listener) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_ diff --git a/public/IRootConsoleMenu.h b/public/IRootConsoleMenu.h index e3fcb97d..34fc04af 100644 --- a/public/IRootConsoleMenu.h +++ b/public/IRootConsoleMenu.h @@ -107,6 +107,6 @@ namespace SourceMod */ virtual void DrawGenericOption(const char *cmd, const char *text) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_ diff --git a/public/IShareSys.h b/public/IShareSys.h index 559f5583..99cbf7a7 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -174,6 +174,6 @@ namespace SourceMod */ virtual void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_ diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 154cfa4b..ca44945c 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -117,6 +117,6 @@ namespace SourceMod const cell_t *params, unsigned int param) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_ diff --git a/public/ITextParsers.h b/public/ITextParsers.h index 4f8654c7..923c65cd 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -350,6 +350,6 @@ namespace SourceMod */ virtual unsigned int GetUTF8CharBytes(const char *stream) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ From b018cd9d3ab74cc9b4007be8250a2098b399ed7e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Feb 2007 09:14:40 +0000 Subject: [PATCH 0408/1664] initial import of the new admin api restructuring --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40439 --- core/AdminCache.cpp | 255 ++++++++++++++++----------------- core/AdminCache.h | 24 ++-- core/msvc8/sourcemod_mm.vcproj | 8 +- core/smn_admin.cpp | 26 +--- plugins/include/admin.inc | 88 +++++++++--- public/IAdminSystem.h | 97 ++++++++++--- 6 files changed, 289 insertions(+), 209 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index fa6bcc9d..5f79433b 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -21,8 +21,8 @@ AdminCache g_Admins; AdminCache::AdminCache() { - m_pCmdOverrides = NULL; - m_pCmdGrpOverrides = NULL; + m_pCmdOverrides = sm_trie_create(); + m_pCmdGrpOverrides = sm_trie_create(); m_pStrings = new BaseStringTable(1024); m_pMemory = m_pStrings->GetMemTable(); m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID; @@ -84,23 +84,42 @@ void AdminCache::OnSourceModShutdown() m_pCacheFwd = NULL; } -void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag) +void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags) { + Trie *pTrie = NULL; if (type == Override_Command) { - _AddCommandOverride(cmd, flag); + pTrie = m_pCmdOverrides; } else if (type == Override_CommandGroup) { - _AddCommandGroupOverride(cmd, flag); + pTrie = m_pCmdGrpOverrides; + } else { + return; } + + sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags); } -bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag) +bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags) { + Trie *pTrie = NULL; + if (type == Override_Command) { - return _GetCommandOverride(cmd, pFlag); + pTrie = m_pCmdOverrides; } else if (type == Override_CommandGroup) { - return _GetCommandGroupOverride(cmd, pFlag); + pTrie = m_pCmdGrpOverrides; + } else { + return false; + } + + void *object; + if (sm_trie_retrieve(pTrie, cmd, &object)) + { + if (pFlags) + { + *pFlags = (FlagBits)object; + } + return true; } return false; @@ -116,72 +135,6 @@ void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type) } } -void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag) -{ - if (!m_pCmdGrpOverrides) - { - m_pCmdGrpOverrides = sm_trie_create(); - } - - /* :TODO: Notify command system */ - - sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag); -} - -void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag) -{ - if (!m_pCmdOverrides) - { - m_pCmdOverrides = sm_trie_create(); - } - - /* :TODO: Notify command system */ - - sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag); -} - -bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag) -{ - if (!m_pCmdGrpOverrides) - { - return false; - } - - if (!pFlag) - { - return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL); - } else { - void *object; - bool ret; - if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object)) - { - *pFlag = (AdminFlag)(int)object; - } - return ret; - } -} - -bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag) -{ - if (!m_pCmdOverrides) - { - return false; - } - - if (!pFlag) - { - return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL); - } else { - void *object; - bool ret; - if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object)) - { - *pFlag = (AdminFlag)(int)object; - } - return ret; - } -} - void AdminCache::_UnsetCommandGroupOverride(const char *group) { if (!m_pCmdGrpOverrides) @@ -233,8 +186,8 @@ AdminId AdminCache::CreateAdmin(const char *name) pUser->grp_table = -1; } - memset(pUser->flags, 0, sizeof(pUser->flags)); - memset(pUser->eflags, 0, sizeof(pUser->flags)); + pUser->flags = 0; + pUser->eflags = 0; pUser->grp_count = 0; pUser->password = -1; pUser->magic = USR_MAGIC_SET; @@ -286,7 +239,7 @@ GroupId AdminCache::AddGroup(const char *group_name) pGroup->next_grp = INVALID_GROUP_ID; pGroup->pCmdGrpTable = NULL; pGroup->pCmdTable = NULL; - memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL); + pGroup->addflags = 0; if (m_FirstGroup == INVALID_GROUP_ID) { @@ -336,12 +289,12 @@ void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled) return; } - if (flag < Admin_None || flag >= AdminFlags_TOTAL) + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL) { return; } - pGroup->addflags[flag] = enabled; + pGroup->addflags |= (1<<(unsigned int)flag); } bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag) @@ -352,15 +305,16 @@ bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag) return false; } - if (flag < Admin_None || flag >= AdminFlags_TOTAL) + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL) { return false; } - return pGroup->addflags[flag]; + FlagBits bit = 1<<(FlagBits)flag; + return ((pGroup->addflags & bit) == bit); } -unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total) +FlagBits AdminCache::GetGroupAddFlags(GroupId id) { AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); if (!pGroup || pGroup->magic != GRP_MAGIC_SET) @@ -368,16 +322,7 @@ unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned return 0; } - unsigned int i; - - for (i = Admin_None; - i < AdminFlags_TOTAL && i < total; - i++) - { - flags[i] = pGroup->addflags[i]; - } - - return i; + return pGroup->addflags; } void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled) @@ -436,8 +381,16 @@ void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id) table[0] = 0; } else { int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table); + /* Break out if this group is already in the list */ + for (int i=0; iCreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table); - /* Get the old address again in caes of resize */ + /* Get the old address again in case of resize */ old_table = (int *)m_pMemory->GetAddress(pOther->immune_table); table[0] = old_table[0]; for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++) @@ -702,14 +655,11 @@ void AdminCache::InvalidateGroup(GroupId id) /* Decrease count */ pUser->grp_count--; /* Recalculate effective flags */ - memset(pUser->eflags, 0, sizeof(pUser->eflags)); + pUser->eflags = pUser->flags; for (unsigned int j=0; jgrp_count; j++) { pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]); - for (unsigned int k=0; keflags[k] = (pUser->flags[k] || pOther->addflags[k]); - } + pUser->eflags |= pOther->addflags; } /* Break now, duplicates aren't allowed */ break; @@ -922,13 +872,14 @@ void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) return; } - if (flag < Admin_None + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL) { return; } - pUser->flags[enabled] = false; + pUser->flags |= (1<<(FlagBits)flag); + pUser->eflags |= (1<<(FlagBits)flag); } bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) @@ -939,23 +890,25 @@ bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) return false; } - if (flag < Admin_None + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL) { return false; } + FlagBits bit = (1<<(FlagBits)flag); + if (mode == Access_Real) { - return pUser->flags[flag]; + return ((pUser->flags & bit) == bit); } else if (mode == Access_Effective) { - return (pUser->flags[flag] || pUser->eflags[flag]); + return ((pUser->eflags & bit) == bit); } return false; } -unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode) +FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); if (!pUser || pUser->magic != USR_MAGIC_SET) @@ -963,21 +916,14 @@ unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int to return 0; } - unsigned int i = 0; if (mode == Access_Real) { - for (i=0; iflags[i]; - } + return pUser->flags; } else if (mode == Access_Effective) { - for (i=0; iflags[i] || pUser->eflags[i]); - } + return pUser->eflags; } - return i; + return 0; } bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) @@ -994,6 +940,19 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) return false; } + /* First check for duplicates */ + if (pUser->grp_count != 0) + { + int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table); + for (unsigned int i=0; igrp_count; i++) + { + if (temp_table[i] == gid) + { + return false; + } + } + } + int *table; if (pUser->grp_count + 1 > pUser->grp_size) { @@ -1024,28 +983,11 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) table = (int *)m_pMemory->GetAddress(pUser->grp_table); } - for (unsigned int i=0; igrp_count; i++) - { - if (table[i] == gid) - { - return false; - } - } - table[pUser->grp_count] = gid; pUser->grp_count++; /* Compute new effective flags */ - for (unsigned int i=Admin_None; - ieflags[i]) - { - pUser->eflags[i] = pGroup->addflags[i]; - } - } + pUser->eflags |= pGroup->addflags; return true; } @@ -1096,3 +1038,52 @@ void AdminCache::SetAdminPassword(AdminId id, const char *password) pUser->password = m_pStrings->AddString(password); } +unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize) +{ + unsigned int i; + for (i=0; i - - + + LocalToString(params[1], &cmd); - if (!g_Admins.GetCommandOverride(cmd, (OverrideType)params[2], &flag)) + if (!g_Admins.GetCommandOverride(cmd, (OverrideType)params[2], &flags)) { return 0; } @@ -46,7 +46,7 @@ static cell_t GetCommandOverride(IPluginContext *pContext, const cell_t *params) cell_t *addr; pContext->LocalToPhysAddr(params[3], &addr); - *addr = (cell_t)flag; + *addr = (cell_t)flags; return 1; } @@ -177,24 +177,10 @@ static cell_t GetAdmGroupCmdOverride(IPluginContext *pContext, const cell_t *par return 1; } -static cell_t GetAdmGroupAddFlagBits(IPluginContext *pContext, const cell_t *params) +static cell_t GetAdmGroupAddFlags(IPluginContext *pContext, const cell_t *params) { GroupId id = (GroupId)params[1]; - bool flags[AdminFlags_TOTAL]; - unsigned int num = g_Admins.GetGroupAddFlagBits(id, flags, AdminFlags_TOTAL); - unsigned int i; - - cell_t *addr; - pContext->LocalToPhysAddr(params[2], &addr); - - for (i=0; - i < num && i < (unsigned int)params[3]; - i++) - { - addr[i] = flags[i] ? 1 : 0; - } - - return i; + return g_Admins.GetGroupAddFlags(id); } REGISTER_NATIVES(adminNatives) @@ -214,6 +200,6 @@ REGISTER_NATIVES(adminNatives) {"GetAdmGroupImmuneCount", GetAdmGroupImmuneCount}, {"AddAdmGroupCmdOverride", AddAdmGroupCmdOverride}, {"GetAdmGroupCmdOverride", GetAdmGroupCmdOverride}, - {"GetAdmGroupAddFlagBits", GetAdmGroupAddFlagBits}, + {"GetAdmGroupAddFlags", GetAdmGroupAddFlags}, {NULL, NULL}, }; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 465c35a8..e0ca35ec 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -17,27 +17,71 @@ #endif #define _admin_included +/** + * Access levels (flags) for admins. + */ enum AdminFlag { - Admin_None = 0, /* Unused */ - Admin_Reservation, /* Reserved slot */ - Admin_Kick, /* Kick another user */ - Admin_Ban, /* Ban another user */ - Admin_Unban, /* Unban another user */ - Admin_Slay, /* Slay/kill/damage another user */ - Admin_Changemap, /* Change the map */ - Admin_Convars, /* Change basic convars */ - Admin_Configs, /* Change configs */ - Admin_Chat, /* Special chat privileges */ - Admin_Vote, /* Special vote privileges */ - Admin_Password, /* Set a server password */ - Admin_RCON, /* Use RCON */ - Admin_Cheats, /* Change sv_cheats and use its commands */ - Admin_Root, /* Root access */ + Admin_Reservation = 0, /**< Reserved slot */ + Admin_Generic, /**< Generic admin abilities */ + Admin_Kick, /**< Kick another user */ + Admin_Ban, /**< Ban another user */ + Admin_Unban, /**< Unban another user */ + Admin_Slay, /**< Slay/kill/damage another user */ + Admin_Changemap, /**< Change the map */ + Admin_Convars, /**< Change basic convars */ + Admin_Config, /**< Change configuration */ + Admin_Chat, /**< Special chat privileges */ + Admin_Vote, /**< Special vote privileges */ + Admin_Password, /**< Set a server password */ + Admin_RCON, /**< Use RCON */ + Admin_Cheats, /**< Change sv_cheats and use its commands */ + Admin_Root, /**< All access by default */ + Admin_Custom1, /**< First custom flag type */ + Admin_Custom2, /**< Second custom flag type */ + Admin_Custom3, /**< Third custom flag type */ + Admin_Custom4, /**< Fourth custom flag type */ + Admin_Custom5, /**< Fifth custom flag type */ + Admin_Custom6, /**< Sixth custom flag type */ /* --- */ AdminFlags_TOTAL, }; +/** + * These define bitwise values for bitstrings (numbers containing bitwise flags). + */ +#define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ +#define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ +#define ADMFLAG_KICK (1<<2) /**< Convenience macro for Admin_Kick as a FlagBit */ +#define ADMFLAG_BAN (1<<3) /**< Convenience macro for Admin_Ban as a FlagBit */ +#define ADMFLAG_UNBAN (1<<4) /**< Convenience macro for Admin_Unban as a FlagBit */ +#define ADMFLAG_SLAY (1<<5) /**< Convenience macro for Admin_Slay as a FlagBit */ +#define ADMFLAG_CHANGEMAP (1<<6) /**< Convenience macro for Admin_Changemap as a FlagBit */ +#define ADMFLAG_CONVARS (1<<7) /**< Convenience macro for Admin_Convars as a FlagBit */ +#define ADMFLAG_CONFIG (1<<8) /**< Convenience macro for Admin_Config as a FlagBit */ +#define ADMFLAG_CHAT (1<<9) /**< Convenience macro for Admin_Chat as a FlagBit */ +#define ADMFLAG_VOTE (1<<10) /**< Convenience macro for Admin_Vote as a FlagBit */ +#define ADMFLAG_PASSWORD (1<<11) /**< Convenience macro for Admin_Password as a FlagBit */ +#define ADMFLAG_RCON (1<<12) /**< Convenience macro for Admin_RCON as a FlagBit */ +#define ADMFLAG_CHEATS (1<<13) /**< Convenience macro for Admin_Cheats as a FlagBit */ +#define ADMFLAG_ROOT (1<<14) /**< Convenience macro for Admin_Root as a FlagBit */ +#define ADMFLAG_CUSTOM1 (1<<15) /**< Convenience macro for Admin_Custom1 as a FlagBit */ +#define ADMFLAG_CUSTOM2 (1<<16) /**< Convenience macro for Admin_Custom2 as a FlagBit */ +#define ADMFLAG_CUSTOM3 (1<<17) /**< Convenience macro for Admin_Custom3 as a FlagBit */ +#define ADMFLAG_CUSTOM4 (1<<18) /**< Convenience macro for Admin_Custom4 as a FlagBit */ +#define ADMFLAG_CUSTOM5 (1<<19) /**< Convenience macro for Admin_Custom5 as a FlagBit */ +#define ADMFLAG_CUSTOM6 (1<<20) /**< Convenience macro for Admin_Custom6 as a FlagBit */ + +stock FlagToBit(AdminFlag:flag) +{ + return (1<<_:flag); +} + +stock AdminFlag:BitToFlag(bit) +{ + /* :TODO: implement */ +} + enum OverrideType { Override_Command = 1, /* Command */ @@ -95,20 +139,20 @@ native DumpAdminCache(cache_flags, bool:rebuild); * * @param cmd String containing command name (case sensitive). * @param type Override type (specific command or group). - * @param flag New admin flag. + * @param flags New admin flag. * @noreturn */ -native AddCommandOverride(const String:cmd[], OverrideType:type, AdminFlag:flag); +native AddCommandOverride(const String:cmd[], OverrideType:type, flags); /** * Returns a command override. * * @param cmd String containing command name (case sensitive). * @param type Override type (specific command or group). - * @param pFlag By-reference cell to store the flag (undefined if not found). + * @param flags By-reference cell to store the flag (undefined if not found). * @return True if there is an override, false otherwise. */ -native bool:GetCommandOverride(const String:cmd[], OverrideType:type, &AdminFlag:flag); +native bool:GetCommandOverride(const String:cmd[], OverrideType:type, &flags); /** * Unsets a command override. @@ -161,11 +205,9 @@ native bool:GetAdmGroupAddFlag(GroupId:id, AdminFlag:flag); * @note These are called "add flags" because they add to a user's flags. * * @param id GroupId of the group. - * @param flags Array to store flags in. - * @param total Total number of flags that can be stored in the array (AdminFlags_TOTAL, usually). - * @return Number of flags that were written to the array. + * @return Bitstring containing the flags enabled. */ -native GetAdmGroupAddFlagBits(GroupId:id, bool:flags[], total); +native GetAdmGroupAddFlags(GroupId:id); /** * Toggles a generic immunity type. diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 9877b893..87558576 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -54,25 +54,53 @@ namespace SourceMod */ enum AdminFlag { - Admin_None = 0, - Admin_Reservation, /**< Reserved slot */ + Admin_Reservation = 0, /**< Reserved slot */ + Admin_Generic, /**< Generic admin abilities */ Admin_Kick, /**< Kick another user */ Admin_Ban, /**< Ban another user */ Admin_Unban, /**< Unban another user */ Admin_Slay, /**< Slay/kill/damage another user */ Admin_Changemap, /**< Change the map */ Admin_Convars, /**< Change basic convars */ - Admin_Configs, /**< Change configs */ + Admin_Config, /**< Change configuration */ Admin_Chat, /**< Special chat privileges */ Admin_Vote, /**< Special vote privileges */ Admin_Password, /**< Set a server password */ Admin_RCON, /**< Use RCON */ Admin_Cheats, /**< Change sv_cheats and use its commands */ Admin_Root, /**< All access by default */ + Admin_Custom1, /**< First custom flag type */ + Admin_Custom2, /**< Second custom flag type */ + Admin_Custom3, /**< Third custom flag type */ + Admin_Custom4, /**< Fourth custom flag type */ + Admin_Custom5, /**< Fifth custom flag type */ + Admin_Custom6, /**< Sixth custom flag type */ /* --- */ AdminFlags_TOTAL, }; + #define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ + #define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ + #define ADMFLAG_KICK (1<<2) /**< Convenience macro for Admin_Kick as a FlagBit */ + #define ADMFLAG_BAN (1<<3) /**< Convenience macro for Admin_Ban as a FlagBit */ + #define ADMFLAG_UNBAN (1<<4) /**< Convenience macro for Admin_Unban as a FlagBit */ + #define ADMFLAG_SLAY (1<<5) /**< Convenience macro for Admin_Slay as a FlagBit */ + #define ADMFLAG_CHANGEMAP (1<<6) /**< Convenience macro for Admin_Changemap as a FlagBit */ + #define ADMFLAG_CONVARS (1<<7) /**< Convenience macro for Admin_Convars as a FlagBit */ + #define ADMFLAG_CONFIG (1<<8) /**< Convenience macro for Admin_Config as a FlagBit */ + #define ADMFLAG_CHAT (1<<9) /**< Convenience macro for Admin_Chat as a FlagBit */ + #define ADMFLAG_VOTE (1<<10) /**< Convenience macro for Admin_Vote as a FlagBit */ + #define ADMFLAG_PASSWORD (1<<11) /**< Convenience macro for Admin_Password as a FlagBit */ + #define ADMFLAG_RCON (1<<12) /**< Convenience macro for Admin_RCON as a FlagBit */ + #define ADMFLAG_CHEATS (1<<13) /**< Convenience macro for Admin_Cheats as a FlagBit */ + #define ADMFLAG_ROOT (1<<14) /**< Convenience macro for Admin_Root as a FlagBit */ + #define ADMFLAG_CUSTOM1 (1<<15) /**< Convenience macro for Admin_Custom1 as a FlagBit */ + #define ADMFLAG_CUSTOM2 (1<<16) /**< Convenience macro for Admin_Custom2 as a FlagBit */ + #define ADMFLAG_CUSTOM3 (1<<17) /**< Convenience macro for Admin_Custom3 as a FlagBit */ + #define ADMFLAG_CUSTOM4 (1<<18) /**< Convenience macro for Admin_Custom4 as a FlagBit */ + #define ADMFLAG_CUSTOM5 (1<<19) /**< Convenience macro for Admin_Custom5 as a FlagBit */ + #define ADMFLAG_CUSTOM6 (1<<20) /**< Convenience macro for Admin_Custom6 as a FlagBit */ + /** * @brief Specifies which type of command to override (command or command group). */ @@ -148,6 +176,8 @@ namespace SourceMod virtual void OnRebuildAdminCache(int cache_flags) =0; }; + typedef unsigned int FlagBits; + /** * @brief Provides functions for manipulating the admin options cache. */ @@ -169,19 +199,19 @@ namespace SourceMod * * @param cmd String containing command name (case sensitive). * @param type Override type (specific command or group). - * @param flag New admin flag. + * @param flags New admin flag. */ - virtual void AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag) =0; + virtual void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags) =0; /** * @brief Returns a command override. * * @param cmd String containing command name (case sensitive). * @param type Override type (specific command or group). - * @param pFlag Optional pointer to the set flag. + * @param pFlags Optional pointer to the set flag. * @return True if there is an override, false otherwise. */ - virtual bool GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag) =0; + virtual bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags) =0; /** * @brief Unsets a command override. @@ -231,11 +261,9 @@ namespace SourceMod * Note: These are called "add flags" because they add to a user's flags. * * @param id GroupId of the group. - * @param flags Array to store flags bits in. - * @param total Total number of flags that can be stored in the array. - * @return Number of flags that were written to the array. + * @return Bit string containing the bits of each flag. */ - virtual unsigned int GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total) =0; + virtual FlagBits GetGroupAddFlags(GroupId id) =0; /** * @brief Toggles a generic immunity type. @@ -391,15 +419,10 @@ namespace SourceMod * @brief Returns a bitarray of flags enabled on an admin. * * @param id AdminId index of the admin. - * @param flag Array to store flag bits in. - * @param total Maximum size of the flag array. * @param mode Access mode to use. - * @return Number of flags written to the array. + * @return A bit string containing which flags are enabled. */ - virtual unsigned int GetAdminFlags(AdminId id, - bool flags[], - unsigned int total, - AccessMode mode) =0; + virtual FlagBits GetAdminFlags(AdminId id, AccessMode mode) =0; /** * @brief Adds a group to an admin's inherited group list. @@ -463,6 +486,44 @@ namespace SourceMod * @return True on success, false otherwise. */ virtual bool InvalidateAdmin(AdminId id) =0; + + /** + * @brief Converts a flag bit string to a bit array. + * + * @param bits Bit string containing the flags. + * @param array Array to write the flags to. Enabled flags will be 'true'. + * @param maxSize Maximum number of flags the array can store. + * @return Number of flags written. + */ + virtual unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize) =0; + + /** + * @brief Converts a flag array to a bit string. + * + * @param array Array containing true or false for each AdminFlag. + * @param maxSize Maximum size of the flag array. + * @return A bit string composed of the array bits. + */ + virtual FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize) =0; + + /** + * @brief Converts an array of flags to bits. + * + * @param array Array containing flags that are enabled. + * @param numFlags Number of flags in the array. + * @return A bit string composed of the array flags. + */ + virtual FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags) =0; + + /** + * @brief Converts a bit string to an array of flags. + * + * @param bits Bit string containing the flags. + * @param array Output array to write flags. + * @param maxSize Maximum size of the flag array. + * @return Number of flags written. + */ + virtual unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize) =0; }; } From 6858d12ad99550815d34153e91939aaf477e6d6b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Feb 2007 10:34:58 +0000 Subject: [PATCH 0409/1664] added some access helper functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40440 --- core/AdminCache.cpp | 121 ++++++++++++++++++++++++++++++++++++++---- core/AdminCache.h | 4 ++ public/IAdminSystem.h | 31 ++++++++++- 3 files changed, 145 insertions(+), 11 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 5f79433b..12dac592 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -35,15 +35,8 @@ AdminCache::AdminCache() AdminCache::~AdminCache() { - if (m_pCmdGrpOverrides) - { - sm_trie_destroy(m_pCmdGrpOverrides); - } - - if (m_pCmdOverrides) - { - sm_trie_destroy(m_pCmdOverrides); - } + sm_trie_destroy(m_pCmdGrpOverrides); + sm_trie_destroy(m_pCmdOverrides); DumpAdminCache(0xFFFFFFFF, false); @@ -193,6 +186,8 @@ AdminId AdminCache::CreateAdmin(const char *name) pUser->magic = USR_MAGIC_SET; pUser->auth.identidx = -1; pUser->auth.index = 0; + pUser->immune_default = false; + pUser->immune_global = false; if (m_FirstUser == INVALID_ADMIN_ID) { @@ -986,9 +981,18 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) table[pUser->grp_count] = gid; pUser->grp_count++; - /* Compute new effective flags */ + /* Compute new effective permissions */ pUser->eflags |= pGroup->addflags; + if (pGroup->immune_default) + { + pUser->immune_default = true; + } + if (pGroup->immune_global) + { + pUser->immune_global = true; + } + return true; } @@ -1087,3 +1091,100 @@ unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsig return num; } + +bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + return ((pUser->eflags & bits) == bits); +} + +bool AdminCache::CanAdminTarget(AdminId id, AdminId target) +{ + /** + * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails. + * First, if the targetted AdminId is INVALID_ADMIN_ID, targeting succeeds. + */ + + if (id == INVALID_ADMIN_ID) + { + return false; + } + + if (target == INVALID_ADMIN_ID) + { + return true; + } + + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target); + if (!pTarget || pTarget->magic != USR_MAGIC_SET) + { + return false; + } + + /** + * Second, if the targeting admin is root, targeting suceeds. + */ + if (pUser->eflags & ADMFLAG_ROOT) + { + return true; + } + + /** Fourth, if the targetted admin has global immunity, targeting fails. */ + if (pTarget->immune_global) + { + return false; + } + + /** + * Fifth, if the targetted admin has default immunity + * and the admin belongs to no groups, targeting fails. + */ + if (pTarget->immune_default && pUser->grp_count < 1) + { + return false; + } + + /** + * Sixth, if the targetted admin has specific immunity from the + * targeting admin via group immunities, targeting fails. + */ + //:TODO: speed this up... maybe with trie hacks. + //idea is to insert %d.%d in the trie after computing this and use it as a cache lookup. + //problem is the trie cannot delete prefixes, so we'd have a problem with invalidations. + if (pTarget->grp_count > 0 && pUser->grp_count > 0) + { + int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table); + int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table); + GroupId id, other; + unsigned int num; + for (unsigned int i=0; igrp_count; i++) + { + id = grp_table[i]; + num = GetGroupImmunityCount(id); + for (unsigned int j=0; jgrp_count; k++) + { + if (other == src_table[k]) + { + return false; + } + } + } + } + } + + return true; +} diff --git a/core/AdminCache.h b/core/AdminCache.h index c35bf2f2..504be115 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -73,6 +73,8 @@ struct AdminUser int next_user; /* Next user in ze list */ int prev_user; /* Prev user in the list */ UserAuth auth; /* Auth method for this user */ + bool immune_global; /* Whether globally immune */ + bool immune_default; /* Whether defaultly immune */ }; class AdminCache : @@ -127,6 +129,8 @@ public: //IAdminSystem FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize); FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags); unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize); + bool CheckAdminFlags(AdminId id, FlagBits bits); + bool CanAdminTarget(AdminId id, AdminId target); private: void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 87558576..db4820d2 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -416,7 +416,7 @@ namespace SourceMod virtual bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) =0; /** - * @brief Returns a bitarray of flags enabled on an admin. + * @brief Returns the bitstring of access flags on an admin. * * @param id AdminId index of the admin. * @param mode Access mode to use. @@ -524,6 +524,35 @@ namespace SourceMod * @return Number of flags written. */ virtual unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize) =0; + + /** + * @brief Checks whether a user has access to a given set of flag bits. + * Note: This is a wrapper around GetAdminFlags(). + * + * @param id AdminId index of admin. + * @param flags Bitstring containing the permissions to check. + * @return True if user has permission, false otherwise. + */ + virtual bool CheckAdminFlags(AdminId id, FlagBits bits) =0; + + /** + * @brief Checks whether an AdminId can target another AdminId. + * + * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails. + * First, if the targetted AdminId is INVALID_ADMIN_ID, targeting succeeds. + * Second, if the targeting admin is root, targeting suceeds. + * Third, if the targetted admin has global immunity, targeting fails. + * Fourth, if the targetted admin has default immunity, + * and the admin belongs to no groups, targeting fails. + * Fifth, if the targetted admin has specific immunity from the + * targeting admin via group immunities, targeting fails. + * Sixth, targeting succeeds if it passes these tests. + * + * @param id AdminId index of admin doing the targeting. Can be INVALID_ADMIN_ID. + * @param target AdminId index of the target admin. Can be INVALID_ADMIN_ID. + * @return True if this admin has permission to target the other admin. + */ + virtual bool CanAdminTarget(AdminId id, AdminId target) =0; }; } From b596e103040109947c571c8775655c8fde1f5265 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Feb 2007 20:32:34 +0000 Subject: [PATCH 0410/1664] heavily cleaned up the player API exposed player API as an interface added client event listeners to API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40441 --- core/CPlayer.cpp | 57 -------- core/CPlayer.h | 93 ------------- core/CPlayerManager.cpp | 201 +++++++++++++++++++++++++++-- core/CPlayerManager.h | 79 ++++++++---- core/msvc8/sourcemod_mm.vcproj | 12 +- core/smn_player.cpp | 36 +++--- public/IPlayerHelpers.h | 229 +++++++++++++++++++++++++++++++++ 7 files changed, 499 insertions(+), 208 deletions(-) delete mode 100644 core/CPlayer.cpp delete mode 100644 core/CPlayer.h create mode 100644 public/IPlayerHelpers.h diff --git a/core/CPlayer.cpp b/core/CPlayer.cpp deleted file mode 100644 index 1dc5de8c..00000000 --- a/core/CPlayer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== - * - * This file is not open source and may not be copied without explicit - * written permission of AlliedModders LLC. This file may not be redistributed - * in whole or significant part. - * For information, see LICENSE.txt or http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#include "CPlayer.h" - -CPlayer::CPlayer() -{ - m_IsConnected = false; - m_IsInGame = false; - m_IsAuthorized = false; - m_PlayerEdict = NULL; -} - -void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) -{ - m_IsConnected = true; - m_Name.assign(name); - m_Ip.assign(ip); - m_PlayerEdict = pEntity; -} - -void CPlayer::Connect() -{ - m_IsInGame = true; -} - -void CPlayer::Authorize(const char *steamid) -{ - m_IsAuthorized = true; - m_AuthID.assign(steamid); -} - -void CPlayer::Disconnect() -{ - m_IsConnected = false; - m_IsInGame = false; - m_IsAuthorized = false; - m_Name.clear(); - m_Ip.clear(); - m_AuthID.clear(); - m_PlayerEdict = NULL; -} - -void CPlayer::SetName(const char *name) -{ - m_Name.assign(name); -} diff --git a/core/CPlayer.h b/core/CPlayer.h deleted file mode 100644 index 4324ad30..00000000 --- a/core/CPlayer.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== - * - * This file is not open source and may not be copied without explicit - * written permission of AlliedModders LLC. This file may not be redistributed - * in whole or significant part. - * For information, see LICENSE.txt or http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_CPLAYER_H_ -#define _INCLUDE_SOURCEMOD_CPLAYER_H_ - -#include -#include - -using namespace SourceHook; - -class CPlayer -{ - friend class CPlayerManager; -public: - CPlayer(); -public: - const char *PlayerName() const; - const char *PlayerIP() const; - const char *PlayerAuthString() const; - edict_t *GetPlayerEdict() const; - bool IsPlayerInGame() const; - bool IsPlayerConnected() const; - bool IsPlayerAuthorized() const; - bool IsPlayerFakeClient() const; - //:TODO: is user alive function -private: - void Initialize(const char *name, const char *ip, edict_t *pEntity); - void Connect(); - void Authorize(const char *steamid); - void Disconnect(); - void SetName(const char *name); -private: - bool m_IsConnected; - bool m_IsInGame; - bool m_IsAuthorized; - String m_Name; - String m_Ip; - String m_AuthID; - edict_t *m_PlayerEdict; -}; - -inline const char *CPlayer::PlayerName() const -{ - return m_Name.c_str(); -} - -inline const char *CPlayer::PlayerIP() const -{ - return m_Ip.c_str(); -} - -inline const char *CPlayer::PlayerAuthString() const -{ - return m_AuthID.c_str(); -} - -inline edict_t *CPlayer::GetPlayerEdict() const -{ - return m_PlayerEdict; -} - -inline bool CPlayer::IsPlayerInGame() const -{ - return m_IsInGame; -} - -inline bool CPlayer::IsPlayerConnected() const -{ - return m_IsConnected; -} - -inline bool CPlayer::IsPlayerAuthorized() const -{ - return m_IsAuthorized; -} - -inline bool CPlayer::IsPlayerFakeClient() const -{ - return (strcmp(m_AuthID.c_str(), "BOT") == 0); -} - -#endif // _INCLUDE_SOURCEMOD_CPLAYER_H_ diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index c242ff5a..65bc9083 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -13,6 +13,7 @@ #include "CPlayerManager.h" #include "ForwardSys.h" +#include "ShareSys.h" CPlayerManager g_PlayerManager; @@ -26,6 +27,7 @@ SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, in void CPlayerManager::OnSourceModAllInitialized() { SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect_Post, true); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); @@ -33,6 +35,8 @@ void CPlayerManager::OnSourceModAllInitialized() SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true); + g_ShareSys.AddInterface(NULL, this); + /* Register OnClientConnect */ ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1); @@ -92,9 +96,21 @@ void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int c bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { - cell_t res = 1; int client = engine->IndexOfEdict(pEntity); + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + if (!pListener->InterceptClientConnect(client, reject, maxrejectlen)) + { + return false; + } + } + + cell_t res = 1; + m_Players[client].Initialize(pszName, pszAddress, pEntity); m_clconnect->PushCell(client); m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK); @@ -104,11 +120,37 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons return (res) ? true : false; } +bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) +{ + int client = engine->IndexOfEdict(pEntity); + bool orig_value = META_RESULT_ORIG_RET(bool); + if (orig_value) + { + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientConnected(client); + } + } + + return true; +} + void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername) { cell_t res; int client = engine->IndexOfEdict(pEntity); + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientPutInServer(client); + } + m_Players[client].Connect(); m_PlayerCount++; m_clputinserver->PushCell(client); @@ -125,24 +167,43 @@ void CPlayerManager::OnClientDisconnect(edict_t *pEntity) cell_t res; int client = engine->IndexOfEdict(pEntity); - if (m_Players[client].IsPlayerConnected()) + if (m_Players[client].IsConnected()) { m_cldisconnect->PushCell(client); m_cldisconnect->Execute(&res, NULL); } - if (m_Players[client].IsPlayerInGame()) + + if (m_Players[client].IsInGame()) { m_PlayerCount--; } + + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientDisconnecting(client); + } + m_Players[client].Disconnect(); } void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) { cell_t res; + int client = engine->IndexOfEdict(pEntity); - m_cldisconnect_post->PushCell(engine->IndexOfEdict(pEntity)); + m_cldisconnect_post->PushCell(client); m_cldisconnect_post->Execute(&res, NULL); + + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientDisconnected(client); + } } void CPlayerManager::OnClientCommand(edict_t *pEntity) @@ -162,8 +223,132 @@ void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity)); m_clinfochanged->Execute(&res, NULL); - if (m_Players[client].IsPlayerInGame()) - { - m_Players[client].SetName(engine->GetClientConVarValue(client, "name")); - } + m_Players[client].SetName(engine->GetClientConVarValue(client, "name")); +} + +int CPlayerManager::GetMaxClients() +{ + return m_maxClients; +} + +CPlayer *CPlayerManager::GetPlayerByIndex(int client) const +{ + if (client > m_maxClients || client < 0) + { + return NULL; + } + return &m_Players[client]; +} + +int CPlayerManager::GetNumPlayers() +{ + return m_PlayerCount; +} + +void CPlayerManager::AddClientListener(IClientListener *listener) +{ + m_hooks.push_back(listener); +} + +void CPlayerManager::RemoveClientListener(IClientListener *listener) +{ + m_hooks.remove(listener); +} + +IGamePlayer *CPlayerManager::GetGamePlayer(edict_t *pEdict) +{ + int index = engine->IndexOfEdict(pEdict); + return GetGamePlayer(index); +} + +IGamePlayer *CPlayerManager::GetGamePlayer(int client) +{ + return GetPlayerByIndex(client); +} + +/******************* + *** PLAYER CODE *** + *******************/ + +CPlayer::CPlayer() +{ + m_IsConnected = false; + m_IsInGame = false; + m_IsAuthorized = false; + m_PlayerEdict = NULL; +} + +void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) +{ + m_IsConnected = true; + m_Name.assign(name); + m_Ip.assign(ip); + m_PlayerEdict = pEntity; +} + +void CPlayer::Connect() +{ + m_IsInGame = true; +} + +void CPlayer::Authorize(const char *steamid) +{ + m_IsAuthorized = true; + m_AuthID.assign(steamid); +} + +void CPlayer::Disconnect() +{ + m_IsConnected = false; + m_IsInGame = false; + m_IsAuthorized = false; + m_Name.clear(); + m_Ip.clear(); + m_AuthID.clear(); + m_PlayerEdict = NULL; +} + +void CPlayer::SetName(const char *name) +{ + m_Name.assign(name); +} + +const char *CPlayer::GetName() const +{ + return m_Name.c_str(); +} + +const char *CPlayer::GetIPAddress() const +{ + return m_Ip.c_str(); +} + +const char *CPlayer::GetAuthString() const +{ + return m_AuthID.c_str(); +} + +edict_t *CPlayer::GetEdict() const +{ + return m_PlayerEdict; +} + +bool CPlayer::IsInGame() const +{ + return m_IsInGame; +} + +bool CPlayer::IsConnected() const +{ + return m_IsConnected; +} + +bool CPlayer::IsAuthorized() const +{ + return m_IsAuthorized; +} + +bool CPlayer::IsFakeClient() const +{ + return (strcmp(m_AuthID.c_str(), "BOT") == 0); } diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index c2dc1dd7..2a2201d1 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -18,11 +18,45 @@ #include #include "sourcemm_api.h" #include -#include "CPlayer.h" +#include +#include +#include -class CPlayer; +using namespace SourceHook; -class CPlayerManager : public SMGlobalClass +class CPlayer : public IGamePlayer +{ + friend class CPlayerManager; +public: + CPlayer(); +public: + const char *GetName() const; + const char *GetIPAddress() const; + const char *GetAuthString() const; + edict_t *GetEdict() const; + bool IsInGame() const; + bool IsConnected() const; + bool IsAuthorized() const; + bool IsFakeClient() const; +private: + void Initialize(const char *name, const char *ip, edict_t *pEntity); + void Connect(); + void Authorize(const char *steamid); + void Disconnect(); + void SetName(const char *name); +private: + bool m_IsConnected; + bool m_IsInGame; + bool m_IsAuthorized; + String m_Name; + String m_Ip; + String m_AuthID; + edict_t *m_PlayerEdict; +}; + +class CPlayerManager : + public SMGlobalClass, + public IPlayerManager { public: CPlayerManager() : m_FirstPass(true) {} @@ -30,20 +64,36 @@ public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: - int GetMaxClients() const; CPlayer *GetPlayerByIndex(int client) const; - int GetPlayerCount() const; public: bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); + bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); void OnClientPutInServer(edict_t *pEntity, char const *playername); void OnClientDisconnect(edict_t *pEntity); void OnClientDisconnect_Post(edict_t *pEntity); void OnClientAuthorized(); //:TODO: any args needed? void OnClientCommand(edict_t *pEntity); void OnClientSettingsChanged(edict_t *pEntity); +public: //IPlayerManager + void AddClientListener(IClientListener *listener); + void RemoveClientListener(IClientListener *listener); + IGamePlayer *GetGamePlayer(int client); + IGamePlayer *GetGamePlayer(edict_t *pEdict); + int GetMaxClients(); + int GetNumPlayers(); +public: + inline int MaxClients() + { + return m_maxClients; + } + inline int NumPlayers() + { + return m_PlayerCount; + } private: void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); private: + List m_hooks; IForward *m_clconnect; IForward *m_cldisconnect; IForward *m_cldisconnect_post; @@ -58,23 +108,4 @@ private: extern CPlayerManager g_PlayerManager; -inline int CPlayerManager::GetMaxClients() const -{ - return m_maxClients; -} - -inline CPlayer *CPlayerManager::GetPlayerByIndex(int client) const -{ - if (client > m_maxClients || client < 0) - { - return NULL; - } - return &m_Players[client]; -} - -inline int CPlayerManager::GetPlayerCount() const -{ - return m_PlayerCount; -} - #endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 1cfa15ee..0332881a 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -191,10 +191,6 @@ RelativePath="..\CLogger.cpp" > - - @@ -285,10 +281,6 @@ RelativePath="..\CLogger.h" > - - @@ -365,6 +357,10 @@ RelativePath="..\..\public\ILibrarySys.h" > + + diff --git a/core/smn_player.cpp b/core/smn_player.cpp index aaa44932..ac1c8873 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -18,26 +18,26 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) { if (params[1]) { - return g_PlayerManager.GetPlayerCount(); + return g_PlayerManager.NumPlayers(); } - int maxplayers = g_PlayerManager.GetMaxClients(); + int maxplayers = g_PlayerManager.MaxClients(); int count = 0; for (int i=1; i<=maxplayers; ++i) { CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(i); - if ((pPlayer->IsPlayerConnected()) && !(pPlayer->IsPlayerInGame())) + if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame())) { count++; } } - return (g_PlayerManager.GetPlayerCount() + count); + return (g_PlayerManager.NumPlayers() + count); } static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params) { - return g_PlayerManager.GetMaxClients(); + return g_PlayerManager.MaxClients(); } static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) @@ -49,12 +49,12 @@ static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) } CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); - if (!pPlayer->IsPlayerConnected()) + if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); } - pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), pPlayer->PlayerName(), NULL); + pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), pPlayer->GetName(), NULL); return 1; } @@ -67,13 +67,13 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) } CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); - if (!pPlayer->IsPlayerConnected()) + if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); } char buf[64], *ptr; - strcpy(buf, pPlayer->PlayerIP()); + strcpy(buf, pPlayer->GetIPAddress()); if (params[4] && (ptr = strchr(buf, ':'))) { @@ -93,12 +93,12 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) } CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); - if (!pPlayer->IsPlayerConnected()) + if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); } - pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->PlayerAuthString()); + pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->GetAuthString()); return 1; } @@ -110,7 +110,7 @@ static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerConnected()) ? 1 : 0; + return (g_PlayerManager.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0; } static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) @@ -121,7 +121,7 @@ static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerInGame()) ? 1 : 0; + return (g_PlayerManager.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0; } static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) @@ -132,7 +132,7 @@ static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsPlayerAuthorized()) ? 1 : 0; + return (g_PlayerManager.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0; } static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) @@ -144,12 +144,12 @@ static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) } CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); - if (!pPlayer->IsPlayerConnected()) + if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); } - return (pPlayer->IsPlayerFakeClient()) ? 1 : 0; + return (pPlayer->IsFakeClient()) ? 1 : 0; } static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) @@ -178,7 +178,7 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) } CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); - if (!pPlayer->IsPlayerInGame()) + if (!pPlayer->IsInGame()) { return pCtx->ThrowNativeError("Client %d is not in game.", index); } @@ -193,7 +193,7 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) buffer[res++] = '\n'; buffer[res] = '\0'; - engine->ClientPrintf(pPlayer->GetPlayerEdict(), buffer); + engine->ClientPrintf(pPlayer->GetEdict(), buffer); return 1; } diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h new file mode 100644 index 00000000..5a4b9ded --- /dev/null +++ b/public/IPlayerHelpers.h @@ -0,0 +1,229 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_IPLAYERHELPERS_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_IPLAYERHELPERS_H_ + +#include + +#define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager" +#define SMINTERFACE_PLAYERMANAGER_VERSION 1 + +struct edict_t; + +/** + * @file IPlayerHelpers.h + * @brief Defines basic helper functions for Half-Life 2 clients + */ +namespace SourceMod +{ + /** + * @brief Abstracts some Half-Life 2 and SourceMod properties about clients. + */ + class IGamePlayer + { + public: + /** + * @brief Returns the player's name. + * + * @return String containing the player's name, + * or NULL if unavailable. + */ + virtual const char *GetName() const =0; + + /** + * @brief Returns the player's IP address. + * + * @return String containing the player's IP address, + * or NULL if unavailable. + */ + virtual const char *GetIPAddress() const =0; + + /** + * @brief Returns the player's authentication string. + * + * @return String containing the player's auth string. + * May be NULL if unavailable. + */ + virtual const char *GetAuthString() const =0; + + /** + * @brief Returns the player's edict_t structure. + * + * @return edict_t pointer, or NULL if unavailable. + */ + virtual edict_t *GetEdict() const =0; + + /** + * @brief Returns whether the player is in game (putinserver). + * + * @return True if in game, false otherwise. + */ + virtual bool IsInGame() const =0; + + /** + * @brief Returns whether the player is connected. + * + * Note: If this returns true, all above functions except for + * GetAuthString() should return non-NULL results. + * + * @return True if connected, false otherwise. + */ + virtual bool IsConnected() const =0; + + /** + * @brief Returns whether the player is a fake client. + * + * @return True if a fake client, false otherwise. + */ + virtual bool IsFakeClient() const =0; + }; + + /** + * @brief Provides callbacks for important client events. + */ + class IClientListener + { + public: + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_PLAYERMANAGER_VERSION; + } + public: + /** + * @brief Called when a client requests connection. + * + * @param client Index of the client. + * @param error Error buffer for a disconnect reason. + * @param maxlength Maximum length of error buffer. + * @return True to allow client, false to reject. + */ + virtual bool InterceptClientConnect(int client, char *error, size_t maxlength) + { + return true; + } + + /** + * @brief Called when a client has connected. + * + * @param client Index of the client. + */ + virtual void OnClientConnected(int client) + { + } + + /** + * @brief Called when a client is put in server. + * + * @param client Index of the client. + */ + virtual void OnClientPutInServer(int client) + { + } + + /** + * @brief Called when a client is disconnecting (not fully disconnected yet). + * + * @param client Index of the client. + */ + virtual void OnClientDisconnecting(int client) + { + } + + /** + * @brief Called when a client has fully disconnected. + * + * @param client Index of the client. + */ + virtual void OnClientDisconnected(int client) + { + } + + /** + * @brief Called when a client has recieved authorization. + * + * @param client Index of the client. + * @param authstring Authorization string. + */ + virtual void OnClientAuthorized(int client, const char *authstring) + { + } + }; + + class IPlayerManager : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_PLAYERMANAGER_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_PLAYERMANAGER_VERSION; + } + public: + /** + * @brief Adds a client listener. + * + * @param listener Pointer to an IClientListener. + */ + virtual void AddClientListener(IClientListener *listener) =0; + + /** + * @brief Removes a client listener. + * + * @param listener Pointer to an IClientListener. + */ + virtual void RemoveClientListener(IClientListener *listener) =0; + + /** + * @brief Retrieves an IGamePlayer object by its client index. + * + * Note: This will return a valid object for any player, connected or not. + * Note: Client indexes start at 1, not 0. + * + * @param client Index of the client. + * @return An IGamePlayer pointer, or NULL if out of range. + */ + virtual IGamePlayer *GetGamePlayer(int client) =0; + + /** + * @brief Retrieves an IGamePlayer object by its edict_t pointer. + * + * @param pEdict Index of the client + * @return An IGamePlayer pointer, or NULL if out of range. + */ + virtual IGamePlayer *GetGamePlayer(edict_t *pEdict) =0; + + /** + * @brief Returns the maximum number of clients. + * + * @return Maximum number of clients. + */ + virtual int GetMaxClients() =0; + + /** + * @brief Returns the number of players currently connected. + * + * @return Current number of connected clients. + */ + virtual int GetNumPlayers() =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_INTERFACE_IPLAYERHELPERS_H_ From 4e5311d9f2c4d7738a7e5462d980cc400fb780a8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 01:14:32 +0000 Subject: [PATCH 0411/1664] added+implemented the rest of the admin natives so far fixed a bug where flags could not be unset --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40442 --- core/AdminCache.cpp | 21 +++- core/smn_admin.cpp | 254 ++++++++++++++++++++++++++++++++++++++ plugins/include/admin.inc | 220 +++++++++++++++++++++++++++++++-- 3 files changed, 481 insertions(+), 14 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 12dac592..05074b8e 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -289,7 +289,14 @@ void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled) return; } - pGroup->addflags |= (1<<(unsigned int)flag); + FlagBits bits = (1<<(FlagBits)flag); + + if (enabled) + { + pGroup->addflags |= bits; + } else { + pGroup->addflags &= ~bits; + } } bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag) @@ -872,9 +879,17 @@ void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) { return; } + + FlagBits bits = (1<<(FlagBits)flag); - pUser->flags |= (1<<(FlagBits)flag); - pUser->eflags |= (1<<(FlagBits)flag); + if (enabled) + { + pUser->flags |= bits; + pUser->eflags |= bits; + } else { + pUser->flags &= ~bits; + pUser->eflags &= ~bits; + } } bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index 4d4b1aee..b3c799ab 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -183,6 +183,241 @@ static cell_t GetAdmGroupAddFlags(IPluginContext *pContext, const cell_t *params return g_Admins.GetGroupAddFlags(id); } +static cell_t RegisterAuthIdentType(IPluginContext *pContext, const cell_t *params) +{ + char *type; + pContext->LocalToString(params[1], &type); + + g_Admins.RegisterAuthIdentType(type); + + return 1; +} + +static cell_t CreateAdmin(IPluginContext *pContext, const cell_t *params) +{ + char *admin; + pContext->LocalToString(params[1], &admin); + + if (admin[0] == '\0') + { + admin = NULL; + } + + return g_Admins.CreateAdmin(admin); +} + +static cell_t GetAdminUsername(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + size_t written; + const char *name = g_Admins.GetAdminName(id); + + if (!name) + { + return 0; + } + + pContext->StringToLocalUTF8(params[2], params[3], name, &written); + + return written; +} + +static cell_t BindAdminIdentity(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + char *auth, *ident; + + pContext->LocalToString(params[2], &auth); + pContext->LocalToString(params[3], &ident); + + return g_Admins.BindAdminIdentity(id, auth, ident); +} + +static cell_t SetAdminFlag(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + AdminFlag flag = (AdminFlag)params[2]; + bool enabled = params[3] ? true : false; + + g_Admins.SetAdminFlag(id, flag, enabled); + + return 1; +} + +static cell_t GetAdminFlag(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + AdminFlag flag = (AdminFlag)params[2]; + AccessMode mode = (AccessMode)params[3]; + + return g_Admins.GetAdminFlag(id, flag, mode); +} + +static cell_t GetAdminFlags(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + AccessMode mode = (AccessMode)params[2]; + + return g_Admins.GetAdminFlags(id, mode); +} + +static cell_t AdminInheritGroup(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + GroupId gid = params[2]; + + return g_Admins.AdminInheritGroup(id, gid); +} + +static cell_t GetAdminGroupCount(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + + return g_Admins.GetAdminGroupCount(id); +} + +static cell_t GetAdminGroup(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + unsigned int index = params[2]; + const char *name; + GroupId gid; + + if ((gid=g_Admins.GetAdminGroup(id, index, &name)) == INVALID_GROUP_ID) + { + return gid; + } + + if (name == NULL) + { + name = ""; + } + + pContext->StringToLocalUTF8(params[3], params[4], name, NULL); + + return gid; +} + +static cell_t SetAdminPassword(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + char *password; + + pContext->LocalToString(params[2], &password); + + g_Admins.SetAdminPassword(id, password); + + return 1; +} + +static cell_t GetAdminPassword(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + const char *password = g_Admins.GetAdminPassword(id); + + if (!password) + { + return 0; + } + + pContext->StringToLocalUTF8(params[2], params[3], password, NULL); + + return 1; +} + +static cell_t FindAdminByIdentity(IPluginContext *pContext, const cell_t *params) +{ + char *auth, *ident; + + pContext->LocalToString(params[1], &auth); + pContext->LocalToString(params[2], &ident); + + return g_Admins.FindAdminByIdentity(auth, ident); +} + +static cell_t RemoveAdmin(IPluginContext *pContext, const cell_t *params) +{ + AdminId id = params[1]; + + return g_Admins.InvalidateAdmin(id); +} + +static cell_t FlagBitsToBitArray(IPluginContext *pContext, const cell_t *params) +{ + FlagBits bits = (FlagBits)params[1]; + bool array[AdminFlags_TOTAL]; + cell_t *addr; + unsigned int numWr = g_Admins.FlagBitsToBitArray(bits, array, AdminFlags_TOTAL); + + pContext->LocalToPhysAddr(params[2], &addr); + + unsigned int i; + for (i=0; i AdminFlags_TOTAL ? params[2] : AdminFlags_TOTAL); + cell_t *addr; + + pContext->LocalToPhysAddr(params[1], &addr); + + for (unsigned int i=0; iLocalToPhysAddr(params[1], &addr); + + if (sizeof(AdminFlag) == sizeof(cell_t)) + { + return g_Admins.FlagArrayToBits((const AdminFlag *)addr, params[2]); + } else { + AdminFlag flags[AdminFlags_TOTAL]; + unsigned int num = ((unsigned)params[2] > AdminFlags_TOTAL ? AdminFlags_TOTAL : params[2]); + + for (unsigned int i=0; iLocalToPhysAddr(params[2], &addr); + + if (sizeof(AdminFlag) == sizeof(cell_t)) + { + return g_Admins.FlagBitsToArray(params[1], (AdminFlag *)addr, params[3]); + } else { + AdminFlag flags[AdminFlags_TOTAL]; + unsigned int num = ((unsigned)params[2] > AdminFlags_TOTAL ? AdminFlags_TOTAL : params[2]); + num = g_Admins.FlagBitsToArray(params[1], flags, num); + + for (unsigned int i=0; i Date: Tue, 6 Feb 2007 05:07:49 +0000 Subject: [PATCH 0412/1664] renamed this plugin --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40443 --- plugins/{admin-base => admin-flatfile}/admin-base.sp | 0 plugins/{admin-base => admin-flatfile}/admin-groups.sp | 0 plugins/{admin-base => admin-flatfile}/admin-levels.sp | 0 plugins/{admin-base => admin-flatfile}/admin-overrides.sp | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename plugins/{admin-base => admin-flatfile}/admin-base.sp (100%) rename plugins/{admin-base => admin-flatfile}/admin-groups.sp (100%) rename plugins/{admin-base => admin-flatfile}/admin-levels.sp (100%) rename plugins/{admin-base => admin-flatfile}/admin-overrides.sp (100%) diff --git a/plugins/admin-base/admin-base.sp b/plugins/admin-flatfile/admin-base.sp similarity index 100% rename from plugins/admin-base/admin-base.sp rename to plugins/admin-flatfile/admin-base.sp diff --git a/plugins/admin-base/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp similarity index 100% rename from plugins/admin-base/admin-groups.sp rename to plugins/admin-flatfile/admin-groups.sp diff --git a/plugins/admin-base/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp similarity index 100% rename from plugins/admin-base/admin-levels.sp rename to plugins/admin-flatfile/admin-levels.sp diff --git a/plugins/admin-base/admin-overrides.sp b/plugins/admin-flatfile/admin-overrides.sp similarity index 100% rename from plugins/admin-base/admin-overrides.sp rename to plugins/admin-flatfile/admin-overrides.sp From 8860ff6224ad3a0fbea732f1f9b95da44caf7bd1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 05:13:24 +0000 Subject: [PATCH 0413/1664] changed how the admin cache is rebuilt renamed the plugin and fixed compilation errors --HG-- rename : plugins/admin-flatfile/admin-base.sp => plugins/admin-flatfile/admin-flatfile.sp extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40444 --- core/AdminCache.cpp | 72 +++++++++++-------- core/AdminCache.h | 2 +- core/smn_admin.cpp | 2 +- core/sourcemod.cpp | 3 +- .../{admin-base.sp => admin-flatfile.sp} | 7 +- plugins/admin-flatfile/admin-groups.sp | 4 -- plugins/admin-flatfile/admin-levels.sp | 14 ++-- plugins/admin-flatfile/admin-overrides.sp | 6 +- plugins/include/admin.inc | 23 +++--- public/IAdminSystem.h | 40 ++++++++--- 10 files changed, 101 insertions(+), 72 deletions(-) rename plugins/admin-flatfile/{admin-base.sp => admin-flatfile.sp} (78%) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 05074b8e..43580376 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -35,11 +35,12 @@ AdminCache::AdminCache() AdminCache::~AdminCache() { + DumpAdminCache(AdminCache_Overrides, false); + DumpAdminCache(AdminCache_Groups, false); + sm_trie_destroy(m_pCmdGrpOverrides); sm_trie_destroy(m_pCmdOverrides); - DumpAdminCache(0xFFFFFFFF, false); - if (m_pGroups) { sm_trie_destroy(m_pGroups); @@ -759,39 +760,52 @@ void AdminCache::InvalidateAdminCache(bool unlink_admins) } } -void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) +void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) { - if (cache_flags & ADMIN_CACHE_OVERRIDES) + List::iterator iter; + IAdminListener *pListener; + cell_t result; + + if (part == AdminCache_Overrides) { DumpCommandOverrideCache(Override_Command); DumpCommandOverrideCache(Override_CommandGroup); - } - - /* This will auto-invalidate the admin cache */ - if (cache_flags & ADMIN_CACHE_GROUPS) - { - InvalidateGroupCache(); - } - - /* If we only requested an admin rebuild, re-use the internal memory */ - if (((cache_flags & ADMIN_CACHE_ADMINS) == ADMIN_CACHE_ADMINS) - && ((cache_flags & (1<<2)) != (1<<2))) - { - InvalidateAdminCache(true); - } - - if (rebuild) - { - List::iterator iter; - IAdminListener *pListener; - cell_t result; - for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + if (rebuild) { - pListener = (*iter); - pListener->OnRebuildAdminCache(cache_flags); + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnRebuildOverrideCache(); + } + m_pCacheFwd->PushCell(part); + m_pCacheFwd->Execute(&result); + } + } else if (part == AdminCache_Groups || part == AdminCache_Admins) { + if (part == AdminCache_Groups) + { + InvalidateGroupCache(); + if (rebuild) + { + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnRebuildGroupCache(); + } + m_pCacheFwd->PushCell(part); + m_pCacheFwd->Execute(&result); + } + } + InvalidateAdminCache(true); + if (rebuild) + { + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnRebuildAdminCache((part == AdminCache_Groups)); + } + m_pCacheFwd->PushCell(AdminCache_Admins); + m_pCacheFwd->Execute(&result); } - m_pCacheFwd->PushCell(cache_flags); - m_pCacheFwd->Execute(&result); } } diff --git a/core/AdminCache.h b/core/AdminCache.h index 504be115..11b452ea 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -107,7 +107,7 @@ public: //IAdminSystem GroupId GetGroupImmunity(GroupId id, unsigned int number); void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule); bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule); - void DumpAdminCache(int cache_flags, bool rebuild); + void DumpAdminCache(AdminCachePart part, bool rebuild); void AddAdminListener(IAdminListener *pListener); void RemoveAdminListener(IAdminListener *pListener); /** User stuff */ diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index b3c799ab..67f1addc 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -17,7 +17,7 @@ static cell_t DumpAdminCache(IPluginContext *pContext, const cell_t *params) { - g_Admins.DumpAdminCache(params[1], (params[2] == 1) ? true : false); + g_Admins.DumpAdminCache((AdminCachePart)params[1], (params[2] == 1) ? true : false); return 1; } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 016f325a..a09ccbc5 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -185,7 +185,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_IsMapLoading = false; - g_Admins.DumpAdminCache(ADMIN_CACHE_GROUPS|ADMIN_CACHE_ADMINS|ADMIN_CACHE_OVERRIDES, true); + g_Admins.DumpAdminCache(AdminCache_Overrides, true); + g_Admins.DumpAdminCache(AdminCache_Groups, true); RETURN_META_VALUE(MRES_IGNORED, true); } diff --git a/plugins/admin-flatfile/admin-base.sp b/plugins/admin-flatfile/admin-flatfile.sp similarity index 78% rename from plugins/admin-flatfile/admin-base.sp rename to plugins/admin-flatfile/admin-flatfile.sp index af9ffb5e..261d7ebb 100644 --- a/plugins/admin-flatfile/admin-base.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -19,14 +19,13 @@ new g_ErrorCount = 0; #include "admin-overrides.sp" #include "admin-groups.sp" -public OnRebuildAdminCache(cache_flags) +public OnRebuildAdminCache(AdminCachePart:part) { RefreshLevels(); - if (cache_flags & ADMIN_CACHE_OVERRIDES) + if (part == AdminCache_Overrides) { ReadOverrides(); - } - if (cache_flags & ADMIN_CACHE_GROUPS) + } else if (part == AdminCache_Groups) { ReadGroups(); } diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index 22e27f59..73cb778d 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -81,10 +81,6 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, continue; } flag = g_FlagLetters[value[i] - 'a']; - if (flag == Admin_None) - { - continue; - } SetAdmGroupAddFlag(g_CurGrp, flag, true); } } else if (StrEqual(key, "immunity")) { diff --git a/plugins/admin-flatfile/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp index ed23529c..81dc3a16 100644 --- a/plugins/admin-flatfile/admin-levels.sp +++ b/plugins/admin-flatfile/admin-levels.sp @@ -9,12 +9,6 @@ static g_LevelState = LEVEL_STATE_NONE; LoadDefaultLetters() { - /* Clear letters first */ - for (new i='a'; i<='z'; i++) - { - g_FlagLetters[i-'a'] = Admin_None; - } - g_FlagLetters['a'-'a'] = Admin_Reservation; g_FlagLetters['b'-'a'] = Admin_Kick; g_FlagLetters['c'-'a'] = Admin_Ban; @@ -22,7 +16,7 @@ LoadDefaultLetters() g_FlagLetters['e'-'a'] = Admin_Slay; g_FlagLetters['f'-'a'] = Admin_Changemap; g_FlagLetters['g'-'a'] = Admin_Convars; - g_FlagLetters['h'-'a'] = Admin_Configs; + g_FlagLetters['h'-'a'] = Admin_Config; g_FlagLetters['i'-'a'] = Admin_Chat; g_FlagLetters['j'-'a'] = Admin_Vote; g_FlagLetters['h'-'a'] = Admin_Password; @@ -78,7 +72,7 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin chr -= 'a'; - new AdminFlag:flag = Admin_None; + new AdminFlag:flag; if (StrEqual(key, "reservation")) { @@ -95,8 +89,8 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin flag = Admin_Changemap; } else if (StrEqual(key, "cvars")) { flag = Admin_Convars; - } else if (StrEqual(key, "configs")) { - flag = Admin_Configs; + } else if (StrEqual(key, "config")) { + flag = Admin_Config; } else if (StrEqual(key, "chat")) { flag = Admin_Chat; } else if (StrEqual(key, "vote")) { diff --git a/plugins/admin-flatfile/admin-overrides.sp b/plugins/admin-flatfile/admin-overrides.sp index cd3a522f..6bb54b61 100644 --- a/plugins/admin-flatfile/admin-overrides.sp +++ b/plugins/admin-flatfile/admin-overrides.sp @@ -50,7 +50,7 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, return SMCParse_Continue; } - new AdminFlag:flag = Admin_None; + new AdminFlag:flag; if (strlen(value) > 1) { @@ -65,9 +65,9 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, if (key[0] == '@') { - AddCommandOverride(key[1], Override_CommandGroup, flag); + AddCommandOverride(key[1], Override_CommandGroup, FlagToBit(flag)); } else { - AddCommandOverride(key, Override_Command, flag); + AddCommandOverride(key, Override_Command, FlagToBit(flag)); } return SMCParse_Continue; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 843aa44e..9d3ce6f5 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -113,26 +113,31 @@ enum AdmAccessMode Access_Effective, /**< Access the user has from their groups */ }; -#define ADMIN_CACHE_OVERRIDES (1<<0) -#define ADMIN_CACHE_ADMINS (1<<1) -#define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) +/** + * @brief Represents the various cache regions. + */ +enum AdminCachePart +{ + AdminCache_Overrides = 0, /**< Global overrides */ + AdminCache_Groups = 1, /**< All groups (automatically invalidates admins too) */ + AdminCache_Admins = 2, /**< All admins */ +}; /** - * Called when part of the admin cache needs to be rebuilt. - * @note Groups should always be rebuilt before admins. + * Called when part of the cache which needs to be rebuilt. * - * @param cache_flags Flags for which cache to dump. + * @param part Part of the admin cache to rebuild. */ -forward OnRebuildAdminCache(cache_flags); +forward OnRebuildAdminCache(AdminCachePart:part); /** * Tells the admin system to dump a portion of the cache. * - * @param cache_flags Flags for which cache to dump. Specifying groups also dumps admins. + * @param part Part of the cache to dump. Specifying groups also dumps admins. * @param rebuild If true, the rebuild forwards will fire. * @noreturn */ -native DumpAdminCache(cache_flags, bool:rebuild); +native DumpAdminCache(AdminCachePart:part, bool:rebuild); /** * Adds a global command flag override. Any command registered with this name diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index db4820d2..af5309ff 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -147,10 +147,6 @@ namespace SourceMod */ typedef int AdminId; - #define ADMIN_CACHE_OVERRIDES (1<<0) - #define ADMIN_CACHE_ADMINS (1<<1) - #define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) - /** * @brief Represents an invalid/nonexistant group or an erroneous operation. */ @@ -161,19 +157,43 @@ namespace SourceMod */ #define INVALID_ADMIN_ID -1 + /** + * @brief Represents the various cache regions. + */ + enum AdminCachePart + { + AdminCache_Overrides = 0, /**< Global overrides */ + AdminCache_Groups = 1, /**< All groups (automatically invalidates admins too) */ + AdminCache_Admins = 2, /**< All admins */ + }; + /** * @brief Provides callbacks for admin cache operations. */ class IAdminListener { + public: + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_ADMINSYS_VERSION; + } public: /** - * Called when part of the admin cache needs to be rebuilt. - * Groups should always be rebuilt before admins. + * @brief Called when the admin cache needs to be rebuilt. * - * @param cache_flags Flags for which cache to dump. + * @param auto_rebuild True if this is being called because of a group rebuild. */ - virtual void OnRebuildAdminCache(int cache_flags) =0; + virtual void OnRebuildAdminCache(bool auto_rebuild) =0; + + /** + * @brief Called when the group cache needs to be rebuilt. + */ + virtual void OnRebuildGroupCache() =0; + + /** + * @brief Called when the global override cache needs to be rebuilt. + */ + virtual void OnRebuildOverrideCache() =0; }; typedef unsigned int FlagBits; @@ -339,10 +359,10 @@ namespace SourceMod * @brief Tells the admin system to dump a portion of the cache. * This calls into plugin forwards to rebuild the cache. * - * @param cache_flags Flags for which cache to dump. Specifying groups also dumps admins. + * @param part Portion of the cache to dump. * @param rebuild If true, the rebuild forwards/events will fire. */ - virtual void DumpAdminCache(int cache_flags, bool rebuild) =0; + virtual void DumpAdminCache(AdminCachePart part, bool rebuild) =0; /** * @brief Adds an admin interface listener. From 0c56f71a6191a5156a7c44536ef5ed781a54019f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 05:48:52 +0000 Subject: [PATCH 0414/1664] cleaned up levels in both the admin plugin and the source code overrides use full flag bits now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40445 --- configs/admin_levels.cfg | 8 +++++- plugins/admin-flatfile/admin-flatfile.sp | 1 + plugins/admin-flatfile/admin-groups.sp | 4 +++ plugins/admin-flatfile/admin-levels.sp | 30 ++++++++++++++++++++--- plugins/admin-flatfile/admin-overrides.sp | 29 ++++++++++++++-------- plugins/include/admin.inc | 3 ++- 6 files changed, 60 insertions(+), 15 deletions(-) diff --git a/configs/admin_levels.cfg b/configs/admin_levels.cfg index 0ddb0248..81d3dc34 100644 --- a/configs/admin_levels.cfg +++ b/configs/admin_levels.cfg @@ -18,12 +18,18 @@ Levels "slay" "e" "changemap" "f" "cvars" "g" - "configs" "h" + "config" "h" "chat" "i" "vote" "j" "password" "k" "rcon" "l" "cheats" "m" + "custom1" "n" + "custom2" "o" + "custom3" "p" + "custom4" "q" + "custom5" "r" + "custom6" "s" //Custom flags START //Custom flags END diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 261d7ebb..072dc12e 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -11,6 +11,7 @@ public Plugin:myinfo = }; /** Various globals */ +new bool:g_FlagsSet[26]; /* Maps whether flags are set */ new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ new g_ErrorCount = 0; diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index 73cb778d..c129d367 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -80,6 +80,10 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, { continue; } + if (!g_FlagsSet[value[i] - 'a']) + { + continue; + } flag = g_FlagLetters[value[i] - 'a']; SetAdmGroupAddFlag(g_CurGrp, flag, true); } diff --git a/plugins/admin-flatfile/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp index 81dc3a16..fa38fa1c 100644 --- a/plugins/admin-flatfile/admin-levels.sp +++ b/plugins/admin-flatfile/admin-levels.sp @@ -9,6 +9,11 @@ static g_LevelState = LEVEL_STATE_NONE; LoadDefaultLetters() { + for (new i='t'; i<'z'; i++) + { + g_FlagsSet[i-'a'] = false; + } + g_FlagLetters['a'-'a'] = Admin_Reservation; g_FlagLetters['b'-'a'] = Admin_Kick; g_FlagLetters['c'-'a'] = Admin_Ban; @@ -19,9 +24,15 @@ LoadDefaultLetters() g_FlagLetters['h'-'a'] = Admin_Config; g_FlagLetters['i'-'a'] = Admin_Chat; g_FlagLetters['j'-'a'] = Admin_Vote; - g_FlagLetters['h'-'a'] = Admin_Password; - g_FlagLetters['i'-'a'] = Admin_RCON; - g_FlagLetters['j'-'a'] = Admin_Cheats; + g_FlagLetters['k'-'a'] = Admin_Password; + g_FlagLetters['l'-'a'] = Admin_RCON; + g_FlagLetters['m'-'a'] = Admin_Cheats; + g_FlagLetters['n'-'a'] = Admin_Custom1; + g_FlagLetters['o'-'a'] = Admin_Custom2; + g_FlagLetters['p'-'a'] = Admin_Custom3; + g_FlagLetters['q'-'a'] = Admin_Custom4; + g_FlagLetters['r'-'a'] = Admin_Custom5; + g_FlagLetters['s'-'a'] = Admin_Custom6; g_FlagLetters['z'-'a'] = Admin_Root; } @@ -103,11 +114,24 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin flag = Admin_Cheats; } else if (StrEqual(key, "root")) { flag = Admin_Root; + } else if (StrEqual(key, "custom1")) { + flag = Admin_Custom1; + } else if (StrEqual(key, "custom2")) { + flag = Admin_Custom2; + } else if (StrEqual(key, "custom3")) { + flag = Admin_Custom3; + } else if (StrEqual(key, "custom4")) { + flag = Admin_Custom4; + } else if (StrEqual(key, "custom5")) { + flag = Admin_Custom5; + } else if (StrEqual(key, "custom6")) { + flag = Admin_Custom6; } else { LogLevelError("Unrecognized flag type: %s", key); } g_FlagLetters[chr] = flag; + g_FlagsSet[chr] = true; } return SMCParse_Continue; diff --git a/plugins/admin-flatfile/admin-overrides.sp b/plugins/admin-flatfile/admin-overrides.sp index 6bb54b61..43b93ac9 100644 --- a/plugins/admin-flatfile/admin-overrides.sp +++ b/plugins/admin-flatfile/admin-overrides.sp @@ -50,24 +50,33 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, return SMCParse_Continue; } - new AdminFlag:flag; + new AdminFlag:array[AdminFlags_TOTAL]; + new flags_total; - if (strlen(value) > 1) + new len = strlen(value); + for (new i=0; i 'z') + { + LogOverrideError("Invalid flag detected: %c", value[i]); + continue; + } + new val = value[i] - 'a'; + if (!g_FlagsSet[val]) + { + LogOverrideError("Invalid flag detected: %c", value[i]); + continue; + } + array[flags_total++] = g_FlagLetters[val]; } - if (value[0] >= 'a' && value[0] <= 'z') - { - flag = g_FlagLetters[value[0] - 'a']; - } + new flags = FlagArrayToBits(array, flags_total); if (key[0] == '@') { - AddCommandOverride(key[1], Override_CommandGroup, FlagToBit(flag)); + AddCommandOverride(key[1], Override_CommandGroup, flags); } else { - AddCommandOverride(key, Override_Command, FlagToBit(flag)); + AddCommandOverride(key, Override_Command, flags); } return SMCParse_Continue; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 9d3ce6f5..3bfad62a 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -44,9 +44,10 @@ enum AdminFlag Admin_Custom5, /**< Fifth custom flag type */ Admin_Custom6, /**< Sixth custom flag type */ /* --- */ - AdminFlags_TOTAL, }; +#define AdminFlags_TOTAL 21 + /** * These define bitwise values for bitstrings (numbers containing bitwise flags). */ From e9204c0bf4988997784a8549b77fde5c6869dc7b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 19:00:58 +0000 Subject: [PATCH 0415/1664] added interface spec for data packs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40446 --- core/msvc8/sourcemod_mm.vcproj | 4 ++++ public/ISourceMod.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0332881a..02e152f4 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -341,6 +341,10 @@ RelativePath="..\..\public\IAdminSystem.h" > + + diff --git a/public/ISourceMod.h b/public/ISourceMod.h index ca44945c..4c3b4116 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -116,6 +116,35 @@ namespace SourceMod SourcePawn::IPluginContext *pContext, const cell_t *params, unsigned int param) =0; + +#if 0 + /** + * @brief Creates a data pack object. + * + * @return A new IDataPack object. + */ + virtual IDataPack *CreateDataPack() =0; + + /** + * @brief Releases a data pack's resources so it can be re-used. + * + * @param pack An IDataPack object to release. + */ + virtual void FreeDataPack(IDataPack *pack) =0; + + /** + * @brief Returns the automated data pack handle type. + * + * The readonly data type is the parent of the writable type. + * Note that calling CloseHandle() on either type will release the data pack. + * The readonly type is inheritable, but due to limitations of the Handle System, + * the writable type is not. + * + * @param readonly If true, the readonly type will be returned. + * @return The Handle type for storing generic data packs. + */ + virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; +#endif }; } From 996924326688019e0f36ec86b492d9af044efa8d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 19:05:45 +0000 Subject: [PATCH 0416/1664] added data pack functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40447 --- public/IDataPack.h | 139 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 public/IDataPack.h diff --git a/public/IDataPack.h b/public/IDataPack.h new file mode 100644 index 00000000..b2394eab --- /dev/null +++ b/public/IDataPack.h @@ -0,0 +1,139 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_DATAPACK_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_DATAPACK_H_ + +#include + +/** + * @file IDataPack.h + * @brief Contains functions for packing data abstractly to/from plugins. The wrappers + * for creating these are contained in ISourceMod.h + */ + +namespace SourceMod +{ + /** + * @brief Specifies a data pack that can only be read. + */ + class IDataReader + { + public: + /** + * @brief Resets the position in the data stream to the beginning. + */ + virtual void Reset() const =0; + + /** + * @brief Retrieves the current stream position. + * + * @return Index into the stream. + */ + virtual size_t GetPosition() const =0; + + /** + * @brief Sets the current stream position. + * + * @param pos Index to set the stream at. + * @return True if succeeded, false if out of bounds. + */ + virtual bool SetPosition(size_t pos) const =0; + + /** + * @brief Reads one cell from the data stream. + * + * @return A cell read from the current position. + */ + virtual cell_t ReadCell() const =0; + + /** + * @brief Reads one float from the data stream. + * + * @return A float read from the current position. + */ + virtual float ReadFloat() const =0; + + /** + * @brief Returns whether or not a specified number of bytes can be read. + * + * @param bytes Number of bytes to simulate reading. + * @return True if can be read, false otherwise. + */ + virtual bool IsReadable(size_t bytes) const =0; + + /** + * @brief Reads a string from the data stream. + * + * @param len Optional pointer to store the string length. + * @return Pointer to the string, or NULL if out of bounds. + */ + virtual const char *ReadString(size_t *len) const =0; + + /** + * @brief Reads the current position as a generic address. + * + * @return Pointer to the memory. + */ + virtual void *GetMemory() const =0; + }; + + /** + * @brief Specifices a data pack that can only be written. + */ + class IDataPack : public IDataReader + { + public: + /** + * @brief Packs one cell into the data stream. + * + * @param cell Cell value to write. + */ + virtual void PackCell(cell_t cell) =0; + + /** + * @brief Packs one float into the data stream. + * + * @param val Float value to write. + */ + virtual void PackFloat(float val) =0; + + /** + * @brief Packs one string into the data stream. + * The length is recorded as well for buffer overrun protection. + * + * @param string String to write. + */ + virtual void PackString(const char *string) =0; + + /** + * @brief Creates a generic block of memory in the stream. + * + * Note that the pointer it returns can be invalidated on further + * writing, since the stream size may grow. You may need to double back + * and fetch the pointer again. + * + * @param size Size of the memory to create in the stream. + * @param addr Optional pointer to store the relocated memory address. + * @return Current position of the stream beforehand. + */ + virtual size_t CreateMemory(size_t size, void **addr) =0; + }; +}; + +#endif //_INCLUDE_SOURCEMOD_INTERFACE_DATAPACK_H_ From d2a3c7f0f7d78728349bee9af46e2dca0164ffac Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 23:30:50 +0000 Subject: [PATCH 0417/1664] ignores bad groups safely now cleaned up code a bit, removed redundancy --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40448 --- plugins/admin-flatfile/admin-flatfile.sp | 28 ++++++++- plugins/admin-flatfile/admin-groups.sp | 71 +++++++++++++---------- plugins/admin-flatfile/admin-levels.sp | 53 ++++++++--------- plugins/admin-flatfile/admin-overrides.sp | 56 +++++++++--------- 4 files changed, 121 insertions(+), 87 deletions(-) diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 072dc12e..61513cb0 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -10,11 +10,13 @@ public Plugin:myinfo = url = "http://www.sourcemod.net/" }; -/** Various globals */ +/** Various parsing globals */ new bool:g_FlagsSet[26]; /* Maps whether flags are set */ new AdminFlag:g_FlagLetters[26]; /* Maps the flag letters */ new bool:g_LoggedFileName = false; /* Whether or not the file name has been logged */ -new g_ErrorCount = 0; +new g_ErrorCount = 0; /* Current error count */ +new g_IgnoreLevel = 0; /* Nested ignored section count, so users can screw up files safely */ +new String:g_Filename[PLATFORM_MAX_PATH]; /* Used for error messages */ #include "admin-levels.sp" #include "admin-overrides.sp" @@ -31,3 +33,25 @@ public OnRebuildAdminCache(AdminCachePart:part) ReadGroups(); } } + +ParseError(const String:format[], {Handle,String,Float,_}:...) +{ + decl String:buffer[512]; + + if (!g_LoggedFileName) + { + LogError("Error(s) detected parsing admin_levels.cfg:"); + g_LoggedFileName = true; + } + + VFormat(buffer, sizeof(buffer), format, 2); + + LogError(" (%d) %s", ++g_ErrorCount, buffer); +} + +InitGlobalStates() +{ + g_ErrorCount = 0; + g_IgnoreLevel = 0; + g_LoggedFileName = false; +} diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index c129d367..199d7073 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -11,32 +11,23 @@ static g_GroupState = GROUP_STATE_NONE; static g_GroupPass = 0 static bool:g_NeedReparse = false; -//:TODO: immunity needs to self-check itself for redundancy in core -//:TODO: invalidating groups internally needs to check immunities //:TODO: reparsing -static LogGroupError(const String:fmt[], {Handle,String,Float,_}:...) -{ - decl String:buffer[512]; - - if (!g_LoggedFileName) - { - LogError("Error(s) detected parsing admin_groups.cfg:"); - g_LoggedFileName = true; - } - - VFormat(buffer, sizeof(buffer), fmt, 2); - - LogError(" (%d) %s", ++g_ErrorCount, buffer); -} - public SMCResult:ReadGroups_NewSection(Handle:smc, const String:name[], bool:opt_quotes) { + if (g_IgnoreLevel) + { + g_IgnoreLevel++; + return SMCParse_Continue; + } + if (g_GroupState == GROUP_STATE_NONE) { if (StrEqual(name, "Groups")) { g_GroupState = GROUP_STATE_GROUPS; + } else { + g_IgnoreLevel++; } } else if (g_GroupState == GROUP_STATE_GROUPS) { if ((g_CurGrp = CreateAdmGroup(name)) == INVALID_GROUP_ID) @@ -48,7 +39,11 @@ public SMCResult:ReadGroups_NewSection(Handle:smc, const String:name[], bool:opt if (StrEqual(name, "Overrides")) { g_GroupState = GROUP_STATE_OVERRIDES; + } else { + g_IgnoreLevel++; } + } else { + g_IgnoreLevel++; } return SMCParse_Continue; @@ -60,7 +55,8 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, bool:key_quotes, bool:value_quotes) { - if (g_CurGrp == INVALID_GROUP_ID) + if (g_CurGrp == INVALID_GROUP_ID + || g_IgnoreLevel) { return SMCParse_Continue; } @@ -130,7 +126,7 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, { SetAdmGroupImmuneFrom(g_CurGrp, id); } else { - LogGroupError("Unable to find group: \"%s\"", value); + ParseError("Unable to find group: \"%s\"", value); } } } @@ -140,6 +136,13 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, public SMCResult:ReadGroups_EndSection(Handle:smc) { + /* If we're ignoring, skip out */ + if (g_IgnoreLevel) + { + g_IgnoreLevel--; + return SMCParse_Continue; + } + if (g_GroupState == GROUP_STATE_OVERRIDES) { g_GroupState = GROUP_STATE_INGROUP; @@ -165,20 +168,13 @@ static InitializeGroupParser() } } -ReadGroups() +InternalReadGroups(const String:path[], pass) { - new String:path[PLATFORM_MAX_PATH]; - - InitializeGroupParser(); - - BuildPath(Path_SM, path, sizeof(path), "configs/admin_groups.cfg"); - /* Set states */ + InitGlobalStates(); g_GroupState = GROUP_STATE_NONE; - g_LoggedFileName = false; - g_ErrorCount = 0; g_CurGrp = INVALID_GROUP_ID; - g_GroupPass = GROUP_PASS_FIRST; + g_GroupPass = pass; g_NeedReparse = false; new SMCError:err = SMC_ParseFile(g_hGroupParser, path); @@ -187,10 +183,23 @@ ReadGroups() decl String:buffer[64]; if (SMC_GetErrorString(err, buffer, sizeof(buffer))) { - LogGroupError("%s", buffer); + ParseError("%s", buffer); } else { - LogGroupError("Fatal parse error"); + ParseError("Fatal parse error"); } } } +ReadGroups() +{ + InitializeGroupParser(); + + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admin_groups.cfg"); + + InternalReadGroups(g_Filename, GROUP_PASS_FIRST); + if (g_NeedReparse) + { + InternalReadGroups(g_Filename, GROUP_PASS_SECOND); + } +} + diff --git a/plugins/admin-flatfile/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp index fa38fa1c..4df8e4f5 100644 --- a/plugins/admin-flatfile/admin-levels.sp +++ b/plugins/admin-flatfile/admin-levels.sp @@ -36,34 +36,31 @@ LoadDefaultLetters() g_FlagLetters['z'-'a'] = Admin_Root; } -static LogLevelError(const String:format[], {Handle,String,Float,_}:...) -{ - decl String:buffer[512]; - - if (!g_LoggedFileName) - { - LogError("Error(s) detected parsing admin_levels.cfg:"); - g_LoggedFileName = true; - } - - VFormat(buffer, sizeof(buffer), format, 2); - - LogError(" (%d) %s", ++g_ErrorCount, buffer); -} - public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt_quotes) { + if (g_IgnoreLevel) + { + g_IgnoreLevel++; + return SMCParse_Continue; + } + if (g_LevelState == LEVEL_STATE_NONE) { if (StrEqual(name, "Levels")) { g_LevelState = LEVEL_STATE_LEVELS; + } else { + g_IgnoreLevel++; } } else if (g_LevelState == LEVEL_STATE_LEVELS) { if (StrEqual(name, "Flags")) { g_LevelState = LEVEL_STATE_FLAGS; + } else { + g_IgnoreLevel++; } + } else { + g_IgnoreLevel++; } return SMCParse_Continue; @@ -71,13 +68,13 @@ public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes) { - if (g_LevelState == LEVEL_STATE_FLAGS) + if (g_LevelState == LEVEL_STATE_FLAGS && !g_IgnoreLevel) { new chr = value[0]; if (chr < 'a' || chr > 'z') { - LogLevelError("Unrecognized character: \"%s\"", value); + ParseError("Unrecognized character: \"%s\"", value); return SMCParse_Continue; } @@ -127,7 +124,7 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin } else if (StrEqual(key, "custom6")) { flag = Admin_Custom6; } else { - LogLevelError("Unrecognized flag type: %s", key); + ParseError("Unrecognized flag type: %s", key); } g_FlagLetters[chr] = flag; @@ -139,6 +136,13 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin public SMCResult:ReadLevels_EndSection(Handle:smc) { + /* If we're ignoring, skip out */ + if (g_IgnoreLevel) + { + g_IgnoreLevel--; + return SMCParse_Continue; + } + if (g_LevelState == LEVEL_STATE_FLAGS) { /* We're totally done parsing */ @@ -165,27 +169,24 @@ static InitializeLevelParser() RefreshLevels() { - new String:path[PLATFORM_MAX_PATH]; - LoadDefaultLetters(); InitializeLevelParser(); - BuildPath(Path_SM, path, sizeof(path), "configs/admin_levels.cfg"); + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admin_levels.cfg"); /* Set states */ + InitGlobalStates(); g_LevelState = LEVEL_STATE_NONE; - g_LoggedFileName = false; - g_ErrorCount = 0; - new SMCError:err = SMC_ParseFile(g_hLevelParser, path); + new SMCError:err = SMC_ParseFile(g_hLevelParser, g_Filename); if (err != SMCError_Okay) { decl String:buffer[64]; if (SMC_GetErrorString(err, buffer, sizeof(buffer))) { - LogLevelError("%s", buffer); + ParseError("%s", buffer); } else { - LogLevelError("Fatal parse error"); + ParseError("Fatal parse error"); } } } diff --git a/plugins/admin-flatfile/admin-overrides.sp b/plugins/admin-flatfile/admin-overrides.sp index 43b93ac9..0bbb8fae 100644 --- a/plugins/admin-flatfile/admin-overrides.sp +++ b/plugins/admin-flatfile/admin-overrides.sp @@ -5,35 +5,31 @@ static Handle:g_hOverrideParser = INVALID_HANDLE; static g_OverrideState = OVERRIDE_STATE_NONE; -static LogOverrideError(const String:format[], {Handle,String,Float,_}:...) -{ - decl String:buffer[512]; - - if (!g_LoggedFileName) - { - LogError("Error(s) detected parsing admin_levels.cfg:"); - g_LoggedFileName = true; - } - - VFormat(buffer, sizeof(buffer), format, 2); - - LogError(" (%d) %s", ++g_ErrorCount, buffer); -} - - public SMCResult:ReadOverrides_NewSection(Handle:smc, const String:name[], bool:opt_quotes) { + if (g_IgnoreLevel) + { + g_IgnoreLevel++; + return SMCParse_Continue; + } + if (g_OverrideState == OVERRIDE_STATE_NONE) { if (StrEqual(name, "Levels")) { g_OverrideState = OVERRIDE_STATE_LEVELS; + } else { + g_IgnoreLevel++; } } else if (g_OverrideState == OVERRIDE_STATE_LEVELS) { if (StrEqual(name, "Overrides")) { g_OverrideState = OVERRIDE_STATE_OVERRIDES; + } else { + g_IgnoreLevel++; } + } else { + g_IgnoreLevel++; } return SMCParse_Continue; @@ -45,7 +41,8 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, bool:key_quotes, bool:value_quotes) { - if (g_OverrideState != OVERRIDE_STATE_OVERRIDES) + if (g_OverrideState != OVERRIDE_STATE_OVERRIDES + || g_IgnoreLevel) { return SMCParse_Continue; } @@ -58,13 +55,13 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, { if (value[i] < 'a' || value[i] > 'z') { - LogOverrideError("Invalid flag detected: %c", value[i]); + ParseError("Invalid flag detected: %c", value[i]); continue; } new val = value[i] - 'a'; if (!g_FlagsSet[val]) { - LogOverrideError("Invalid flag detected: %c", value[i]); + ParseError("Invalid flag detected: %c", value[i]); continue; } array[flags_total++] = g_FlagLetters[val]; @@ -84,6 +81,13 @@ public SMCResult:ReadOverrides_KeyValue(Handle:smc, public SMCResult:ReadOverrides_EndSection(Handle:smc) { + /* If we're ignoring, skip out */ + if (g_IgnoreLevel) + { + g_IgnoreLevel--; + return SMCParse_Continue; + } + if (g_OverrideState == OVERRIDE_STATE_LEVELS) { g_OverrideState = OVERRIDE_STATE_NONE; @@ -110,27 +114,23 @@ static InitializeOverrideParser() ReadOverrides() { - new String:path[PLATFORM_MAX_PATH]; - InitializeOverrideParser(); - BuildPath(Path_SM, path, sizeof(path), "configs/admin_levels.cfg"); + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admin_levels.cfg"); /* Set states */ + InitGlobalStates(); g_OverrideState = OVERRIDE_STATE_NONE; - g_LoggedFileName = false; - g_ErrorCount = 0; - new SMCError:err = SMC_ParseFile(g_hOverrideParser, path); + new SMCError:err = SMC_ParseFile(g_hOverrideParser, g_Filename); if (err != SMCError_Okay) { decl String:buffer[64]; if (SMC_GetErrorString(err, buffer, sizeof(buffer))) { - LogOverrideError("%s", buffer); + ParseError("%s", buffer); } else { - LogOverrideError("Fatal parse error"); + ParseError("Fatal parse error"); } } } - From 70ae8ad8b6672b93a6cd6ae842e8c2b1e3a87c8f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Feb 2007 23:39:25 +0000 Subject: [PATCH 0418/1664] fixed a small bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40449 --- plugins/admin-flatfile/admin-flatfile.sp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 61513cb0..2a3d8dd4 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -40,7 +40,7 @@ ParseError(const String:format[], {Handle,String,Float,_}:...) if (!g_LoggedFileName) { - LogError("Error(s) detected parsing admin_levels.cfg:"); + LogError("Error(s) detected parsing %s", g_Filename); g_LoggedFileName = true; } From 64f9ff3022147e0341c0f0e312ba27482b3b858e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 02:17:19 +0000 Subject: [PATCH 0419/1664] added user reading --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40450 --- plugins/admin-flatfile/admin-flatfile.sp | 27 +++- plugins/admin-flatfile/admin-groups.sp | 24 ++- plugins/admin-flatfile/admin-levels.sp | 20 +++ plugins/admin-flatfile/admin-overrides.sp | 20 +++ plugins/admin-flatfile/admin-users.sp | 178 ++++++++++++++++++++++ 5 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 plugins/admin-flatfile/admin-users.sp diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 2a3d8dd4..73566e96 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -1,3 +1,24 @@ +/** + * admin-flatfile.sp + * Manages the standard flat files for admins. This is the file to compile. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + #include #include @@ -21,6 +42,7 @@ new String:g_Filename[PLATFORM_MAX_PATH]; /* Used for error messages */ #include "admin-levels.sp" #include "admin-overrides.sp" #include "admin-groups.sp" +#include "admin-users.sp" public OnRebuildAdminCache(AdminCachePart:part) { @@ -28,9 +50,10 @@ public OnRebuildAdminCache(AdminCachePart:part) if (part == AdminCache_Overrides) { ReadOverrides(); - } else if (part == AdminCache_Groups) - { + } else if (part == AdminCache_Groups) { ReadGroups(); + } else if (part == AdminCache_Admins) { + ReadUsers(); } } diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index 199d7073..605c426c 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -1,3 +1,23 @@ +/** + * admin-groups.sp + * Reads the admin_groups.cfg file. Do not compile this directly. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #define GROUP_STATE_NONE 0 #define GROUP_STATE_GROUPS 1 #define GROUP_STATE_INGROUP 2 @@ -11,8 +31,6 @@ static g_GroupState = GROUP_STATE_NONE; static g_GroupPass = 0 static bool:g_NeedReparse = false; -//:TODO: reparsing - public SMCResult:ReadGroups_NewSection(Handle:smc, const String:name[], bool:opt_quotes) { if (g_IgnoreLevel) @@ -168,7 +186,7 @@ static InitializeGroupParser() } } -InternalReadGroups(const String:path[], pass) +static InternalReadGroups(const String:path[], pass) { /* Set states */ InitGlobalStates(); diff --git a/plugins/admin-flatfile/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp index 4df8e4f5..6f7171c6 100644 --- a/plugins/admin-flatfile/admin-levels.sp +++ b/plugins/admin-flatfile/admin-levels.sp @@ -1,3 +1,23 @@ +/* + * admin-levels.sp + * Reads access flags from the admin_levels.cfg file. Do not compile this directly. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #define LEVEL_STATE_NONE 0 #define LEVEL_STATE_LEVELS 1 #define LEVEL_STATE_FLAGS 2 diff --git a/plugins/admin-flatfile/admin-overrides.sp b/plugins/admin-flatfile/admin-overrides.sp index 0bbb8fae..32768d52 100644 --- a/plugins/admin-flatfile/admin-overrides.sp +++ b/plugins/admin-flatfile/admin-overrides.sp @@ -1,3 +1,23 @@ +/* + * admin-overrides.sp + * Reads overrides from the admin_levels.cfg file. Do not compile this directly. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #define OVERRIDE_STATE_NONE 0 #define OVERRIDE_STATE_LEVELS 1 #define OVERRIDE_STATE_OVERRIDES 2 diff --git a/plugins/admin-flatfile/admin-users.sp b/plugins/admin-flatfile/admin-users.sp new file mode 100644 index 00000000..49b35499 --- /dev/null +++ b/plugins/admin-flatfile/admin-users.sp @@ -0,0 +1,178 @@ +/** + * admin-users.sp + * Reads the admins.cfg file. Do not compile this directly. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define USER_STATE_NONE 0 +#define USER_STATE_ADMINS 1 +#define USER_STATE_INADMIN 2 + +static Handle:g_hUserParser = INVALID_HANDLE; +static AdminId:g_CurUser = INVALID_ADMIN_ID; +static g_UserState = USER_STATE_NONE; +static String:g_CurAuth[64]; +static String:g_CurIdent[64]; + +public SMCResult:ReadUsers_NewSection(Handle:smc, const String:name[], bool:opt_quotes) +{ + if (g_IgnoreLevel) + { + g_IgnoreLevel++; + return SMCParse_Continue; + } + + if (g_UserState == USER_STATE_NONE) + { + if (StrEqual(name, "Admins")) + { + g_UserState = USER_STATE_ADMINS; + g_CurUser = INVALID_ADMIN_ID; + } else { + g_IgnoreLevel++; + } + } else if (g_UserState == USER_STATE_ADMINS) { + g_UserState = USER_STATE_INADMIN; + g_CurUser = CreateAdmin(name); + g_CurAuth[0] = '\0'; + g_CurIdent[0] = '\0'; + } else { + g_IgnoreLevel++; + } + + return SMCParse_Continue; +} + +public SMCResult:ReadUsers_KeyValue(Handle:smc, + const String:key[], + const String:value[], + bool:key_quotes, + bool:value_quotes) +{ + if (g_UserState != USER_STATE_INADMIN + || g_IgnoreLevel + || g_CurUser == INVALID_ADMIN_ID) + { + return SMCParse_Continue; + } + + new bool:auth = false; + + if (StrEqual(key, "auth")) + { + auth = true; + StrCopy(g_CurAuth, sizeof(g_CurAuth), value); + } else if (StrEqual(key, "ident")) { + auth = true; + StrCopy(g_CurIdent, sizeof(g_CurIdent), value); + } else if (StrEqual(key, "password")) { + SetAdminPassword(g_CurUser, value); + } else if (StrEqual(key, "group")) { + new GroupId:id = FindAdmGroup(value); + if (id == INVALID_GROUP_ID) + { + ParseError("Unknown group \"%s\"", value); + } else if (!AdminInheritGroup(g_CurUser, id)) { + ParseError("Unable to inherit group \"%s\"", value); + } + } else if (StrEqual(key, "flags")) { + new len = strlen(value); + + for (new i=0; i 'z') + { + ParseError("Invalid flag detected: %c", value[i]); + continue; + } + new val = value[i] - 'a'; + if (!g_FlagsSet[val]) + { + ParseError("Invalid flag detected: %c", value[i]); + continue; + } + SetAdminFlag(g_CurUser, g_FlagLetters[val], true); + } + } + + if (auth && g_CurIdent[0] && g_CurAuth[0]) + { + if (BindAdminIdentity(g_CurUser, g_CurAuth, g_CurIdent)) + { + g_CurAuth[0] = '\0'; + g_CurIdent[0] = '\0'; + } else { + ParseError("Failed to bind auth \"%s\" to identity \"%s\"", g_CurAuth, g_CurIdent); + } + } + + return SMCParse_Continue; +} + +public SMCResult:ReadUsers_EndSection(Handle:smc) +{ + if (g_IgnoreLevel) + { + g_IgnoreLevel--; + return SMCParse_Continue; + } + + if (g_UserState == USER_STATE_INADMIN) + { + g_UserState = USER_STATE_ADMINS; + g_CurUser = INVALID_ADMIN_ID; + } else if (g_UserState == USER_STATE_ADMINS) { + g_UserState = USER_STATE_NONE; + } + + return SMCParse_Continue; +} + +static InitializeUserParser() +{ + if (g_hUserParser == INVALID_HANDLE) + { + g_hUserParser = SMC_CreateParser(); + SMC_SetReaders(g_hUserParser, + ReadUsers_NewSection, + ReadUsers_KeyValue, + ReadUsers_EndSection); + } +} + +ReadUsers() +{ + InitializeUserParser(); + + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admims.cfg"); + + /* Set states */ + InitGlobalStates(); + g_UserState = USER_STATE_NONE; + + new SMCError:err = SMC_ParseFile(g_hUserParser, g_Filename); + if (err != SMCError_Okay) + { + decl String:buffer[64]; + if (SMC_GetErrorString(err, buffer, sizeof(buffer))) + { + ParseError("%s", buffer); + } else { + ParseError("Fatal parse error"); + } + } +} From 8c8b240617fd8ae7a4c4743dfe34303a9fec3775 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 03:16:44 +0000 Subject: [PATCH 0420/1664] fixed a bug in group reading fixed an error in the group config file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40451 --- configs/admin_groups.cfg | 2 +- plugins/admin-flatfile/admin-groups.sp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/admin_groups.cfg b/configs/admin_groups.cfg index ed4c4142..26f5f16e 100644 --- a/configs/admin_groups.cfg +++ b/configs/admin_groups.cfg @@ -16,7 +16,7 @@ Groups * ":CSDM" "allow" * "csdm_enable" "deny" */ - Commands + Overrides { } "flags" "abcdefghiz" diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index 605c426c..34221286 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -111,7 +111,7 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc, } else { /* If we can't find the group, we'll need to schedule a reparse */ new GroupId:id = FindAdmGroup(value); - if (id == INVALID_GROUP_ID) + if (id != INVALID_GROUP_ID) { SetAdmGroupImmuneFrom(g_CurGrp, id); } else { From 06fa51700fa6c2c2da66a5a1b7ebf3d5f6737af6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 03:34:24 +0000 Subject: [PATCH 0421/1664] tested and fixed a few issues in the flat file reader fixed the admin_levels.cfg file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40452 --- configs/admin_levels.cfg | 58 +++++++++++++++----------- plugins/admin-flatfile/admin-levels.sp | 39 +++++++++-------- plugins/admin-flatfile/admin-users.sp | 2 +- 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/configs/admin_levels.cfg b/configs/admin_levels.cfg index 81d3dc34..140f2cfa 100644 --- a/configs/admin_levels.cfg +++ b/configs/admin_levels.cfg @@ -11,43 +11,51 @@ Levels */ Flags { - "reservation" "a" - "kick" "b" - "ban" "c" - "unban" "d" - "slay" "e" - "changemap" "f" - "cvars" "g" - "config" "h" - "chat" "i" - "vote" "j" - "password" "k" - "rcon" "l" - "cheats" "m" - "custom1" "n" - "custom2" "o" - "custom3" "p" - "custom4" "q" - "custom5" "r" - "custom6" "s" + "reservation" "a" //Reserved slots + "generic" "b" //Generic admin, required for admins + "kick" "c" //Kick other players + "ban" "d" //Banning other players + "unban" "e" //Removing bans + "slay" "f" //Slaying other players + "changemap" "g" //Changing the map + "cvars" "h" //Changing cvars + "config" "i" //Changing configs + "chat" "j" //Special chat privileges + "vote" "k" //Voting + "password" "l" //Password the server + "rcon" "m" //Remote console + "cheats" "n" //Change sv_cheats and related commands - //Custom flags START - //Custom flags END + /** + * Custom flags can be used by plugins, but they can also be used to + * for you to expand on the previous groups, using Overrides. + */ - //Note - root is a magic access flag that grants all permissions. + "custom1" "o" + "custom2" "p" + "custom3" "q" + "custom4" "r" + "custom5" "s" + "custom6" "t" + + /** + * Root is a magic access flag that grants all permissions. + * This should only be given to trusted administrators. + * Root users can only be targetted by other root users. + */ "root" "z" } /** * By default, commands are registered with three pieces of information: * 1)Command Name (for example, "csdm_enable") - * 2)Command Group Name (for example, "CSDM") + * 2)Command Group Name (for example, "CSDM") * 3)Command Level (for example, "changemap") * You can override the default flags assigned to individual commands or command groups in this way. * To override a group, use the "@" character before the name. Example: * Examples: - * "@CSDM" "i" // Override the CSDM group - * "csdm_enable" "j" // Override the csdm_enable command + * "@CSDM" "b" // Override the CSDM group to 'b' flag + * "csdm_enable" "bgi" // Override the csdm_enable command to 'bgi' flags * Note that for overrides, order is important. In the above example, csdm_enable overwrites * any setting that csdm_enable previously had. */ diff --git a/plugins/admin-flatfile/admin-levels.sp b/plugins/admin-flatfile/admin-levels.sp index 6f7171c6..2081c7f7 100644 --- a/plugins/admin-flatfile/admin-levels.sp +++ b/plugins/admin-flatfile/admin-levels.sp @@ -35,24 +35,25 @@ LoadDefaultLetters() } g_FlagLetters['a'-'a'] = Admin_Reservation; - g_FlagLetters['b'-'a'] = Admin_Kick; - g_FlagLetters['c'-'a'] = Admin_Ban; - g_FlagLetters['d'-'a'] = Admin_Unban; - g_FlagLetters['e'-'a'] = Admin_Slay; - g_FlagLetters['f'-'a'] = Admin_Changemap; - g_FlagLetters['g'-'a'] = Admin_Convars; - g_FlagLetters['h'-'a'] = Admin_Config; - g_FlagLetters['i'-'a'] = Admin_Chat; - g_FlagLetters['j'-'a'] = Admin_Vote; - g_FlagLetters['k'-'a'] = Admin_Password; - g_FlagLetters['l'-'a'] = Admin_RCON; - g_FlagLetters['m'-'a'] = Admin_Cheats; - g_FlagLetters['n'-'a'] = Admin_Custom1; - g_FlagLetters['o'-'a'] = Admin_Custom2; - g_FlagLetters['p'-'a'] = Admin_Custom3; - g_FlagLetters['q'-'a'] = Admin_Custom4; - g_FlagLetters['r'-'a'] = Admin_Custom5; - g_FlagLetters['s'-'a'] = Admin_Custom6; + g_FlagLetters['b'-'a'] = Admin_Generic; + g_FlagLetters['c'-'a'] = Admin_Kick; + g_FlagLetters['d'-'a'] = Admin_Ban; + g_FlagLetters['e'-'a'] = Admin_Unban; + g_FlagLetters['f'-'a'] = Admin_Slay; + g_FlagLetters['g'-'a'] = Admin_Changemap; + g_FlagLetters['h'-'a'] = Admin_Convars; + g_FlagLetters['i'-'a'] = Admin_Config; + g_FlagLetters['j'-'a'] = Admin_Chat; + g_FlagLetters['k'-'a'] = Admin_Vote; + g_FlagLetters['l'-'a'] = Admin_Password; + g_FlagLetters['m'-'a'] = Admin_RCON; + g_FlagLetters['n'-'a'] = Admin_Cheats; + g_FlagLetters['o'-'a'] = Admin_Custom1; + g_FlagLetters['p'-'a'] = Admin_Custom2; + g_FlagLetters['q'-'a'] = Admin_Custom3; + g_FlagLetters['r'-'a'] = Admin_Custom4; + g_FlagLetters['s'-'a'] = Admin_Custom5; + g_FlagLetters['t'-'a'] = Admin_Custom6; g_FlagLetters['z'-'a'] = Admin_Root; } @@ -107,6 +108,8 @@ public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const Strin flag = Admin_Reservation; } else if (StrEqual(key, "kick")) { flag = Admin_Kick; + } else if (StrEqual(key, "generic")) { + flag = Admin_Generic; } else if (StrEqual(key, "ban")) { flag = Admin_Ban; } else if (StrEqual(key, "unban")) { diff --git a/plugins/admin-flatfile/admin-users.sp b/plugins/admin-flatfile/admin-users.sp index 49b35499..2dbb57c8 100644 --- a/plugins/admin-flatfile/admin-users.sp +++ b/plugins/admin-flatfile/admin-users.sp @@ -158,7 +158,7 @@ ReadUsers() { InitializeUserParser(); - BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admims.cfg"); + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admins.cfg"); /* Set states */ InitGlobalStates(); From 085264e8373baf17dcdc37faf0417453b87695fb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 08:42:48 +0000 Subject: [PATCH 0422/1664] Execute result pointer is now optional fixed a bug where result could be filled with no executions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40453 --- core/systems/ForwardSys.cpp | 17 +++++++++++------ public/IForwardSys.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 95fd06c6..70536027 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -391,15 +391,20 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) } } - if (m_ExecType == ET_Event || m_ExecType == ET_Hook) + if (success) { - cur_result = high_result; - } else if (m_ExecType == ET_Ignore) { - cur_result = 0; + if (m_ExecType == ET_Event || m_ExecType == ET_Hook) + { + cur_result = high_result; + } else if (m_ExecType == ET_Ignore) { + cur_result = 0; + } + if (result) + { + *result = cur_result; + } } - *result = cur_result; - if (filter) { filter->OnExecuteEnd(&cur_result, success, failed); diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 4fddf472..63e8c5db 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -165,7 +165,7 @@ namespace SourceMod /** * @brief Executes the forward. * - * @param result Pointer to store result in. + * @param result Optional pointer to store result in. * @param filter Optional pointer to an IForwardFilter. * @return Error code, if any. */ From 03fd3139c5e8d68276130c45910ca9723fdaf6d9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 08:44:48 +0000 Subject: [PATCH 0423/1664] added steamid auth functions added better bot detection added gameframe hook for timer renamed more playermanager stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40454 --- core/CPlayerManager.cpp | 159 +++++++++++++++++++++++++++++----- core/CPlayerManager.h | 11 ++- core/sm_stringutil.cpp | 2 +- core/smn_player.cpp | 42 ++++----- core/sourcemm_api.cpp | 3 + core/sourcemm_api.h | 1 + core/sourcemod.cpp | 32 +++++++ core/sourcemod.h | 20 +++-- plugins/include/sourcemod.inc | 9 ++ 9 files changed, 225 insertions(+), 54 deletions(-) diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 65bc9083..2d423a68 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -15,7 +15,7 @@ #include "ForwardSys.h" #include "ShareSys.h" -CPlayerManager g_PlayerManager; +CPlayerManager g_Players; SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int); SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *); @@ -24,6 +24,17 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *) SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int); +CPlayerManager::CPlayerManager() +{ + m_AuthQueue = NULL; + m_FirstPass = true; +} + +CPlayerManager::~CPlayerManager() +{ + delete [] m_AuthQueue; +} + void CPlayerManager::OnSourceModAllInitialized() { SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); @@ -37,28 +48,17 @@ void CPlayerManager::OnSourceModAllInitialized() g_ShareSys.AddInterface(NULL, this); - /* Register OnClientConnect */ ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; - m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1); - - /* Register OnClientPutInServer */ ParamType p2[] = {Param_Cell}; + ParamType p3[] = {Param_Cell, Param_String}; + + m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1); m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2); - - /* Register OnClientDisconnect */ m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2); - - /* Register OnClientDisconnect_Post */ m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2); - - /* Register OnClientCommand */ m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2); - - /* Register OnClientSettingsChanged */ m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); - - /* Register OnClientAuthorized */ - //:TODO: + m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p2); } void CPlayerManager::OnSourceModShutdown() @@ -78,6 +78,7 @@ void CPlayerManager::OnSourceModShutdown() g_Forwards.ReleaseForward(m_cldisconnect_post); g_Forwards.ReleaseForward(m_clcommand); g_Forwards.ReleaseForward(m_clinfochanged); + g_Forwards.ReleaseForward(m_clauth); delete [] m_Players; } @@ -90,7 +91,79 @@ void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int c m_maxClients = clientMax; m_PlayerCount = 0; m_Players = new CPlayer[m_maxClients + 1]; + m_AuthQueue = new unsigned int[m_maxClients + 1]; m_FirstPass = false; + + memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1)); + } +} + +void CPlayerManager::RunAuthChecks() +{ + CPlayer *pPlayer; + const char *authstr; + unsigned int removed = 0; + for (unsigned int i=1; i<=m_AuthQueue[0]; i++) + { + pPlayer = GetPlayerByIndex(m_AuthQueue[i]); + authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict); + if (authstr && authstr[0] != '\0' + && (strcmp(authstr, "STEAM_ID_PENDING") != 0)) + { + /* Set authorization */ + pPlayer->m_AuthID.assign(authstr); + pPlayer->m_IsAuthorized = true; + + /* Send to extensions */ + List::iterator iter; + IClientListener *pListener; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientAuthorized(m_AuthQueue[i], authstr); + } + + /* Send to plugins */ + if (m_clauth->GetFunctionCount()) + { + m_clauth->PushCell(m_AuthQueue[i]); + m_clauth->PushString(authstr); + m_clauth->Execute(NULL); + } + + /* Mark as removed from queue */ + m_AuthQueue[i] = 0; + removed++; + } + } + + /* Clean up the queue */ + if (removed) + { + /* We don't have to compcat the list if it's empty */ + if (removed != m_AuthQueue[0]) + { + unsigned int diff = 0; + for (unsigned int i=1; i<=m_AuthQueue[0]; i++) + { + /* If this member is removed... */ + if (m_AuthQueue[i] == 0) + { + /* Increase the differential */ + diff++; + } else { + /* diff cannot increase faster than i+1 */ + assert(i > diff); + assert(i - diff >= 1); + /* move this index down */ + m_AuthQueue[i - diff] = m_AuthQueue[i]; + } + } + m_AuthQueue[0] -= removed; + } else { + m_AuthQueue[0] = 0; + g_SourceMod.SetAuthChecking(false); + } } } @@ -117,6 +190,12 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons m_clconnect->PushCell(maxrejectlen); m_clconnect->Execute(&res, NULL); + if (res) + { + m_AuthQueue[++m_AuthQueue[0]] = client; + g_SourceMod.SetAuthChecking(true); + } + return (res) ? true : false; } @@ -143,6 +222,25 @@ void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playernam cell_t res; int client = engine->IndexOfEdict(pEntity); + CPlayer *pPlayer = GetPlayerByIndex(client); + if (!pPlayer->IsConnected()) + { + /* Run manual connection routines */ + char error[255]; + if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error))) + { + /* :TODO: kick the bot if it's rejected */ + return; + } + List::iterator iter; + IClientListener *pListener = NULL; + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientConnected(client); + } + } + List::iterator iter; IClientListener *pListener = NULL; for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) @@ -186,6 +284,27 @@ void CPlayerManager::OnClientDisconnect(edict_t *pEntity) pListener->OnClientDisconnecting(client); } + /** + * Remove client from auth queue if necessary + */ + if (!m_Players[client].IsAuthorized()) + { + for (unsigned int i=1; i<=m_AuthQueue[0]; i++) + { + if (m_AuthQueue[i] == client) + { + /* Move everything ahead of us back by one */ + for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++) + { + m_AuthQueue[j-1] = m_AuthQueue[j]; + } + /* Remove us and break */ + m_AuthQueue[0]--; + break; + } + } + } + m_Players[client].Disconnect(); } @@ -275,7 +394,7 @@ CPlayer::CPlayer() m_IsConnected = false; m_IsInGame = false; m_IsAuthorized = false; - m_PlayerEdict = NULL; + m_pEdict = NULL; } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -283,7 +402,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) m_IsConnected = true; m_Name.assign(name); m_Ip.assign(ip); - m_PlayerEdict = pEntity; + m_pEdict = pEntity; } void CPlayer::Connect() @@ -305,7 +424,7 @@ void CPlayer::Disconnect() m_Name.clear(); m_Ip.clear(); m_AuthID.clear(); - m_PlayerEdict = NULL; + m_pEdict = NULL; } void CPlayer::SetName(const char *name) @@ -330,7 +449,7 @@ const char *CPlayer::GetAuthString() const edict_t *CPlayer::GetEdict() const { - return m_PlayerEdict; + return m_pEdict; } bool CPlayer::IsInGame() const diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index 2a2201d1..4ef1ace9 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -21,6 +21,7 @@ #include #include #include +#include using namespace SourceHook; @@ -51,7 +52,7 @@ private: String m_Name; String m_Ip; String m_AuthID; - edict_t *m_PlayerEdict; + edict_t *m_pEdict; }; class CPlayerManager : @@ -59,12 +60,14 @@ class CPlayerManager : public IPlayerManager { public: - CPlayerManager() : m_FirstPass(true) {} + CPlayerManager(); + ~CPlayerManager(); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: CPlayer *GetPlayerByIndex(int client) const; + void RunAuthChecks(); public: bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); @@ -100,12 +103,14 @@ private: IForward *m_clputinserver; IForward *m_clcommand; IForward *m_clinfochanged; + IForward *m_clauth; CPlayer *m_Players; int m_maxClients; int m_PlayerCount; bool m_FirstPass; + unsigned int *m_AuthQueue; }; -extern CPlayerManager g_PlayerManager; +extern CPlayerManager g_Players; #endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 83d2b40d..1839fa5c 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -72,7 +72,7 @@ try_serverlang: pCtx->ThrowNativeError("Translation failure: English language not found."); goto error_out; } - } else if ((target >= 1) && (target <= g_PlayerManager.GetMaxClients())) { + } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { langname = "en"; //:TODO: read player's lang if (!langname || !g_Translator.GetLanguageByCode(langname, &langid)) { diff --git a/core/smn_player.cpp b/core/smn_player.cpp index ac1c8873..0d46b02b 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -18,37 +18,37 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) { if (params[1]) { - return g_PlayerManager.NumPlayers(); + return g_Players.NumPlayers(); } - int maxplayers = g_PlayerManager.MaxClients(); + int maxplayers = g_Players.MaxClients(); int count = 0; for (int i=1; i<=maxplayers; ++i) { - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(i); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(i); if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame())) { count++; } } - return (g_PlayerManager.NumPlayers() + count); + return (g_Players.NumPlayers() + count); } static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params) { - return g_PlayerManager.MaxClients(); + return g_Players.MaxClients(); } static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); @@ -61,12 +61,12 @@ static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); @@ -87,12 +87,12 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); @@ -105,45 +105,45 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0; + return (g_Players.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0; } static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0; + return (g_Players.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0; } static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - return (g_PlayerManager.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0; + return (g_Players.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0; } static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { return pCtx->ThrowNativeError("Client %d is not connected.", index); @@ -172,12 +172,12 @@ static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_PlayerManager.GetMaxClients())) + if ((index < 1) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d.", index); } - CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsInGame()) { return pCtx->ThrowNativeError("Client %d is not in game.", index); diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 1bbd5f0b..bb3af1a3 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -21,6 +21,7 @@ IVEngineServer *engine = NULL; IServerGameDLL *gamedll = NULL; IServerGameClients *serverClients = NULL; ISmmPluginManager *g_pMMPlugins = NULL; +CGlobalVars *gpGlobals = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -41,6 +42,8 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen return false; } + gpGlobals = ismm->pGlobals(); + return g_SourceMod.InitializeSourceMod(error, maxlen, late); } diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 12e6cf3b..6b1842e3 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -45,6 +45,7 @@ extern IVEngineServer *engine; extern IServerGameDLL *gamedll; extern IServerGameClients *serverClients; extern ISmmPluginManager *g_pMMPlugins; +extern CGlobalVars *gpGlobals; PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index a09ccbc5..72e57d91 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -23,9 +23,11 @@ #include "ExtensionSys.h" #include "AdminCache.h" #include "sm_stringutil.h" +#include "CPlayerManager.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); +SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool); SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -35,6 +37,8 @@ SourceHook::String g_BaseDir; ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; IVirtualMachine *g_pVM; IdentityToken_t *g_pCoreIdent = NULL; +float g_LastTime = 0.0f; +float g_LastAuthCheck = 0.0f; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef unsigned int (*GETEXPORTCOUNT)(); @@ -150,6 +154,7 @@ void SourceModBase::StartSourceMod(bool late) /* First initialize the global hooks we need */ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -178,6 +183,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch { m_IsMapLoading = true; m_ExecPluginReload = true; + g_LastTime = 0.0f; + g_LastAuthCheck = 0.0f; g_Logger.MapChange(pMapName); @@ -191,6 +198,25 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch RETURN_META_VALUE(MRES_IGNORED, true); } +void SourceModBase::GameFrame(bool simulating) +{ + /** + * Note: This is all hardcoded rather than delegated to save + * precious CPU cycles. + */ + float curtime = gpGlobals->curtime; + if (curtime - g_LastTime > 0.1f) + { + if (m_CheckingAuth + && (gpGlobals->curtime - g_LastAuthCheck > 0.7f)) + { + g_LastAuthCheck = gpGlobals->curtime; + g_Players.RunAuthChecks(); + } + g_LastTime = curtime; + } +} + void SourceModBase::LevelShutdown() { if (m_ExecPluginReload) @@ -280,6 +306,7 @@ void SourceModBase::CloseSourceMod() SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); /* Rest In Peace */ ShutdownJIT(); @@ -349,6 +376,11 @@ void SourceModBase::SetGlobalTarget(unsigned int index) m_target = index; } +void SourceModBase::SetAuthChecking(bool set) +{ + m_CheckingAuth = set; +} + unsigned int SourceModBase::GetGlobalTarget() const { return m_target; diff --git a/core/sourcemod.h b/core/sourcemod.h index bbe290a2..a906b759 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -37,8 +37,8 @@ public: void StartSourceMod(bool late); /** - * @brief Shuts down all SourceMod components - */ + * @brief Shuts down all SourceMod components + */ void CloseSourceMod(); /** @@ -47,8 +47,8 @@ public: bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); /** - * @brief Level shutdown hook - */ + * @brief Level shutdown hook + */ void LevelShutdown(); /** @@ -57,15 +57,14 @@ public: bool IsMapLoading(); /** - * @brief Stores the global target index. - */ + * @brief Stores the global target index. + */ void SetGlobalTarget(unsigned int index); /** - * @brief Returns the global target index. - */ + * @brief Returns the global target index. + */ unsigned int GetGlobalTarget() const; - public: //ISourceMod const char *GetModPath(); const char *GetSourceModPath(); @@ -73,17 +72,20 @@ public: //ISourceMod void LogMessage(IExtension *pExt, const char *format, ...); void LogError(IExtension *pExt, const char *format, ...); size_t FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param); + void SetAuthChecking(bool set); private: /** * @brief Loading plugins */ void DoGlobalPluginLoads(); + void GameFrame(bool simulating); private: char m_SMBaseDir[PLATFORM_MAX_PATH+1]; char m_SMRelDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; bool m_ExecPluginReload; unsigned int m_target; + bool m_CheckingAuth; }; extern SourceModBase g_SourceMod; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 33876e00..21fcd148 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -136,6 +136,15 @@ forward OnClientCommand(client); */ forward OnClientSettingsChanged(client); +/** + * Called when a client receives a Steam ID. + * @note This is called by bots, but the ID will be "BOT" + * + * @param client Player index. + * @param auth Player auth string. + */ +forward OnClientAuthorized(client, const String:auth[]); + /** * Returns the maximum number of clients allowed on the server. * From 4ad7f36207f1f77e8281b03655494394b03925f1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 19:30:53 +0000 Subject: [PATCH 0424/1664] fixed auth string being returned as true if not available --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40455 --- core/smn_player.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 0d46b02b..76ef0750 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -98,7 +98,13 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Client %d is not connected.", index); } + if (!pPlayer->IsAuthorized()) + { + return 0; + } + pCtx->StringToLocal(params[2], static_cast(params[3]), pPlayer->GetAuthString()); + return 1; } From 6908858807415cb638439e835d551f454a837486 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Feb 2007 19:34:58 +0000 Subject: [PATCH 0425/1664] fixed a bug where mapupdated plugins would not get unloaded on deletion --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40456 --- core/systems/PluginSys.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 95cded30..d941ef0e 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -478,7 +478,6 @@ time_t CPlugin::GetFileTimeStamp() if (stat(path, &s) != 0) #endif { - g_Logger.LogError("Could not obtain plugin time stamp, error: %d", errno); return 0; } else { return s.st_mtime; @@ -1625,12 +1624,8 @@ void CPluginManager::ReloadOrUnloadPlugins() { UnloadPlugin((IPlugin *)pl); } else if (pl->GetType() == PluginType_MapUpdated) { - t=pl->GetFileTimeStamp(); - if (!t) - { - continue; - } - if (t > pl->GetTimeStamp()) + t = pl->GetFileTimeStamp(); + if (!t || t > pl->GetTimeStamp()) { pl->SetTimeStamp(t); UnloadPlugin((IPlugin *)pl); From d2887a8c3da79ba4d19ccfa250a58ae5c2581a03 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 8 Feb 2007 01:10:48 +0000 Subject: [PATCH 0426/1664] fixed the parameter order here --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40457 --- plugins/include/string.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 6c715484..b87503cd 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -135,12 +135,12 @@ native StringToInt(const String:str[], nBase=10); /** * Converts an integer to a string. * + * @param num Integer to convert. * @param str Buffer to store string in. * @param maxlength Maximum length of string buffer. - * @param num Integer to convert. * @return Number of cells written to buffer. */ -native IntToString(String:str[], maxlength, num); +native IntToString(num, String:str[], maxlength); /** * Converts a string to a floating point number. From 7a29aad6fa0f817fe5f8b0e13ce3cc375c0b5f45 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 8 Feb 2007 01:11:09 +0000 Subject: [PATCH 0427/1664] removed an old todo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40458 --- core/CPlayerManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 2d423a68..eb23cd26 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -331,8 +331,6 @@ void CPlayerManager::OnClientCommand(edict_t *pEntity) m_clcommand->PushCell(engine->IndexOfEdict(pEntity)); m_clcommand->Execute(&res, NULL); - - //:TODO: res should be evaluated here for something, DOCUMENT this in the INC FILE! } void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) From 67c76a9380fde6474510f05bed41c8905b63ece9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 8 Feb 2007 01:11:45 +0000 Subject: [PATCH 0428/1664] added gameevents to the publicly available interfaces --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40459 --- core/sourcemm_api.cpp | 2 ++ core/sourcemm_api.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index bb3af1a3..bc53626f 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -22,6 +22,7 @@ IServerGameDLL *gamedll = NULL; IServerGameClients *serverClients = NULL; ISmmPluginManager *g_pMMPlugins = NULL; CGlobalVars *gpGlobals = NULL; +IGameEventManager2 *gameevents = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -32,6 +33,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); + GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL) { diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 6b1842e3..a6627af6 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -16,6 +16,7 @@ #include #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -46,6 +47,7 @@ extern IServerGameDLL *gamedll; extern IServerGameClients *serverClients; extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; +extern IGameEventManager2 *gameevents; PLUGIN_GLOBALVARS(); From db676e8bfce9124ce940fba55904a6fbc89e36d8 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 8 Feb 2007 04:53:56 +0000 Subject: [PATCH 0429/1664] Corrected parameter order for FloatToString --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40460 --- plugins/include/string.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index b87503cd..b8dd34d4 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -153,9 +153,9 @@ native Float:StringToFloat(const String:str[]); /** * Converts a floating point number to a string. * + * @param num Floating point number to convert. * @param str Buffer to store string in. * @param maxlength Maximum length of string buffer. - * @param num Floating point number to convert. * @return Number of cells written to buffer. */ -native FloatToString(String:str[], maxlength, Float:num); +native FloatToString(Float:num, String:str[], maxlength); From 130004894616c93215d6a73f7755626559aa930b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 8 Feb 2007 04:56:08 +0000 Subject: [PATCH 0430/1664] Typo fix and removal of a semicolon in the name of consistency? --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40461 --- core/sm_globals.h | 2 +- public/IDataPack.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sm_globals.h b/core/sm_globals.h index 7d65b1f8..73a5018a 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -57,7 +57,7 @@ public: } /** - * @brief Called after SourceMod is completely shutted down + * @brief Called after SourceMod is completely shut down */ virtual void OnSourceModAllShutdown() { diff --git a/public/IDataPack.h b/public/IDataPack.h index b2394eab..1cc0446e 100644 --- a/public/IDataPack.h +++ b/public/IDataPack.h @@ -134,6 +134,6 @@ namespace SourceMod */ virtual size_t CreateMemory(size_t size, void **addr) =0; }; -}; +} #endif //_INCLUDE_SOURCEMOD_INTERFACE_DATAPACK_H_ From 471da79fa5d2e5eb3f42acb778bda70e69a2f82e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 8 Feb 2007 20:37:24 +0000 Subject: [PATCH 0431/1664] added a wrapper for getclientconvarvalue fixed a bug in the player manager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40462 --- core/CPlayerManager.cpp | 2 +- core/smn_player.cpp | 27 +++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index eb23cd26..53e240b6 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -350,7 +350,7 @@ int CPlayerManager::GetMaxClients() CPlayer *CPlayerManager::GetPlayerByIndex(int client) const { - if (client > m_maxClients || client < 0) + if (client > m_maxClients || client < 1) { return NULL; } diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 76ef0750..804a0a17 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -175,6 +175,32 @@ static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t sm_GetClientInfo(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + char *key; + pContext->LocalToString(params[2], &key); + + const char *val = engine->GetClientConVarValue(client, key); + if (!val) + { + return false; + } + + pContext->StringToLocalUTF8(params[3], params[4], val, NULL); + return 1; +} + static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; @@ -217,6 +243,7 @@ REGISTER_NATIVES(playernatives) {"IsPlayerFakeClient", sm_IsPlayerFakeClient}, {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, + {"GetClientInfo", sm_GetClientInfo}, {NULL, NULL} }; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 21fcd148..3aa2a633 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -226,6 +226,17 @@ native bool:IsPlayerAuthorized(client); */ native bool:IsPlayerFakeClient(client); +/** + * Retrieves values from client replicated keys. + * + * @param client Player's index. + * @param key Key string. + * @param value Buffer to store value. + * @param maxlen Maximum length of valve (UTF-8 safe). + * @return True on success, false otherwise. + */ +native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); + /** * Sends a message to the server console. * From fdba3e1f66fe8365306a63fab507f82dfc781ba0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 8 Feb 2007 21:41:28 +0000 Subject: [PATCH 0432/1664] Initial import of convar stuff 1) Natives to create, find, set, and get convars 2) "cvars" option added to sm menu 3) Some internal additions to CPlugin to store a convar list Still some things left to do... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40463 --- core/CConVarManager.cpp | 160 ++++++++++ core/CConVarManager.h | 54 ++++ core/convar_sm.h | 529 +++++++++++++++++++++++++++++++++ core/msvc8/sourcemod_mm.vcproj | 20 ++ core/sm_srvcmds.h | 1 - core/sm_stringutil.cpp | 2 +- core/smn_convar.cpp | 293 ++++++++++++++++++ core/sourcemm_api.cpp | 2 + core/sourcemm_api.h | 3 + core/systems/PluginSys.cpp | 17 +- core/systems/PluginSys.h | 27 +- plugins/include/console.inc | 201 +++++++++++++ plugins/include/sourcemod.inc | 1 + 13 files changed, 1306 insertions(+), 4 deletions(-) create mode 100644 core/CConVarManager.cpp create mode 100644 core/CConVarManager.h create mode 100644 core/convar_sm.h create mode 100644 core/smn_convar.cpp create mode 100644 plugins/include/console.inc diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp new file mode 100644 index 00000000..185ecab0 --- /dev/null +++ b/core/CConVarManager.cpp @@ -0,0 +1,160 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "CConVarManager.h" +#include "CLogger.h" +#include "PluginSys.h" +#include "sm_srvcmds.h" + +CConVarManager g_ConVarManager; + +CConVarManager::CConVarManager() +{ + m_ConVarType = 0; + m_CvarCache = sm_trie_create(); +} + +CConVarManager::~CConVarManager() +{ + sm_trie_destroy(m_CvarCache); +} + +void CConVarManager::OnSourceModAllInitialized() +{ + HandleAccess sec; + + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; + + m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); + + g_RootMenu.AddRootConsoleCommand("cvars", "View convars associated with a plugin", this); +} + +void CConVarManager::OnSourceModShutdown() +{ + g_RootMenu.RemoveRootConsoleCommand("cvars", this); + + g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); +} + +void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) +{ + g_SMAPI->UnregisterConCmdBase(g_PLAPI, static_cast(object)); +} + +void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ + if (argcount >= 3) + { + int id = 1; + + int num = atoi(g_RootMenu.GetArgument(2)); + + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + g_RootMenu.ConsolePrint("[SM] Plugin index not found."); + return; + } + + CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + int convarnum = pl->GetConVarCount(); + + if (convarnum == 0) + { + g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); + return; + } + + g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); + + for (int i = 0; i < convarnum; i++, id++) + { + ConVar *cvar = pl->GetConVarByIndex(i); + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); + } + + return; + } + + g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); +} + +Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) +{ + ConVar *cvar = NULL; + void *temp = NULL; + Handle_t hndl = 0; + + // Find out if the convar exists already + cvar = icvar->FindVar(name); + + // If the convar already exists... + if (cvar != NULL) + { + IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); + + // This isn't a fatal error because we can handle it, but user should be warned anyways + g_Logger.LogError("[SM] Warning: Plugin \"%s\" has attempted to create already existing convar \"%s\"", pl->GetFilename(), name); + + // First check if we already have a handle to it + if (sm_trie_retrieve(m_CvarCache, name, &temp)) + { + // If we do, then return that handle + return reinterpret_cast(temp); + } else { + // If we don't, then create a new handle from the convar and return it + return g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + } + } + + // Since we didn't find an existing convar, now we can create it + cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); + + // Add new convar to plugin's list + g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); + + // Create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + // Insert the handle into our cache + sm_trie_insert(m_CvarCache, name, reinterpret_cast(hndl)); + + return hndl; +} + +Handle_t CConVarManager::FindConVar(const char *name) +{ + ConVar *cvar = NULL; + void *temp = NULL; + + // Search for convar + cvar = icvar->FindVar(name); + + // If it doesn't exist, then return an invalid handle + if (cvar == NULL) + { + return BAD_HANDLE; + } + + // At this point, convar exists, so find out if we already have a handle for it + if (sm_trie_retrieve(m_CvarCache, name, &temp)) + { + // If we do, then return that handle + return reinterpret_cast(temp); + } + + // If we don't, then create a new handle from the convar and return it + return g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); +} \ No newline at end of file diff --git a/core/CConVarManager.h b/core/CConVarManager.h new file mode 100644 index 00000000..e3574932 --- /dev/null +++ b/core/CConVarManager.h @@ -0,0 +1,54 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "HandleSys.h" +#include "sm_trie.h" +#include + +class CConVarManager : + public SMGlobalClass, + public IHandleTypeDispatch, + public IRootConsoleCommand +{ +public: + CConVarManager(); + ~CConVarManager(); +public: // SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: // IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: //IRootConsoleCommand + void OnRootConsoleCommand(const char *command, unsigned int argcount); +public: + inline HandleType_t GetHandleType() + { + return m_ConVarType; + } +public: + Handle_t CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, + int flags, bool hasMin, float min, bool hasMax, float max); + Handle_t FindConVar(const char* name); +private: + HandleType_t m_ConVarType; + Trie *m_CvarCache; +}; + +extern CConVarManager g_ConVarManager; + +#endif // _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ \ No newline at end of file diff --git a/core/convar_sm.h b/core/convar_sm.h new file mode 100644 index 00000000..01f51e9e --- /dev/null +++ b/core/convar_sm.h @@ -0,0 +1,529 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: 2006-08-13 06:34:30 -0500 (Sun, 13 Aug 2006) $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//=============================================================================// + +#ifndef CONVAR_H +#define CONVAR_H +#if _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" + +#ifdef _WIN32 +#define FORCEINLINE_CVAR FORCEINLINE +#elif _LINUX +#define FORCEINLINE_CVAR __inline__ FORCEINLINE +#else +#error "implement me" +#endif + +// The default, no flags at all +#define FCVAR_NONE 0 + +// Command to ConVars and ConCommands +// ConVar Systems +#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. +#define FCVAR_LAUNCHER (1<<1) // defined by launcher +#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL +#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL +#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system. +#define FCVAR_DATACACHE (1<<19) // Defined by the datacache system. +#define FCVAR_STUDIORENDER (1<<15) // Defined by the studiorender system. +#define FCVAR_FILESYSTEM (1<<21) // Defined by the file system. +#define FCVAR_PLUGIN (1<<18) // Defined by a 3rd party plugin. +#define FCVAR_TOOLSYSTEM (1<<20) // Defined by an IToolSystem library +#define FCVAR_SOUNDSYSTEM (1<<23) // Defined by the soundsystem library +#define FCVAR_INPUTSYSTEM (1<<25) // Defined by the inputsystem dll +#define FCVAR_NETWORKSYSTEM (1<<26) // Defined by the network system +// NOTE!! if you add a cvar system, add it here too!!!! +// the engine lacks a cvar flag, but needs it for xbox +// an engine cvar is thus a cvar not marked with any other system +#define FCVAR_NON_ENGINE ((FCVAR_LAUNCHER|FCVAR_GAMEDLL|FCVAR_CLIENTDLL|FCVAR_MATERIAL_SYSTEM|FCVAR_DATACACHE|FCVAR_STUDIORENDER|FCVAR_FILESYSTEM|FCVAR_PLUGIN|FCVAR_TOOLSYSTEM|FCVAR_SOUNDSYSTEM|FCVAR_INPUTSYSTEM|FCVAR_NETWORKSYSTEM)) + +// ConVar only +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc +#define FCVAR_NOTIFY (1<<8) // notifies players when changed +#define FCVAR_USERINFO (1<<9) // changes the client's info string +#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats + +#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar + +// It's a ConVar that's shared between the client and the server. +// At signon, the values of all such ConVars are sent from the server to the client (skipped for local +// client, of course ) +// If a change is requested it must come from the console (i.e., no remote client changes) +// If a value is changed while a server is active, it's replicated to all connected clients +#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time +#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file +#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles + +#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server + +#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox + + +// #define FCVAR_AVAILABLE (1<<27) +// #define FCVAR_AVAILABLE (1<<28) +// #define FCVAR_AVAILABLE (1<<29) +// #define FCVAR_AVAILABLE (1<<30) +// #define FCVAR_AVAILABLE (1<<31) + + +class ConVar; +class ConCommand; +class ConCommandBase; + +// Any executable that wants to use ConVars need to implement one of +// these to hook up access to console variables. +class IConCommandBaseAccessor +{ +public: + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase( ConCommandBase *pVar )=0; +}; + + +// You don't have to instantiate one of these, just call its +// OneTimeInit function when your executable is initializing. +class ConCommandBaseMgr +{ +public: + // Call this ONCE when the executable starts up. + static void OneTimeInit( IConCommandBaseAccessor *pAccessor ); +#ifdef _XBOX + static bool Fixup( ConCommandBase* pConCommandBase ); +#ifndef _RETAIL + static void PublishCommands( bool bForce ); +#endif +#endif +}; + +// Called when a ConVar changes value +typedef void ( *FnChangeCallback )( ConVar *var, char const *pOldString ); + +// Called when a ConCommand needs to execute +typedef void ( *FnCommandCallback )( void ); + +#define COMMAND_COMPLETION_MAXITEMS 64 +#define COMMAND_COMPLETION_ITEM_LENGTH 64 + +// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings +typedef int ( *FnCommandCompletionCallback )( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- +class ConCommandBase +{ + friend class ConCommandBaseMgr; + friend class CCvar; + friend class ConVar; + friend class ConCommand; + +public: + ConCommandBase( void ); + ConCommandBase( char const *pName, char const *pHelpString = 0, + int flags = 0 ); + + virtual ~ConCommandBase( void ); + + virtual bool IsCommand( void ) const; + + // Check flag + virtual bool IsBitSet( int flag ) const; + // Set flag + virtual void AddFlags( int flags ); + + // Return name of cvar + virtual char const *GetName( void ) const; + + // Return help text for cvar + virtual char const *GetHelpText( void ) const; + + // Deal with next pointer + const ConCommandBase *GetNext( void ) const; + void SetNext( ConCommandBase *next ); + + virtual bool IsRegistered( void ) const; + + // Global methods + static ConCommandBase const *GetCommands( void ); + static void AddToList( ConCommandBase *var ); + static void RemoveFlaggedCommands( int flag ); + static void RevertFlaggedCvars( int flag ); + static ConCommandBase const *FindCommand( char const *name ); + +protected: + virtual void Create( char const *pName, char const *pHelpString = 0, + int flags = 0 ); + + // Used internally by OneTimeInit to initialize. + virtual void Init(); + + // Internal copy routine ( uses new operator from correct module ) + char *CopyString( char const *from ); + + // Next ConVar in chain + ConCommandBase *m_pNext; + +private: + // Has the cvar been added to the global list? + bool m_bRegistered; + + // Static data + char const *m_pszName; + char const *m_pszHelpString; + + // ConVar flags + int m_nFlags; + +protected: + + // ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through + // all the console variables and registers them. + static ConCommandBase *s_pConCommandBases; + + // ConVars in this executable use this 'global' to access values. + static IConCommandBaseAccessor *s_pAccessor; + +public: // Hackalicous + int GetFlags() { return m_nFlags; } + void SetFlags(int flags) { m_nFlags = flags; } +}; + +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- +class ConCommand : public ConCommandBase +{ +friend class ConCommandBaseMgr; +friend class CCvar; +#ifdef _STATIC_LINKED +friend class G_ConCommand; +friend class C_ConCommand; +friend class M_ConCommand; +friend class S_ConCommand; +friend class D_ConCommand; +#endif + +public: + typedef ConCommandBase BaseClass; + + ConCommand( void ); + ConCommand( char const *pName, FnCommandCallback callback, + char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + + virtual ~ConCommand( void ); + + virtual bool IsCommand( void ) const; + + virtual int AutoCompleteSuggest( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); + + virtual bool CanAutoComplete( void ); + + // Invoke the function + virtual void Dispatch( void ); +private: + virtual void Create( char const *pName, FnCommandCallback callback, + char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + + // Call this function when executing the command + FnCommandCallback m_fnCommandCallback; + + FnCommandCompletionCallback m_fnCompletionCallback; + bool m_bHasCompletionCallback; +public: // Hackalicous + FnCommandCallback GetCallback() { return m_fnCommandCallback; } +}; + +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- +class ConVar : public ConCommandBase +{ +friend class ConCommandBaseMgr; +friend class CCvar; +friend class CDefaultCvar; +#ifdef _STATIC_LINKED +friend class G_ConVar; +friend class C_ConVar; +friend class M_ConVar; +friend class S_ConVar; +friend class D_ConVar; +#endif + +public: + typedef ConCommandBase BaseClass; + + ConVar( char const *pName, char const *pDefaultValue, int flags = 0); + + ConVar( char const *pName, char const *pDefaultValue, int flags, + char const *pHelpString ); + ConVar( char const *pName, char const *pDefaultValue, int flags, + char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ); + ConVar( char const *pName, char const *pDefaultValue, int flags, + char const *pHelpString, FnChangeCallback callback ); + ConVar( char const *pName, char const *pDefaultValue, int flags, + char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, + FnChangeCallback callback ); + + virtual ~ConVar( void ); + + virtual bool IsBitSet( int flag ) const; + virtual char const* GetHelpText( void ) const; + virtual bool IsRegistered( void ) const; + virtual char const *GetName( void ) const; + virtual void AddFlags( int flags ); + virtual bool IsCommand( void ) const; + + // Install a change callback (there shouldn't already be one....) + void InstallChangeCallback( FnChangeCallback callback ); + + // Retrieve value + FORCEINLINE_CVAR float GetFloat( void ) const; + FORCEINLINE_CVAR int GetInt( void ) const; + FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } + FORCEINLINE_CVAR char const *GetString( void ) const; + + // Any function that allocates/frees memory needs to be virtual or else you'll have crashes + // from alloc/free across dll/exe boundaries. + + // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue). + virtual void SetValue( char const *value ); + virtual void SetValue( float value ); + virtual void SetValue( int value ); + + // Reset to default value + void Revert( void ); + + // True if it has a min/max setting + bool GetMin( float& minVal ) const; + bool GetMax( float& maxVal ) const; + char const *GetDefault( void ) const; + + static void RevertAll( void ); +private: + // Called by CCvar when the value of a var is changing. + virtual void InternalSetValue(char const *value); + // For CVARs marked FCVAR_NEVER_AS_STRING + virtual void InternalSetFloatValue( float fNewValue ); + virtual void InternalSetIntValue( int nValue ); + + virtual bool ClampValue( float& value ); + virtual void ChangeStringValue( char const *tempVal ); + + virtual void Create( char const *pName, char const *pDefaultValue, int flags = 0, + char const *pHelpString = 0, bool bMin = false, float fMin = 0.0, + bool bMax = false, float fMax = false, FnChangeCallback callback = 0 ); + + // Used internally by OneTimeInit to initialize. + virtual void Init(); + +private: + + // This either points to "this" or it points to the original declaration of a ConVar. + // This allows ConVars to exist in separate modules, and they all use the first one to be declared. + // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar). + ConVar *m_pParent; + + // Static data + char const *m_pszDefaultValue; + + // Value + // Dynamically allocated + char *m_pszString; + int m_StringLength; + + // Values + float m_fValue; + int m_nValue; + + // Min/Max values + bool m_bHasMin; + float m_fMinVal; + bool m_bHasMax; + float m_fMaxVal; + + // Call this function when ConVar changes + FnChangeCallback m_fnChangeCallback; +public: // Hackalicous + FnChangeCallback GetCallback() { return m_fnChangeCallback; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +// Output : float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float ConVar::GetFloat( void ) const +{ + return m_pParent->m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int ConVar::GetInt( void ) const +{ + return m_pParent->m_nValue; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +// Output : char const * +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR char const *ConVar::GetString( void ) const +{ + if ( m_nFlags & FCVAR_NEVER_AS_STRING ) + { + return "FCVAR_NEVER_AS_STRING"; + } + + return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : ""; +} + + +#ifdef _STATIC_LINKED +// identifies subsystem via piggybacking constructors with flags +class G_ConCommand : public ConCommand +{ +public: + G_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_GAMEDLL, completionFunc) {} +}; + +class C_ConCommand : public ConCommand +{ +public: + C_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_CLIENTDLL, completionFunc) {} +}; + +class M_ConCommand : public ConCommand +{ +public: + M_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_MATERIAL_SYSTEM, completionFunc) {} +}; + +class S_ConCommand : public ConCommand +{ +public: + S_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_STUDIORENDER, completionFunc) {} +}; + +class D_ConCommand : public ConCommand +{ +public: + D_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_DATACACHE, completionFunc) {} +}; + +typedef void ( *G_FnChangeCallback )( G_ConVar *var, char const *pOldString ); +typedef void ( *C_FnChangeCallback )( C_ConVar *var, char const *pOldString ); +typedef void ( *M_FnChangeCallback )( M_ConVar *var, char const *pOldString ); +typedef void ( *S_FnChangeCallback )( S_ConVar *var, char const *pOldString ); +typedef void ( *D_FnChangeCallback )( D_ConVar *var, char const *pOldString ); + +class G_ConVar : public ConVar +{ +public: + G_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL) {} + G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString ) {} + G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax) {} + G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, (FnChangeCallback)callback ) {} + G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {} +}; + +class C_ConVar : public ConVar +{ +public: + C_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL) {} + C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString ) {} + C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax) {} + C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, (FnChangeCallback)callback ) {} + C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {} +}; + +class M_ConVar : public ConVar +{ +public: + M_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM) {} + M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString ) {} + M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax) {} + M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, (FnChangeCallback)callback ) {} + M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {} +}; + +class S_ConVar : public ConVar +{ +public: + S_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER) {} + S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString ) {} + S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax) {} + S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, (FnChangeCallback)callback ) {} + S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, S_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {} +}; + +class D_ConVar : public ConVar +{ +public: + D_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE) {} + D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString ) {} + D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax) {} + D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, (FnChangeCallback)callback ) {} + D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, D_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {} +}; + +// redirect these declarations to their specific subsystem +#ifdef GAME_DLL +#define ConCommand G_ConCommand +#define ConVar G_ConVar +#endif +#ifdef CLIENT_DLL +#define ConCommand C_ConCommand +#define ConVar C_ConVar +#endif +#ifdef MATERIALSYSTEM_DLL +#define ConCommand M_ConCommand +#define ConVar M_ConVar +#endif +#ifdef STUDIORENDER_DLL +#define ConCommand S_ConCommand +#define ConVar S_ConVar +#endif +#ifdef DATACACHE_DLL +#define ConCommand D_ConCommand +#define ConVar D_ConVar +#endif +#endif // _STATIC_LINKED + +//----------------------------------------------------------------------------- +// Purpose: Utility to quicky generate a simple console command +//----------------------------------------------------------------------------- +#define CON_COMMAND( name, description ) \ + static void name(); \ + static ConCommand name##_command( #name, name, description ); \ + static void name() + +//----------------------------------------------------------------------------- +// Purpose: Utility to quicky generate a simple console command +//----------------------------------------------------------------------------- +#define CON_COMMAND_F( name, description, flags ) \ + static void name(); \ + static ConCommand name##_command( #name, name, description, flags ); \ + static void name() + + +#endif // CONVAR_H diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 02e152f4..7dfbbdde 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -183,6 +183,10 @@ RelativePath="..\AdminCache.cpp" > + + @@ -227,6 +231,10 @@ RelativePath="..\smn_admin.cpp" > + + @@ -273,6 +281,10 @@ RelativePath="..\AdminCache.h" > + + @@ -626,6 +638,14 @@ > + + + + diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 11b399ee..1b190f3c 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -18,7 +18,6 @@ #include #include "PluginSys.h" #include "sourcemm_api.h" -#include #include #include #include "sm_trie.h" diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 1839fa5c..f544704c 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -50,7 +50,7 @@ inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, un for (size_t i=0; iGetFileByIndex(i)); + phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i)); err = phrfl->GetTranslation(key, langid, pTrans); } diff --git a/core/smn_convar.cpp b/core/smn_convar.cpp new file mode 100644 index 00000000..716fb70e --- /dev/null +++ b/core/smn_convar.cpp @@ -0,0 +1,293 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "HandleSys.h" +#include "CConVarManager.h" + +static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) +{ + char *name, *defaultVal, *helpText; + + pContext->LocalToString(params[1], &name); + + // While the engine seems to accept a blank convar name, it causes a crash upon server quit + if (name == NULL || strcmp(name, "") == 0) + { + pContext->ThrowNativeError("Null or blank convar name is not allowed."); + return BAD_HANDLE; + } + + pContext->LocalToString(params[2], &defaultVal); + pContext->LocalToString(params[3], &helpText); + + bool hasMin = params[5] ? true : false; + bool hasMax = params[7] ? true : false; + float min = sp_ctof(params[6]); + float max = sp_ctof(params[8]); + + return g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max); +} + +static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params) +{ + char *name; + + pContext->LocalToString(params[1], &name); + + // While the engine seems to accept a blank convar name, it causes a crash upon server quit + if (name == NULL || strcmp(name, "") == 0) + { + return BAD_HANDLE; + } + + return g_ConVarManager.FindConVar(name); +} + +static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + return cvar->GetBool(); +} + +static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + return cvar->GetInt(); +} + +/* This handles both SetConVarBool() and SetConVarInt() */ +static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + cvar->SetValue(params[2]); + + return 1; +} + +static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + float value = cvar->GetFloat(); + + return sp_ftoc(value); +} + +static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + float value = sp_ctof(params[2]); + cvar->SetValue(value); + + return 1; +} + +static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + pContext->StringToLocalUTF8(params[2], params[3], cvar->GetString(), NULL); + + return 1; +} + +static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + char *value; + pContext->LocalToString(params[2], &value); + + cvar->SetValue(value); + + return 1; +} + +static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + return cvar->GetFlags(); +} + +static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + cvar->SetFlags(params[2]); + + return 1; +} + +static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + cell_t *addr; + bool hasMin; + float min; + + pContext->LocalToPhysAddr(params[2], &addr); + + hasMin = cvar->GetMin(min); + *addr = sp_ftoc(min); + + return hasMin; +} + +static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + cell_t *addr; + bool hasMax; + float max; + + pContext->LocalToPhysAddr(params[2], &addr); + + hasMax = cvar->GetMax(max); + *addr = sp_ftoc(max); + + return hasMax; +} + +static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + cvar->Revert(); + + return 1; +} + +REGISTER_NATIVES(convarNatives) +{ + {"CreateConVar", sm_CreateConVar}, + {"FindConVar", sm_FindConVar}, + {"GetConVarBool", sm_GetConVarBool}, + {"SetConVarBool", sm_SetConVarNum}, + {"GetConVarInt", sm_GetConVarInt}, + {"SetConVarInt", sm_SetConVarNum}, + {"GetConVarFloat", sm_GetConVarFloat}, + {"SetConVarFloat", sm_SetConVarFloat}, + {"GetConVarString", sm_GetConVarString}, + {"SetConVarString", sm_SetConVarString}, + {"GetConVarFlags", sm_GetConVarFlags}, + {"SetConVarFlags", sm_SetConVarFlags}, + {"GetConVarMin", sm_GetConVarMin}, + {"GetConVarMax", sm_GetConVarMax}, + {"ResetConVar", sm_ResetConVar}, + {NULL, NULL} +}; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index bc53626f..2980ab61 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -22,6 +22,7 @@ IServerGameDLL *gamedll = NULL; IServerGameClients *serverClients = NULL; ISmmPluginManager *g_pMMPlugins = NULL; CGlobalVars *gpGlobals = NULL; +ICvar *icvar = NULL; IGameEventManager2 *gameevents = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -33,6 +34,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); + GET_V_IFACE_CURRENT(engineFactory, icvar, ICvar, VENGINE_CVAR_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL) diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index a6627af6..10a2d346 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -14,8 +14,10 @@ #ifndef _INCLUDE_SOURCEMOD_MM_API_H_ #define _INCLUDE_SOURCEMOD_MM_API_H_ +#include "convar_sm.h" #include #include +#include #include /** @@ -45,6 +47,7 @@ extern SourceMod_Core g_SourceMod_Core; extern IVEngineServer *engine; extern IServerGameDLL *gamedll; extern IServerGameClients *serverClients; +extern ICvar *icvar; extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; extern IGameEventManager2 *gameevents; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index d941ef0e..6699cf26 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -504,11 +504,26 @@ size_t CPlugin::GetLangFileCount() const return m_PhraseFiles.size(); } -unsigned int CPlugin::GetFileByIndex(unsigned int index) const +unsigned int CPlugin::GetLangFileByIndex(unsigned int index) const { return m_PhraseFiles.at(index); } +void CPlugin::AddConVar(ConVar *convar) +{ + m_ConVarList.push_back(convar); +} + +size_t CPlugin::GetConVarCount() const +{ + return m_ConVarList.size(); +} + +ConVar *CPlugin::GetConVarByIndex(size_t index) const +{ + return m_ConVarList.at(index); +} + /******************* * PLUGIN ITERATOR * *******************/ diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 4954fe40..c2e97786 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -28,6 +28,7 @@ #include "sm_trie.h" #include "sourcemod.h" #include +#include "convar_sm.h" using namespace SourceHook; @@ -191,7 +192,7 @@ public: /** * Get language file index based on the vector index. */ - unsigned int GetFileByIndex(unsigned int index) const; + unsigned int GetLangFileByIndex(unsigned int index) const; public: /** * Returns the modification time during last plugin load. @@ -207,6 +208,21 @@ public: * Returns true if the plugin was running, but is now invalid. */ bool WasRunning(); + + /** + * Adds a convar to the plugin's list + */ + void AddConVar(ConVar *convar); + + /** + * Get convar count for this plugin. + */ + size_t GetConVarCount() const; + + /** + * Get convar pointer based on the vector index. + */ + ConVar *GetConVarByIndex(size_t index) const; protected: void UpdateInfo(); void SetTimeStamp(time_t t); @@ -224,6 +240,7 @@ private: Handle_t m_handle; bool m_WasRunning; CVector m_PhraseFiles; + CVector m_ConVarList; }; class CPluginManager : @@ -316,6 +333,14 @@ public: */ CPlugin *GetPluginByOrder(int num); + /** + * Internal version of FindPluginByContext() + */ + inline CPlugin *GetPluginByCtx(const sp_context_t *ctx) + { + return reinterpret_cast(ctx->user[SM_CONTEXTVAR_MYSELF]); + } + /** * Gets status text for a status code */ diff --git a/plugins/include/console.inc b/plugins/include/console.inc new file mode 100644 index 00000000..fdf9cf5e --- /dev/null +++ b/plugins/include/console.inc @@ -0,0 +1,201 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _console_included + #endinput +#endif +#define _console_included + +/** + * Flags for console commands and console variables + * @note The descriptions for each constant come directly from the Source SDK. + */ +#define FCVAR_NONE 0 /**< The default, no flags at all */ +#define FCVAR_UNREGISTERED (1<<0) /**< If this is set, don't add to linked list, etc. */ +#define FCVAR_LAUNCHER (1<<1) /**< Defined by launcher. */ +#define FCVAR_GAMEDLL (1<<2) /**< Defined by the game DLL. */ +#define FCVAR_CLIENTDLL (1<<3) /**< Defined by the client DLL. */ +#define FCVAR_MATERIAL_SYSTEM (1<<4) /**< Defined by the material system. */ +#define FCVAR_PROTECTED (1<<5) /**< It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value. */ +#define FCVAR_SPONLY (1<<6) /**< This cvar cannot be changed by clients connected to a multiplayer server. */ +#define FCVAR_ARCHIVE (1<<7) /**< Set to cause it to be saved to vars.rc */ +#define FCVAR_NOTIFY (1<<8) /**< Notifies players when changed. */ +#define FCVAR_USERINFO (1<<9) /**< Changes the client's info string. */ +#define FCVAR_PRINTABLEONLY (1<<10) /**< This cvar's string cannot contain unprintable characters (e.g., used for player name, etc.) */ +#define FCVAR_UNLOGGED (1<<11) /**< If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log */ +#define FCVAR_NEVER_AS_STRING (1<<12) /**< Never try to print that cvar. */ +#define FCVAR_REPLICATED (1<<13) /**< Server setting enforced on clients. */ +#define FCVAR_CHEAT (1<<14) /**< Only useable in singleplayer / debug / multiplayer & sv_cheats */ +#define FCVAR_STUDIORENDER (1<<15) /**< Defined by the studiorender system. */ +#define FCVAR_DEMO (1<<16) /**< Record this cvar when starting a demo file. */ +#define FCVAR_DONTRECORD (1<<17) /**< Don't record these command in demo files. */ +#define FCVAR_PLUGIN (1<<18) /**< Defined by a 3rd party plugin. */ +#define FCVAR_DATACACHE (1<<19) /**< Defined by the datacache system. */ +#define FCVAR_TOOLSYSTEM (1<<20) /**< Defined by an IToolSystem library */ +#define FCVAR_FILESYSTEM (1<<21) /**< Defined by the file system. */ +#define FCVAR_NOT_CONNECTED (1<<22) /**< Cvar cannot be changed by a client that is connected to a server. */ +#define FCVAR_SOUNDSYSTEM (1<<23) /**< Defined by the soundsystem library. */ +#define FCVAR_ARCHIVE_XBOX (1<<24) /**< Cvar written to config.cfg on the Xbox. */ +#define FCVAR_INPUTSYSTEM (1<<25) /**< Defined by the inputsystem DLL. */ +#define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ +#define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ + +/** + * Creates a new console variable. + * + * @param name Name of new convar. + * @param defaultValue String containing the default value of new convar. + * @param helpText Optional description of the convar. + * @param flags Optional bitstream of flags determining how the convar should be handled. (See FCVAR_* constants for more details) + * @param hasMin Optional boolean that determines if the convar has a minimum value. + * @param min Minimum floating point value that the convar can have if hasMin is true. + * @param hasMax Optional boolean that determines if the convar has a maximum value. + * @param max Maximum floating point value that the convar can have if hasMax is true. + * @return A handle to the newly created convar. If the convar already exists, INVALID_HANDLE is returned. + */ +native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:helpText[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); + +/** + * Searches for a console variable. + * + * @param name Name of convar to find. + * @return A handle to the convar if it is found. INVALID_HANDLE otherwise. + */ +native Handle:FindConVar(const String:name[]); + +/** + * Returns the boolean value of a console variable. + * + * @param convar Handle to the convar. + * @return The boolean value of the convar. + * @error Invalid or corrupt Handle. + */ +native bool:GetConVarBool(Handle:convar); + +/** + * Sets the boolean value of a console variable. + * + * @param convar Handle to the convar. + * @param value New boolean value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarBool(Handle:convar, bool:value); + +/** + * Returns the integer value of a console variable. + * + * @param convar Handle to the convar. + * @return The integer value of the convar. + * @error Invalid or corrupt Handle. + */ +native GetConVarInt(Handle:convar); + +/** + * Sets the integer value of a console variable. + * + * @param convar Handle to the convar. + * @param value New integer value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarInt(Handle:convar, value); + +/** + * Returns the floating point value of a console variable. + * + * @param convar Handle to the convar. + * @return The floating point value of the convar. + * @error Invalid or corrupt Handle. + */ +native Float:GetConVarFloat(Handle:convar); + +/** + * Sets the floating point value of a console variable. + * + * @param convar Handle to the convar. + * @param value New floating point value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarFloat(Handle:convar, Float:value); + +/** + * Retrieves the string value of a console variable. + * + * @param convar Handle to the convar. + * @param value Buffer to store the value of the convar. + * @param maxlen Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetConVarString(Handle:convar, String:value[], maxlen); + +/** + * Sets the string value of a console variable. + * + * @param convar Handle to the convar. + * @param value New string value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarString(Handle:convar, const String:value[]); + +/** + * Returns the bitstring of flags on a console variable. + * + * @param convar Handle to the convar. + * @return A bitstring containing the FCVAR_* flags that are enabled. + * @error Invalid or corrupt Handle. + */ +native GetConVarFlags(Handle:convar); + +/** + * Sets the bitstring of flags on a console variable. + * + * @param convar Handle to the convar. + * @param flags A bitstring containing the FCVAR_* flags to enable. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarFlags(Handle:convar, flags); + +/** + * Retrieves the minimum floating point value that a console variable can contain. + * + * @param convar Handle to the convar. + * @param min By-reference cell to store the minimum floating point value. + * @return True if the convar has a minimum value set, false otherwise. + * @error Invalid or corrupt Handle. + */ +native bool:GetConVarMin(Handle:convar, &Float:min); + +/** + * Retrieves the maximum floating point value that a console variable can contain. + * + * @param convar Handle to the convar. + * @param min By-reference cell to store the maximum floating point value. + * @return True if the convar has a maximum value set, false otherwise. + * @error Invalid or corrupt Handle. + */ +native bool:GetConVarMax(Handle:convar, &Float:max); + +/** + * Resets the console variable to its default value. + * + * @param convar Handle to the convar. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native ResetConVar(Handle:convar); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 3aa2a633..5cde54a1 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -32,6 +32,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. From 1c80875ea319756e6a46ec76ff572c7ec8d4f391 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 9 Feb 2007 01:08:59 +0000 Subject: [PATCH 0433/1664] initial import of binding user admin ids to players in game --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40464 --- core/AdminCache.cpp | 33 ++++++++ core/AdminCache.h | 4 + core/CPlayerManager.cpp | 55 +++++++++++++ core/CPlayerManager.h | 8 ++ core/smn_player.cpp | 150 ++++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 63 ++++++++++++++ public/IAdminSystem.h | 9 ++ public/IPlayerHelpers.h | 16 ++++ 8 files changed, 338 insertions(+) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 43580376..6537bc6b 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -16,6 +16,7 @@ #include "AdminCache.h" #include "ShareSys.h" #include "ForwardSys.h" +#include "CPlayerManager.h" AdminCache g_Admins; @@ -31,6 +32,7 @@ AdminCache::AdminCache() m_pCacheFwd = NULL; m_FirstGroup = -1; m_pAuthTables = sm_trie_create(); + m_InvalidatingAdmins = false; } AdminCache::~AdminCache() @@ -544,6 +546,11 @@ bool AdminCache::InvalidateAdmin(AdminId id) return false; } + if (!m_InvalidatingAdmins) + { + g_Players.ClearAdminId(id); + } + /* Unlink from the dbl link list */ if (id == m_FirstUser && id == m_LastUser) { @@ -738,6 +745,8 @@ void AdminCache::RegisterAuthIdentType(const char *name) void AdminCache::InvalidateAdminCache(bool unlink_admins) { + m_InvalidatingAdmins = true; + g_Players.ClearAllAdmins(); /* Wipe the identity cache first */ List::iterator iter; for (iter=m_AuthMethods.begin(); @@ -758,6 +767,7 @@ void AdminCache::InvalidateAdminCache(bool unlink_admins) m_LastUser = -1; m_FreeUserList = -1; } + m_InvalidatingAdmins = false; } void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) @@ -950,6 +960,23 @@ FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode) return 0; } +void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + if (mode == Access_Real) + { + pUser->flags = bits; + pUser->eflags = bits; + } else if (mode == Access_Effective) { + pUser->eflags = bits; + } +} + bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); @@ -1025,6 +1052,12 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) return true; } +bool AdminCache::IsValidAdmin(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + return (pUser != NULL && pUser->magic == USR_MAGIC_SET); +} + unsigned int AdminCache::GetAdminGroupCount(AdminId id) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); diff --git a/core/AdminCache.h b/core/AdminCache.h index 11b452ea..9d4eaae9 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -131,6 +131,9 @@ public: //IAdminSystem unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize); bool CheckAdminFlags(AdminId id, FlagBits bits); bool CanAdminTarget(AdminId id, AdminId target); + void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits); +public: + bool IsValidAdmin(AdminId id); private: void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); @@ -155,6 +158,7 @@ public: int m_FirstUser; int m_LastUser; int m_FreeUserList; + bool m_InvalidatingAdmins; }; extern AdminCache g_Admins; diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 53e240b6..e23a6783 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -14,6 +14,7 @@ #include "CPlayerManager.h" #include "ForwardSys.h" #include "ShareSys.h" +#include "AdminCache.h" CPlayerManager g_Players; @@ -383,6 +384,26 @@ IGamePlayer *CPlayerManager::GetGamePlayer(int client) return GetPlayerByIndex(client); } +void CPlayerManager::ClearAdminId(AdminId id) +{ + for (int i=1; i<=m_maxClients; i++) + { + if (m_Players[i].m_Admin == id) + { + m_Players[i].DumpAdmin(true); + } + } +} + +void CPlayerManager::ClearAllAdmins() +{ + for (int i=1; i<=m_maxClients; i++) + { + m_Players[i].DumpAdmin(true); + } +} + + /******************* *** PLAYER CODE *** *******************/ @@ -393,6 +414,8 @@ CPlayer::CPlayer() m_IsInGame = false; m_IsAuthorized = false; m_pEdict = NULL; + m_Admin = INVALID_ADMIN_ID; + m_TempAdmin = false; } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -416,6 +439,7 @@ void CPlayer::Authorize(const char *steamid) void CPlayer::Disconnect() { + DumpAdmin(false); m_IsConnected = false; m_IsInGame = false; m_IsAuthorized = false; @@ -469,3 +493,34 @@ bool CPlayer::IsFakeClient() const { return (strcmp(m_AuthID.c_str(), "BOT") == 0); } + +void CPlayer::SetAdminId(AdminId id, bool temporary) +{ + if (!m_IsConnected) + { + return; + } + + DumpAdmin(false); + + m_Admin = id; + m_TempAdmin = temporary; +} + +AdminId CPlayer::GetAdminId() const +{ + return m_Admin; +} + +void CPlayer::DumpAdmin(bool deleting) +{ + if (m_Admin != INVALID_ADMIN_ID) + { + if (m_TempAdmin && !deleting) + { + g_Admins.InvalidateAdmin(m_Admin); + } + m_Admin = INVALID_ADMIN_ID; + m_TempAdmin = false; + } +} diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index 4ef1ace9..a621de88 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -19,6 +19,7 @@ #include "sourcemm_api.h" #include #include +#include #include #include #include @@ -39,12 +40,15 @@ public: bool IsConnected() const; bool IsAuthorized() const; bool IsFakeClient() const; + void SetAdminId(AdminId id, bool temporary); + AdminId GetAdminId() const; private: void Initialize(const char *name, const char *ip, edict_t *pEntity); void Connect(); void Authorize(const char *steamid); void Disconnect(); void SetName(const char *name); + void DumpAdmin(bool deleting); private: bool m_IsConnected; bool m_IsInGame; @@ -52,6 +56,8 @@ private: String m_Name; String m_Ip; String m_AuthID; + AdminId m_Admin; + bool m_TempAdmin; edict_t *m_pEdict; }; @@ -68,6 +74,8 @@ public: //SMGlobalClass public: CPlayer *GetPlayerByIndex(int client) const; void RunAuthChecks(); + void ClearAdminId(AdminId id); + void ClearAllAdmins(); public: bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 804a0a17..fb271179 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -12,6 +12,7 @@ */ #include "CPlayerManager.h" +#include "AdminCache.h" #include "sm_stringutil.h" static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) @@ -230,6 +231,150 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + if (!g_Admins.IsValidAdmin(params[2])) + { + return pContext->ThrowNativeError("AdminId %x is not valid.", params[2]); + } + + pPlayer->SetAdminId(params[2], params[3] ? true : false); + + return 1; +} + +static cell_t GetUserAdmin(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + return pPlayer->GetAdminId(); +} + +static cell_t AddUserFlags(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + id = g_Admins.CreateAdmin(NULL); + pPlayer->SetAdminId(id, true); + } + + cell_t *addr; + for (int i=2; i<=params[0]; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + g_Admins.SetAdminFlag(id, (AdminFlag)*addr, true); + } + + return 1; +} + +static cell_t RemoveUserFlags(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + return 0; + } + + cell_t *addr; + for (int i=2; i<=params[0]; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + g_Admins.SetAdminFlag(id, (AdminFlag)*addr, false); + } + + return 1; +} + +static cell_t SetUserFlagBits(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + id = g_Admins.CreateAdmin(NULL); + pPlayer->SetAdminId(id, true); + } + + g_Admins.SetAdminFlags(id, Access_Effective, params[2]); + + return 1; +} + +static cell_t GetUserFlagBits(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + return 0; + } + + return g_Admins.GetAdminFlags(id, Access_Effective); +} + REGISTER_NATIVES(playernatives) { {"GetMaxClients", sm_GetMaxClients}, @@ -244,6 +389,11 @@ REGISTER_NATIVES(playernatives) {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, {"GetClientInfo", sm_GetClientInfo}, + {"SetUserAdmin", SetUserAdmin}, + {"AddUserFlags", AddUserFlags}, + {"RemoveUserFlags", RemoveUserFlags}, + {"SetUserFlagBits", SetUserFlagBits}, + {"GetUserFlagBits", GetUserFlagBits}, {NULL, NULL} }; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 5cde54a1..131fd2e3 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -235,9 +235,72 @@ native bool:IsPlayerFakeClient(client); * @param value Buffer to store value. * @param maxlen Maximum length of valve (UTF-8 safe). * @return True on success, false otherwise. + * @error Invalid client index, or client not connected. */ native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); +/** + * Sets a client's AdminId. + * + * @param client Player's index. + * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. + * @param temp True if the id should be freed on disconnect. + * @noreturn + * @error Invalid client index, client not connected, or bogus AdminId. + */ +native SetUserAdmin(client, AdminId:id, bool:temp=false); + +/** + * Retrieves a client's AdminId. + * + * @param client Player's index. + * @return AdminId of the client, or INVALID_ADMIN_ID if none. + * @error Invalid client index, or client not connected. + */ +native AdminId:GetUserAdmin(client); + +/** + * Sets access flags on a client. If the client is not an admin, + * a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param ... Flags to set on the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native AddUserFlags(client, {AdminFlag}:...); + +/** + * Removes flags from a client. If the client is not an admin, + * this has no effect. + * + * @param client Player's index. + * @param ... Flags to remove from the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native RemoveUserFlags(client, {AdminFlag}:...); + +/** + * Sets access flags on a client using bits instead of flags. If the + * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param flags Bitstring of flags to set on client. + * @noreturn + */ +native SetUserFlagBits(client, flags); + +/** + * Returns client access flags. If the client is not an admin, + * the result is always 0. + * + * @param client Player's index. + * @return Flags + * @error Invalid client index, or client not connected. + */ +native GetUserFlagBits(client); + /** * Sends a message to the server console. * diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index af5309ff..be93cbe9 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -444,6 +444,15 @@ namespace SourceMod */ virtual FlagBits GetAdminFlags(AdminId id, AccessMode mode) =0; + /** + * @brief Sets the bitstring of access flags on an admin. + * + * @param id AdminId index of the admin. + * @param mode Access mode to use (real affects both). + * @param bits Bitstring to set. + */ + virtual void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits) =0; + /** * @brief Adds a group to an admin's inherited group list. * Any flags the group has will be added to the admin's effective flags. diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 5a4b9ded..3642409f 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -20,6 +20,7 @@ #define _INCLUDE_SOURCEMOD_INTERFACE_IPLAYERHELPERS_H_ #include +#include #define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager" #define SMINTERFACE_PLAYERMANAGER_VERSION 1 @@ -92,6 +93,21 @@ namespace SourceMod * @return True if a fake client, false otherwise. */ virtual bool IsFakeClient() const =0; + + /** + * @brief Returns the client's AdminId, if any. + * + * @return AdminId, or INVALID_ADMIN_ID if none. + */ + virtual AdminId GetAdminId() const =0; + + /** + * @brief Sets the client's AdminId. + * + * @param id AdminId to set. + * @param temp If true, the id will be invalidated on disconnect. + */ + virtual void SetAdminId(AdminId id, bool temp) =0; }; /** From 18aabecfd36b1978439a2235a652aa59cf7d0d2e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 9 Feb 2007 04:38:57 +0000 Subject: [PATCH 0434/1664] fixed a bug where early returns could cause the stack to not pop properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40465 --- sourcepawn/compiler/sc1.c | 11 +++++++---- sourcepawn/compiler/sctracker.c | 7 +++++-- sourcepawn/compiler/sctracker.h | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 4372cd44..b9e4ed34 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -4041,7 +4041,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc * has only a single statement in its body (no compound block) and that * statement declares a new variable */ - popstacklist(); + popstacklist(1); declared=0; } /* if */ if ((lastst!=tRETURN) && (lastst!=tGOTO)){ @@ -5503,8 +5503,11 @@ static void compound(int stmt_sameline,int starttok) if (lastst!=tRETURN) destructsymbols(&loctab,nestlevel); if (lastst!=tRETURN && lastst!=tGOTO) { - popheaplist(); - popstacklist(); + popheaplist(1); + popstacklist(1); + } else { + popheaplist(0); + popstacklist(0); } testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ declared=save_decl; @@ -5845,7 +5848,7 @@ static int dofor(void) * variable in "expr1". */ destructsymbols(&loctab,nestlevel); - popstacklist(); + popstacklist(1); testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ declared=save_decl; delete_symbols(&loctab,nestlevel,FALSE,TRUE); diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 5c5693f6..b3bbc1a9 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -402,12 +402,15 @@ void genheapfree(int stop_id) } } -void popstacklist() +void popstacklist(int codegen) { memuse_list_t *oldlist; assert(stackusage != NULL); - _stack_genusage(stackusage, 1); + if (codegen) + { + _stack_genusage(stackusage, 1); + } assert(stackusage->head==NULL); oldlist = stackusage->prev; diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index ed4576bf..1aecdc09 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -95,7 +95,7 @@ int markheap(int type, int size); * Stack functions */ void pushstacklist(); -void popstacklist(); +void popstacklist(int codegen); int markstack(int type, int size); /** * Generates code to free mem usage, but does not pop the list. From 57c1f0dd4d3dbf0952591eece4a089ad8069cc36 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 9 Feb 2007 04:41:03 +0000 Subject: [PATCH 0435/1664] added and tested admin authentication. WOOT. only steam-based works for now. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40466 --- core/CPlayerManager.cpp | 2 +- core/smn_player.cpp | 17 +++++++ plugins/admin-auth.sp | 59 ++++++++++++++++++++++++ plugins/admin-flatfile/admin-flatfile.sp | 2 +- plugins/admin-flatfile/admin-users.sp | 2 +- plugins/include/helpers.inc | 45 ++++++++++++++++++ plugins/include/sourcemod.inc | 28 +++++++---- 7 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 plugins/admin-auth.sp create mode 100644 plugins/include/helpers.inc diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index e23a6783..052c709c 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -59,7 +59,7 @@ void CPlayerManager::OnSourceModAllInitialized() m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2); m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2); m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); - m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p2); + m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p3); } void CPlayerManager::OnSourceModShutdown() diff --git a/core/smn_player.cpp b/core/smn_player.cpp index fb271179..df86366a 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -375,6 +375,22 @@ static cell_t GetUserFlagBits(IPluginContext *pContext, const cell_t *params) return g_Admins.GetAdminFlags(id, Access_Effective); } +static cell_t GetClientUserId(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + return engine->GetPlayerUserId(pPlayer->GetEdict()); +} + REGISTER_NATIVES(playernatives) { {"GetMaxClients", sm_GetMaxClients}, @@ -394,6 +410,7 @@ REGISTER_NATIVES(playernatives) {"RemoveUserFlags", RemoveUserFlags}, {"SetUserFlagBits", SetUserFlagBits}, {"GetUserFlagBits", GetUserFlagBits}, + {"GetClientUserId", GetClientUserId}, {NULL, NULL} }; diff --git a/plugins/admin-auth.sp b/plugins/admin-auth.sp new file mode 100644 index 00000000..ae599166 --- /dev/null +++ b/plugins/admin-auth.sp @@ -0,0 +1,59 @@ +/** + * admin-flatfile.sp + * Manages the standard flat files for admins. This is the file to compile. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +public Plugin:myinfo = +{ + name = "Admin Auth", + author = "AlliedModders LLC", + description = "Authenticates Admins", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public OnClientAuthorized(client, const String:auth[]) +{ + if (StrEqual(auth, "BOT") + || StrEqual(auth, "STEAM_ID_LAN")) + { + return; + } + + new AdminId:id + if ((id = FindAdminByIdentity("steam", auth)) == INVALID_ADMIN_ID) + { + return; + } + + decl String:buffer[256], String:account[64]; + + FormatUserLogText(client, buffer, sizeof(buffer)); + + if (GetAdminUsername(id, account, sizeof(account))) + { + LogMessage("%s authenticated to account \"%s\"", buffer, account); + } else { + LogMessage("%s authenticated to an anonymous account", buffer); + } + + SetUserAdmin(client, id); +} diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 73566e96..97a26ee7 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -24,7 +24,7 @@ public Plugin:myinfo = { - name = "Admin Base", + name = "Admin File Reader", author = "AlliedModders LLC", description = "Reads admin files", version = "1.0.0.0", diff --git a/plugins/admin-flatfile/admin-users.sp b/plugins/admin-flatfile/admin-users.sp index 2dbb57c8..4c091fe9 100644 --- a/plugins/admin-flatfile/admin-users.sp +++ b/plugins/admin-flatfile/admin-users.sp @@ -76,7 +76,7 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc, { auth = true; StrCopy(g_CurAuth, sizeof(g_CurAuth), value); - } else if (StrEqual(key, "ident")) { + } else if (StrEqual(key, "identity")) { auth = true; StrCopy(g_CurIdent, sizeof(g_CurIdent), value); } else if (StrEqual(key, "password")) { diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc new file mode 100644 index 00000000..2b0427f7 --- /dev/null +++ b/plugins/include/helpers.inc @@ -0,0 +1,45 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _helpers_included + #endinput +#endif +#define _helpers_included + +/** + * Formats a user's info as log text. + * + * @param client Client index. + * @param buffer Buffer for text. + * @param maxlength Maximum length of text. + */ +stock FormatUserLogText(client, String:buffer[], maxlength) +{ + decl String:auth[32]; + decl String:name[40]; + + new userid = GetClientUserId(client); + if (!GetClientAuthString(client, auth, sizeof(auth))) + { + StrCopy(auth, sizeof(auth), "UNKNOWN"); + } + if (!GetClientName(client, name, sizeof(name))) + { + StrCopy(name, sizeof(name), "UNKNOWN"); + } + + /** Currently, no team stuff ... */ + + Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth); +} diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 131fd2e3..4ee73244 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -164,9 +164,9 @@ native GetClientCount(bool:inGameOnly=true); /** * Returns the client's name. * - * @param client Player index. - * @param name Buffer to store the client's name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). * @return True on success, false otherwise. * @error If the client is not connected an error will be thrown. */ @@ -179,8 +179,8 @@ native bool:GetClientName(client, String:name[], maxlen); * @param name Buffer to store the client's ip address. * @param maxlen Maximum length of string buffer (includes NULL terminator). * @param remport Remove client's port from the ip string (true by default). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. */ native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); @@ -190,11 +190,21 @@ native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); * @param client Player index. * @param auth Buffer to store the client's auth string. * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. */ native bool:GetClientAuthString(client, String:auth[], maxlen); +/** + * Retrieves a client's user id, which is an index incremented for every client + * that joins the server. + * + * @param client Player index. + * @return User id of the client. + * @error If the client is not connected or the index is invalid. + */ +native GetClientUserId(client); + /** * Returns if a certain player is connected. * @@ -346,4 +356,6 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); * @param ... Format arguments. * @noreturn */ -native LogError(const String:format[], {Handle,Float,String,_}:...); \ No newline at end of file +native LogError(const String:format[], {Handle,Float,String,_}:...); + +#include From 47acc11df77b947a18887b0f92291596585b25f4 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 9 Feb 2007 22:12:39 +0000 Subject: [PATCH 0436/1664] expanded data pack natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40467 --- plugins/include/datapack.inc | 57 ++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/plugins/include/datapack.inc b/plugins/include/datapack.inc index 3f40df8d..5e491d6d 100644 --- a/plugins/include/datapack.inc +++ b/plugins/include/datapack.inc @@ -35,6 +35,26 @@ native Handle:CreateDataPack(); */ native WritePackCell(Handle:pack, cell); +/** + * Packs a float into a data pack. + * + * @param pack Handle to the data pack. + * @param val Float to add. + * @noreturn + * @error Invalid handle. + */ +native WritePackFloat(Handle:pack, Float:val); + +/** + * Packs a string into a data pack. + * + * @param pack Handle to the data pack. + * @param str String to add. + * @noreturn + * @error Invalid handle. + */ +native WritePackString(Handle:pack, String:str[]); + /** * Reads a cell from a data pack. * @@ -44,12 +64,33 @@ native WritePackCell(Handle:pack, cell); */ native ReadPackCell(Handle:pack); +/** + * Reads a float from a data pack. + * + * @param pack Handle to the data pack. + * @return Float value. + * @error Invalid handle, or bounds error. + */ +native Float:ReadPackFloat(Handle:pack); + +/** + * Reads a string from a data pack. + * + * @param pack Handle to the data pack. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @noreturn + * @error Invalid handle, or bounds error. + */ +native ReadPackString(Handle:pack, String:buffer[], maxlen); + /** * Resets the position in a data pack. * * @param pack Handle to the data pack. * @param clear If true, clears the contained data. * @noreturn + * @error Invalid handle. */ native ResetPack(Handle:pack, bool:clear=false); @@ -58,6 +99,7 @@ native ResetPack(Handle:pack, bool:clear=false); * * @param pack Handle to the data pack. * @return Numerical position in the data pack. + * @error Invalid handle. */ native GetPackPosition(Handle:pack); @@ -67,6 +109,17 @@ native GetPackPosition(Handle:pack); * @param pack Handle to the data pack. * @param position New position to set. * @noreturn - * @error Position is beyond the pack bounds. + * @error Invalid handle, or position is beyond the pack bounds. */ -native SetPackPosition(Handle:pack, position); \ No newline at end of file +native SetPackPosition(Handle:pack, position); + +/** + * Returns whether or not a specified number of bytes from the data pack + * position to the end can be read. + * + * @param pack Handle to the data pack. + * @param bytes Number of bytes to simulate reading. + * @return True if can be read, false otherwise. + * @error Invalid handle. + */ +native bool:IsPackReadable(Handle:pack, bytes); From 09236c2d7a05e66b85ffc7a6137b2916996bc13e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 10 Feb 2007 10:38:23 +0000 Subject: [PATCH 0437/1664] Fixed native errors not being logged - hope I did this correctly... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40468 --- core/CDbgReporter.cpp | 2 ++ core/CDbgReporter.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp index 0833dbd7..f2f46ad8 100644 --- a/core/CDbgReporter.cpp +++ b/core/CDbgReporter.cpp @@ -15,6 +15,8 @@ #include "CLogger.h" #include "PluginSys.h" +CDbgReporter g_DbgReporter; + void CDbgReporter::OnSourceModAllInitialized() { g_pSourcePawn->SetDebugListener(this); diff --git a/core/CDbgReporter.h b/core/CDbgReporter.h index 523f26f9..020438c4 100644 --- a/core/CDbgReporter.h +++ b/core/CDbgReporter.h @@ -29,5 +29,7 @@ private: int _GetPluginIndex(IPluginContext *ctx); }; +extern CDbgReporter g_DbgReporter; + #endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ From 1d44bdf37a2af16e3c02b8a50618832f8d21ba6a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 10 Feb 2007 23:34:30 +0000 Subject: [PATCH 0438/1664] added makefile for build tool --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40469 --- tools/builder/Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tools/builder/Makefile diff --git a/tools/builder/Makefile b/tools/builder/Makefile new file mode 100644 index 00000000..767b444f --- /dev/null +++ b/tools/builder/Makefile @@ -0,0 +1,15 @@ +CS = /usr/mono/bin/mcs +NAME = builder +BINARY = $(NAME).exe + +OBJECTS = ABuilder.cs AssemblyInfo.cs Config.cs LinuxBuilder.cs Win32Builder.cs \ + Package.cs PkgCore.cs Main.cs + +default: all + +all: $(OBJECTS) + $(CS) $(OBJECTS) -o $(BINARY) + +clean: + rm -rf $(BINARY) + From 682e7d4ab6e5419accc3a54ad6c9a70203a289d2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 11 Feb 2007 00:17:54 +0000 Subject: [PATCH 0439/1664] fixed build on linux problems --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40470 --- core/AdminCache.cpp | 4 ++-- core/CConVarManager.h | 3 ++- core/CPlayerManager.cpp | 2 +- core/Makefile | 4 ++-- core/sm_stringutil.cpp | 11 ++++++----- core/smn_float.cpp | 2 ++ core/smn_player.cpp | 1 + core/svn_version.h | 22 +++++++++++----------- core/systems/ForwardSys.h | 2 +- core/systems/PluginSys.cpp | 3 ++- 10 files changed, 30 insertions(+), 24 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 6537bc6b..b03f3110 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -1109,7 +1109,7 @@ unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigne unsigned int i; for (i=0; iGetContext()); + size_t langcount = pl->GetLangFileCount(); + void *new_params[MAX_TRANSLATE_PARAMS]; + unsigned int max_params = 0; try_serverlang: if (target == LANG_SERVER) @@ -89,9 +94,7 @@ try_serverlang: goto error_out; } - Translation pTrans; - CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); - size_t langcount = pl->GetLangFileCount(); + max_params = pTrans.fmt_count; if (!TryTranslation(pl, key, langid, langcount, &pTrans)) { @@ -109,8 +112,6 @@ try_serverlang: } } - void *new_params[MAX_TRANSLATE_PARAMS]; - unsigned int max_params = pTrans.fmt_count; for (size_t i=0; iLocalToPhysAddr(params[*arg], reinterpret_cast(&new_params[i])); diff --git a/core/smn_float.cpp b/core/smn_float.cpp index e54fd80b..4a8e8c34 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -12,6 +12,8 @@ */ #include +#include +#include #include "sm_globals.h" /**************************************** diff --git a/core/smn_player.cpp b/core/smn_player.cpp index df86366a..fa6da607 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -406,6 +406,7 @@ REGISTER_NATIVES(playernatives) {"PrintToConsole", sm_PrintToConsole}, {"GetClientInfo", sm_GetClientInfo}, {"SetUserAdmin", SetUserAdmin}, + {"GetUserAdmin", GetUserAdmin}, {"AddUserFlags", AddUserFlags}, {"RemoveUserFlags", RemoveUserFlags}, {"SetUserFlagBits", SetUserFlagBits}, diff --git a/core/svn_version.h b/core/svn_version.h index 75ccd495..97147a48 100644 --- a/core/svn_version.h +++ b/core/svn_version.h @@ -1,11 +1,11 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 429 -#define SVN_REVISION_STRING "429" -#define SVN_FILE_VERSION 1,0,0,429 - -#endif //_INCLUDE_SVN_VERSION_H_ - +/** This file is autogenerated by build scripts */ + +#ifndef _INCLUDE_SVN_VERSION_H_ +#define _INCLUDE_SVN_VERSION_H_ + +#define SVN_REVISION 468 +#define SVN_REVISION_STRING "468" +#define SVN_FILE_VERSION 1,0,0,468 + +#endif //_INCLUDE_SVN_VERSION_H_ + diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index e8e16ae7..db283fde 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -84,7 +84,7 @@ protected: /* :TODO: I want a caching list type here. * Destroying these things and using new/delete for their members feels bad. */ - List m_functions; + mutable List m_functions; List m_paused; /* Type and name information */ diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6699cf26..e1761185 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1658,4 +1658,5 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused) pListener = (*iter); pListener->OnPluginPauseChange(pl, paused); } -} \ No newline at end of file +} + From 0d54b19b8eaeb71c6c7e764f09e75fb5c6b8992b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 11 Feb 2007 11:09:38 +0000 Subject: [PATCH 0440/1664] More convar insanity 1) Added natives: HookConVarChange(), UnhookConVarChange(), and GetConVarName() 2) Fixed bug(s) where ConVar handles were being created when they didn't need to be 3) Fixed bug where convars not created by SourceMod would be unregistered --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40471 --- core/CConVarManager.cpp | 258 ++++++++++++++++++++++++++++++---- core/CConVarManager.h | 51 ++++++- core/smn_convar.cpp | 89 +++++++++--- plugins/include/console.inc | 45 +++++- public/sourcepawn/sp_vm_api.h | 4 +- 5 files changed, 397 insertions(+), 50 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 185ecab0..5e54b82b 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -15,43 +15,86 @@ #include "CLogger.h" #include "PluginSys.h" #include "sm_srvcmds.h" +#include "sm_stringutil.h" CConVarManager g_ConVarManager; -CConVarManager::CConVarManager() +CConVarManager::CConVarManager() : m_ConVarType(0) { - m_ConVarType = 0; - m_CvarCache = sm_trie_create(); + // Create a convar lookup trie + m_ConVarCache = sm_trie_create(); } CConVarManager::~CConVarManager() { - sm_trie_destroy(m_CvarCache); + List::iterator i; + + // Destroy our convar lookup trie + sm_trie_destroy(m_ConVarCache); + + // Destroy all the ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + delete (*i); + } + + m_ConVars.clear(); } void CConVarManager::OnSourceModAllInitialized() { HandleAccess sec; + // Set up access rights for the 'ConVar' handle type sec.access[HandleAccess_Read] = 0; - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + // Create the 'ConVar' handle type m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); - g_RootMenu.AddRootConsoleCommand("cvars", "View convars associated with a plugin", this); + // Add the 'cvars' option to the 'sm' console command + g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); } void CConVarManager::OnSourceModShutdown() { + IChangeableForward *fwd; + List::iterator i; + + // Iterate list of ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + fwd = (*i)->changeForward; + + // Free any convar-change forwards that still exist + if (fwd) + { + g_Forwards.ReleaseForward(fwd); + } + } + + // Remove the 'cvars' option from the 'sm' console command g_RootMenu.RemoveRootConsoleCommand("cvars", this); + // Remove the 'ConVar' handle type g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) { - g_SMAPI->UnregisterConCmdBase(g_PLAPI, static_cast(object)); + ConVarInfo *info; + ConCommandBase *cvar = static_cast(object); + + // Find convar in lookup trie + sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); + + // If convar was created by SourceMod plugin... + if (info->sourceMod) + { + // Then unregister it + g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); + } } void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) @@ -60,15 +103,20 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc { int id = 1; + // Get plugin index that was passed int num = atoi(g_RootMenu.GetArgument(2)); + // If invalid plugin index... if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) { g_RootMenu.ConsolePrint("[SM] Plugin index not found."); return; } + // Get plugin object CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + + // Get number of convars created by plugin int convarnum = pl->GetConVarCount(); if (convarnum == 0) @@ -79,6 +127,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); + // Iterate convar list and display each one for (int i = 0; i < convarnum; i++, id++) { ConVar *cvar = pl->GetConVarByIndex(i); @@ -88,13 +137,14 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc return; } + // Display usage of subcommand g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); } Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) { ConVar *cvar = NULL; - void *temp = NULL; + ConVarInfo *info = NULL; Handle_t hndl = 0; // Find out if the convar exists already @@ -103,33 +153,59 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name // If the convar already exists... if (cvar != NULL) { - IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); - - // This isn't a fatal error because we can handle it, but user should be warned anyways - g_Logger.LogError("[SM] Warning: Plugin \"%s\" has attempted to create already existing convar \"%s\"", pl->GetFilename(), name); - // First check if we already have a handle to it - if (sm_trie_retrieve(m_CvarCache, name, &temp)) + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) { // If we do, then return that handle - return reinterpret_cast(temp); + return info->handle; } else { - // If we don't, then create a new handle from the convar and return it - return g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + return hndl; } } - // Since we didn't find an existing convar, now we can create it + // To prevent creating a convar that has the same name as a console command... ugh + ConCommandBase *pBase = icvar->GetCommands(); + + while (pBase) + { + if (strcmp(pBase->GetName(), name) == 0) + { + return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); + } + + pBase = const_cast(pBase->GetNext()); + } + + // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); // Add new convar to plugin's list g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); - // Create a new handle from the convar + // Create a handle from the new convar hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - // Insert the handle into our cache - sm_trie_insert(m_CvarCache, name, reinterpret_cast(hndl)); + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = true; + info->changeForward = NULL; + info->origCallback = NULL; + + m_ConVars.push_back(info); + + // Insert the handle into our lookup trie + sm_trie_insert(m_ConVarCache, name, info); return hndl; } @@ -137,7 +213,8 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name Handle_t CConVarManager::FindConVar(const char *name) { ConVar *cvar = NULL; - void *temp = NULL; + ConVarInfo *info = NULL; + Handle_t hndl = 0; // Search for convar cvar = icvar->FindVar(name); @@ -149,12 +226,139 @@ Handle_t CConVarManager::FindConVar(const char *name) } // At this point, convar exists, so find out if we already have a handle for it - if (sm_trie_retrieve(m_CvarCache, name, &temp)) + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) { // If we do, then return that handle - return reinterpret_cast(temp); + return info->handle; } - // If we don't, then create a new handle from the convar and return it - return g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + // Insert the handle into our cache + sm_trie_insert(m_ConVarCache, name, info); + + return hndl; +} + +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + char fwdName[64]; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function: %d", funcid); + return; + } + + // Create a forward name + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); + + // First find out if the forward already exists + g_Forwards.FindForward(fwdName, &fwd); + + // If the forward doesn't exist... + if (fwd == NULL) + { + // This is the forward's parameter type list + ParamType p[] = {Param_Cell, Param_String, Param_String}; + + // Create the forward + fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Set the convar's forward to the newly created one + info->changeForward = fwd; + + // Set the convar's callback to our static one + cvar->InstallChangeCallback(OnConVarChanged); + } + } + + // Add the function to the forward's list + fwd->AddFunction(func); +} + +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function: %d", funcid); + return; + } + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Get the forward + fwd = info->changeForward; + + // If the forward doesn't exist, we can't unhook anything + if (fwd == NULL) + { + pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName()); + return; + } + + // Remove the function from the forward's list + if (!fwd->RemoveFunction(func)) + { + pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName()); + return; + } + + // If the forward now has 0 functions in it... + if (fwd->GetFunctionCount() == 0) + { + // Free this forward + g_Forwards.ReleaseForward(fwd); + info->changeForward = NULL; + + // Put the back the original convar callback + cvar->InstallChangeCallback(info->origCallback); + } + } +} + +void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) +{ + Trie *cache = g_ConVarManager.GetConVarCache(); + ConVarInfo *info; + + // Find the convar in the lookup trie + sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); + + FnChangeCallback origCallback = info->origCallback; + IChangeableForward *fwd = info->changeForward; + + // If there was a change callback installed previously, call it + if (origCallback) + { + origCallback(cvar, oldValue); + } + + // Now call forwards in plugins that have hooked this + fwd->PushCell(info->handle); + fwd->PushString(cvar->GetString()); + fwd->PushString(oldValue); + fwd->Execute(NULL); } \ No newline at end of file diff --git a/core/CConVarManager.h b/core/CConVarManager.h index 6ca9bae7..b21184de 100644 --- a/core/CConVarManager.h +++ b/core/CConVarManager.h @@ -17,9 +17,24 @@ #include "sm_globals.h" #include "sourcemm_api.h" #include "HandleSys.h" +#include "ForwardSys.h" #include "sm_trie.h" +#include #include +using namespace SourceHook; + +/** + * Holds SourceMod-specific information about a convar + */ +struct ConVarInfo +{ + Handle_t handle; /**< Handle to convar */ + bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */ + IChangeableForward *changeForward; /**< Forward associated with convar */ + FnChangeCallback origCallback; /**< The original callback function */ +}; + class CConVarManager : public SMGlobalClass, public IHandleTypeDispatch, @@ -36,17 +51,51 @@ public: // IHandleTypeDispatch public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: + /** + * Get the 'ConVar' handle type ID. + */ inline HandleType_t GetHandleType() { return m_ConVarType; } + + /** + * Get the convar lookup trie. + */ + inline Trie *GetConVarCache() + { + return m_ConVarCache; + } public: + /** + * Create a convar and return a handle to it. + */ Handle_t CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max); + + /** + * Searches for a convar and returns a handle to it + */ Handle_t FindConVar(const char* name); + + /** + * Add a function to call when the specified convar changes. + */ + void HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); + + /** + * Remove a function from the forward that will be called when the specified convar changes. + */ + void UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); +private: + /** + * Static callback that Valve's ConVar class executes when the convar's value changes. + */ + static void OnConVarChanged(ConVar *cvar, const char *oldValue); private: HandleType_t m_ConVarType; - Trie *m_CvarCache; + List m_ConVars; + Trie *m_ConVarCache; }; extern CConVarManager g_ConVarManager; diff --git a/core/smn_convar.cpp b/core/smn_convar.cpp index 716fb70e..ef7acf11 100644 --- a/core/smn_convar.cpp +++ b/core/smn_convar.cpp @@ -25,8 +25,7 @@ static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) // While the engine seems to accept a blank convar name, it causes a crash upon server quit if (name == NULL || strcmp(name, "") == 0) { - pContext->ThrowNativeError("Null or blank convar name is not allowed."); - return BAD_HANDLE; + return pContext->ThrowNativeError("Null or blank convar name is not allowed."); } pContext->LocalToString(params[2], &defaultVal); @@ -55,6 +54,40 @@ static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params) return g_ConVarManager.FindConVar(name); } +static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + g_ConVarManager.HookConVarChange(pContext, cvar, static_cast(params[2])); + + return 1; +} + +static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + g_ConVarManager.UnhookConVarChange(pContext, cvar, static_cast(params[2])); + + return 1; +} + static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -255,6 +288,23 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) return hasMax; } +static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + ConVar *cvar; + + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + } + + pContext->StringToLocalUTF8(params[2], params[3], cvar->GetName(), NULL); + + return 1; +} + static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -274,20 +324,23 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) REGISTER_NATIVES(convarNatives) { - {"CreateConVar", sm_CreateConVar}, - {"FindConVar", sm_FindConVar}, - {"GetConVarBool", sm_GetConVarBool}, - {"SetConVarBool", sm_SetConVarNum}, - {"GetConVarInt", sm_GetConVarInt}, - {"SetConVarInt", sm_SetConVarNum}, - {"GetConVarFloat", sm_GetConVarFloat}, - {"SetConVarFloat", sm_SetConVarFloat}, - {"GetConVarString", sm_GetConVarString}, - {"SetConVarString", sm_SetConVarString}, - {"GetConVarFlags", sm_GetConVarFlags}, - {"SetConVarFlags", sm_SetConVarFlags}, - {"GetConVarMin", sm_GetConVarMin}, - {"GetConVarMax", sm_GetConVarMax}, - {"ResetConVar", sm_ResetConVar}, - {NULL, NULL} + {"CreateConVar", sm_CreateConVar}, + {"FindConVar", sm_FindConVar}, + {"HookConVarChange", sm_HookConVarChange}, + {"UnhookConVarChange", sm_UnhookConVarChange}, + {"GetConVarBool", sm_GetConVarBool}, + {"SetConVarBool", sm_SetConVarNum}, + {"GetConVarInt", sm_GetConVarInt}, + {"SetConVarInt", sm_SetConVarNum}, + {"GetConVarFloat", sm_GetConVarFloat}, + {"SetConVarFloat", sm_SetConVarFloat}, + {"GetConVarString", sm_GetConVarString}, + {"SetConVarString", sm_SetConVarString}, + {"GetConVarFlags", sm_GetConVarFlags}, + {"SetConVarFlags", sm_SetConVarFlags}, + {"GetConVarName", sm_GetConVarName}, + {"GetConVarMin", sm_GetConVarMin}, + {"GetConVarMax", sm_GetConVarMax}, + {"ResetConVar", sm_ResetConVar}, + {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index fdf9cf5e..1a18a93b 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -74,6 +74,36 @@ native Handle:CreateConVar(const String:name[], const String:defaultValue[], con */ native Handle:FindConVar(const String:name[]); +/** + * Called when a console variable's value is changed. + * + * @param convar Handle to the convar that was changed. + * @param oldValue String containing the value of the convar before it was changed. + * @param newValue String containing the new value of the convar. + * @noreturn + */ +functag OnConVarChanged public(Handle:convar, const String:oldValue[], const String:newValue[]); + +/** + * Creates a hook for when a console variable's value is changed. + * + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native HookConVarChange(Handle:convar, OnConVarChanged:callback); + +/** + * Removes a hook for when a console variable's value is changed. + * + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. + * @return True on success, false otherwise. + * @error Invalid or corrupt Handle. + */ +native bool:UnhookConVarChange(Handle:convar, OnConVarChanged:callback); + /** * Returns the boolean value of a console variable. * @@ -136,11 +166,11 @@ native SetConVarFloat(Handle:convar, Float:value); * * @param convar Handle to the convar. * @param value Buffer to store the value of the convar. - * @param maxlen Maximum length of string buffer. + * @param maxlength Maximum length of string buffer. * @noreturn * @error Invalid or corrupt Handle. */ -native GetConVarString(Handle:convar, String:value[], maxlen); +native GetConVarString(Handle:convar, String:value[], maxlength); /** * Sets the string value of a console variable. @@ -171,6 +201,17 @@ native GetConVarFlags(Handle:convar); */ native SetConVarFlags(Handle:convar, flags); +/** + * Retrieves the name of a console variable. + * + * @param convar Handle to the convar. + * @param value Buffer to store the name of the convar. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetConVarName(Handle:convar, const String:name[], maxlength); + /** * Retrieves the minimum floating point value that a console variable can contain. * diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index eefe6201..99568264 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -224,7 +224,7 @@ namespace SourcePawn class IPluginContext { public: - /** Virtual destructr */ + /** Virtual destructor */ virtual ~IPluginContext() { }; public: /** @@ -265,7 +265,7 @@ namespace SourcePawn virtual IPluginDebugInfo *GetDebugInfo() =0; /** - * @brief Allocs memory on the secondary stack of a plugin. + * @brief Allocates memory on the secondary stack of a plugin. * Note that although called a heap, it is in fact a stack. * * @param cells Number of cells to allocate. From efff3951826a8a50c95d09c430a3a68fcf57db24 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 11 Feb 2007 11:20:38 +0000 Subject: [PATCH 0441/1664] Fixed Linux build... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40472 --- core/CConVarManager.cpp | 729 ++++++++++++++++++++-------------------- core/Makefile | 4 +- 2 files changed, 367 insertions(+), 366 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 5e54b82b..e5627007 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -1,364 +1,365 @@ -/** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ - -#include "CConVarManager.h" -#include "CLogger.h" -#include "PluginSys.h" -#include "sm_srvcmds.h" -#include "sm_stringutil.h" - -CConVarManager g_ConVarManager; - -CConVarManager::CConVarManager() : m_ConVarType(0) -{ - // Create a convar lookup trie - m_ConVarCache = sm_trie_create(); -} - -CConVarManager::~CConVarManager() -{ - List::iterator i; - - // Destroy our convar lookup trie - sm_trie_destroy(m_ConVarCache); - - // Destroy all the ConVarInfo structures - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) - { - delete (*i); - } - - m_ConVars.clear(); -} - -void CConVarManager::OnSourceModAllInitialized() -{ - HandleAccess sec; - - // Set up access rights for the 'ConVar' handle type - sec.access[HandleAccess_Read] = 0; - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - - // Create the 'ConVar' handle type - m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); - - // Add the 'cvars' option to the 'sm' console command - g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); -} - -void CConVarManager::OnSourceModShutdown() -{ - IChangeableForward *fwd; - List::iterator i; - - // Iterate list of ConVarInfo structures - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) - { - fwd = (*i)->changeForward; - - // Free any convar-change forwards that still exist - if (fwd) - { - g_Forwards.ReleaseForward(fwd); - } - } - - // Remove the 'cvars' option from the 'sm' console command - g_RootMenu.RemoveRootConsoleCommand("cvars", this); - - // Remove the 'ConVar' handle type - g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); -} - -void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) -{ - ConVarInfo *info; - ConCommandBase *cvar = static_cast(object); - - // Find convar in lookup trie - sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); - - // If convar was created by SourceMod plugin... - if (info->sourceMod) - { - // Then unregister it - g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); - } -} - -void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) -{ - if (argcount >= 3) - { - int id = 1; - - // Get plugin index that was passed - int num = atoi(g_RootMenu.GetArgument(2)); - - // If invalid plugin index... - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) - { - g_RootMenu.ConsolePrint("[SM] Plugin index not found."); - return; - } - - // Get plugin object - CPlugin *pl = g_PluginSys.GetPluginByOrder(num); - - // Get number of convars created by plugin - int convarnum = pl->GetConVarCount(); - - if (convarnum == 0) - { - g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); - return; - } - - g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); - - // Iterate convar list and display each one - for (int i = 0; i < convarnum; i++, id++) - { - ConVar *cvar = pl->GetConVarByIndex(i); - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); - } - - return; - } - - // Display usage of subcommand - g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); -} - -Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) -{ - ConVar *cvar = NULL; - ConVarInfo *info = NULL; - Handle_t hndl = 0; - - // Find out if the convar exists already - cvar = icvar->FindVar(name); - - // If the convar already exists... - if (cvar != NULL) - { - // First check if we already have a handle to it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) - { - // If we do, then return that handle - return info->handle; - } else { - // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); - - m_ConVars.push_back(info); - - return hndl; - } - } - - // To prevent creating a convar that has the same name as a console command... ugh - ConCommandBase *pBase = icvar->GetCommands(); - - while (pBase) - { - if (strcmp(pBase->GetName(), name) == 0) - { - return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); - } - - pBase = const_cast(pBase->GetNext()); - } - - // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); - - // Add new convar to plugin's list - g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); - - // Create a handle from the new convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = true; - info->changeForward = NULL; - info->origCallback = NULL; - - m_ConVars.push_back(info); - - // Insert the handle into our lookup trie - sm_trie_insert(m_ConVarCache, name, info); - - return hndl; -} - -Handle_t CConVarManager::FindConVar(const char *name) -{ - ConVar *cvar = NULL; - ConVarInfo *info = NULL; - Handle_t hndl = 0; - - // Search for convar - cvar = icvar->FindVar(name); - - // If it doesn't exist, then return an invalid handle - if (cvar == NULL) - { - return BAD_HANDLE; - } - - // At this point, convar exists, so find out if we already have a handle for it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) - { - // If we do, then return that handle - return info->handle; - } - - // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); - - m_ConVars.push_back(info); - - // Insert the handle into our cache - sm_trie_insert(m_ConVarCache, name, info); - - return hndl; -} - -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) -{ - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - char fwdName[64]; - ConVarInfo *info = NULL; - - // This shouldn't happen... - if (func == NULL) - { - pContext->ThrowNativeError("Invalid function: %d", funcid); - return; - } - - // Create a forward name - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); - - // First find out if the forward already exists - g_Forwards.FindForward(fwdName, &fwd); - - // If the forward doesn't exist... - if (fwd == NULL) - { - // This is the forward's parameter type list - ParamType p[] = {Param_Cell, Param_String, Param_String}; - - // Create the forward - fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); - - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) - { - // Set the convar's forward to the newly created one - info->changeForward = fwd; - - // Set the convar's callback to our static one - cvar->InstallChangeCallback(OnConVarChanged); - } - } - - // Add the function to the forward's list - fwd->AddFunction(func); -} - -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) -{ - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - ConVarInfo *info = NULL; - - // This shouldn't happen... - if (func == NULL) - { - pContext->ThrowNativeError("Invalid function: %d", funcid); - return; - } - - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) - { - // Get the forward - fwd = info->changeForward; - - // If the forward doesn't exist, we can't unhook anything - if (fwd == NULL) - { - pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName()); - return; - } - - // Remove the function from the forward's list - if (!fwd->RemoveFunction(func)) - { - pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName()); - return; - } - - // If the forward now has 0 functions in it... - if (fwd->GetFunctionCount() == 0) - { - // Free this forward - g_Forwards.ReleaseForward(fwd); - info->changeForward = NULL; - - // Put the back the original convar callback - cvar->InstallChangeCallback(info->origCallback); - } - } -} - -void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) -{ - Trie *cache = g_ConVarManager.GetConVarCache(); - ConVarInfo *info; - - // Find the convar in the lookup trie - sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); - - FnChangeCallback origCallback = info->origCallback; - IChangeableForward *fwd = info->changeForward; - - // If there was a change callback installed previously, call it - if (origCallback) - { - origCallback(cvar, oldValue); - } - - // Now call forwards in plugins that have hooked this - fwd->PushCell(info->handle); - fwd->PushString(cvar->GetString()); - fwd->PushString(oldValue); - fwd->Execute(NULL); -} \ No newline at end of file +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "CConVarManager.h" +#include "CLogger.h" +#include "PluginSys.h" +#include "sm_srvcmds.h" +#include "sm_stringutil.h" + +CConVarManager g_ConVarManager; + +CConVarManager::CConVarManager() : m_ConVarType(0) +{ + // Create a convar lookup trie + m_ConVarCache = sm_trie_create(); +} + +CConVarManager::~CConVarManager() +{ + List::iterator i; + + // Destroy our convar lookup trie + sm_trie_destroy(m_ConVarCache); + + // Destroy all the ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + delete (*i); + } + + m_ConVars.clear(); +} + +void CConVarManager::OnSourceModAllInitialized() +{ + HandleAccess sec; + + // Set up access rights for the 'ConVar' handle type + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + // Create the 'ConVar' handle type + m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); + + // Add the 'cvars' option to the 'sm' console command + g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); +} + +void CConVarManager::OnSourceModShutdown() +{ + IChangeableForward *fwd; + List::iterator i; + + // Iterate list of ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + fwd = (*i)->changeForward; + + // Free any convar-change forwards that still exist + if (fwd) + { + g_Forwards.ReleaseForward(fwd); + } + } + + // Remove the 'cvars' option from the 'sm' console command + g_RootMenu.RemoveRootConsoleCommand("cvars", this); + + // Remove the 'ConVar' handle type + g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); +} + +void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) +{ + ConVarInfo *info; + ConCommandBase *cvar = static_cast(object); + + // Find convar in lookup trie + sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); + + // If convar was created by SourceMod plugin... + if (info->sourceMod) + { + // Then unregister it + g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); + } +} + +void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ + if (argcount >= 3) + { + int id = 1; + + // Get plugin index that was passed + int num = atoi(g_RootMenu.GetArgument(2)); + + // If invalid plugin index... + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + g_RootMenu.ConsolePrint("[SM] Plugin index not found."); + return; + } + + // Get plugin object + CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + + // Get number of convars created by plugin + int convarnum = pl->GetConVarCount(); + + if (convarnum == 0) + { + g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); + return; + } + + g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); + + // Iterate convar list and display each one + for (int i = 0; i < convarnum; i++, id++) + { + ConVar *cvar = pl->GetConVarByIndex(i); + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); + } + + return; + } + + // Display usage of subcommand + g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); +} + +Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) +{ + ConVar *cvar = NULL; + ConVarInfo *info = NULL; + Handle_t hndl = 0; + + // Find out if the convar exists already + cvar = icvar->FindVar(name); + + // If the convar already exists... + if (cvar != NULL) + { + // First check if we already have a handle to it + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + { + // If we do, then return that handle + return info->handle; + } else { + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + return hndl; + } + } + + // To prevent creating a convar that has the same name as a console command... ugh + ConCommandBase *pBase = icvar->GetCommands(); + + while (pBase) + { + if (strcmp(pBase->GetName(), name) == 0) + { + return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); + } + + pBase = const_cast(pBase->GetNext()); + } + + // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! + cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); + + // Add new convar to plugin's list + g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); + + // Create a handle from the new convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = true; + info->changeForward = NULL; + info->origCallback = NULL; + + m_ConVars.push_back(info); + + // Insert the handle into our lookup trie + sm_trie_insert(m_ConVarCache, name, info); + + return hndl; +} + +Handle_t CConVarManager::FindConVar(const char *name) +{ + ConVar *cvar = NULL; + ConVarInfo *info = NULL; + Handle_t hndl = 0; + + // Search for convar + cvar = icvar->FindVar(name); + + // If it doesn't exist, then return an invalid handle + if (cvar == NULL) + { + return BAD_HANDLE; + } + + // At this point, convar exists, so find out if we already have a handle for it + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + { + // If we do, then return that handle + return info->handle; + } + + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + // Insert the handle into our cache + sm_trie_insert(m_ConVarCache, name, info); + + return hndl; +} + +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + char fwdName[64]; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function: %d", funcid); + return; + } + + // Create a forward name + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); + + // First find out if the forward already exists + g_Forwards.FindForward(fwdName, &fwd); + + // If the forward doesn't exist... + if (fwd == NULL) + { + // This is the forward's parameter type list + ParamType p[] = {Param_Cell, Param_String, Param_String}; + + // Create the forward + fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Set the convar's forward to the newly created one + info->changeForward = fwd; + + // Set the convar's callback to our static one + cvar->InstallChangeCallback(OnConVarChanged); + } + } + + // Add the function to the forward's list + fwd->AddFunction(func); +} + +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function: %d", funcid); + return; + } + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Get the forward + fwd = info->changeForward; + + // If the forward doesn't exist, we can't unhook anything + if (fwd == NULL) + { + pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName()); + return; + } + + // Remove the function from the forward's list + if (!fwd->RemoveFunction(func)) + { + pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName()); + return; + } + + // If the forward now has 0 functions in it... + if (fwd->GetFunctionCount() == 0) + { + // Free this forward + g_Forwards.ReleaseForward(fwd); + info->changeForward = NULL; + + // Put the back the original convar callback + cvar->InstallChangeCallback(info->origCallback); + } + } +} + +void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) +{ + Trie *cache = g_ConVarManager.GetConVarCache(); + ConVarInfo *info; + + // Find the convar in the lookup trie + sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); + + FnChangeCallback origCallback = info->origCallback; + IChangeableForward *fwd = info->changeForward; + + // If there was a change callback installed previously, call it + if (origCallback) + { + origCallback(cvar, oldValue); + } + + // Now call forwards in plugins that have hooked this + fwd->PushCell(info->handle); + fwd->PushString(cvar->GetString()); + fwd->PushString(oldValue); + fwd->Execute(NULL); +} + diff --git a/core/Makefile b/core/Makefile index b1576f89..c0d90301 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,8 +19,8 @@ BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk -OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CDbgReporter.cpp CLogger.cpp \ - CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ +OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CConVarManager.cpp CDbgReporter.cpp \ + CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ smn_player.cpp smn_string.cpp smn_textparse.cpp smn_convar.cpp smn_admin.cpp \ From c5e98f7dc2a57692a5ef31851ed959132f3266e6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 05:13:53 +0000 Subject: [PATCH 0442/1664] added ability to specify extra options to the build line --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40473 --- tools/builder/Config.cs | 5 +++++ tools/builder/LinuxBuilder.cs | 5 +++++ tools/builder/Win32Builder.cs | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/tools/builder/Config.cs b/tools/builder/Config.cs index 4f7700e7..b46dc785 100644 --- a/tools/builder/Config.cs +++ b/tools/builder/Config.cs @@ -19,6 +19,7 @@ namespace builder public string SVNVersion; public string ProductVersion; public string Compressor; + public string BuildOptions; public builder.BasePlatform Platform; public Config() @@ -99,6 +100,10 @@ namespace builder else if (key.CompareTo("Compressor") == 0) { Compressor = val; + } + else if (key.CompareTo("BuildOptions") == 0) + { + BuildOptions = val; } } } diff --git a/tools/builder/LinuxBuilder.cs b/tools/builder/LinuxBuilder.cs index ccda2027..02532f6b 100644 --- a/tools/builder/LinuxBuilder.cs +++ b/tools/builder/LinuxBuilder.cs @@ -29,6 +29,11 @@ namespace builder info.Arguments = "zcvf \"" + name + "\" \"" + ltarget + "\""; info.UseShellExecute = false; + if (cfg.BuildOptions != null) + { + info.Arguments += " " + cfg.BuildOptions; + } + Process p = Process.Start(info); p.WaitForExit(); diff --git a/tools/builder/Win32Builder.cs b/tools/builder/Win32Builder.cs index fda67bb2..cb758f44 100644 --- a/tools/builder/Win32Builder.cs +++ b/tools/builder/Win32Builder.cs @@ -29,6 +29,11 @@ namespace builder info.Arguments = "-r \"" + name + "\" \"" + ltarget + "\""; info.UseShellExecute = false; + if (cfg.BuildOptions != null) + { + info.Arguments += " " + cfg.BuildOptions; + } + Process p = Process.Start(info); p.WaitForExit(); From 2747f06eb7af274d8323c6a8bc2d651cbe2fcbc1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 05:43:14 +0000 Subject: [PATCH 0443/1664] totally wrong place, i'm stupid --bail --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40474 --- tools/builder/LinuxBuilder.cs | 11 ++++++----- tools/builder/Win32Builder.cs | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/builder/LinuxBuilder.cs b/tools/builder/LinuxBuilder.cs index 02532f6b..a352bdb9 100644 --- a/tools/builder/LinuxBuilder.cs +++ b/tools/builder/LinuxBuilder.cs @@ -29,11 +29,6 @@ namespace builder info.Arguments = "zcvf \"" + name + "\" \"" + ltarget + "\""; info.UseShellExecute = false; - if (cfg.BuildOptions != null) - { - info.Arguments += " " + cfg.BuildOptions; - } - Process p = Process.Start(info); p.WaitForExit(); @@ -96,6 +91,12 @@ namespace builder info.FileName = cfg.BuilderPath; info.Arguments = ""; info.UseShellExecute = false; + + if (cfg.BuildOptions != null) + { + info.Arguments += " " + cfg.BuildOptions; + } + p = Process.Start(info); p.WaitForExit(); p.Close(); diff --git a/tools/builder/Win32Builder.cs b/tools/builder/Win32Builder.cs index cb758f44..ed0a082a 100644 --- a/tools/builder/Win32Builder.cs +++ b/tools/builder/Win32Builder.cs @@ -29,11 +29,6 @@ namespace builder info.Arguments = "-r \"" + name + "\" \"" + ltarget + "\""; info.UseShellExecute = false; - if (cfg.BuildOptions != null) - { - info.Arguments += " " + cfg.BuildOptions; - } - Process p = Process.Start(info); p.WaitForExit(); @@ -83,6 +78,11 @@ namespace builder info.Arguments = "/rebuild " + lib.ReleaseBuild + " " + projectFile; info.UseShellExecute = false; + if (cfg.BuildOptions != null) + { + info.Arguments += " " + cfg.BuildOptions; + } + Process p = Process.Start(info); p.WaitForExit(); p.Close(); From dd9b57585318f2753f8b82b72ddee7993c6bda59 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 05:46:00 +0000 Subject: [PATCH 0444/1664] Fixed up some error messages... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40475 --- core/CConVarManager.cpp | 9 ++++----- core/CDbgReporter.cpp | 2 +- core/smn_convar.cpp | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index e5627007..8320888e 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -259,7 +259,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu // This shouldn't happen... if (func == NULL) { - pContext->ThrowNativeError("Invalid function: %d", funcid); + pContext->ThrowNativeError("Invalid function specified"); return; } @@ -302,7 +302,7 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, // This shouldn't happen... if (func == NULL) { - pContext->ThrowNativeError("Invalid function: %d", funcid); + pContext->ThrowNativeError("Invalid function specified"); return; } @@ -315,14 +315,14 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, // If the forward doesn't exist, we can't unhook anything if (fwd == NULL) { - pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName()); + pContext->ThrowNativeError("Convar \"%s\" has no active hook", cvar->GetName()); return; } // Remove the function from the forward's list if (!fwd->RemoveFunction(func)) { - pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName()); + pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", cvar->GetName()); return; } @@ -362,4 +362,3 @@ void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) fwd->PushString(oldValue); fwd->Execute(NULL); } - diff --git a/core/CDbgReporter.cpp b/core/CDbgReporter.cpp index f2f46ad8..601de0e5 100644 --- a/core/CDbgReporter.cpp +++ b/core/CDbgReporter.cpp @@ -41,7 +41,7 @@ void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *err const char *custerr; if ((custerr=error->GetCustomErrorString()) != NULL) { - g_Logger.LogError("[SM] Native \"%s\" reported: \"%s\"", lastname, custerr); + g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr); } else { g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname); } diff --git a/core/smn_convar.cpp b/core/smn_convar.cpp index ef7acf11..9efccae6 100644 --- a/core/smn_convar.cpp +++ b/core/smn_convar.cpp @@ -25,7 +25,7 @@ static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) // While the engine seems to accept a blank convar name, it causes a crash upon server quit if (name == NULL || strcmp(name, "") == 0) { - return pContext->ThrowNativeError("Null or blank convar name is not allowed."); + return pContext->ThrowNativeError("Null or blank convar name is not allowed"); } pContext->LocalToString(params[2], &defaultVal); From ce7f2ae23b749de12a386f2f5f42f7393cecf0a3 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 05:53:49 +0000 Subject: [PATCH 0445/1664] More error message fix-ups: removed periods from single sentence native errors - did I miss any? Probably... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40476 --- core/sm_stringutil.cpp | 4 +-- core/smn_float.cpp | 4 +-- core/smn_player.cpp | 60 +++++++++++++++++++++--------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index b8c3d764..4e425168 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -74,7 +74,7 @@ try_serverlang: langname = "en"; //:TODO: read serverlang if (!TryServerLanguage(langname ? langname : "en", &langid)) { - pCtx->ThrowNativeError("Translation failure: English language not found."); + pCtx->ThrowNativeError("Translation failure: English language not found"); goto error_out; } } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { @@ -83,7 +83,7 @@ try_serverlang: { if (langname && !strcmp(langname, "en")) { - pCtx->ThrowNativeError("Translation failure: English language not found."); + pCtx->ThrowNativeError("Translation failure: English language not found"); goto error_out; } target = LANG_SERVER; diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 4a8e8c34..4973a22f 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -88,7 +88,7 @@ static cell_t sm_Logarithm(IPluginContext *pCtx, const cell_t *params) if ((val <= 0) || (base <= 0)) { - return pCtx->ThrowNativeError("Cannot evaluate the logarithm of zero or a negative number (val:%f base:%f).", val, base); + return pCtx->ThrowNativeError("Cannot evaluate the logarithm of zero or a negative number (val:%f base:%f)", val, base); } if (base == 10.0) { @@ -121,7 +121,7 @@ static cell_t sm_SquareRoot(IPluginContext *pCtx, const cell_t *params) if (val < 0.0) { - return pCtx->ThrowNativeError("Cannot evaluate the square root of a negative number (val:%f).", val); + return pCtx->ThrowNativeError("Cannot evaluate the square root of a negative number (val:%f)", val); } return sp_ftoc(sqrt(val)); diff --git a/core/smn_player.cpp b/core/smn_player.cpp index fa6da607..41378cf2 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -46,13 +46,13 @@ static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { - return pCtx->ThrowNativeError("Client %d is not connected.", index); + return pCtx->ThrowNativeError("Client %d is not connected", index); } pCtx->StringToLocalUTF8(params[2], static_cast(params[3]), pPlayer->GetName(), NULL); @@ -64,13 +64,13 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { - return pCtx->ThrowNativeError("Client %d is not connected.", index); + return pCtx->ThrowNativeError("Client %d is not connected", index); } char buf[64], *ptr; @@ -90,13 +90,13 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { - return pCtx->ThrowNativeError("Client %d is not connected.", index); + return pCtx->ThrowNativeError("Client %d is not connected", index); } if (!pPlayer->IsAuthorized()) @@ -114,7 +114,7 @@ static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } return (g_Players.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0; @@ -125,7 +125,7 @@ static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } return (g_Players.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0; @@ -136,7 +136,7 @@ static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } return (g_Players.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0; @@ -147,13 +147,13 @@ static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsConnected()) { - return pCtx->ThrowNativeError("Client %d is not connected.", index); + return pCtx->ThrowNativeError("Client %d is not connected", index); } return (pPlayer->IsFakeClient()) ? 1 : 0; @@ -182,11 +182,11 @@ static cell_t sm_GetClientInfo(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } char *key; @@ -207,13 +207,13 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) { - return pCtx->ThrowNativeError("Invalid client index %d.", index); + return pCtx->ThrowNativeError("Invalid client index %d", index); } CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); if (!pPlayer->IsInGame()) { - return pCtx->ThrowNativeError("Client %d is not in game.", index); + return pCtx->ThrowNativeError("Client %d is not in game", index); } char buffer[1024]; @@ -237,15 +237,15 @@ static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } if (!g_Admins.IsValidAdmin(params[2])) { - return pContext->ThrowNativeError("AdminId %x is not valid.", params[2]); + return pContext->ThrowNativeError("AdminId %x is not valid", params[2]); } pPlayer->SetAdminId(params[2], params[3] ? true : false); @@ -259,11 +259,11 @@ static cell_t GetUserAdmin(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } return pPlayer->GetAdminId(); @@ -275,11 +275,11 @@ static cell_t AddUserFlags(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } AdminId id; @@ -305,11 +305,11 @@ static cell_t RemoveUserFlags(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } AdminId id; @@ -334,11 +334,11 @@ static cell_t SetUserFlagBits(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } AdminId id; @@ -359,11 +359,11 @@ static cell_t GetUserFlagBits(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } AdminId id; @@ -381,11 +381,11 @@ static cell_t GetClientUserId(IPluginContext *pContext, const cell_t *params) CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer) { - return pContext->ThrowNativeError("Invalid client index %d.", client); + return pContext->ThrowNativeError("Invalid client index %d", client); } if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Client %d is not connected.", client); + return pContext->ThrowNativeError("Client %d is not connected", client); } return engine->GetPlayerUserId(pPlayer->GetEdict()); From 1ac8d82d90d9f012e5d2d28ad3c3e30c67df307d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 05:56:27 +0000 Subject: [PATCH 0446/1664] --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40477 --- tools/builder/Win32Builder.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/builder/Win32Builder.cs b/tools/builder/Win32Builder.cs index ed0a082a..c3e72aa2 100644 --- a/tools/builder/Win32Builder.cs +++ b/tools/builder/Win32Builder.cs @@ -75,14 +75,15 @@ namespace builder info.WorkingDirectory = path; info.FileName = cfg.BuilderPath; - info.Arguments = "/rebuild " + lib.ReleaseBuild + " " + projectFile; info.UseShellExecute = false; if (cfg.BuildOptions != null) { - info.Arguments += " " + cfg.BuildOptions; + info.Arguments = cfg.BuildOptions + " "; } + info.Arguments += "/rebuild " + lib.ReleaseBuild + " " + projectFile; + Process p = Process.Start(info); p.WaitForExit(); p.Close(); From c83b9236b0d31e27b7ba828c69e9ab571f29710b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 07:11:00 +0000 Subject: [PATCH 0447/1664] Fixed return value on UnhookConVarChange --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40478 --- core/CConVarManager.cpp | 728 ++++++++++++++++++------------------ plugins/include/console.inc | 4 +- 2 files changed, 366 insertions(+), 366 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 8320888e..4a6c6e0e 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -1,364 +1,364 @@ -/** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ - -#include "CConVarManager.h" -#include "CLogger.h" -#include "PluginSys.h" -#include "sm_srvcmds.h" -#include "sm_stringutil.h" - -CConVarManager g_ConVarManager; - -CConVarManager::CConVarManager() : m_ConVarType(0) -{ - // Create a convar lookup trie - m_ConVarCache = sm_trie_create(); -} - -CConVarManager::~CConVarManager() -{ - List::iterator i; - - // Destroy our convar lookup trie - sm_trie_destroy(m_ConVarCache); - - // Destroy all the ConVarInfo structures - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) - { - delete (*i); - } - - m_ConVars.clear(); -} - -void CConVarManager::OnSourceModAllInitialized() -{ - HandleAccess sec; - - // Set up access rights for the 'ConVar' handle type - sec.access[HandleAccess_Read] = 0; - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - - // Create the 'ConVar' handle type - m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); - - // Add the 'cvars' option to the 'sm' console command - g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); -} - -void CConVarManager::OnSourceModShutdown() -{ - IChangeableForward *fwd; - List::iterator i; - - // Iterate list of ConVarInfo structures - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) - { - fwd = (*i)->changeForward; - - // Free any convar-change forwards that still exist - if (fwd) - { - g_Forwards.ReleaseForward(fwd); - } - } - - // Remove the 'cvars' option from the 'sm' console command - g_RootMenu.RemoveRootConsoleCommand("cvars", this); - - // Remove the 'ConVar' handle type - g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); -} - -void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) -{ - ConVarInfo *info; - ConCommandBase *cvar = static_cast(object); - - // Find convar in lookup trie - sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); - - // If convar was created by SourceMod plugin... - if (info->sourceMod) - { - // Then unregister it - g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); - } -} - -void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) -{ - if (argcount >= 3) - { - int id = 1; - - // Get plugin index that was passed - int num = atoi(g_RootMenu.GetArgument(2)); - - // If invalid plugin index... - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) - { - g_RootMenu.ConsolePrint("[SM] Plugin index not found."); - return; - } - - // Get plugin object - CPlugin *pl = g_PluginSys.GetPluginByOrder(num); - - // Get number of convars created by plugin - int convarnum = pl->GetConVarCount(); - - if (convarnum == 0) - { - g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); - return; - } - - g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); - - // Iterate convar list and display each one - for (int i = 0; i < convarnum; i++, id++) - { - ConVar *cvar = pl->GetConVarByIndex(i); - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); - } - - return; - } - - // Display usage of subcommand - g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); -} - -Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) -{ - ConVar *cvar = NULL; - ConVarInfo *info = NULL; - Handle_t hndl = 0; - - // Find out if the convar exists already - cvar = icvar->FindVar(name); - - // If the convar already exists... - if (cvar != NULL) - { - // First check if we already have a handle to it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) - { - // If we do, then return that handle - return info->handle; - } else { - // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); - - m_ConVars.push_back(info); - - return hndl; - } - } - - // To prevent creating a convar that has the same name as a console command... ugh - ConCommandBase *pBase = icvar->GetCommands(); - - while (pBase) - { - if (strcmp(pBase->GetName(), name) == 0) - { - return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); - } - - pBase = const_cast(pBase->GetNext()); - } - - // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); - - // Add new convar to plugin's list - g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); - - // Create a handle from the new convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = true; - info->changeForward = NULL; - info->origCallback = NULL; - - m_ConVars.push_back(info); - - // Insert the handle into our lookup trie - sm_trie_insert(m_ConVarCache, name, info); - - return hndl; -} - -Handle_t CConVarManager::FindConVar(const char *name) -{ - ConVar *cvar = NULL; - ConVarInfo *info = NULL; - Handle_t hndl = 0; - - // Search for convar - cvar = icvar->FindVar(name); - - // If it doesn't exist, then return an invalid handle - if (cvar == NULL) - { - return BAD_HANDLE; - } - - // At this point, convar exists, so find out if we already have a handle for it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) - { - // If we do, then return that handle - return info->handle; - } - - // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); - - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); - - m_ConVars.push_back(info); - - // Insert the handle into our cache - sm_trie_insert(m_ConVarCache, name, info); - - return hndl; -} - -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) -{ - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - char fwdName[64]; - ConVarInfo *info = NULL; - - // This shouldn't happen... - if (func == NULL) - { - pContext->ThrowNativeError("Invalid function specified"); - return; - } - - // Create a forward name - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); - - // First find out if the forward already exists - g_Forwards.FindForward(fwdName, &fwd); - - // If the forward doesn't exist... - if (fwd == NULL) - { - // This is the forward's parameter type list - ParamType p[] = {Param_Cell, Param_String, Param_String}; - - // Create the forward - fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); - - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) - { - // Set the convar's forward to the newly created one - info->changeForward = fwd; - - // Set the convar's callback to our static one - cvar->InstallChangeCallback(OnConVarChanged); - } - } - - // Add the function to the forward's list - fwd->AddFunction(func); -} - -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) -{ - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - ConVarInfo *info = NULL; - - // This shouldn't happen... - if (func == NULL) - { - pContext->ThrowNativeError("Invalid function specified"); - return; - } - - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) - { - // Get the forward - fwd = info->changeForward; - - // If the forward doesn't exist, we can't unhook anything - if (fwd == NULL) - { - pContext->ThrowNativeError("Convar \"%s\" has no active hook", cvar->GetName()); - return; - } - - // Remove the function from the forward's list - if (!fwd->RemoveFunction(func)) - { - pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", cvar->GetName()); - return; - } - - // If the forward now has 0 functions in it... - if (fwd->GetFunctionCount() == 0) - { - // Free this forward - g_Forwards.ReleaseForward(fwd); - info->changeForward = NULL; - - // Put the back the original convar callback - cvar->InstallChangeCallback(info->origCallback); - } - } -} - -void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) -{ - Trie *cache = g_ConVarManager.GetConVarCache(); - ConVarInfo *info; - - // Find the convar in the lookup trie - sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); - - FnChangeCallback origCallback = info->origCallback; - IChangeableForward *fwd = info->changeForward; - - // If there was a change callback installed previously, call it - if (origCallback) - { - origCallback(cvar, oldValue); - } - - // Now call forwards in plugins that have hooked this - fwd->PushCell(info->handle); - fwd->PushString(cvar->GetString()); - fwd->PushString(oldValue); - fwd->Execute(NULL); -} +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "CConVarManager.h" +#include "CLogger.h" +#include "PluginSys.h" +#include "sm_srvcmds.h" +#include "sm_stringutil.h" + +CConVarManager g_ConVarManager; + +CConVarManager::CConVarManager() : m_ConVarType(0) +{ + // Create a convar lookup trie + m_ConVarCache = sm_trie_create(); +} + +CConVarManager::~CConVarManager() +{ + List::iterator i; + + // Destroy our convar lookup trie + sm_trie_destroy(m_ConVarCache); + + // Destroy all the ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + delete (*i); + } + + m_ConVars.clear(); +} + +void CConVarManager::OnSourceModAllInitialized() +{ + HandleAccess sec; + + // Set up access rights for the 'ConVar' handle type + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + // Create the 'ConVar' handle type + m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); + + // Add the 'cvars' option to the 'sm' console command + g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); +} + +void CConVarManager::OnSourceModShutdown() +{ + IChangeableForward *fwd; + List::iterator i; + + // Iterate list of ConVarInfo structures + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + { + fwd = (*i)->changeForward; + + // Free any convar-change forwards that still exist + if (fwd) + { + g_Forwards.ReleaseForward(fwd); + } + } + + // Remove the 'cvars' option from the 'sm' console command + g_RootMenu.RemoveRootConsoleCommand("cvars", this); + + // Remove the 'ConVar' handle type + g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); +} + +void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) +{ + ConVarInfo *info; + ConCommandBase *cvar = static_cast(object); + + // Find convar in lookup trie + sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); + + // If convar was created by SourceMod plugin... + if (info->sourceMod) + { + // Then unregister it + g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); + } +} + +void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ + if (argcount >= 3) + { + int id = 1; + + // Get plugin index that was passed + int num = atoi(g_RootMenu.GetArgument(2)); + + // If invalid plugin index... + if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + { + g_RootMenu.ConsolePrint("[SM] Plugin index not found."); + return; + } + + // Get plugin object + CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + + // Get number of convars created by plugin + int convarnum = pl->GetConVarCount(); + + if (convarnum == 0) + { + g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); + return; + } + + g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); + + // Iterate convar list and display each one + for (int i = 0; i < convarnum; i++, id++) + { + ConVar *cvar = pl->GetConVarByIndex(i); + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); + } + + return; + } + + // Display usage of subcommand + g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); +} + +Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) +{ + ConVar *cvar = NULL; + ConVarInfo *info = NULL; + Handle_t hndl = 0; + + // Find out if the convar exists already + cvar = icvar->FindVar(name); + + // If the convar already exists... + if (cvar != NULL) + { + // First check if we already have a handle to it + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + { + // If we do, then return that handle + return info->handle; + } else { + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + return hndl; + } + } + + // To prevent creating a convar that has the same name as a console command... ugh + ConCommandBase *pBase = icvar->GetCommands(); + + while (pBase) + { + if (strcmp(pBase->GetName(), name) == 0) + { + return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); + } + + pBase = const_cast(pBase->GetNext()); + } + + // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! + cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); + + // Add new convar to plugin's list + g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); + + // Create a handle from the new convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = true; + info->changeForward = NULL; + info->origCallback = NULL; + + m_ConVars.push_back(info); + + // Insert the handle into our lookup trie + sm_trie_insert(m_ConVarCache, name, info); + + return hndl; +} + +Handle_t CConVarManager::FindConVar(const char *name) +{ + ConVar *cvar = NULL; + ConVarInfo *info = NULL; + Handle_t hndl = 0; + + // Search for convar + cvar = icvar->FindVar(name); + + // If it doesn't exist, then return an invalid handle + if (cvar == NULL) + { + return BAD_HANDLE; + } + + // At this point, convar exists, so find out if we already have a handle for it + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + { + // If we do, then return that handle + return info->handle; + } + + // If we don't, then create a new handle from the convar + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + + info = new ConVarInfo; + info->handle = hndl; + info->sourceMod = false; + info->changeForward = NULL; + info->origCallback = cvar->GetCallback(); + + m_ConVars.push_back(info); + + // Insert the handle into our cache + sm_trie_insert(m_ConVarCache, name, info); + + return hndl; +} + +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + char fwdName[64]; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function specified"); + return; + } + + // Create a forward name + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); + + // First find out if the forward already exists + g_Forwards.FindForward(fwdName, &fwd); + + // If the forward doesn't exist... + if (fwd == NULL) + { + // This is the forward's parameter type list + ParamType p[] = {Param_Cell, Param_String, Param_String}; + + // Create the forward + fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Set the convar's forward to the newly created one + info->changeForward = fwd; + + // Set the convar's callback to our static one + cvar->InstallChangeCallback(OnConVarChanged); + } + } + + // Add the function to the forward's list + fwd->AddFunction(func); +} + +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +{ + IPluginFunction *func = pContext->GetFunctionById(funcid); + IChangeableForward *fwd = NULL; + ConVarInfo *info = NULL; + + // This shouldn't happen... + if (func == NULL) + { + pContext->ThrowNativeError("Invalid function specified"); + return; + } + + // Find the convar in the lookup trie + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + { + // Get the forward + fwd = info->changeForward; + + // If the forward doesn't exist, we can't unhook anything + if (fwd == NULL) + { + pContext->ThrowNativeError("Convar \"%s\" has no active hook", cvar->GetName()); + return; + } + + // Remove the function from the forward's list + if (!fwd->RemoveFunction(func)) + { + pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", cvar->GetName()); + return; + } + + // If the forward now has 0 functions in it... + if (fwd->GetFunctionCount() == 0) + { + // Free this forward + g_Forwards.ReleaseForward(fwd); + info->changeForward = NULL; + + // Put the back the original convar callback + cvar->InstallChangeCallback(info->origCallback); + } + } +} + +void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) +{ + Trie *cache = g_ConVarManager.GetConVarCache(); + ConVarInfo *info; + + // Find the convar in the lookup trie + sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); + + FnChangeCallback origCallback = info->origCallback; + IChangeableForward *fwd = info->changeForward; + + // If there was a change callback installed previously, call it + if (origCallback) + { + origCallback(cvar, oldValue); + } + + // Now call forwards in plugins that have hooked this + fwd->PushCell(info->handle); + fwd->PushString(cvar->GetString()); + fwd->PushString(oldValue); + fwd->Execute(NULL); +} diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 1a18a93b..810754e0 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -99,10 +99,10 @@ native HookConVarChange(Handle:convar, OnConVarChanged:callback); * * @param convar Handle to the convar. * @param callback An OnConVarChanged function pointer. - * @return True on success, false otherwise. + * @noreturn * @error Invalid or corrupt Handle. */ -native bool:UnhookConVarChange(Handle:convar, OnConVarChanged:callback); +native UnhookConVarChange(Handle:convar, OnConVarChanged:callback); /** * Returns the boolean value of a console variable. From 7b8eaf4f7526787e81046f5255cafcb0495c3393 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 07:22:25 +0000 Subject: [PATCH 0448/1664] Specified more error scenarios... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40479 --- plugins/include/console.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 810754e0..58b04506 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -63,6 +63,7 @@ * @param hasMax Optional boolean that determines if the convar has a maximum value. * @param max Maximum floating point value that the convar can have if hasMax is true. * @return A handle to the newly created convar. If the convar already exists, INVALID_HANDLE is returned. + * @error Convar name is blank or is the same as a console command. */ native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:helpText[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); @@ -90,7 +91,7 @@ functag OnConVarChanged public(Handle:convar, const String:oldValue[], const Str * @param convar Handle to the convar. * @param callback An OnConVarChanged function pointer. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle or invalid callback function. */ native HookConVarChange(Handle:convar, OnConVarChanged:callback); @@ -100,7 +101,7 @@ native HookConVarChange(Handle:convar, OnConVarChanged:callback); * @param convar Handle to the convar. * @param callback An OnConVarChanged function pointer. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. */ native UnhookConVarChange(Handle:convar, OnConVarChanged:callback); From afd3d3dc88869d4bfad5b1df37bab412b71e867e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 08:28:35 +0000 Subject: [PATCH 0449/1664] fixed a silly bug in translation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40480 --- core/sm_stringutil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 4e425168..069cac25 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -94,8 +94,6 @@ try_serverlang: goto error_out; } - max_params = pTrans.fmt_count; - if (!TryTranslation(pl, key, langid, langcount, &pTrans)) { if (target != LANG_SERVER) @@ -112,6 +110,8 @@ try_serverlang: } } + max_params = pTrans.fmt_count; + for (size_t i=0; iLocalToPhysAddr(params[*arg], reinterpret_cast(&new_params[i])); From 6cff249b5cca2ca22760df7fb662d69859ab985a Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 09:00:55 +0000 Subject: [PATCH 0450/1664] Fixed tabs, hopefully... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40481 --- plugins/include/admin.inc | 101 +++++++++--------- plugins/include/console.inc | 189 +++++++++++++++++----------------- plugins/include/core.inc | 2 +- plugins/include/datapack.inc | 11 +- plugins/include/files.inc | 51 ++++----- plugins/include/float.inc | 3 +- plugins/include/geoip.inc | 2 +- plugins/include/handles.inc | 10 +- plugins/include/helpers.inc | 1 + plugins/include/lang.inc | 3 +- plugins/include/sourcemod.inc | 27 ++--- plugins/include/string.inc | 19 ++-- plugins/include/textparse.inc | 71 ++++++------- 13 files changed, 250 insertions(+), 240 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 3bfad62a..d803edf3 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -127,7 +128,7 @@ enum AdminCachePart /** * Called when part of the cache which needs to be rebuilt. * - * @param part Part of the admin cache to rebuild. + * @param part Part of the admin cache to rebuild. */ forward OnRebuildAdminCache(AdminCachePart:part); @@ -326,9 +327,9 @@ native bool:BindAdminIdentity(AdminId:id, const String:auth[], const String:iden /** * Sets whether or not a flag is enabled on an admin. * - * @param id AdminId index of the admin. - * @param flag Admin flag to use. - * @param enabled True to enable, false to disable. + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param enabled True to enable, false to disable. * @noreturn */ native SetAdminFlag(AdminId:id, AdminFlag:flag, bool:enabled); @@ -336,19 +337,19 @@ native SetAdminFlag(AdminId:id, AdminFlag:flag, bool:enabled); /** * Returns whether or not a flag is enabled on an admin. * - * @param id AdminId index of the admin. - * @param flag Admin flag to use. - * @param mode Access mode to check. - * @return True if enabled, false otherwise. + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param mode Access mode to check. + * @return True if enabled, false otherwise. */ native bool:GetAdminFlag(AdminId:id, AdminFlag:flag, AdmAccessMode:mode); /** * Returns the bitstring of access flags on an admin. * - * @param id AdminId index of the admin. - * @param mode Access mode to use. - * @return A bitstring containing which flags are enabled. + * @param id AdminId index of the admin. + * @param mode Access mode to use. + * @return A bitstring containing which flags are enabled. */ native GetAdminFlags(AdminId:id, AdmAccessMode:mode); @@ -356,39 +357,39 @@ native GetAdminFlags(AdminId:id, AdmAccessMode:mode); * Adds a group to an admin's inherited group list. Any flags the group has * will be added to the admin's effective flags. * - * @param id AdminId index of the admin. - * @param gid GroupId index of the group. - * @return True on success, false on invalid input or duplicate membership. + * @param id AdminId index of the admin. + * @param gid GroupId index of the group. + * @return True on success, false on invalid input or duplicate membership. */ native bool:AdminInheritGroup(AdminId:id, GroupId:gid); /** * Returns the number of groups this admin is a member of. * - * @param id AdminId index of the admin. - * @return Number of groups this admin is a member of. + * @param id AdminId index of the admin. + * @return Number of groups this admin is a member of. */ native GetAdminGroupCount(AdminId:id); /** * Returns group information from an admin. * - * @param id AdminId index of the admin. - * @param index Group number to retrieve, from 0 to N-1, where N - * is the value of GetAdminGroupCount(id). - * @param name Buffer to store the group's name. - * Note: This will safely chop UTF-8 strings. - * @param maxlength Maximum size of the output name buffer. - * @return A GroupId index and a name pointer, or - * INVALID_GROUP_ID and NULL if an error occurred. + * @param id AdminId index of the admin. + * @param index Group number to retrieve, from 0 to N-1, where N + * is the value of GetAdminGroupCount(id). + * @param name Buffer to store the group's name. + * Note: This will safely chop UTF-8 strings. + * @param maxlength Maximum size of the output name buffer. + * @return A GroupId index and a name pointer, or + * INVALID_GROUP_ID and NULL if an error occurred. */ native GroupId:GetAdminGroup(AdminId:id, index, const String:name[], maxlength) =0; /** * Sets a password on an admin. * - * @param id AdminId index of the admin. - * @param passwd String containing the password. + * @param id AdminId index of the admin. + * @param passwd String containing the password. * @noreturn */ native SetAdminPassword(AdminId:id, const String:password[]); @@ -396,20 +397,20 @@ native SetAdminPassword(AdminId:id, const String:password[]); /** * Gets an admin's password. * - * @param id AdminId index of the admin. - * @param name Optional buffer to store the admin's password. - * @param maxlength Maximum size of the output name buffer. - * Note: This will safely chop UTF-8 strings. - * @return True if there was a password set, false otherwise. + * @param id AdminId index of the admin. + * @param name Optional buffer to store the admin's password. + * @param maxlength Maximum size of the output name buffer. + * Note: This will safely chop UTF-8 strings. + * @return True if there was a password set, false otherwise. */ native bool:GetAdminPassword(AdminId:id, const String:buffer[]="", maxlength=0); /** * Attempts to find an admin by an auth method and an identity. * - * @param auth Auth method to try. - * @param identity Identity string to look up. - * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. + * @param auth Auth method to try. + * @param identity Identity string to look up. + * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. */ native AdminId:FindAdminByIdentity(const String:auth[], const String:identity[]); @@ -418,46 +419,46 @@ native AdminId:FindAdminByIdentity(const String:auth[], const String:identity[]) * * Note: This will remove any bindings to a specific user. * - * @param id AdminId index to remove/invalidate. - * @return True on success, false otherwise. + * @param id AdminId index to remove/invalidate. + * @return True on success, false otherwise. */ native bool:RemoveAdmin(AdminId:id); /** * Converts a flag bit string to a bit array. * - * @param bits Bit string containing the flags. - * @param array Array to write the flags to. Enabled flags will be 'true'. - * @param maxSize Maximum number of flags the array can store. - * @return Number of flags written. + * @param bits Bit string containing the flags. + * @param array Array to write the flags to. Enabled flags will be 'true'. + * @param maxSize Maximum number of flags the array can store. + * @return Number of flags written. */ native FlagBitsToBitArray(bits, bool:array[], maxSize); /** * Converts a flag array to a bit string. * - * @param array Array containing true or false for each AdminFlag. - * @param maxSize Maximum size of the flag array. - * @return A bit string composed of the array bits. + * @param array Array containing true or false for each AdminFlag. + * @param maxSize Maximum size of the flag array. + * @return A bit string composed of the array bits. */ native FlagBitArrayToBits(const bool:array[], maxSize); /** * Converts an array of flags to bits. * - * @param array Array containing flags that are enabled. - * @param numFlags Number of flags in the array. - * @return A bit string composed of the array flags. + * @param array Array containing flags that are enabled. + * @param numFlags Number of flags in the array. + * @return A bit string composed of the array flags. */ native FlagArrayToBits(const AdminFlag:array[], numFlags) =0; /** * Converts a bit string to an array of flags. * - * @param bits Bit string containing the flags. - * @param array Output array to write flags. - * @param maxSize Maximum size of the flag array. - * @return Number of flags written. + * @param bits Bit string containing the flags. + * @param array Output array to write flags. + * @param maxSize Maximum size of the flag array. + * @return Number of flags written. */ native FlagBitsToArray(bits, AdminFlag:array[], maxSize) =0; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 58b04506..445b9972 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -21,66 +22,66 @@ * Flags for console commands and console variables * @note The descriptions for each constant come directly from the Source SDK. */ -#define FCVAR_NONE 0 /**< The default, no flags at all */ -#define FCVAR_UNREGISTERED (1<<0) /**< If this is set, don't add to linked list, etc. */ -#define FCVAR_LAUNCHER (1<<1) /**< Defined by launcher. */ -#define FCVAR_GAMEDLL (1<<2) /**< Defined by the game DLL. */ -#define FCVAR_CLIENTDLL (1<<3) /**< Defined by the client DLL. */ -#define FCVAR_MATERIAL_SYSTEM (1<<4) /**< Defined by the material system. */ -#define FCVAR_PROTECTED (1<<5) /**< It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value. */ -#define FCVAR_SPONLY (1<<6) /**< This cvar cannot be changed by clients connected to a multiplayer server. */ -#define FCVAR_ARCHIVE (1<<7) /**< Set to cause it to be saved to vars.rc */ -#define FCVAR_NOTIFY (1<<8) /**< Notifies players when changed. */ -#define FCVAR_USERINFO (1<<9) /**< Changes the client's info string. */ -#define FCVAR_PRINTABLEONLY (1<<10) /**< This cvar's string cannot contain unprintable characters (e.g., used for player name, etc.) */ -#define FCVAR_UNLOGGED (1<<11) /**< If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log */ -#define FCVAR_NEVER_AS_STRING (1<<12) /**< Never try to print that cvar. */ -#define FCVAR_REPLICATED (1<<13) /**< Server setting enforced on clients. */ -#define FCVAR_CHEAT (1<<14) /**< Only useable in singleplayer / debug / multiplayer & sv_cheats */ -#define FCVAR_STUDIORENDER (1<<15) /**< Defined by the studiorender system. */ -#define FCVAR_DEMO (1<<16) /**< Record this cvar when starting a demo file. */ -#define FCVAR_DONTRECORD (1<<17) /**< Don't record these command in demo files. */ -#define FCVAR_PLUGIN (1<<18) /**< Defined by a 3rd party plugin. */ -#define FCVAR_DATACACHE (1<<19) /**< Defined by the datacache system. */ -#define FCVAR_TOOLSYSTEM (1<<20) /**< Defined by an IToolSystem library */ -#define FCVAR_FILESYSTEM (1<<21) /**< Defined by the file system. */ -#define FCVAR_NOT_CONNECTED (1<<22) /**< Cvar cannot be changed by a client that is connected to a server. */ -#define FCVAR_SOUNDSYSTEM (1<<23) /**< Defined by the soundsystem library. */ -#define FCVAR_ARCHIVE_XBOX (1<<24) /**< Cvar written to config.cfg on the Xbox. */ -#define FCVAR_INPUTSYSTEM (1<<25) /**< Defined by the inputsystem DLL. */ -#define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ -#define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ +#define FCVAR_NONE 0 /**< The default, no flags at all */ +#define FCVAR_UNREGISTERED (1<<0) /**< If this is set, don't add to linked list, etc. */ +#define FCVAR_LAUNCHER (1<<1) /**< Defined by launcher. */ +#define FCVAR_GAMEDLL (1<<2) /**< Defined by the game DLL. */ +#define FCVAR_CLIENTDLL (1<<3) /**< Defined by the client DLL. */ +#define FCVAR_MATERIAL_SYSTEM (1<<4) /**< Defined by the material system. */ +#define FCVAR_PROTECTED (1<<5) /**< It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value. */ +#define FCVAR_SPONLY (1<<6) /**< This cvar cannot be changed by clients connected to a multiplayer server. */ +#define FCVAR_ARCHIVE (1<<7) /**< Set to cause it to be saved to vars.rc */ +#define FCVAR_NOTIFY (1<<8) /**< Notifies players when changed. */ +#define FCVAR_USERINFO (1<<9) /**< Changes the client's info string. */ +#define FCVAR_PRINTABLEONLY (1<<10) /**< This cvar's string cannot contain unprintable characters (e.g., used for player name, etc.) */ +#define FCVAR_UNLOGGED (1<<11) /**< If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log */ +#define FCVAR_NEVER_AS_STRING (1<<12) /**< Never try to print that cvar. */ +#define FCVAR_REPLICATED (1<<13) /**< Server setting enforced on clients. */ +#define FCVAR_CHEAT (1<<14) /**< Only useable in singleplayer / debug / multiplayer & sv_cheats */ +#define FCVAR_STUDIORENDER (1<<15) /**< Defined by the studiorender system. */ +#define FCVAR_DEMO (1<<16) /**< Record this cvar when starting a demo file. */ +#define FCVAR_DONTRECORD (1<<17) /**< Don't record these command in demo files. */ +#define FCVAR_PLUGIN (1<<18) /**< Defined by a 3rd party plugin. */ +#define FCVAR_DATACACHE (1<<19) /**< Defined by the datacache system. */ +#define FCVAR_TOOLSYSTEM (1<<20) /**< Defined by an IToolSystem library */ +#define FCVAR_FILESYSTEM (1<<21) /**< Defined by the file system. */ +#define FCVAR_NOT_CONNECTED (1<<22) /**< Cvar cannot be changed by a client that is connected to a server. */ +#define FCVAR_SOUNDSYSTEM (1<<23) /**< Defined by the soundsystem library. */ +#define FCVAR_ARCHIVE_XBOX (1<<24) /**< Cvar written to config.cfg on the Xbox. */ +#define FCVAR_INPUTSYSTEM (1<<25) /**< Defined by the inputsystem DLL. */ +#define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ +#define FCVAR_VPHYSICS (1<<27)/**< Defined by vphysics. */ /** * Creates a new console variable. * - * @param name Name of new convar. - * @param defaultValue String containing the default value of new convar. - * @param helpText Optional description of the convar. - * @param flags Optional bitstream of flags determining how the convar should be handled. (See FCVAR_* constants for more details) - * @param hasMin Optional boolean that determines if the convar has a minimum value. - * @param min Minimum floating point value that the convar can have if hasMin is true. - * @param hasMax Optional boolean that determines if the convar has a maximum value. - * @param max Maximum floating point value that the convar can have if hasMax is true. + * @param name Name of new convar. + * @param defaultValue String containing the default value of new convar. + * @param helpText Optional description of the convar. + * @param flags Optional bitstream of flags determining how the convar should be handled. (See FCVAR_* constants for more details) + * @param hasMin Optional boolean that determines if the convar has a minimum value. + * @param min Minimum floating point value that the convar can have if hasMin is true. + * @param hasMax Optional boolean that determines if the convar has a maximum value. + * @param max Maximum floating point value that the convar can have if hasMax is true. * @return A handle to the newly created convar. If the convar already exists, INVALID_HANDLE is returned. - * @error Convar name is blank or is the same as a console command. + * @error Convar name is blank or is the same as a console command. */ native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:helpText[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); /** * Searches for a console variable. * - * @param name Name of convar to find. - * @return A handle to the convar if it is found. INVALID_HANDLE otherwise. + * @param name Name of convar to find. + * @return A handle to the convar if it is found. INVALID_HANDLE otherwise. */ native Handle:FindConVar(const String:name[]); /** * Called when a console variable's value is changed. * - * @param convar Handle to the convar that was changed. - * @param oldValue String containing the value of the convar before it was changed. - * @param newValue String containing the new value of the convar. + * @param convar Handle to the convar that was changed. + * @param oldValue String containing the value of the convar before it was changed. + * @param newValue String containing the new value of the convar. * @noreturn */ functag OnConVarChanged public(Handle:convar, const String:oldValue[], const String:newValue[]); @@ -88,156 +89,156 @@ functag OnConVarChanged public(Handle:convar, const String:oldValue[], const Str /** * Creates a hook for when a console variable's value is changed. * - * @param convar Handle to the convar. - * @param callback An OnConVarChanged function pointer. + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. * @noreturn - * @error Invalid or corrupt Handle or invalid callback function. + * @error Invalid or corrupt Handle or invalid callback function. */ native HookConVarChange(Handle:convar, OnConVarChanged:callback); /** * Removes a hook for when a console variable's value is changed. * - * @param convar Handle to the convar. - * @param callback An OnConVarChanged function pointer. + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. * @noreturn - * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. + * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. */ native UnhookConVarChange(Handle:convar, OnConVarChanged:callback); /** * Returns the boolean value of a console variable. * - * @param convar Handle to the convar. - * @return The boolean value of the convar. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @return The boolean value of the convar. + * @error Invalid or corrupt Handle. */ native bool:GetConVarBool(Handle:convar); /** * Sets the boolean value of a console variable. * - * @param convar Handle to the convar. - * @param value New boolean value. + * @param convar Handle to the convar. + * @param value New boolean value. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SetConVarBool(Handle:convar, bool:value); /** * Returns the integer value of a console variable. * - * @param convar Handle to the convar. - * @return The integer value of the convar. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @return The integer value of the convar. + * @error Invalid or corrupt Handle. */ native GetConVarInt(Handle:convar); /** * Sets the integer value of a console variable. * - * @param convar Handle to the convar. - * @param value New integer value. + * @param convar Handle to the convar. + * @param value New integer value. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SetConVarInt(Handle:convar, value); /** * Returns the floating point value of a console variable. * - * @param convar Handle to the convar. - * @return The floating point value of the convar. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @return The floating point value of the convar. + * @error Invalid or corrupt Handle. */ native Float:GetConVarFloat(Handle:convar); /** * Sets the floating point value of a console variable. * - * @param convar Handle to the convar. - * @param value New floating point value. + * @param convar Handle to the convar. + * @param value New floating point value. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SetConVarFloat(Handle:convar, Float:value); /** * Retrieves the string value of a console variable. * - * @param convar Handle to the convar. - * @param value Buffer to store the value of the convar. - * @param maxlength Maximum length of string buffer. + * @param convar Handle to the convar. + * @param value Buffer to store the value of the convar. + * @param maxlength Maximum length of string buffer. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native GetConVarString(Handle:convar, String:value[], maxlength); /** * Sets the string value of a console variable. * - * @param convar Handle to the convar. - * @param value New string value. + * @param convar Handle to the convar. + * @param value New string value. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SetConVarString(Handle:convar, const String:value[]); /** * Returns the bitstring of flags on a console variable. * - * @param convar Handle to the convar. - * @return A bitstring containing the FCVAR_* flags that are enabled. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @return A bitstring containing the FCVAR_* flags that are enabled. + * @error Invalid or corrupt Handle. */ native GetConVarFlags(Handle:convar); /** * Sets the bitstring of flags on a console variable. * - * @param convar Handle to the convar. - * @param flags A bitstring containing the FCVAR_* flags to enable. + * @param convar Handle to the convar. + * @param flags A bitstring containing the FCVAR_* flags to enable. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SetConVarFlags(Handle:convar, flags); /** * Retrieves the name of a console variable. * - * @param convar Handle to the convar. - * @param value Buffer to store the name of the convar. - * @param maxlength Maximum length of string buffer. + * @param convar Handle to the convar. + * @param value Buffer to store the name of the convar. + * @param maxlength Maximum length of string buffer. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native GetConVarName(Handle:convar, const String:name[], maxlength); /** * Retrieves the minimum floating point value that a console variable can contain. * - * @param convar Handle to the convar. - * @param min By-reference cell to store the minimum floating point value. - * @return True if the convar has a minimum value set, false otherwise. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @param min By-reference cell to store the minimum floating point value. + * @return True if the convar has a minimum value set, false otherwise. + * @error Invalid or corrupt Handle. */ native bool:GetConVarMin(Handle:convar, &Float:min); /** * Retrieves the maximum floating point value that a console variable can contain. * - * @param convar Handle to the convar. - * @param min By-reference cell to store the maximum floating point value. - * @return True if the convar has a maximum value set, false otherwise. - * @error Invalid or corrupt Handle. + * @param convar Handle to the convar. + * @param min By-reference cell to store the maximum floating point value. + * @return True if the convar has a maximum value set, false otherwise. + * @error Invalid or corrupt Handle. */ native bool:GetConVarMax(Handle:convar, &Float:max); /** * Resets the console variable to its default value. * - * @param convar Handle to the convar. + * @param convar Handle to the convar. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native ResetConVar(Handle:convar); diff --git a/plugins/include/core.inc b/plugins/include/core.inc index c520295d..0e345757 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -38,4 +39,3 @@ struct Extension #define AUTOLOAD_EXTENSIONS #define REQUIRE_EXTENSIONS - diff --git a/plugins/include/datapack.inc b/plugins/include/datapack.inc index 5e491d6d..0e493eda 100644 --- a/plugins/include/datapack.inc +++ b/plugins/include/datapack.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -21,7 +22,7 @@ /** * Creates a new data pack. * - * @return A Handle to the data pack. Must be closed with CloseHandle(). + * @return A Handle to the data pack. Must be closed with CloseHandle(). */ native Handle:CreateDataPack(); @@ -90,7 +91,7 @@ native ReadPackString(Handle:pack, String:buffer[], maxlen); * @param pack Handle to the data pack. * @param clear If true, clears the contained data. * @noreturn - * @error Invalid handle. + * @error Invalid handle. */ native ResetPack(Handle:pack, bool:clear=false); @@ -99,7 +100,7 @@ native ResetPack(Handle:pack, bool:clear=false); * * @param pack Handle to the data pack. * @return Numerical position in the data pack. - * @error Invalid handle. + * @error Invalid handle. */ native GetPackPosition(Handle:pack); @@ -119,7 +120,7 @@ native SetPackPosition(Handle:pack, position); * * @param pack Handle to the data pack. * @param bytes Number of bytes to simulate reading. - * @return True if can be read, false otherwise. - * @error Invalid handle. + * @return True if can be read, false otherwise. + * @error Invalid handle. */ native bool:IsPackReadable(Handle:pack, bytes); diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 677a0681..4df1f731 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -78,17 +79,17 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type= * @note Files are closed with CloseHandle(). * @note File Handles can be cloned. * - * @param file File to open. - * @param mode Open mode. - * @return A Handle to the file, INVALID_HANDLE on open error. + * @param file File to open. + * @param mode Open mode. + * @return A Handle to the file, INVALID_HANDLE on open error. */ native Handle:OpenFile(const String:file[], const String:mode[]); /** * @brief Deletes a file. * - * @param path Path of the file to delete. - * @return True on success, false otherwise. + * @param path Path of the file to delete. + * @return True on success, false otherwise. */ native bool:DeleteFile(const String:path[]); @@ -105,34 +106,34 @@ native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength); /** * @brief Tests if the end of file has been reached. * - * @param file Handle to the file. - * @return True if end of file has been reached, false otherwise. + * @param file Handle to the file. + * @return True if end of file has been reached, false otherwise. */ native bool:IsEndOfFile(Handle:file); /** * @brief Sets the file position indicator. * - * @param file Handle to the file. - * @param position Position relative to what is specified in whence. - * @param whence Look at the SEEK_* definitions. - * @return True on success, false otherwise. + * @param file Handle to the file. + * @param position Position relative to what is specified in whence. + * @param whence Look at the SEEK_* definitions. + * @return True on success, false otherwise. */ native bool:FileSeek(Handle:file, position, whence); /** * @brief Get current position in the file. * - * @param file Handle to the file. - * @return Value for the file position indicator. + * @param file Handle to the file. + * @return Value for the file position indicator. */ native FilePosition(Handle:file); /** * @brief Checks if a file exists. * - * @param path Path to the file. - * @return True if the file exists, false otherwise. + * @param path Path to the file. + * @return True if the file exists, false otherwise. */ native bool:FileExists(const String:path[]); @@ -148,16 +149,16 @@ native bool:RenameFile(const String:newpath[], const String:oldpath[]); /** * @brief Checks if a directory exists. * - * @param path Path to the directory. - * @return True if the directory exists, false otherwise. + * @param path Path to the directory. + * @return True if the directory exists, false otherwise. */ native bool:DirExists(const String:path[]); /** * @brief Get the file size in bytes. * - * @param path Path to the file. - * @return File size in bytes, -1 if file not found. + * @param path Path to the file. + * @return File size in bytes, -1 if file not found. */ native FileSize(const String:path[]); @@ -165,8 +166,8 @@ native FileSize(const String:path[]); * @brief Removes a directory. * @note On most Operating Systems you cannot remove a directory which has files inside it. * - * @param path Path to the directory. - * @return True on success, false otherwise. + * @param path Path to the directory. + * @return True on success, false otherwise. */ native bool:RemoveDir(const String:path[]); @@ -174,9 +175,9 @@ native bool:RemoveDir(const String:path[]); * @brief Writes a line of text in a file. * @note This native will append the newline character. * - * @param hndl Handle to the file. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return True on success, false otherwise. + * @param hndl Handle to the file. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return True on success, false otherwise. */ native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,_}:...); diff --git a/plugins/include/float.inc b/plugins/include/float.inc index a1bf2034..0d9f8139 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -319,4 +320,4 @@ stock Float:DegToRad(Float:angle) stock Float:RadToDeg(Float:angle) { return (angle*180)/FLOAT_PI; -} \ No newline at end of file +} diff --git a/plugins/include/geoip.inc b/plugins/include/geoip.inc index 66271799..161e9210 100644 --- a/plugins/include/geoip.inc +++ b/plugins/include/geoip.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -70,4 +71,3 @@ public Extension:__ext_geoip = required = 0, #endif }; - diff --git a/plugins/include/handles.inc b/plugins/include/handles.inc index 554dd632..8655c5c4 100644 --- a/plugins/include/handles.inc +++ b/plugins/include/handles.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -29,7 +30,7 @@ enum Handle * This is provided for situations only where testing for handle validity is needed. * * @param hndl Handle to test for validity. - * @return True if handle is valid, false otherwise. + * @return True if handle is valid, false otherwise. */ native bool:IsValidHandle(Handle:hndl); @@ -41,7 +42,7 @@ native bool:IsValidHandle(Handle:hndl); * sure you read the documentation on whatever provided the Handle. * * @param hndl Handle to close. - * @return True if successful, false if not closeable. + * @return True if successful, false if not closeable. * @error Invalid handles will cause a run time error. */ native bool:CloseHandle(Handle:hndl); @@ -59,9 +60,8 @@ native bool:CloseHandle(Handle:hndl); * * @param hndl Handle to clone/duplicate. * @param plugin Optional Handle to another plugin to mark as the new owner. - * If no owner is passed, the owner becomes the calling plugin. - * @return Handle on success, INVALID_HANDLE if not cloneable. + * If no owner is passed, the owner becomes the calling plugin. + * @return Handle on success, INVALID_HANDLE if not cloneable. * @error Invalid handles will cause a run time error. */ native Handle:CloneHandle(Handle:hndl, Handle:plugin=INVALID_HANDLE); - diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc index 2b0427f7..61fd8f82 100644 --- a/plugins/include/helpers.inc +++ b/plugins/include/helpers.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/plugins/include/lang.inc b/plugins/include/lang.inc index 66fff159..ea6ef4a5 100644 --- a/plugins/include/lang.inc +++ b/plugins/include/lang.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -23,4 +24,4 @@ * @param path Translation file. * @noreturn */ -native LoadTranslations(const String:file[]); \ No newline at end of file +native LoadTranslations(const String:file[]); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 4ee73244..279584a4 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -20,7 +21,7 @@ struct Plugin { const String:name[], /* Plugin Name */ - const String:description[], /* Plugin Description */ + const String:description[], /* Plugin Description */ const String:author[], /* Plugin Author */ const String:version[], /* Plugin Version */ const String:url[], /* Plugin URL */ @@ -82,7 +83,7 @@ forward OnPluginEnd(); /** * Called when the plugin's pause status is changing. * - * @param pause True if the plugin is being paused, false otherwise. + * @param pause True if the plugin is being paused, false otherwise. * @noreturn */ forward OnPluginPauseChange(bool:pause); @@ -164,11 +165,11 @@ native GetClientCount(bool:inGameOnly=true); /** * Returns the client's name. * - * @param client Player index. - * @param name Buffer to store the client's name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. */ native bool:GetClientName(client, String:name[], maxlen); @@ -334,8 +335,8 @@ native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:... /** * Logs a generic message to the HL2 logs. * - * @param format String format. - * @param ... Format arguments. + * @param format String format. + * @param ... Format arguments. * @noreturn */ native LogToGame(const String:format[], {Handle,Float,String,_}:...); @@ -343,8 +344,8 @@ native LogToGame(const String:format[], {Handle,Float,String,_}:...); /** * Logs a plugin message to the SourceMod logs. * - * @param format String format. - * @param ... Format arguments. + * @param format String format. + * @param ... Format arguments. * @noreturn */ native LogMessage(const String:format[], {Handle,Float,String,_}:...); @@ -352,8 +353,8 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); /** * Logs a plugin error message to the SourceMod logs. * - * @param format String format. - * @param ... Format arguments. + * @param format String format. + * @param ... Format arguments. * @noreturn */ native LogError(const String:format[], {Handle,Float,String,_}:...); diff --git a/plugins/include/string.inc b/plugins/include/string.inc index b8dd34d4..6d61f7de 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -27,8 +28,8 @@ /** * Calculates the length of a string. * - * @param str String to check. - * @return Length of string, in cells (NOT characters). + * @param str String to check. + * @return Length of string, in cells (NOT characters). */ native strlen(const String:str[]); @@ -38,9 +39,9 @@ native strlen(const String:str[]); * @param str String to search in. * @param substr Substring to find inside the original string. * @param caseSensitive If true (default), search is case sensitive. - * If false, search is case insensitive. - * @return -1 on failure (no match found). Any other value - * indicates a position in the string where the match starts. + * If false, search is case insensitive. + * @return -1 on failure (no match found). Any other value + * indicates a position in the string where the match starts. */ native StrContains(const String:str[], const String:substr[], bool:caseSensitive=true); @@ -50,10 +51,10 @@ native StrContains(const String:str[], const String:substr[], bool:caseSensitive * @param str1 First string (left). * @param str2 Second string (right). * @param caseSensitive If true (default), comparison is case sensitive. - * If false, comparison is case insensitive. - * @return -1 if str1 < str2 - * 0 if str1 == str2 - * 1 if str1 > str2 + * If false, comparison is case insensitive. + * @return -1 if str1 < str2 + * 0 if str1 == str2 + * 1 if str1 > str2 */ native StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=true); diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc index c39dc6f7..e03cd4d6 100644 --- a/plugins/include/textparse.inc +++ b/plugins/include/textparse.inc @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== @@ -26,25 +27,25 @@ enum SMCResult { - SMCParse_Continue, //continue parsing - SMCParse_Halt, //stop parsing here - SMCParse_HaltFail //stop parsing and return failure + SMCParse_Continue, /**< Continue parsing */ + SMCParse_Halt, /**< Stop parsing here */ + SMCParse_HaltFail /**< Stop parsing and return failure */ }; enum SMCError { - SMCError_Okay = 0, //no error - SMCError_StreamOpen, //stream failed to open - SMCError_StreamError, //the stream died... somehow - SMCError_Custom, //a custom handler threw an error - SMCError_InvalidSection1, //a section was declared without quotes, and had extra tokens - SMCError_InvalidSection2, //a section was declared without any header - SMCError_InvalidSection3, //a section ending was declared with too many unknown tokens - SMCError_InvalidSection4, //a section ending has no matching beginning - SMCError_InvalidSection5, //a section beginning has no matching ending - SMCError_InvalidTokens, //there were too many unidentifiable strings on one line - SMCError_TokenOverflow, //the token buffer overflowed - SMCError_InvalidProperty1, //a property was declared outside of any section + SMCError_Okay = 0, /**< No error */ + SMCError_StreamOpen, /**< Stream failed to open */ + SMCError_StreamError, /**< The stream died... somehow */ + SMCError_Custom, /**< A custom handler threw an error */ + SMCError_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ + SMCError_InvalidSection2, /**< A section was declared without any header */ + SMCError_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ + SMCError_InvalidSection4, /**< A section ending has no matching beginning */ + SMCError_InvalidSection5, /**< A section beginning has no matching ending */ + SMCError_InvalidTokens, /**< There were too many unidentifiable strings on one line */ + SMCError_TokenOverflow, /**< The token buffer overflowed */ + SMCError_InvalidProperty1, /**< A property was declared outside of any section */ }; /** @@ -57,12 +58,12 @@ native Handle:SMC_CreateParser(); /** * Parses an SMC file. * - * @param smc A Handle to an SMC Parse structure. - * @param file A string containing the file path. - * @param line An optional by reference cell to store the last line number read. - * @param col An optional by reference cell to store the last column number read. - * @return An SMCParseError result. - * @error Invalid or corrupt Handle. + * @param smc A Handle to an SMC Parse structure. + * @param file A string containing the file path. + * @param line An optional by reference cell to store the last line number read. + * @param col An optional by reference cell to store the last column number read. + * @return An SMCParseError result. + * @error Invalid or corrupt Handle. */ native SMCError:SMC_ParseFile(Handle:smc, const String:file[], &line=0, &col=0); @@ -71,10 +72,10 @@ native SMCError:SMC_ParseFile(Handle:smc, const String:file[], &line=0, &col=0); * @note SMCError_Okay returns false. * @note SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false. * - * @param error The SMCParseError code. - * @param buffer A string buffer for the error (contents undefined on failure). - * @param buf_max The maximum size of the buffer. - * @return True on success, false otherwise. + * @param error The SMCParseError code. + * @param buffer A string buffer for the error (contents undefined on failure). + * @param buf_max The maximum size of the buffer. + * @return True on success, false otherwise. */ native bool:SMC_GetErrorString(SMCError:error, String:buffer[], buf_max); @@ -89,10 +90,10 @@ functag SMC_ParseStart public(Handle:smc); /** * Sets the SMC_ParseStart function of a parse Handle. * - * @param smc Handle to an SMC Parse. - * @param func SMC_ParseStart function. + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseStart function. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SMC_SetParseStart(Handle:smc, SMC_ParseStart:func); @@ -100,8 +101,8 @@ native SMC_SetParseStart(Handle:smc, SMC_ParseStart:func); * Called when parsing is halted. * * @param smc The SMC Parse Handle. - * @param halted True if abnormally halted, false otherwise. - * @param failed True if parsing failed, false otherwise. + * @param halted True if abnormally halted, false otherwise. + * @param failed True if parsing failed, false otherwise. * @noreturn */ functag SMC_ParseEnd public(Handle:smc, bool:halted, bool:failed); @@ -109,10 +110,10 @@ functag SMC_ParseEnd public(Handle:smc, bool:halted, bool:failed); /** * Sets the SMC_ParseEnd of a parse handle. * - * @param smc Handle to an SMC Parse. - * @param func SMC_ParseEnd function. + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseEnd function. * @noreturn - * @error Invalid or corrupt Handle. + * @error Invalid or corrupt Handle. */ native SMC_SetParseEnd(Handle:smc, SMC_ParseEnd:func); @@ -172,8 +173,8 @@ functag SMC_RawLine SMCResult:public(Handle:smc, const String:line[], lineno); /** * Sets a raw line reader on an SMC parser Handle. * - * @param smc Handle to an SMC Parse. - * @param func SMC_RawLine function. + * @param smc Handle to an SMC Parse. + * @param func SMC_RawLine function. * @noreturn */ native SMC_SetRawLine(Handle:smc, SMC_RawLine:func); From 8d1d75f55183d858f9c5a5aaf7b108a76a568699 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 13:20:19 +0000 Subject: [PATCH 0451/1664] Fixed minor spacing issue in console.inc Added preliminary syntax highlighting file for UltraEdit/UEStudio --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40482 --- editor/ultraedit/wordfile.txt | 65 +++++++++++++++++++++++++++++++++++ plugins/include/console.inc | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 editor/ultraedit/wordfile.txt diff --git a/editor/ultraedit/wordfile.txt b/editor/ultraedit/wordfile.txt new file mode 100644 index 00000000..1890ebf4 --- /dev/null +++ b/editor/ultraedit/wordfile.txt @@ -0,0 +1,65 @@ +/L20"SourcePawn" Line Comment = // Block Comment On = /* Block Comment Off = */ Escape Char = \ String Chars = "' File Extensions = INC SP +/Delimiters = ~!@%^&*()-+=|\/{}[]:;"'<> , .? +/Function String = "%^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" +/Function String 1 = "%[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" +/Function String 2 = "%^{native^}^{forward^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" +/Function String 3 = "%^{native^}^{forward^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" +/Function String 4 = "%^{public^}^{stock^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" +/Function String 5 = "%^{public^}^{stock^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)"/ +/Indent Strings = "{" +/Unindent Strings = "}" +/C1"Keywords" +assert +break +case const continue +decl default do +else enum exit +for forward functag +goto +if +native new +operator +public +return +sleep static stock struct switch +while +/C2"Directives" +#assert #define #else #elseif #emit #endif #endinput #endscript #if #include #pragma #error #tryinclude #undef +align +ctrlchar +defined dynamic +library +pack +rational +semicolon +tabsize +/C3"Operators" ++ +- += +// / +% +& +> +< +^ +! +| +~ +: +? +cellof chars +sizeof +tagof +/C4"Tags" +bool +Float Function +Handle +Plugin +String +/C5"Constants" +//TODO +/C6"Stocks" +//TODO +/C7"Natives" +//TODO \ No newline at end of file diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 445b9972..ab96b353 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -50,7 +50,7 @@ #define FCVAR_ARCHIVE_XBOX (1<<24) /**< Cvar written to config.cfg on the Xbox. */ #define FCVAR_INPUTSYSTEM (1<<25) /**< Defined by the inputsystem DLL. */ #define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ -#define FCVAR_VPHYSICS (1<<27)/**< Defined by vphysics. */ +#define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ /** * Creates a new console variable. From 58ea6d1e651ce1d92076b07970a66ec7a90fb5e2 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 12 Feb 2007 13:32:42 +0000 Subject: [PATCH 0452/1664] Err, some missing keywords and corrections to UltraEdit/UEStudio syntax highlighting file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40483 --- editor/ultraedit/wordfile.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/editor/ultraedit/wordfile.txt b/editor/ultraedit/wordfile.txt index 1890ebf4..402596c7 100644 --- a/editor/ultraedit/wordfile.txt +++ b/editor/ultraedit/wordfile.txt @@ -10,18 +10,17 @@ /Unindent Strings = "}" /C1"Keywords" assert -break +begin break case const continue decl default do else enum exit -for forward functag -goto +for forward funcenum functag if native new operator public return -sleep static stock struct switch +static stock struct switch while /C2"Directives" #assert #define #else #elseif #emit #endif #endinput #endscript #if #include #pragma #error #tryinclude #undef @@ -48,7 +47,7 @@ tabsize ~ : ? -cellof chars +cellsof chars sizeof tagof /C4"Tags" @@ -58,7 +57,10 @@ Handle Plugin String /C5"Constants" -//TODO +cellbits cellmax cellmin charbits charmax +myinfo +__version +INVALID_HANDLE /C6"Stocks" //TODO /C7"Natives" From 89716abdcfed2dc42e1b06dc7015c8f67e7d3b76 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 18:25:16 +0000 Subject: [PATCH 0453/1664] fixed error code being off by one --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40484 --- core/CTextParsers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/CTextParsers.cpp b/core/CTextParsers.cpp index c3180536..b1e8a205 100644 --- a/core/CTextParsers.cpp +++ b/core/CTextParsers.cpp @@ -930,6 +930,7 @@ const char *CTextParsers::GetSMCErrorString(SMCParseError err) "Section declared without header", "Section declared with unknown tokens", "Section ending without a matching section beginning", + "Section beginning without a matching ending", "Line contained too many invalid tokens", "Token buffer overflowed", "A property was declared outside of a section", From ea9815d2f5022e65b948d9cb88de8cf96b4f6dfc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 19:41:50 +0000 Subject: [PATCH 0454/1664] removed invalid options from the config file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40485 --- configs/plugin_settings.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/configs/plugin_settings.cfg b/configs/plugin_settings.cfg index 0e97e68d..c0f8dad2 100644 --- a/configs/plugin_settings.cfg +++ b/configs/plugin_settings.cfg @@ -13,8 +13,6 @@ * * You can also have an "Options" section declaring options to pass onto the JIT: * "debug" - Whether or not to load the plugin in debug mode - * "inl_errors" - Internal optimization to inline error checks. Results in larger but faster code. - * "inl_natives" - Internal optimization to inline native calls. Results in larger code (unknown speed effect). */ "Plugins" From c5316168dee0c840760d69d0d9bfa1cc1bd297b4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Feb 2007 19:45:23 +0000 Subject: [PATCH 0455/1664] moved two console commands --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40486 --- plugins/include/console.inc | 21 +++++++++++++++++++++ plugins/include/sourcemod.inc | 20 -------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index ab96b353..1b46c24d 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -52,6 +52,27 @@ #define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ #define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ + +/** + * Sends a message to the server console. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native PrintToServer(const String:format[], {Handle,Float,String,_}:...); + +/** + * Sends a message to a client's console. + * + * @param client Player index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error If the client is not connected an error will be thrown. + */ +native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); + /** * Creates a new console variable. * diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 279584a4..6592a949 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -312,26 +312,6 @@ native SetUserFlagBits(client, flags); */ native GetUserFlagBits(client); -/** - * Sends a message to the server console. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @noreturn - */ -native PrintToServer(const String:format[], {Handle,Float,String,_}:...); - -/** - * Sends a message to a client's console. - * - * @param client Player index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @noreturn - * @error If the client is not connected an error will be thrown. - */ -native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); - /** * Logs a generic message to the HL2 logs. * From 4f1101a006ae5ef5a4d23bd1601e540478c1fb0b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Feb 2007 03:19:59 +0000 Subject: [PATCH 0456/1664] changed these numbers for future expandability --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40487 --- public/IForwardSys.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 63e8c5db..97ed2b9a 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -52,8 +52,8 @@ namespace SourceMod enum ResultType { Pl_Continue = 0, /**< No result */ - Pl_Handled = 1, /**< Result was handled, stop at the end */ - Pl_Stop = 2, /**< Result was handled, stop now */ + Pl_Handled = 3, /**< Result was handled, stop at the end */ + Pl_Stop = 4, /**< Result was handled, stop now */ }; /** From d5a7ba694c67b0dd7352444411374cf4b3b5b5af Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 13 Feb 2007 06:12:33 +0000 Subject: [PATCH 0457/1664] Changed "sm cvars" to "sm convars" in the name of consistency I guess --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40488 --- core/CConVarManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 4a6c6e0e..87042ca8 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -54,7 +54,7 @@ void CConVarManager::OnSourceModAllInitialized() m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); // Add the 'cvars' option to the 'sm' console command - g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); + g_RootMenu.AddRootConsoleCommand("convars", "View convars created by a plugin", this); } void CConVarManager::OnSourceModShutdown() @@ -75,7 +75,7 @@ void CConVarManager::OnSourceModShutdown() } // Remove the 'cvars' option from the 'sm' console command - g_RootMenu.RemoveRootConsoleCommand("cvars", this); + g_RootMenu.RemoveRootConsoleCommand("convars", this); // Remove the 'ConVar' handle type g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); @@ -125,7 +125,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc return; } - g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name); + g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\"", pl->GetPublicInfo()->name); // Iterate convar list and display each one for (int i = 0; i < convarnum; i++, id++) @@ -138,7 +138,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc } // Display usage of subcommand - g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>"); + g_RootMenu.ConsolePrint("[SM] Usage: sm convars <#>"); } Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) From fbeabce6bf9f5b6c3a278641eaa322b7549165b1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Feb 2007 06:26:01 +0000 Subject: [PATCH 0458/1664] added event result types --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40489 --- plugins/include/core.inc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 0e345757..36670c72 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -24,6 +24,16 @@ struct PlVers version, }; +/** + * Specifies what to do after a hook completes. + */ +enum Result +{ + Plugin_Continue = 0, /**< Continue with the original action */ + Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */ + Plugin_Stop = 4, /**< Immediately stop the hook chain and handle the original */ +} + public PlVers:__version = { version = SOURCEMOD_PLUGINAPI_VERSION, From 1ff370b91d306bc41895583ad324e5d437ed9b77 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 13 Feb 2007 16:11:04 +0000 Subject: [PATCH 0459/1664] initial implementation of data packs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40490 --- core/CDataPack.cpp | 176 ++++++++++++++++++++ core/CDataPack.h | 53 ++++++ core/msvc8/sourcemod_mm.vcproj | 14 +- core/smn_datapacks.cpp | 288 +++++++++++++++++++++++++++++++++ core/sourcemod.cpp | 41 ++++- core/sourcemod.h | 22 ++- public/IDataPack.h | 10 +- public/ISourceMod.h | 9 +- 8 files changed, 597 insertions(+), 16 deletions(-) create mode 100644 core/CDataPack.cpp create mode 100644 core/CDataPack.h create mode 100644 core/smn_datapacks.cpp diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp new file mode 100644 index 00000000..09e932e4 --- /dev/null +++ b/core/CDataPack.cpp @@ -0,0 +1,176 @@ +#include +#include +#include "CDataPack.h" + +#define DATAPACK_INITIAL_SIZE 512 + +CDataPack::CDataPack() +{ + m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE); + m_capacity = DATAPACK_INITIAL_SIZE; + Initialize(); +} + +CDataPack::~CDataPack() +{ + free(m_pBase); +} + +void CDataPack::Initialize() +{ + m_curptr = m_pBase; + m_size = 0; +} + +void CDataPack::CheckSize(size_t typesize) +{ + if (m_curptr - m_pBase + typesize <= m_capacity) + { + return; + } + + size_t pos = m_curptr - m_pBase; + do + { + m_capacity *= 2; + m_pBase = (char *)realloc(m_pBase, m_capacity); + m_curptr = m_pBase + pos; + } while (m_curptr - m_pBase + typesize > m_capacity); +} + +void CDataPack::ResetSize() +{ + m_size = 0; +} + +size_t CDataPack::CreateMemory(size_t size, void **addr) +{ + size_t pos = m_curptr - m_pBase; + + m_pBase = (char *)realloc(m_pBase, size); + m_curptr = m_pBase + pos; + m_capacity = size; + + if (addr) + { + *addr = m_pBase; + } + + return pos; +} + +void CDataPack::PackCell(cell_t cell) +{ + CheckSize(sizeof(cell_t)); + + *(cell_t *)m_curptr = cell; + m_curptr += sizeof(cell_t); + m_size += sizeof(cell_t); +} + +void CDataPack::PackFloat(float val) +{ + CheckSize(sizeof(float)); + + *(float *)m_curptr = val; + m_curptr += sizeof(float); + m_size += sizeof(float); +} + +void CDataPack::PackString(const char *string) +{ + size_t len = strlen(string); + size_t maxsize = sizeof(size_t) + len + 1; + CheckSize(maxsize); + + // Pack the string length first for buffer overrun checking. + *(size_t *)m_curptr = len; + m_curptr += sizeof(size_t); + + // Now pack the string. + memcpy(m_curptr, string, len); + m_curptr[len] = '\0'; + m_curptr += len + 1; + + m_size += maxsize; +} + +void CDataPack::Reset() const +{ + m_curptr = m_pBase; +} + +size_t CDataPack::GetPosition() const +{ + return static_cast(m_curptr - m_pBase); +} + +bool CDataPack::SetPosition(size_t pos) const +{ + if (pos > m_size-1) + { + return false; + } + m_curptr = m_pBase + pos; + + return true; +} + +cell_t CDataPack::ReadCell() const +{ + if (!IsReadable(sizeof(cell_t))) + { + return 0; + } + cell_t val = *reinterpret_cast(m_curptr); + m_curptr += sizeof(cell_t); + return val; +} + +float CDataPack::ReadFloat() const +{ + if (!IsReadable(sizeof(float))) + { + return 0; + } + float val = *reinterpret_cast(m_curptr); + m_curptr += sizeof(float); + return val; +} + +bool CDataPack::IsReadable(size_t bytes) const +{ + return (bytes + (m_curptr - m_pBase) > m_size) ? false : true; +} + +const char *CDataPack::ReadString(size_t *len) const +{ + if (!IsReadable(sizeof(size_t))) + { + return 0; + } + + size_t real_len = *(size_t *)m_curptr; + + m_curptr += sizeof(size_t); + char *str = (char *)m_curptr; + + if ((strlen(str) != real_len) || !(IsReadable(real_len+1))) + { + return NULL; + } + + if (len) + { + *len = real_len; + } + + m_curptr += real_len + 1; + + return str; +} + +void *CDataPack::GetMemory() const +{ + return m_curptr; +} diff --git a/core/CDataPack.h b/core/CDataPack.h new file mode 100644 index 00000000..0aae8592 --- /dev/null +++ b/core/CDataPack.h @@ -0,0 +1,53 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_ +#define _INCLUDE_SOURCEMOD_CDATAPACK_H_ + +#include + +using namespace SourceMod; + +class CDataPack : public IDataPack +{ +public: + CDataPack(); + ~CDataPack(); +public: //IDataReader + void Reset() const; + size_t GetPosition() const; + bool SetPosition(size_t pos) const; + cell_t ReadCell() const; + float ReadFloat() const; + bool IsReadable(size_t bytes) const; + const char *ReadString(size_t *len) const; + void *GetMemory() const; +public: //IDataPack + void ResetSize(); + void PackCell(cell_t cell); + void PackFloat(float val); + void PackString(const char *string); + size_t CreateMemory(size_t size, void **addr); +public: + void Initialize(); +private: + void CheckSize(size_t sizetype); +private: + char *m_pBase; + mutable char *m_curptr; + size_t m_capacity; + size_t m_size; +}; + +#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ \ No newline at end of file diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7dfbbdde..7bdd8347 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -235,6 +239,10 @@ RelativePath="..\smn_convar.cpp" > + + @@ -285,6 +293,10 @@ RelativePath="..\CConVarManager.h" > + + diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp new file mode 100644 index 00000000..fdf9ca3e --- /dev/null +++ b/core/smn_datapacks.cpp @@ -0,0 +1,288 @@ +#include "sm_globals.h" +#include "HandleSys.h" +#include "CDataPack.h" + +HandleType_t g_DataPackType; + +class DataPackNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + g_DataPackType = g_HandleSys.CreateType("DataPack", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_DataPackType, g_pCoreIdent); + g_DataPackType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + g_SourceMod.FreeDataPack(reinterpret_cast(object)); + } +}; + +static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params) +{ + IDataPack *pDataPack = g_SourceMod.CreateDataPack(); + + if (!pDataPack) + { + return 0; + } + + return g_HandleSys.CreateHandle(g_DataPackType, pDataPack, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t smn_WritePackCell(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->PackCell(params[2]); + + return 1; +} + +static cell_t smn_WritePackFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->PackFloat(sp_ctof(params[2])); + + return 1; +} + +static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + int err; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + char *str; + if ((err=pContext->LocalToString(params[2], &str)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + pDataPack->PackString(str); + + return 1; +} + +static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->IsReadable(sizeof(cell_t))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + return pDataPack->ReadCell(); +} + +static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->IsReadable(sizeof(float))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + return sp_ftoc(pDataPack->ReadFloat()); +} + +static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + const char *str; + if (!(str=pDataPack->ReadString(NULL))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + pContext->StringToLocal(params[2], params[3], str); + + return 1; +} + +static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->Reset(); + if (params[2]) + { + pDataPack->ResetSize(); + } + + return 1; +} + +static cell_t smn_GetPackPosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + return static_cast(pDataPack->GetPosition()); +} + +static cell_t smn_SetPackPosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->SetPosition(params[2])) + { + return pContext->ThrowNativeError("Invalid DataPack position, %d is out of bounds", params[2]); + } + + return 1; +} + +static cell_t smn_IsPackReadable(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + return pDataPack->IsReadable(params[2]) ? 1 : 0; +} + +static DataPackNatives s_DataPackNatives; + +REGISTER_NATIVES(datapacknatives) +{ + {"CreateDataPack", smn_CreateDataPack}, + {"WritePackCell", smn_WritePackCell}, + {"WritePackFloat", smn_WritePackFloat}, + {"WritePackString", smn_WritePackString}, + {"ReadPackCell", smn_ReadPackCell}, + {"ReadPackFloat", smn_ReadPackFloat}, + {"ReadPackString", smn_ReadPackString}, + {"ResetPack", smn_ResetPack}, + {"GetPackPosition", smn_GetPackPosition}, + {"SetPackPosition", smn_SetPackPosition}, + {"IsPackReadable", smn_IsPackReadable}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 72e57d91..f25222fe 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -226,7 +226,7 @@ void SourceModBase::LevelShutdown() } } -bool SourceModBase::IsMapLoading() +bool SourceModBase::IsMapLoading() const { return m_IsMapLoading; } @@ -296,6 +296,16 @@ void SourceModBase::CloseSourceMod() pBase = pBase->m_pGlobalClassNext; } + /* Delete all data packs */ + CStack::iterator iter; + CDataPack *pd; + for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) + { + pd = (*iter); + delete pd; + } + m_freepacks.popall(); + /* Notify! */ pBase = SMGlobalClass::head; while (pBase) @@ -361,12 +371,12 @@ size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContex return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); } -const char *SourceModBase::GetSourceModPath() +const char *SourceModBase::GetSourceModPath() const { return m_SMBaseDir; } -const char *SourceModBase::GetModPath() +const char *SourceModBase::GetModPath() const { return g_BaseDir.c_str(); } @@ -386,6 +396,31 @@ unsigned int SourceModBase::GetGlobalTarget() const return m_target; } +IDataPack *SourceModBase::CreateDataPack() +{ + CDataPack *pack; + if (m_freepacks.empty()) + { + pack = new CDataPack; + } else { + pack = m_freepacks.front(); + m_freepacks.pop(); + pack->Initialize(); + } + return pack; +} + +void SourceModBase::FreeDataPack(IDataPack *pack) +{ + m_freepacks.push(static_cast(pack)); +} + +Handle_t SourceModBase::GetDataPackHandleType(bool readonly) +{ + //:TODO: + return 0; +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index a906b759..f1ea52d1 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -16,6 +16,10 @@ #include "sm_globals.h" #include +#include +#include "CDataPack.h" + +using namespace SourceHook; /** * @brief Implements SourceMod's global overall management, API, and logic @@ -52,9 +56,9 @@ public: void LevelShutdown(); /** - * @brief Returns whether or not a mapload is in progress + * @brief Returns whether or not a map load is in progress */ - bool IsMapLoading(); + bool IsMapLoading() const; /** * @brief Stores the global target index. @@ -65,14 +69,21 @@ public: * @brief Returns the global target index. */ unsigned int GetGlobalTarget() const; + + /** + * @brief Sets whether if SoureMod needs to check player auths. + */ + void SetAuthChecking(bool set); public: //ISourceMod - const char *GetModPath(); - const char *GetSourceModPath(); + const char *GetModPath() const; + const char *GetSourceModPath() const; size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); void LogMessage(IExtension *pExt, const char *format, ...); void LogError(IExtension *pExt, const char *format, ...); size_t FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param); - void SetAuthChecking(bool set); + IDataPack *CreateDataPack(); + void FreeDataPack(IDataPack *pack); + HandleType_t GetDataPackHandleType(bool readonly=false); private: /** * @brief Loading plugins @@ -80,6 +91,7 @@ private: void DoGlobalPluginLoads(); void GameFrame(bool simulating); private: + CStack m_freepacks; char m_SMBaseDir[PLATFORM_MAX_PATH+1]; char m_SMRelDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; diff --git a/public/IDataPack.h b/public/IDataPack.h index 1cc0446e..d5e3fc89 100644 --- a/public/IDataPack.h +++ b/public/IDataPack.h @@ -70,7 +70,8 @@ namespace SourceMod virtual float ReadFloat() const =0; /** - * @brief Returns whether or not a specified number of bytes can be read. + * @brief Returns whether or not a specified number of bytes from the current stream + * position to the end can be read. * * @param bytes Number of bytes to simulate reading. * @return True if can be read, false otherwise. @@ -94,11 +95,16 @@ namespace SourceMod }; /** - * @brief Specifices a data pack that can only be written. + * @brief Specifies a data pack that can only be written. */ class IDataPack : public IDataReader { public: + /** + * @brief Resets the used size of the stream back to zero. + */ + virtual void ResetSize() =0; + /** * @brief Packs one cell into the data stream. * diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 4c3b4116..db24b346 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -24,6 +24,7 @@ #include #include +#include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" #define SMINTERFACE_SOURCEMOD_VERSION 1 @@ -42,7 +43,7 @@ namespace SourceMod }; /** - * @brief Contains miscellanious helper functions. + * @brief Contains miscellaneous helper functions. */ class ISourceMod : public SMInterface { @@ -61,14 +62,14 @@ namespace SourceMod * * @return A string containing the full mod path. */ - virtual const char *GetModPath() =0; + virtual const char *GetModPath() const =0; /** * @brief Returns the full path to the SourceMod directory. * * @return A string containing the full SourceMod path. */ - virtual const char *GetSourceModPath() =0; + virtual const char *GetSourceModPath() const =0; /** * @brief Builds a platform path for a specific target base path. @@ -117,7 +118,6 @@ namespace SourceMod const cell_t *params, unsigned int param) =0; -#if 0 /** * @brief Creates a data pack object. * @@ -144,7 +144,6 @@ namespace SourceMod * @return The Handle type for storing generic data packs. */ virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; -#endif }; } From 3b151e1790f42b34dbf0831c7b84cd447b815278 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 13 Feb 2007 16:39:47 +0000 Subject: [PATCH 0460/1664] new lines for linux --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40491 --- core/CDataPack.h | 2 +- core/smn_datapacks.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/CDataPack.h b/core/CDataPack.h index 0aae8592..cb514306 100644 --- a/core/CDataPack.h +++ b/core/CDataPack.h @@ -50,4 +50,4 @@ private: size_t m_size; }; -#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ \ No newline at end of file +#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp index fdf9ca3e..573715c1 100644 --- a/core/smn_datapacks.cpp +++ b/core/smn_datapacks.cpp @@ -285,4 +285,4 @@ REGISTER_NATIVES(datapacknatives) {"SetPackPosition", smn_SetPackPosition}, {"IsPackReadable", smn_IsPackReadable}, {NULL, NULL} -}; \ No newline at end of file +}; From 20441b70d366aaf252c6c83277b11b8383466b71 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Feb 2007 19:20:48 +0000 Subject: [PATCH 0461/1664] added plugin properties --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40492 --- core/systems/PluginSys.cpp | 22 ++++++++++++++++++++++ core/systems/PluginSys.h | 3 +++ public/IPluginSys.h | 24 +++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index e1761185..74fbb82d 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -40,6 +40,7 @@ CPlugin::CPlugin(const char *file) snprintf(m_filename, sizeof(m_filename), "%s", file); m_handle = 0; m_ident = NULL; + m_pProps = sm_trie_create(); } CPlugin::~CPlugin() @@ -75,6 +76,10 @@ CPlugin::~CPlugin() g_pSourcePawn->FreeFromMemory(m_plugin); m_plugin = NULL; } + if (!m_pProps) + { + sm_trie_destroy(m_pProps); + } } void CPlugin::InitIdentity() @@ -125,6 +130,23 @@ CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) return pPlugin; } +bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */) +{ + bool exists = sm_trie_retrieve(m_pProps, prop, ptr); + + if (exists && remove) + { + sm_trie_delete(m_pProps, prop); + } + + return exists; +} + +bool CPlugin::SetProperty(const char *prop, void *ptr) +{ + return sm_trie_insert(m_pProps, prop, ptr); +} + ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm) { if (!m_plugin) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index c2e97786..039eb47c 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -117,6 +117,8 @@ public: virtual unsigned int GetSerial() const; virtual const sp_plugin_t *GetPluginStructure() const; virtual IdentityToken_t *GetIdentity() const; + virtual bool SetProperty(const char *prop, void *ptr); + virtual bool GetProperty(const char *prop, void **ptr, bool remove=false); public: /** * Creates a plugin object with default values. @@ -241,6 +243,7 @@ private: bool m_WasRunning; CVector m_PhraseFiles; CVector m_ConVarList; + Trie *m_pProps; }; class CPluginManager : diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 6bafd2e7..7cbcb5a9 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -28,7 +28,7 @@ #include #define SMINTERFACE_PLUGINSYSTEM_NAME "IPluginManager" -#define SMINTERFACE_PLUGINSYSTEM_VERSION 1 +#define SMINTERFACE_PLUGINSYSTEM_VERSION 2 /** Context user slot 3 is used Core for holding an IPluginContext pointer. */ #define SM_CONTEXTVAR_USER 3 @@ -154,6 +154,28 @@ namespace SourceMod * @brief Returns a plugin's identity token. */ virtual IdentityToken_t *GetIdentity() const =0; + + /** + * @brief Sets a property on this plugin. This is used for per-plugin + * data from extensions or other parts of core. The property's value must + * be manually destructed when the plugin is destroyed. + * + * @param prop String containing name of the property. + * @param ptr Generic pointer to set. + * @return True on success, false if the property is already set. + */ + virtual bool SetProperty(const char *prop, void *ptr) =0; + + /** + * @brief Gets a property from a plugin. + * + * @param prop String containing the property's name. + * @param ptr Optional pointer to the generic pointer. + * @param remove Optional boolean value; if true, property is removed + * (so it can be set again). + * @return True if the property existed, false otherwise. + */ + virtual bool GetProperty(const char *prop, void **ptr, bool remove=false) =0; }; From bb79b1e6a93c580916363262a8683bc84f8c1a71 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 14 Feb 2007 01:25:45 +0000 Subject: [PATCH 0462/1664] Removed convar stuff from CPlugin, now uses plugin properties for convar listing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40493 --- core/CConVarManager.cpp | 45 ++++++++++++++++++++++++++++++++------ core/CConVarManager.h | 8 +++++-- core/systems/HandleSys.h | 2 +- core/systems/PluginSys.cpp | 15 ------------- core/systems/PluginSys.h | 16 -------------- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 87042ca8..d4de4ea0 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -12,10 +12,12 @@ */ #include "CConVarManager.h" -#include "CLogger.h" #include "PluginSys.h" +#include "ForwardSys.h" +#include "HandleSys.h" #include "sm_srvcmds.h" #include "sm_stringutil.h" +#include CConVarManager g_ConVarManager; @@ -81,6 +83,17 @@ void CConVarManager::OnSourceModShutdown() g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } +void CConVarManager::OnPluginDestroyed(IPlugin *plugin) +{ + CVector *cvarList; + + // If plugin has a convar list, free its memory + if (plugin->GetProperty("ConVar", reinterpret_cast(&cvarList), true)) + { + delete cvarList; + } +} + void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) { ConVarInfo *info; @@ -116,10 +129,13 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc // Get plugin object CPlugin *pl = g_PluginSys.GetPluginByOrder(num); - // Get number of convars created by plugin - int convarnum = pl->GetConVarCount(); + CVector *cvarList = NULL; - if (convarnum == 0) + // Get convar list from 'ConVar' property + pl->GetProperty("ConVar", reinterpret_cast(&cvarList)); + + // If no cvar list... + if (cvarList == NULL) { g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); return; @@ -128,9 +144,9 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\"", pl->GetPublicInfo()->name); // Iterate convar list and display each one - for (int i = 0; i < convarnum; i++, id++) + for (size_t i = 0; i < cvarList->size(); i++, id++) { - ConVar *cvar = pl->GetConVarByIndex(i); + ConVar *cvar = (*cvarList)[i]; g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); } @@ -145,6 +161,7 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name { ConVar *cvar = NULL; ConVarInfo *info = NULL; + CVector *cvarList = NULL; Handle_t hndl = 0; // Find out if the convar exists already @@ -190,8 +207,22 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); + // Find plugin creating convar + IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); + + // Get convar list from 'ConVar' property of plugin + pl->GetProperty("ConVar", reinterpret_cast(&cvarList)); + + // If 'ConVar' property doesn't exist... + if (cvarList == NULL) + { + // Then create it + cvarList = new CVector; + pl->SetProperty("ConVar", cvarList); + } + // Add new convar to plugin's list - g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar); + cvarList->push_back(cvar); // Create a handle from the new convar hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); diff --git a/core/CConVarManager.h b/core/CConVarManager.h index b21184de..80a05dda 100644 --- a/core/CConVarManager.h +++ b/core/CConVarManager.h @@ -16,10 +16,11 @@ #include "sm_globals.h" #include "sourcemm_api.h" -#include "HandleSys.h" -#include "ForwardSys.h" #include "sm_trie.h" #include +#include +#include +#include #include using namespace SourceHook; @@ -38,6 +39,7 @@ struct ConVarInfo class CConVarManager : public SMGlobalClass, public IHandleTypeDispatch, + public IPluginsListener, public IRootConsoleCommand { public: @@ -48,6 +50,8 @@ public: // SMGlobalClass void OnSourceModShutdown(); public: // IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); +public: // IPluginsListener + void OnPluginDestroyed(IPlugin *plugin); public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 46b56d7a..97962562 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -40,7 +40,7 @@ * * The second vector is the identity linked list. An identity has its own handle, so * these handles are used as sentinel nodes for index linking. They point to the first and last - * index into the handle array. Each subsequent Handle who is owned by that indentity is mapped into + * index into the handle array. Each subsequent Handle who is owned by that identity is mapped into * that list. This lets owning identities be unloaded in O(n) time. * * Eventually, there may be a third list for type chains. diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 74fbb82d..8651a455 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -531,21 +531,6 @@ unsigned int CPlugin::GetLangFileByIndex(unsigned int index) const return m_PhraseFiles.at(index); } -void CPlugin::AddConVar(ConVar *convar) -{ - m_ConVarList.push_back(convar); -} - -size_t CPlugin::GetConVarCount() const -{ - return m_ConVarList.size(); -} - -ConVar *CPlugin::GetConVarByIndex(size_t index) const -{ - return m_ConVarList.at(index); -} - /******************* * PLUGIN ITERATOR * *******************/ diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 039eb47c..2b46fed0 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -210,21 +210,6 @@ public: * Returns true if the plugin was running, but is now invalid. */ bool WasRunning(); - - /** - * Adds a convar to the plugin's list - */ - void AddConVar(ConVar *convar); - - /** - * Get convar count for this plugin. - */ - size_t GetConVarCount() const; - - /** - * Get convar pointer based on the vector index. - */ - ConVar *GetConVarByIndex(size_t index) const; protected: void UpdateInfo(); void SetTimeStamp(time_t t); @@ -242,7 +227,6 @@ private: Handle_t m_handle; bool m_WasRunning; CVector m_PhraseFiles; - CVector m_ConVarList; Trie *m_pProps; }; From 8f9a0706bfb4088a50a46915a32e3ff2957de6ff Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Feb 2007 11:03:03 +0000 Subject: [PATCH 0463/1664] improved data pack type checking added readmemory member --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40494 --- core/CDataPack.cpp | 76 +++++++++++++++++++++++++++++++++++------- core/CDataPack.h | 1 + core/smn_datapacks.cpp | 4 +-- public/IDataPack.h | 8 +++++ 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp index 09e932e4..576e808c 100644 --- a/core/CDataPack.cpp +++ b/core/CDataPack.cpp @@ -2,7 +2,7 @@ #include #include "CDataPack.h" -#define DATAPACK_INITIAL_SIZE 512 +#define DATAPACK_INITIAL_SIZE 4//512 CDataPack::CDataPack() { @@ -45,36 +45,47 @@ void CDataPack::ResetSize() size_t CDataPack::CreateMemory(size_t size, void **addr) { + CheckSize(sizeof(size_t) + size); size_t pos = m_curptr - m_pBase; - m_pBase = (char *)realloc(m_pBase, size); - m_curptr = m_pBase + pos; - m_capacity = size; + *(size_t *)m_curptr = size; + m_curptr += sizeof(size_t); if (addr) { - *addr = m_pBase; + *addr = m_curptr; } + m_curptr += size; + m_size += sizeof(size_t) + size; + return pos; } void CDataPack::PackCell(cell_t cell) { - CheckSize(sizeof(cell_t)); + CheckSize(sizeof(size_t) + sizeof(cell_t)); + + *(size_t *)m_curptr = sizeof(cell_t); + m_curptr += sizeof(size_t); *(cell_t *)m_curptr = cell; m_curptr += sizeof(cell_t); - m_size += sizeof(cell_t); + + m_size += sizeof(size_t) + sizeof(cell_t); } void CDataPack::PackFloat(float val) { - CheckSize(sizeof(float)); + CheckSize(sizeof(size_t) + sizeof(float)); + + *(size_t *)m_curptr = sizeof(float); + m_curptr += sizeof(size_t); *(float *)m_curptr = val; m_curptr += sizeof(float); - m_size += sizeof(float); + + m_size += sizeof(size_t) + sizeof(float); } void CDataPack::PackString(const char *string) @@ -118,10 +129,17 @@ bool CDataPack::SetPosition(size_t pos) const cell_t CDataPack::ReadCell() const { - if (!IsReadable(sizeof(cell_t))) + if (!IsReadable(sizeof(size_t) + sizeof(cell_t))) { return 0; } + if (*reinterpret_cast(m_curptr) != sizeof(cell_t)) + { + return 0; + } + + m_curptr += sizeof(size_t); + cell_t val = *reinterpret_cast(m_curptr); m_curptr += sizeof(cell_t); return val; @@ -129,10 +147,17 @@ cell_t CDataPack::ReadCell() const float CDataPack::ReadFloat() const { - if (!IsReadable(sizeof(float))) + if (!IsReadable(sizeof(size_t) + sizeof(float))) { return 0; } + if (*reinterpret_cast(m_curptr) != sizeof(float)) + { + return 0; + } + + m_curptr += sizeof(size_t); + float val = *reinterpret_cast(m_curptr); m_curptr += sizeof(float); return val; @@ -147,7 +172,7 @@ const char *CDataPack::ReadString(size_t *len) const { if (!IsReadable(sizeof(size_t))) { - return 0; + return NULL; } size_t real_len = *(size_t *)m_curptr; @@ -174,3 +199,30 @@ void *CDataPack::GetMemory() const { return m_curptr; } + +void *CDataPack::ReadMemory(size_t *size) const +{ + if (!IsReadable(sizeof(size_t))) + { + return NULL; + } + + size_t bytecount = *(size_t *)m_curptr; + m_curptr += sizeof(size_t); + + if (!IsReadable(bytecount)) + { + return NULL; + } + + void *ptr = m_curptr; + + if (size) + { + *size = bytecount; + } + + m_curptr += bytecount; + + return ptr; +} diff --git a/core/CDataPack.h b/core/CDataPack.h index cb514306..5e86c86b 100644 --- a/core/CDataPack.h +++ b/core/CDataPack.h @@ -33,6 +33,7 @@ public: //IDataReader bool IsReadable(size_t bytes) const; const char *ReadString(size_t *len) const; void *GetMemory() const; + void *ReadMemory(size_t *size) const; public: //IDataPack void ResetSize(); void PackCell(cell_t cell); diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp index 573715c1..ad5d91ba 100644 --- a/core/smn_datapacks.cpp +++ b/core/smn_datapacks.cpp @@ -123,7 +123,7 @@ static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); } - if (!pDataPack->IsReadable(sizeof(cell_t))) + if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(cell_t))) { return pContext->ThrowNativeError("DataPack operation is out of bounds."); } @@ -147,7 +147,7 @@ static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); } - if (!pDataPack->IsReadable(sizeof(float))) + if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(float))) { return pContext->ThrowNativeError("DataPack operation is out of bounds."); } diff --git a/public/IDataPack.h b/public/IDataPack.h index d5e3fc89..6874428b 100644 --- a/public/IDataPack.h +++ b/public/IDataPack.h @@ -92,6 +92,14 @@ namespace SourceMod * @return Pointer to the memory. */ virtual void *GetMemory() const =0; + + /** + * @brief Reads the current position as a generic data type. + * + * @param size Optional pointer to store the size of the data type. + * @return Pointer to the data, or NULL if out of bounds. + */ + virtual void *ReadMemory(size_t *size) const =0; }; /** From 5fadb866641dfb4335a09f6627ddafb6d0a7299a Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Feb 2007 11:07:22 +0000 Subject: [PATCH 0464/1664] removed debug code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40495 --- core/CDataPack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp index 576e808c..bbda1f1a 100644 --- a/core/CDataPack.cpp +++ b/core/CDataPack.cpp @@ -2,7 +2,7 @@ #include #include "CDataPack.h" -#define DATAPACK_INITIAL_SIZE 4//512 +#define DATAPACK_INITIAL_SIZE 512 CDataPack::CDataPack() { From 3287dc14429305813469288b6975733950b2377f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Feb 2007 11:29:59 +0000 Subject: [PATCH 0465/1664] forgot to add the headers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40496 --- core/CDataPack.cpp | 14 ++++++++++++++ core/smn_datapacks.cpp | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp index bbda1f1a..d4c19fdf 100644 --- a/core/CDataPack.cpp +++ b/core/CDataPack.cpp @@ -1,3 +1,17 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + #include #include #include "CDataPack.h" diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp index ad5d91ba..4128c992 100644 --- a/core/smn_datapacks.cpp +++ b/core/smn_datapacks.cpp @@ -1,3 +1,17 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + #include "sm_globals.h" #include "HandleSys.h" #include "CDataPack.h" From 911a33395773df43e18cc3fe43bbb301f65abad9 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Feb 2007 17:03:54 +0000 Subject: [PATCH 0466/1664] updated makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40497 --- core/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/Makefile b/core/Makefile index c0d90301..c08a148e 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,11 +19,12 @@ BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk -OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CConVarManager.cpp CDbgReporter.cpp \ - CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ +OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CConVarManager.cpp CDataPack.cpp \ + CDbgReporter.cpp CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ smn_player.cpp smn_string.cpp smn_textparse.cpp smn_convar.cpp smn_admin.cpp \ + smn_datapacks.cpp smn_lang.cpp \ systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ systems/PluginSys.cpp systems/ShareSys.cpp vm/sp_vm_basecontext.cpp \ @@ -49,7 +50,7 @@ endif GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) -CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -mfpmath=sse -msse -DSOURCEMOD_BUILD CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti ifeq "$(GCC_VERSION)" "4" From 12b9e2750e552ad90eaead6f6d674d5f0db95fc7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 14 Feb 2007 17:48:49 +0000 Subject: [PATCH 0467/1664] made these names more consistent, except for authorized, since only players get authids --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40498 --- core/smn_player.cpp | 6 +++--- plugins/include/sourcemod.inc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 41378cf2..006cb0cf 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -398,10 +398,10 @@ REGISTER_NATIVES(playernatives) {"GetClientName", sm_GetClientName}, {"GetClientIP", sm_GetClientIP}, {"GetClientAuthString", sm_GetClientAuthStr}, - {"IsPlayerConnected", sm_IsPlayerConnected}, + {"IsClientConnected", sm_IsPlayerConnected}, {"IsPlayerInGame", sm_IsPlayerIngame}, - {"IsPlayerAuthorized", sm_IsPlayerAuthorized}, - {"IsPlayerFakeClient", sm_IsPlayerFakeClient}, + {"IsClientAuthorized", sm_IsPlayerAuthorized}, + {"IsFakeClient", sm_IsPlayerFakeClient}, {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, {"GetClientInfo", sm_GetClientInfo}, diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 6592a949..fc0cb0a0 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -212,7 +212,7 @@ native GetClientUserId(client); * @param client Player index. * @return True if player is connected to the server, false otherwise. */ -native bool:IsPlayerConnected(client); +native bool:IsClientConnected(client); /** * Returns if a certain player has entered the game. @@ -228,7 +228,7 @@ native bool:IsPlayerInGame(client); * @param client Player index. * @return True if player has been authenticated, false otherwise. */ -native bool:IsPlayerAuthorized(client); +native bool:IsClientAuthorized(client); /** * Returns if a certain player is a fake client. @@ -236,7 +236,7 @@ native bool:IsPlayerAuthorized(client); * @param client Player index. * @return True if player is a fake client, false otherwise. */ -native bool:IsPlayerFakeClient(client); +native bool:IsFakeClient(client); /** * Retrieves values from client replicated keys. From 7a8152aba371f18907933535dc9e5e7807dd071f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 14 Feb 2007 17:49:18 +0000 Subject: [PATCH 0468/1664] initial import of bulk include for events and messages this is not in sourcemod.inc until it's done --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40499 --- plugins/include/eventsmsgs.inc | 240 +++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 plugins/include/eventsmsgs.inc diff --git a/plugins/include/eventsmsgs.inc b/plugins/include/eventsmsgs.inc new file mode 100644 index 00000000..4543e2c2 --- /dev/null +++ b/plugins/include/eventsmsgs.inc @@ -0,0 +1,240 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _eventsmsgs_included + #endinput +#endif +#define _eventsmsgs_included + +enum UserMsg +{ + INVALID_MESSAGE_ID = -1, +}; + +#define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */ +#define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */ + +//:NOTE: none of this is implemented yet, remove this notice and add to sourcemod.inc once it's done! +//:NOTE: for DS, add main event natives below EndMessage but above bf_ stuff + +/** + * Returns the ID of a given message, or -1 on failure. + * + * @param msg String containing message name (case sensitive). + * @return A message index, or INVALID_MESSAGE_ID on failure. + */ +native UserMsg:GetUserMessageId(const String:msg[]); + +/** + * Starts a usermessage (network message). + * @note Only one message can be active at a time. + * + * @param msg Message index to start. + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +native Handle:StartMessage(UserMsg:msg, clients[], numClients, flags); + +/** + * Ends a previously started user message (network message). + * + * @noreturn + */ +native EndMessage(); + +/** + * Writes a single bit to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param bit Bit to write (true for 1, false for 0). + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteBool(Handle:bf, bool:bit); + +/** + * Writes a byte to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param byte Byte to write (value will be written as 8bit). + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteByte(Handle:bf, byte); + +/** + * Writes a byte to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param chr Character to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteChar(Handle:bf, chr); + +/** + * Writes a 16bit integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 16bit). + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteShort(Handle:bf, num); + +/** + * Writes a 16bit unsigned integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 16bit). + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteWord(Handle:bf, num); + +/** + * Writes a normal integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 32bit). + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteNum(Handle:bf, num); + +/** + * Writes a floating point number to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Number to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteFloat(Handle:bf, Float:num); + +/** + * Writes a string to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param string Text string to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteString(Handle:bf, const String:string[]); + +/** + * Writes an entity to a writable bitbuffer (bf_write). + * @note This is a wrapper around BfWriteShort(). + * + * @param bf bf_write handle to write to. + * @param ent Entity index to write. + * @noreturn + * @error Invalid or incorrect Handle, or invalid entity. + */ +native BfWriteEntity(Handle:bf, ent); + +/** + * Writes a bit angle to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param angle Angle to write. + * @param numBits Optional number of bits to use. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteAngle(Handle:bf, Float:angle, numBits=8); + +/** + * Writes a coordinate to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param coord Coordinate to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteCoord(Handle:bf, Float:coord); + +/** + * Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). + * + * @param bif bf_write handle to write to. + * @param coord Coordinate array to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteVecCoord(Handle:bf, Float:coord[3]); + +/** + * Writes a 3D normal vector to a writable bitbuffer (bf_write). + * + * @param bif bf_write handle to write to. + * @param vec Vector to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteVecNormal(Handle:bf, Float:vec[3]); + +/** + * Writes a 3D angle vector to a writable bitbuffer (bf_write). + * + * @param bif bf_write handle to write to. + * @param angles Angle vector to write. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfWriteAngles(Handle:bf, Float:angles[3]); + +/** + * Starts a usermessage (network message) that broadcasts to all clients. + * + * @param msg Message index to start. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle:StartMessageAll(UserMsg:msg, flags=0) +{ + new maxClients = GetMaxClients(); + new total = 0; + new clients[maxClients]; + for (new i=1; i<=maxClients; i++) + { + if (IsClientConnected(i)) + { + clients[total++] = i; + } + } + return StartMessage(msg, clients, total, flags); +} + +/** + * Starts a simpler usermessage (network message) for one client. + * + * @param msg Message index to start. + * @param client Client to send to. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle:StartMessageOne(UserMsg:msg, client, flags=0) +{ + new players[1]; + + players[0] = client; + + return StartMsesage(msg, players, 1, flags); +} From 06b9b09ea6b82db1eb42b84a3b8431a17063648e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 14 Feb 2007 23:44:40 +0000 Subject: [PATCH 0469/1664] Plugin forwards for convar changes are no longer called if the new and old values are the same --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40500 --- core/CConVarManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index d4de4ea0..32128386 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -372,6 +372,13 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) { + // If the values are the same... + if (strcmp(cvar->GetString(), oldValue) == 0) + { + // Exit early in order to not trigger callbacks + return; + } + Trie *cache = g_ConVarManager.GetConVarCache(); ConVarInfo *info; From 0655c1b34c522962f277508ba19fa7b9b5427882 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 15 Feb 2007 01:02:34 +0000 Subject: [PATCH 0470/1664] Fixed up a few things in preliminary UltraEdit syntax highlighting file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40501 --- editor/ultraedit/wordfile.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/editor/ultraedit/wordfile.txt b/editor/ultraedit/wordfile.txt index 402596c7..c6455f0e 100644 --- a/editor/ultraedit/wordfile.txt +++ b/editor/ultraedit/wordfile.txt @@ -8,6 +8,8 @@ /Function String 5 = "%^{public^}^{stock^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)"/ /Indent Strings = "{" /Unindent Strings = "}" +/Open Fold Strings = "{" +/Close Fold Strings = "}" /C1"Keywords" assert begin break @@ -57,11 +59,13 @@ Handle Plugin String /C5"Constants" -cellbits cellmax cellmin charbits charmax +__Pawn __version +cellbits cellmax cellmin charbits charmax charmin +debug myinfo -__version +ucharmax INVALID_HANDLE /C6"Stocks" -//TODO +# TODO /C7"Natives" -//TODO \ No newline at end of file +# TODO \ No newline at end of file From 745375f393f36753224e8e2b7d1acdb950830963 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Feb 2007 20:35:17 +0000 Subject: [PATCH 0471/1664] added engine callclass --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40502 --- core/sourcemm_api.cpp | 1 + core/sourcemm_api.h | 3 +++ core/sourcemod.cpp | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 2980ab61..fedd22e8 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -24,6 +24,7 @@ ISmmPluginManager *g_pMMPlugins = NULL; CGlobalVars *gpGlobals = NULL; ICvar *icvar = NULL; IGameEventManager2 *gameevents = NULL; +CallClass *enginePatch = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 10a2d346..5acbfbe7 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -51,6 +51,9 @@ extern ICvar *icvar; extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; extern IGameEventManager2 *gameevents; +extern SourceHook::CallClass *enginePatch; + +#define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index f25222fe..375844f8 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -156,6 +156,8 @@ void SourceModBase::StartSourceMod(bool late) SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); + enginePatch = SH_GET_CALLCLASS(engine); + /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) @@ -314,6 +316,12 @@ void SourceModBase::CloseSourceMod() pBase = pBase->m_pGlobalClassNext; } + if (enginePatch) + { + SH_RELEASE_CALLCLASS(enginePatch); + enginePatch = NULL; + } + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); From 81509e1ee4ca99961467afa125abbee6aa67cbf1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Feb 2007 22:16:19 +0000 Subject: [PATCH 0472/1664] renamed Result to Action --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40503 --- plugins/include/core.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 36670c72..5c867e7f 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -27,7 +27,7 @@ struct PlVers /** * Specifies what to do after a hook completes. */ -enum Result +enum Action { Plugin_Continue = 0, /**< Continue with the original action */ Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */ From 165b705354219f9634bfe585f66752197ee3026f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Feb 2007 22:17:01 +0000 Subject: [PATCH 0473/1664] implemented+tested RegServerCmd() renamed internal project console stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40504 --- core/CConCmdManager.cpp | 269 +++++++++++++++++++++++ core/CConCmdManager.h | 81 +++++++ core/msvc8/sourcemod_mm.vcproj | 94 ++++---- core/{smn_convar.cpp => smn_console.cpp} | 21 ++ plugins/include/console.inc | 72 ++++++ 5 files changed, 496 insertions(+), 41 deletions(-) create mode 100644 core/CConCmdManager.cpp create mode 100644 core/CConCmdManager.h rename core/{smn_convar.cpp => smn_console.cpp} (91%) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp new file mode 100644 index 00000000..4c6aeea1 --- /dev/null +++ b/core/CConCmdManager.cpp @@ -0,0 +1,269 @@ +#include "CConCmdManager.h" +#include "sm_srvcmds.h" + +CConCmdManager g_ConCmds; + +SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false); +SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int); + +struct PlCmdInfo +{ + ConCmdInfo *pInfo; + CmdType type; +}; + +typedef List CmdList; + +char *sm_strdup(const char *str) +{ + char *ptr = new char[strlen(str)+1]; + strcpy(ptr, str); + return ptr; +} + +CConCmdManager::CConCmdManager() +{ + m_pCmds = sm_trie_create(); +} + +CConCmdManager::~CConCmdManager() +{ + sm_trie_destroy(m_pCmds); +} + +void CConCmdManager::OnSourceModAllInitialized() +{ + g_PluginSys.AddPluginsListener(this); + g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false); +} + +void CConCmdManager::OnSourceModShutdown() +{ + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false); + g_RootMenu.RemoveRootConsoleCommand("cmds", this); + g_PluginSys.RemovePluginsListener(this); +} + +void CConCmdManager::OnPluginLoaded(IPlugin *plugin) +{ + /* Nothing yet... */ +} + +void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) +{ + CmdList *pList; + if (plugin->GetProperty("CommandList", (void **)&pList, true)) + { + CmdList::iterator iter; + for (iter=pList->begin(); + iter!=pList->end(); + iter++) + { + PlCmdInfo &cmd = (*iter); + if (cmd.type == Cmd_Server + || cmd.type == Cmd_Console) + { + ConCmdInfo *pInfo = cmd.pInfo; + /* See if there are still hooks */ + if (pInfo->srvhooks + && pInfo->srvhooks->GetFunctionCount()) + { + continue; + } + /* Remove the command */ + RemoveConCmd(pInfo); + } + } + delete pList; + } +} + +void CommandCallback() +{ + g_ConCmds.InternalDispatch(); +} + +void CConCmdManager::SetCommandClient(int client) +{ + m_CmdClient = client + 1; +} + +void CConCmdManager::InternalDispatch() +{ + if (m_CmdClient) + { + return; + } + + const char *cmd = engine->Cmd_Argv(0); + ConCmdInfo *pInfo; + if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo)) + { + return; + } + + cell_t result = Pl_Continue; + if (pInfo->srvhooks) + { + pInfo->srvhooks->Execute(&result); + } + + if (result >= Pl_Handled) + { + if (!pInfo->sourceMod) + { + RETURN_META(MRES_SUPERCEDE); + } + return; + } +} + +void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, + const char *name, + const char *description, + int flags) + +{ + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + + if (!pInfo->srvhooks) + { + pInfo->srvhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_Cell); + } + + pInfo->srvhooks->AddFunction(pFunction); + + /* Add to the plugin */ + CmdList *pList; + IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + if (!pPlugin->GetProperty("CommandList", (void **)&pList)) + { + pList = new CmdList(); + pPlugin->SetProperty("CommandList", pList); + } + PlCmdInfo info; + info.pInfo = pInfo; + info.type = Cmd_Console; + pList->push_back(info); +} + +void CConCmdManager::AddToCmdList(ConCmdInfo *info) +{ + List::iterator iter = m_CmdList.begin(); + ConCmdInfo *pInfo; + bool inserted = false; + const char *orig; + + if (info->pCmd) + { + orig = info->pCmd->GetName(); + } + + /* Insert this into the help list, SORTED alphabetically. */ + while (iter != m_CmdList.end()) + { + const char *cmd = NULL; + pInfo = (*iter); + if (pInfo->pCmd) + { + cmd = pInfo->pCmd->GetName(); + } + if (strcmp(orig, cmd) < 0) + { + m_CmdList.insert(iter, info); + inserted = true; + break; + } + iter++; + } + + if (!inserted) + { + m_CmdList.push_back(info); + } +} + +void CConCmdManager::RemoveConCmd(ConCmdInfo *info) +{ + /* Remove console-specific information */ + if (info->pCmd) + { + /* Remove from the trie */ + sm_trie_delete(m_pCmds, info->pCmd->GetName()); + + if (info->sourceMod) + { + /* Unlink from SourceMM */ + g_SMAPI->UnregisterConCmdBase(g_PLAPI, info->pCmd); + /* Delete the command's memory */ + char *new_help = const_cast(info->pCmd->GetHelpText()); + char *new_name = const_cast(info->pCmd->GetName()); + delete [] new_help; + delete [] new_name; + delete info->pCmd; + } else { + /* Remove the external hook */ + SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, info->pCmd, CommandCallback, false); + } + } + + /* Remove from list */ + m_CmdList.remove(info); + + /* Free forwards */ + if (info->srvhooks) + { + g_Forwards.ReleaseForward(info->srvhooks); + } +} + +ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) +{ + ConCmdInfo *pInfo; + if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo)) + { + pInfo = new ConCmdInfo(); + /* Find the commandopan */ + ConCommandBase *pBase = icvar->GetCommands(); + ConCommand *pCmd = NULL; + while (pBase) + { + if (pBase->IsCommand() + && (strcmp(pBase->GetName(), name) == 0)) + { + pCmd = (ConCommand *)pBase; + break; + } + pBase = const_cast(pBase->GetNext()); + } + + if (!pCmd) + { + /* Note that we have to duplicate because the source might not be + * a static string, and these expect static memory. + */ + if (!description) + { + description = ""; + } + char *new_name = sm_strdup(name); + char *new_help = sm_strdup(description); + pCmd = new ConCommand(new_name, CommandCallback, new_help, flags); + pInfo->sourceMod = true; + } else { + SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CommandCallback, false); + } + + pInfo->pCmd = pCmd; + + sm_trie_insert(m_pCmds, name, pInfo); + AddToCmdList(pInfo); + } + + return pInfo; +} + +void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ +} diff --git a/core/CConCmdManager.h b/core/CConCmdManager.h new file mode 100644 index 00000000..247b3a64 --- /dev/null +++ b/core/CConCmdManager.h @@ -0,0 +1,81 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "ForwardSys.h" +#include "sm_trie.h" +#include +#include + +using namespace SourceHook; + +enum CmdType +{ + Cmd_Server, + Cmd_Console, + Cmd_Client +}; + +struct ConCmdInfo +{ + ConCmdInfo() + { + sourceMod = false; + pCmd = NULL; + srvhooks = NULL; + } + bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ + ConCommand *pCmd; /**< Pointer to the command itself */ + IChangeableForward *srvhooks; /**< Hooks on this name as a server command */ +}; + +class CConCmdManager : + public SMGlobalClass, + public IRootConsoleCommand, + public IPluginsListener +{ + friend void CommandCallback(); +public: + CConCmdManager(); + ~CConCmdManager(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: //IPluginsListener + void OnPluginLoaded(IPlugin *plugin); + void OnPluginDestroyed(IPlugin *plugin); +public: //IRootConsoleCommand + void OnRootConsoleCommand(const char *command, unsigned int argcount); +public: + void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); +private: + void InternalDispatch(); + ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags); + void SetCommandClient(int client); + void AddToCmdList(ConCmdInfo *info); + void RemoveConCmd(ConCmdInfo *info); +private: + Trie *m_pCmds; + List m_CmdList; + int m_CmdClient; +}; + +extern CConCmdManager g_ConCmds; + +#endif // _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ + diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7bdd8347..4e251710 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -231,46 +235,6 @@ RelativePath="..\sm_trie.cpp" > - - - - - - - - - - - - - - - - - - - - @@ -289,6 +253,10 @@ RelativePath="..\AdminCache.h" > + + @@ -658,6 +626,50 @@ > + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/smn_convar.cpp b/core/smn_console.cpp similarity index 91% rename from core/smn_convar.cpp rename to core/smn_console.cpp index 9efccae6..4a9275a7 100644 --- a/core/smn_convar.cpp +++ b/core/smn_console.cpp @@ -15,6 +15,7 @@ #include "sourcemm_api.h" #include "HandleSys.h" #include "CConVarManager.h" +#include "CConCmdManager.h" static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) { @@ -322,6 +323,25 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params) +{ + char *name,*help; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pContext->LocalToString(params[3], &help); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + g_ConCmds.AddServerCommand(pFunction, name, help, params[4]); + + return 1; +} + REGISTER_NATIVES(convarNatives) { {"CreateConVar", sm_CreateConVar}, @@ -342,5 +362,6 @@ REGISTER_NATIVES(convarNatives) {"GetConVarMin", sm_GetConVarMin}, {"GetConVarMax", sm_GetConVarMax}, {"ResetConVar", sm_ResetConVar}, + {"RegServerCmd", sm_RegServerCmd}, {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 1b46c24d..1bacbcf6 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -73,6 +73,78 @@ native PrintToServer(const String:format[], {Handle,Float,String,_}:...); */ native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); +/** + * Called when a server-only command is invoked. + * + * @return A Result value. Not handling the command + * means that Source will report it as "not found." + */ +functag SrvCmd Action:public(); + +/** + * Creates a server-only console command, or hooks an already existing one. + * + * @param cmd Name of the command to hook or create. + * @param callback A function to use as a callback for when the command is invoked. + * @param description Optional description to use for command creation. + * @param flags Optional flags to use for command creation. + * @noreturn + */ +native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:description[]="", flags=0); + +#if 0 +/** + * Called when a generic console command is invoked. + * + * @param client Index of the client, or 0 from the server. + * @return A Result value. Not handling the command + * means that Source will report it as "not found." + */ +functag ConCmd Action:public(client); + +/** + * Creates a console command, or hooks an already existing one. + * + * @param cmd Name of the command to hook or create. + * @param callback A function to use as a callback for when the command is invoked. + * @param description Optional description to use for command creation. + * @param flags Optional flags to use for command creation. + * @noreturn + */ +native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0); + +/** + * Hooks a specific client-only command. + * + * @param cmd String to match against the beginning of each client command. + * @param callback A function to use as a callback for when the command is invoked. + * @param description Optional description string to use for help. + * @noreturn + */ +native RegClientCmd(const String:cmd[], ConCmd:callback, const String:description[]=""); + +/** + * Creates a console command as an administrative command. If the command does not exist, + * it is created. This command cannot be used to create duplicate admin commands. + * + * @param cmd String containing command to register. + * @param callback A function to use as a callback for when the command is invoked. + * @param adminflags Administrative flags (bitstring) to use for permissions. + * @param group String containing the command group to use. If empty, + * the plugin's filename will be used instead. + * @param description Optional description to use for help. + * @param flags Optional console flags. + * @noreturn + * @error If this command has already been registered as an admin command. + */ +native RegAdminCmd(const String:cmd[], + ConCmd:callback, + adminflags, + const String:group[]="", + const String:description[]="", + flags=0); +#endif + /** * Creates a new console variable. * From dcb10ee3a28fda0d88c6133357b20d5d39453330 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 00:04:14 +0000 Subject: [PATCH 0474/1664] added per-plugin command listing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40505 --- core/CConCmdManager.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ core/CConVarManager.cpp | 4 ++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 4c6aeea1..b0586dfc 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -266,4 +266,56 @@ ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *descr void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount) { + if (argcount >= 3) + { + const char *text = engine->Cmd_Argv(2); + int id = atoi(text); + CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(id); + + if (!pPlugin) + { + g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id); + return; + } + + CmdList *pList; + if (!pPlugin->GetProperty("CommandList", (void **)&pList)) + { + g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename()); + return; + } + if (!pList->size()) + { + g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename()); + return; + } + + CmdList::iterator iter; + const char *type = NULL; + const char *name; + const char *help; + g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]"); + for (iter=pList->begin(); + iter!=pList->end(); + iter++) + { + PlCmdInfo &cmd = (*iter); + if (cmd.type == Cmd_Server) + { + type = "server"; + } else if (cmd.type == Cmd_Console) { + type = "console"; + } else if (cmd.type == Cmd_Client) { + type = "client"; + } + name = cmd.pInfo->pCmd->GetName(); + help = cmd.pInfo->pCmd->GetHelpText(); + g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); + + } + + return; + } + + g_RootMenu.ConsolePrint("[SM] Usage: sm cmds "); } diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 32128386..32cfd609 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -122,7 +122,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc // If invalid plugin index... if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) { - g_RootMenu.ConsolePrint("[SM] Plugin index not found."); + g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", num); return; } @@ -154,7 +154,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc } // Display usage of subcommand - g_RootMenu.ConsolePrint("[SM] Usage: sm convars <#>"); + g_RootMenu.ConsolePrint("[SM] Usage: sm convars "); } Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) From 76903cd919c5831e41a46228f6f59d34838d2163 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 02:17:41 +0000 Subject: [PATCH 0475/1664] added client-based console commands extended console command functions to have an argument number renamed Result to Action --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40506 --- core/CConCmdManager.cpp | 109 +++++++++++++++++++++++++++++++--- core/CConCmdManager.h | 4 ++ core/CPlayerManager.cpp | 27 +++++++-- core/smn_console.cpp | 20 +++++++ plugins/include/console.inc | 6 +- plugins/include/sourcemod.inc | 2 +- 6 files changed, 150 insertions(+), 18 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index b0586dfc..20858ed6 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -40,6 +40,7 @@ void CConCmdManager::OnSourceModAllInitialized() void CConCmdManager::OnSourceModShutdown() { + /* All commands should already be removed by the time we're done */ SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false); g_RootMenu.RemoveRootConsoleCommand("cmds", this); g_PluginSys.RemovePluginsListener(this); @@ -53,6 +54,7 @@ void CConCmdManager::OnPluginLoaded(IPlugin *plugin) void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) { CmdList *pList; + List removed; if (plugin->GetProperty("CommandList", (void **)&pList, true)) { CmdList::iterator iter; @@ -65,14 +67,25 @@ void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) || cmd.type == Cmd_Console) { ConCmdInfo *pInfo = cmd.pInfo; + /* See if this is being removed */ + if (removed.find(pInfo) != removed.end()) + { + continue; + } /* See if there are still hooks */ if (pInfo->srvhooks && pInfo->srvhooks->GetFunctionCount()) { continue; } + if (pInfo->conhooks + && pInfo->conhooks->GetFunctionCount()) + { + continue; + } /* Remove the command */ RemoveConCmd(pInfo); + removed.push_back(pInfo); } } delete pList; @@ -89,12 +102,39 @@ void CConCmdManager::SetCommandClient(int client) m_CmdClient = client + 1; } +ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) +{ + const char *cmd = engine->Cmd_Argv(0); + int args = engine->Cmd_Argc() - 1; + + ConCmdInfo *pInfo; + if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo)) + { + cell_t result = type; + if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) + { + pInfo->conhooks->PushCell(client); + pInfo->conhooks->PushCell(args); + pInfo->conhooks->Execute(&result); + } + if (result >= Pl_Stop) + { + return Pl_Stop; + } + type = (ResultType)result; + } + + return type; +} + void CConCmdManager::InternalDispatch() { - if (m_CmdClient) - { - return; - } + /** + * Note: Console commands will EITHER go through IServerGameDLL::ClientCommand, + * OR this dispatch. They will NEVER go through both. + * -- + * Whether or not it goes through the callback is determined by FCVAR_GAMEDLL + */ const char *cmd = engine->Cmd_Argv(0); ConCmdInfo *pInfo; @@ -104,9 +144,33 @@ void CConCmdManager::InternalDispatch() } cell_t result = Pl_Continue; - if (pInfo->srvhooks) + int args = engine->Cmd_Argc() - 1; + + if (m_CmdClient == 0) { - pInfo->srvhooks->Execute(&result); + if (pInfo->srvhooks && pInfo->srvhooks->GetFunctionCount()) + { + pInfo->srvhooks->PushCell(args); + pInfo->srvhooks->Execute(&result); + } + + /* Check if there's an early stop */ + if (result >= Pl_Stop) + { + if (!pInfo->sourceMod) + { + RETURN_META(MRES_SUPERCEDE); + } + return; + } + } + + /* Execute console command hooks */ + if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) + { + pInfo->conhooks->PushCell(m_CmdClient); + pInfo->conhooks->PushCell(args); + pInfo->conhooks->Execute(&result); } if (result >= Pl_Handled) @@ -119,6 +183,34 @@ void CConCmdManager::InternalDispatch() } } +void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, + const char *name, + const char *description, + int flags) +{ + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + + if (!pInfo->conhooks) + { + pInfo->conhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_Cell); + } + + pInfo->conhooks->AddFunction(pFunction); + + /* Add to the plugin */ + CmdList *pList; + IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + if (!pPlugin->GetProperty("CommandList", (void **)&pList)) + { + pList = new CmdList(); + pPlugin->SetProperty("CommandList", pList); + } + PlCmdInfo info; + info.pInfo = pInfo; + info.type = Cmd_Console; + pList->push_back(info); +} + void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, @@ -144,7 +236,7 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, } PlCmdInfo info; info.pInfo = pInfo; - info.type = Cmd_Console; + info.type = Cmd_Server; pList->push_back(info); } @@ -310,8 +402,7 @@ void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argc } name = cmd.pInfo->pCmd->GetName(); help = cmd.pInfo->pCmd->GetHelpText(); - g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); - + g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); } return; diff --git a/core/CConCmdManager.h b/core/CConCmdManager.h index 247b3a64..d924483c 100644 --- a/core/CConCmdManager.h +++ b/core/CConCmdManager.h @@ -38,10 +38,12 @@ struct ConCmdInfo sourceMod = false; pCmd = NULL; srvhooks = NULL; + conhooks = NULL; } bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ ConCommand *pCmd; /**< Pointer to the command itself */ IChangeableForward *srvhooks; /**< Hooks on this name as a server command */ + IChangeableForward *conhooks; /**< Hooks on this name as a console command */ }; class CConCmdManager : @@ -63,6 +65,8 @@ public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); + void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); + ResultType DispatchClientCommand(int client, ResultType type); private: void InternalDispatch(); ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags); diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 69f70bd9..91c74fb2 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -15,6 +15,7 @@ #include "ForwardSys.h" #include "ShareSys.h" #include "AdminCache.h" +#include "CConCmdManager.h" CPlayerManager g_Players; @@ -51,15 +52,14 @@ void CPlayerManager::OnSourceModAllInitialized() ParamType p1[] = {Param_Cell, Param_String, Param_Cell}; ParamType p2[] = {Param_Cell}; - ParamType p3[] = {Param_Cell, Param_String}; m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1); m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2); m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2); m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2); - m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2); + m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell); m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); - m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p3); + m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String); } void CPlayerManager::OnSourceModShutdown() @@ -197,6 +197,7 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons g_SourceMod.SetAuthChecking(true); } + //:todo: this must meta return return (res) ? true : false; } @@ -328,10 +329,26 @@ void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) void CPlayerManager::OnClientCommand(edict_t *pEntity) { - cell_t res; + cell_t res = Pl_Continue; + int client = engine->IndexOfEdict(pEntity); - m_clcommand->PushCell(engine->IndexOfEdict(pEntity)); + int args = engine->Cmd_Argc() - 1; + + m_clcommand->PushCell(client); + m_clcommand->PushCell(args); m_clcommand->Execute(&res, NULL); + + if (res >= Pl_Stop) + { + RETURN_META(MRES_SUPERCEDE); + } + + res = g_ConCmds.DispatchClientCommand(client, (ResultType)res); + + if (res >= Pl_Handled) + { + RETURN_META(MRES_SUPERCEDE); + } } void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 4a9275a7..3651e4bf 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -342,6 +342,25 @@ static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params) +{ + char *name,*help; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pContext->LocalToString(params[3], &help); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]); + + return 1; +} + REGISTER_NATIVES(convarNatives) { {"CreateConVar", sm_CreateConVar}, @@ -363,5 +382,6 @@ REGISTER_NATIVES(convarNatives) {"GetConVarMax", sm_GetConVarMax}, {"ResetConVar", sm_ResetConVar}, {"RegServerCmd", sm_RegServerCmd}, + {"RegConsoleCmd", sm_RegConsoleCmd}, {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 1bacbcf6..84125f50 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -79,7 +79,7 @@ native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:... * @return A Result value. Not handling the command * means that Source will report it as "not found." */ -functag SrvCmd Action:public(); +functag SrvCmd Action:public(argCount); /** * Creates a server-only console command, or hooks an already existing one. @@ -92,7 +92,6 @@ functag SrvCmd Action:public(); */ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:description[]="", flags=0); -#if 0 /** * Called when a generic console command is invoked. * @@ -100,7 +99,7 @@ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:descriptio * @return A Result value. Not handling the command * means that Source will report it as "not found." */ -functag ConCmd Action:public(client); +functag ConCmd Action:public(client, argCount); /** * Creates a console command, or hooks an already existing one. @@ -113,6 +112,7 @@ functag ConCmd Action:public(client); */ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0); +#if 0 /** * Hooks a specific client-only command. * diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index fc0cb0a0..e0e7ab00 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -128,7 +128,7 @@ forward OnClientDisconnect_Post(client); * @param client Player index. * @noreturn */ -forward OnClientCommand(client); +forward OnClientCommand(client, argCount); /** * Called whenever the client's settings are changed. From a75e87a0760faad80a51823f413859d125b33b1e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 03:47:10 +0000 Subject: [PATCH 0476/1664] removed this potential feature, not useful enough --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40507 --- plugins/include/console.inc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 84125f50..ec0258a2 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -113,16 +113,6 @@ functag ConCmd Action:public(client, argCount); native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0); #if 0 -/** - * Hooks a specific client-only command. - * - * @param cmd String to match against the beginning of each client command. - * @param callback A function to use as a callback for when the command is invoked. - * @param description Optional description string to use for help. - * @noreturn - */ -native RegClientCmd(const String:cmd[], ConCmd:callback, const String:description[]=""); - /** * Creates a console command as an administrative command. If the command does not exist, * it is created. This command cannot be used to create duplicate admin commands. From 165b8ed893fe7eb3a514e01b5f7ceef01d806666 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 04:16:31 +0000 Subject: [PATCH 0477/1664] fixed a serious potential bug with swapping plugins to debug mode, leaving stale function pointers without plugin removal --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40508 --- core/vm/sp_vm_basecontext.cpp | 35 ++++++++++++++++++++++++++++------- core/vm/sp_vm_basecontext.h | 2 +- core/vm/sp_vm_function.cpp | 2 ++ core/vm/sp_vm_function.h | 9 +++++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 0107045b..302fb186 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -66,14 +66,19 @@ BaseContext::BaseContext(sp_context_t *_ctx) } } -void BaseContext::FlushFunctionCache() +void BaseContext::FlushFunctionCache(bool remove) { if (m_pub_funcs) { for (uint32_t i=0; iplugin->info.publics_num; i++) { - delete m_pub_funcs[i]; - m_pub_funcs[i] = NULL; + if (remove) + { + delete m_pub_funcs[i]; + m_pub_funcs[i] = NULL; + } else if (m_pub_funcs[i]) { + m_pub_funcs[i]->Invalidate(); + } } } @@ -81,15 +86,20 @@ void BaseContext::FlushFunctionCache() { for (unsigned int i=0; iInvalidate(); + } } } } BaseContext::~BaseContext() { - FlushFunctionCache(); + FlushFunctionCache(true); delete [] m_pub_funcs; m_pub_funcs = NULL; delete [] m_priv_funcs; @@ -105,7 +115,7 @@ void BaseContext::SetContext(sp_context_t *_ctx) ctx = _ctx; ctx->context = this; ctx->dbreak = GlobalDebugBreak; - FlushFunctionCache(); + FlushFunctionCache(false); } IVirtualMachine *BaseContext::GetVirtualMachine() @@ -850,6 +860,8 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) { m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); pFunc = m_pub_funcs[func_id]; + } else if (pFunc->IsInvalidated()) { + pFunc->Set(ctx->publics[func_id].code_offs, this); } } else { /* :TODO: currently not used */ @@ -892,6 +904,15 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) m_pub_funcs[index] = new CFunction(pub->code_offs, this); } pFunc = m_pub_funcs[index]; + } else if (pFunc->IsInvalidated()) { + sp_public_t *pub = NULL; + GetPublicByIndex(index, &pub); + if (pub) + { + pFunc->Set(pub->code_offs, this); + } else { + pFunc = NULL; + } } return pFunc; diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 232a7967..4c001a54 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -79,7 +79,7 @@ namespace SourcePawn void SetContext(sp_context_t *_ctx); private: void SetErrorMessage(const char *msg, va_list ap); - void FlushFunctionCache(); + void FlushFunctionCache(bool remove); private: sp_context_t *ctx; #if defined SOURCEMOD_BUILD diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 04ce7a23..c4fc339f 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -25,6 +25,7 @@ void CFunction::Set(uint32_t code_addr, IPluginContext *plugin) m_pContext = plugin; m_curparam = 0; m_errorstate = SP_ERROR_NONE; + m_Invalid = false; } int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) @@ -46,6 +47,7 @@ CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), m_errorstate(SP_ERROR_NONE) { + m_Invalid = false; } int CFunction::PushCell(cell_t cell) diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index b61a51fa..2eaaf229 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -46,6 +46,14 @@ public: virtual void Cancel(); virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); virtual IPluginContext *GetParentContext(); + inline bool IsInvalidated() + { + return m_Invalid; + } + inline void Invalidate() + { + m_Invalid = true; + } public: void Set(uint32_t code_addr, IPluginContext *plugin); private: @@ -63,6 +71,7 @@ private: unsigned int m_curparam; int m_errorstate; CFunction *m_pNext; + bool m_Invalid; }; #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ From eb2afc8c56b31348276e161180e55161eba34249 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 04:43:48 +0000 Subject: [PATCH 0478/1664] fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40509 --- core/CConCmdManager.cpp | 16 ++++++---------- core/Makefile | 3 ++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 20858ed6..878eec78 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -245,22 +245,16 @@ void CConCmdManager::AddToCmdList(ConCmdInfo *info) List::iterator iter = m_CmdList.begin(); ConCmdInfo *pInfo; bool inserted = false; - const char *orig; + const char *orig = NULL; - if (info->pCmd) - { - orig = info->pCmd->GetName(); - } + orig = info->pCmd->GetName(); /* Insert this into the help list, SORTED alphabetically. */ while (iter != m_CmdList.end()) { const char *cmd = NULL; pInfo = (*iter); - if (pInfo->pCmd) - { - cmd = pInfo->pCmd->GetName(); - } + cmd = pInfo->pCmd->GetName(); if (strcmp(orig, cmd) < 0) { m_CmdList.insert(iter, info); @@ -278,7 +272,9 @@ void CConCmdManager::AddToCmdList(ConCmdInfo *info) void CConCmdManager::RemoveConCmd(ConCmdInfo *info) { - /* Remove console-specific information */ + /* Remove console-specific information + * This should always be true as of right now + */ if (info->pCmd) { /* Remove from the trie */ diff --git a/core/Makefile b/core/Makefile index c08a148e..5d0a8835 100644 --- a/core/Makefile +++ b/core/Makefile @@ -21,9 +21,10 @@ HL2LIB = $(HL2SDK)/linux_sdk OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CConVarManager.cpp CDataPack.cpp \ CDbgReporter.cpp CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ + CConCmdManager.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ - smn_player.cpp smn_string.cpp smn_textparse.cpp smn_convar.cpp smn_admin.cpp \ + smn_player.cpp smn_string.cpp smn_textparse.cpp smn_console.cpp smn_admin.cpp \ smn_datapacks.cpp smn_lang.cpp \ systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ From c91542fbe8d0ec493ce5e7e7d595c8a481535c90 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Feb 2007 07:48:38 +0000 Subject: [PATCH 0479/1664] Moved this... for now Also added missing header --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40510 --- core/CConCmdManager.cpp | 21 ++++++++++++++------- core/sm_stringutil.cpp | 6 ++++++ core/sm_stringutil.h | 1 + 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 878eec78..fd4123d8 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -1,5 +1,19 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + #include "CConCmdManager.h" #include "sm_srvcmds.h" +#include "sm_stringutil.h" CConCmdManager g_ConCmds; @@ -14,13 +28,6 @@ struct PlCmdInfo typedef List CmdList; -char *sm_strdup(const char *str) -{ - char *ptr = new char[strlen(str)+1]; - strcpy(ptr, str); - return ptr; -} - CConCmdManager::CConCmdManager() { m_pCmds = sm_trie_create(); diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 069cac25..75db7263 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -794,3 +794,9 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) return (len >= maxlength) ? (maxlength - 1) : len; } +char *sm_strdup(const char *str) +{ + char *ptr = new char[strlen(str)+1]; + strcpy(ptr, str); + return ptr; +} diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index d47b4b7b..5189f7e5 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -27,5 +27,6 @@ const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); +char *sm_strdup(const char *str); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ From 0fbb38ef8efda0d4df8168302e5c8416903755cb Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 16 Feb 2007 18:47:16 +0000 Subject: [PATCH 0480/1664] initial user message implementation with its natives and such --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40511 --- core/CMsgIdPool.h | 63 ++++ core/CellRecipientFilter.h | 91 +++++ core/msvc8/sourcemod_mm.vcproj | 18 +- core/smn_bitbuffer.cpp | 348 ++++++++++++++++++ core/smn_usermsgs.cpp | 190 ++++++++++ core/sourcemod.h | 1 + .../include/{eventsmsgs.inc => bitbuffer.inc} | 85 +---- plugins/include/sourcemod.inc | 2 + plugins/include/usermessages.inc | 109 ++++++ 9 files changed, 824 insertions(+), 83 deletions(-) create mode 100644 core/CMsgIdPool.h create mode 100644 core/CellRecipientFilter.h create mode 100644 core/smn_bitbuffer.cpp create mode 100644 core/smn_usermsgs.cpp rename plugins/include/{eventsmsgs.inc => bitbuffer.inc} (63%) create mode 100644 plugins/include/usermessages.inc diff --git a/core/CMsgIdPool.h b/core/CMsgIdPool.h new file mode 100644 index 00000000..de84ce4d --- /dev/null +++ b/core/CMsgIdPool.h @@ -0,0 +1,63 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ +#define _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ + +#include "sm_trie.h" +#include "sourcemm_api.h" + +#define INVALID_MESSAGE_ID -1 + +class CMessageIdPool +{ +public: + CMessageIdPool() + { + m_Names = sm_trie_create(); + } + ~CMessageIdPool() + { + sm_trie_destroy(m_Names); + } +public: + int GetMessageId(const char *name) + { + int msgid; + if (!sm_trie_retrieve(m_Names, name, reinterpret_cast(&msgid))) + { + char buf[255]; + int dummy; + msgid = 0; + + while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy)) + { + if (strcmp(name, buf) == 0) + { + sm_trie_insert(m_Names, name, reinterpret_cast(msgid)); + return msgid; + } + msgid++; + } + + return INVALID_MESSAGE_ID; + } + + return msgid; + } +private: + Trie *m_Names; +}; + +#endif //_INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ diff --git a/core/CellRecipientFilter.h b/core/CellRecipientFilter.h new file mode 100644 index 00000000..1a082088 --- /dev/null +++ b/core/CellRecipientFilter.h @@ -0,0 +1,91 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_ +#define _INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_ + +#include +#include + +class CellRecipientFilter : public IRecipientFilter +{ +public: + CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0), m_CellRecipients(NULL) {} + ~CellRecipientFilter() {} +public: //IRecipientFilter + bool IsReliable() const; + bool IsInitMessage() const; + int GetRecipientCount() const; + int GetRecipientIndex(int slot) const; +public: + void SetRecipientPtr(cell_t *ptr, size_t count); + void SetReliable(bool isreliable); + void SetInitMessage(bool isinitmsg); + void ResetFilter(); +private: + bool m_Reliable; + bool m_InitMessage; + size_t m_Size; + cell_t *m_CellRecipients; +}; + +inline void CellRecipientFilter::ResetFilter() +{ + m_Reliable = false; + m_InitMessage = false; + m_Size = 0; + m_CellRecipients = NULL; +} + +inline bool CellRecipientFilter::IsReliable() const +{ + return m_Reliable; +} + +inline bool CellRecipientFilter::IsInitMessage() const +{ + return m_InitMessage; +} + +inline int CellRecipientFilter::GetRecipientCount() const +{ + return m_Size; +} + +inline int CellRecipientFilter::GetRecipientIndex(int slot) const +{ + if ((slot < 0) || (slot >= GetRecipientCount())) + { + return -1; + } + return static_cast(m_CellRecipients[slot]); +} + +inline void CellRecipientFilter::SetInitMessage(bool isinitmsg) +{ + m_InitMessage = isinitmsg; +} + +inline void CellRecipientFilter::SetReliable(bool isreliable) +{ + m_Reliable = isreliable; +} + +inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count) +{ + m_CellRecipients = ptr; + m_Size = count; +} + +#endif //_INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 4e251710..79a348b2 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + + + @@ -633,6 +641,10 @@ RelativePath="..\smn_admin.cpp" > + + @@ -669,6 +681,10 @@ RelativePath="..\smn_textparse.cpp" > + + diff --git a/core/smn_bitbuffer.cpp b/core/smn_bitbuffer.cpp new file mode 100644 index 00000000..cc3adf9f --- /dev/null +++ b/core/smn_bitbuffer.cpp @@ -0,0 +1,348 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include +#include +#include "sourcemod.h" +#include "HandleSys.h" + +static cell_t smn_BfWriteBool(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteOneBit(params[2]); + + return 1; +} + +static cell_t smn_BfWriteByte(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteByte(params[2]); + + return 1; +} + +static cell_t smn_BfWriteChar(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteChar(params[2]); + + return 1; +} + +static cell_t smn_BfWriteShort(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteShort(params[2]); + + return 1; +} + +static cell_t smn_BfWriteWord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteWord(params[2]); + + return 1; +} + +static cell_t smn_BfWriteNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteLong(static_cast(params[2])); + + return 1; +} + +static cell_t smn_BfWriteFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteFloat(sp_ctof(params[2])); + + return 1; +} + +static cell_t smn_BfWriteString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + int err; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + char *str; + if ((err=pCtx->LocalToString(params[2], &str)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + pBitBuf->WriteString(str); + + return 1; +} + +static cell_t smn_BfWriteEntity(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteShort(params[2]); + + return 1; +} + +static cell_t smn_BfWriteAngle(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteBitAngle(sp_ctof(params[2]), params[3]); + + return 1; +} + +static cell_t smn_BfWriteCoord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pBitBuf->WriteBitCoord(sp_ctof(params[2])); + + return 1; +} + +static cell_t smn_BfWriteVecCoord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pVec; + pCtx->LocalToPhysAddr(params[2], &pVec); + Vector vec(sp_ctof(pVec[0]), sp_ctof(pVec[1]), sp_ctof(pVec[2])); + pBitBuf->WriteBitVec3Coord(vec); + + return 1; +} + +static cell_t smn_BfWriteVecNormal(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pVec; + pCtx->LocalToPhysAddr(params[2], &pVec); + Vector vec(sp_ctof(pVec[0]), sp_ctof(pVec[1]), sp_ctof(pVec[2])); + pBitBuf->WriteBitVec3Normal(vec); + + return 1; +} + +static cell_t smn_BfWriteAngles(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_write *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_WrBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pAng; + pCtx->LocalToPhysAddr(params[2], &pAng); + QAngle ang(sp_ctof(pAng[0]), sp_ctof(pAng[1]), sp_ctof(pAng[2])); + pBitBuf->WriteBitAngles(ang); + + return 1; +} + +REGISTER_NATIVES(wrbitbufnatives) +{ + {"BfWriteBool", smn_BfWriteBool}, + {"BfWriteByte", smn_BfWriteByte}, + {"BfWriteChar", smn_BfWriteChar}, + {"BfWriteShort", smn_BfWriteShort}, + {"BfWriteWord", smn_BfWriteWord}, + {"BfWriteNum", smn_BfWriteNum}, + {"BfWriteFloat", smn_BfWriteFloat}, + {"BfWriteString", smn_BfWriteString}, + {"BfWriteEntity", smn_BfWriteEntity}, + {"BfWriteAngle", smn_BfWriteAngle}, + {"BfWriteCoord", smn_BfWriteCoord}, + {"BfWriteVecCoord", smn_BfWriteVecCoord}, + {"BfWriteVecNormal", smn_BfWriteVecNormal}, + {"BfWriteAngles", smn_BfWriteAngles}, + {NULL, NULL} +}; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp new file mode 100644 index 00000000..ad869666 --- /dev/null +++ b/core/smn_usermsgs.cpp @@ -0,0 +1,190 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "HandleSys.h" +#include "CellRecipientFilter.h" +#include "CMsgIdPool.h" + +#define USERMSG_PASSTHRU (1<<0) +#define USERMSG_PASSTHRU_ALL (1<<1) +#define USERMSG_RELIABLE (1<<2) +#define USERMSG_INITMSG (1<<3) + +CMessageIdPool g_MessageIds; +CellRecipientFilter g_MsgRecFilter; +HandleType_t g_WrBitBufType; +Handle_t g_CurMsgHandle; +bool g_IsMsgInExec = false; +int g_CurMsgFlags = 0; + +class UsrMessageNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent); + g_WrBitBufType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + } +}; + +static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) +{ + char *msgname; + int err; + if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + return g_MessageIds.GetMessageId(msgname); +} + +static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) +{ + char *msgname; + cell_t *cl_array; + int msgid, err; + bf_write *pBitBuf; + + if (g_IsMsgInExec) + { + return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress"); + } + + if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if ((msgid=g_MessageIds.GetMessageId(msgname)) == INVALID_MESSAGE_ID) + { + return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname); + } + + pCtx->LocalToPhysAddr(params[2], &cl_array); + g_CurMsgFlags = params[4]; + + g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]); + if (g_CurMsgFlags & USERMSG_INITMSG) + { + g_MsgRecFilter.SetInitMessage(true); + } + if (g_CurMsgFlags & USERMSG_RELIABLE) + { + g_MsgRecFilter.SetReliable(true); + } + + if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages + { + pBitBuf = engine->UserMessageBegin(static_cast(&g_MsgRecFilter), msgid); + } else { + pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast(&g_MsgRecFilter), msgid); + } + + g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); + g_IsMsgInExec = true; + + return g_CurMsgHandle; +} + +static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params) +{ + cell_t *cl_array; + bf_write *pBitBuf; + int msgid = params[1]; + + if (g_IsMsgInExec) + { + return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress"); + } + + if (msgid < 0 || msgid > 255) + { + return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid); + } + + pCtx->LocalToPhysAddr(params[2], &cl_array); + g_CurMsgFlags = params[4]; + + g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]); + if (g_CurMsgFlags & USERMSG_INITMSG) + { + g_MsgRecFilter.SetInitMessage(true); + } + if (g_CurMsgFlags & USERMSG_RELIABLE) + { + g_MsgRecFilter.SetReliable(true); + } + + if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages + { + pBitBuf = engine->UserMessageBegin(static_cast(&g_MsgRecFilter), msgid); + } else { + pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast(&g_MsgRecFilter), msgid); + } + + g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); + g_IsMsgInExec = true; + + return g_CurMsgHandle; +} + +static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params) +{ + HandleSecurity sec; + + if (!g_IsMsgInExec) + { + return pCtx->ThrowNativeError("Unable to end message, no message is in progress"); + } + + if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) + { + engine->MessageEnd(); + } else { + ENGINE_CALL(MessageEnd)(); + } + + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + g_HandleSys.FreeHandle(g_CurMsgHandle, &sec); + + g_IsMsgInExec = false; + g_CurMsgFlags = 0; + g_MsgRecFilter.ResetFilter(); + + return 1; +} + +static UsrMessageNatives s_UsrMessageNatives; + +REGISTER_NATIVES(usrmsgnatives) +{ + {"GetUserMessageId", smn_GetUserMessageId}, + {"StartMessage", smn_StartMessage}, + {"StartMessageEx", smn_StartMessageEx}, + {"EndMessage", smn_EndMessage}, + {NULL, NULL} +}; diff --git a/core/sourcemod.h b/core/sourcemod.h index f1ea52d1..2913d71a 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -101,5 +101,6 @@ private: }; extern SourceModBase g_SourceMod; +extern HandleType_t g_WrBitBufType; #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/plugins/include/eventsmsgs.inc b/plugins/include/bitbuffer.inc similarity index 63% rename from plugins/include/eventsmsgs.inc rename to plugins/include/bitbuffer.inc index 4543e2c2..b6ec5bdf 100644 --- a/plugins/include/eventsmsgs.inc +++ b/plugins/include/bitbuffer.inc @@ -12,49 +12,11 @@ * * Version: $Id$ */ - -#if defined _eventsmsgs_included + +#if defined _bitbuffer_included #endinput #endif -#define _eventsmsgs_included - -enum UserMsg -{ - INVALID_MESSAGE_ID = -1, -}; - -#define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */ -#define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */ - -//:NOTE: none of this is implemented yet, remove this notice and add to sourcemod.inc once it's done! -//:NOTE: for DS, add main event natives below EndMessage but above bf_ stuff - -/** - * Returns the ID of a given message, or -1 on failure. - * - * @param msg String containing message name (case sensitive). - * @return A message index, or INVALID_MESSAGE_ID on failure. - */ -native UserMsg:GetUserMessageId(const String:msg[]); - -/** - * Starts a usermessage (network message). - * @note Only one message can be active at a time. - * - * @param msg Message index to start. - * @param clients Array containing player indexes to broadcast to. - * @param numClients Number of players in the array. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - */ -native Handle:StartMessage(UserMsg:msg, clients[], numClients, flags); - -/** - * Ends a previously started user message (network message). - * - * @noreturn - */ -native EndMessage(); +#define _bitbuffer_included /** * Writes a single bit to a writable bitbuffer (bf_write). @@ -197,44 +159,3 @@ native BfWriteVecNormal(Handle:bf, Float:vec[3]); * @error Invalid or incorrect Handle. */ native BfWriteAngles(Handle:bf, Float:angles[3]); - -/** - * Starts a usermessage (network message) that broadcasts to all clients. - * - * @param msg Message index to start. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - */ -stock Handle:StartMessageAll(UserMsg:msg, flags=0) -{ - new maxClients = GetMaxClients(); - new total = 0; - new clients[maxClients]; - for (new i=1; i<=maxClients; i++) - { - if (IsClientConnected(i)) - { - clients[total++] = i; - } - } - return StartMessage(msg, clients, total, flags); -} - -/** - * Starts a simpler usermessage (network message) for one client. - * - * @param msg Message index to start. - * @param client Client to send to. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - */ -stock Handle:StartMessageOne(UserMsg:msg, client, flags=0) -{ - new players[1]; - - players[0] = client; - - return StartMsesage(msg, players, 1, flags); -} diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e0e7ab00..43c4c6c7 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -34,6 +34,8 @@ struct Plugin #include #include #include +#include +#include /** * Declare this as a struct in your plugin to expose its information. diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc new file mode 100644 index 00000000..0f05b739 --- /dev/null +++ b/plugins/include/usermessages.inc @@ -0,0 +1,109 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _eventsmsgs_included + #endinput +#endif +#define _eventsmsgs_included + +enum UserMsg +{ + INVALID_MESSAGE_ID = -1, +}; + +#define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */ +#define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */ +#define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */ +#define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */ + +/** + * Returns the ID of a given message, or -1 on failure. + * + * @param msg String containing message name (case sensitive). + * @return A message index, or INVALID_MESSAGE_ID on failure. + */ +native UserMsg:GetUserMessageId(const String:msg[]); + +/** + * Starts a usermessage (network message). + * @note Only one message can be active at a time. + * + * @param msgname Message name to start. + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +native Handle:StartMessage(String:msgname[], clients[], numClients, flags); + +/** + * Starts a usermessage (network message). + * @note Only one message can be active at a time. + * + * @param msg Message index to start. + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags); + +/** + * Ends a previously started user message (network message). + * + * @noreturn + */ +native EndMessage(); + +/** + * Starts a usermessage (network message) that broadcasts to all clients. + * + * @param msgname Message name to start. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle:StartMessageAll(String:msgname[], flags=0) +{ + new maxClients = GetMaxClients(); + new total = 0; + new clients[maxClients]; + for (new i=1; i<=maxClients; i++) + { + if (IsClientConnected(i)) + { + clients[total++] = i; + } + } + return StartMessage(msgname, clients, total, flags); +} + +/** + * Starts a simpler usermessage (network message) for one client. + * + * @param msgname Message name to start. + * @param client Client to send to. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle:StartMessageOne(String:msgname[], client, flags=0) +{ + new players[1]; + + players[0] = client; + + return StartMessage(msgname, players, 1, flags); +} From bf69dad3bf8ac452edaf0e83360d307a4487b151 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 16 Feb 2007 18:50:27 +0000 Subject: [PATCH 0481/1664] Id was broken for this file --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40512 --- plugins/include/sourcemod.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 43c4c6c7..e01e8109 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -10,7 +10,7 @@ * may change at any time. To view the latest information, see: * http://www.sourcemod.net/license.php * - * Version: $Id: sourcemod.inc 432 2007-02-02 22:47:14Z damagedsoul $ + * Version: $Id$ */ #if defined _sourcemod_included From 371c76466806fba1f2a214e946067651f5851d7d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 19:12:27 +0000 Subject: [PATCH 0482/1664] initial import of usermessage interface --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40513 --- public/IUserMessages.h | 131 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 public/IUserMessages.h diff --git a/public/IUserMessages.h b/public/IUserMessages.h new file mode 100644 index 00000000..d25b2b8b --- /dev/null +++ b/public/IUserMessages.h @@ -0,0 +1,131 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_ + +#include +#include +#include + +/** + * @file IUserMessages.h + * @brief Contains functions for advanced usermessage hooking. + */ + +#define SMINTERFACE_USERMSGS_NAME "IUserMessages" +#define SMINTERFACE_USERMSGS_VERSION 1 + +namespace SourceMod +{ + /** + * @brief Listens to user messages sent from the server. + */ + class IUserMessageListener + { + public: + /** + * @brief Called when a hooked user message is being sent + * and all interceptions have finished. + * + * @param msg_id Message Id. + * @param bf bf_write structure containing written bytes. + * @param pFilter Recipient filter. + */ + virtual void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) + { + } + + /** + * @brief Called when a hooked user message is intercepted. + * + * @param msg_id Message Id. + * @param bf bf_write structure containing written bytes. + * @param pFtiler Recipient filter. + * @return True to allow message, false to scrap it. + */ + virtual bool InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) + { + return true; + } + + /** + * @brief Called when a hooked user message is sent, regardless of the hook type. + * @param mgs_id Message Id. + */ + virtual void OnUserMessageSent(int msg_id) + { + } + }; + + /** + * @brief Contains functions for hooking user messages. + */ + class IUserMessages : public SMInterface + { + public: + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_USERMSGS_VERSION; + } + virtual const char *GetInterfaceName() + { + return SMINTERFACE_USERMSGS_NAME; + } + public: + /** + * @brief Finds a message id by name. + * + * Note: due to a bug in Valve's earlier SDK versions, this + * may cause crashes alongside IServerGameDLL003 if the message is + * not found. + * + * @param msg Case-sensitive string containing the message. + * @return A message index, or -1 on failure. + */ + virtual int GetMessageIndex(const char *msg) =0; + + /** + * @brief Sets a hook on a user message. + * + * @param msg_id Message Id. + * @param pListener Pointer to an IUserMessageListener. + * @param intercept If true, message will be intercepted rather than merely hooked. + * @return True on success, false otherwise. + */ + virtual bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false) =0; + + /** + * @brief Wrapper around UserMessageBegin for more options. + * + * @param mgs_id Message Id. + * @param players Array containing player indexes. + * @param playersNum Number of players in the array. + * @param flags Flags to use for sending the message. + * @return bf_write structure to write message with. + */ + virtual bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) =0; + + /** + * @brief Wrapper around UserMessageEnd for use with StartMessage(). + */ + virtual void EndMessage() =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_ From 2b8a69dfcc55adfb107656d9b5d8a59192baac11 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Feb 2007 20:07:40 +0000 Subject: [PATCH 0483/1664] spec'd out more of the message hooking stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40514 --- plugins/include/usermessages.inc | 70 ++++++++++++++++++++++++++++++++ public/IUserMessages.h | 10 +++++ 2 files changed, 80 insertions(+) diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 0f05b739..6afb1053 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -39,24 +39,28 @@ native UserMsg:GetUserMessageId(const String:msg[]); /** * Starts a usermessage (network message). * @note Only one message can be active at a time. + * @note It is illegal to send any message while a non-intercept hook is in progress. * * @param msgname Message name to start. * @param clients Array containing player indexes to broadcast to. * @param numClients Number of players in the array. * @return A handle to a bf_write bit packing structure, or * INVALID_HANDLE on failure. + * @error Invalid message name or unable to start a message. */ native Handle:StartMessage(String:msgname[], clients[], numClients, flags); /** * Starts a usermessage (network message). * @note Only one message can be active at a time. + * @note It is illegal to send any message while a non-intercept hook is in progress. * * @param msg Message index to start. * @param clients Array containing player indexes to broadcast to. * @param numClients Number of players in the array. * @return A handle to a bf_write bit packing structure, or * INVALID_HANDLE on failure. + * @error Invalid message name or unable to start a message. */ native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags); @@ -67,8 +71,73 @@ native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags); */ native EndMessage(); +/** + * @brief Called when a message is hooked + * + * @param msg_id Message index. + * @param players Array containing player indexes. + * @param playersNum Number of players in the array. + * @param reliable True if message is reliable, false otherwise. + * @param init True if message is an initmsg, false otherwise. + * @return Ignored for normal hooks. For intercept hooks, false blocks + * the message from being sent, and true continues. + */ +functag MsgHook bool:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); + +/** + * @brief Hooks a user message. + * + * @param msg_id Message index. + * @param hook Function to use as a hook. + * @param intercept If intercept is true, message will be fully intercepted, + * allowing the user to block the message. Otherwise, + * the hook is normal and ignores the return value. + * @noreturn + * @error Invalid message index. + */ +native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); + +/** + * @brief Removes one usermessage hook. + * + * @param msg_id Message index. + * @param hook Function used for the hook. + * @param intercept Specifies whether the hook was an intercept hook or not. + * @noreturn + * @error Invalid message index. + */ +native UnHookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); + +/** + * @brief Called when a message is finished sending. + * + * @param msg_id Message index. + */ +functag MsgSentNotify public(UserMsg:msg_id); + +/** + * @brief Notifies when a message has finished sending. + * + * @param msg_id Message index. + * @param notify Notification function. + * @noreturn + * @error Invalid message index. + */ +native NotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify); + +/** + * @brief Removes a user message notification. + * + * @param msg_id Message index. + * @param notify Notification function. + * @noreturn + * @error Invalid message index. + */ +native RemoveNotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify); + /** * Starts a usermessage (network message) that broadcasts to all clients. + * @note See StartMessage or StartMessageEx(). * * @param msgname Message name to start. * @param flags Optional flags to set. @@ -92,6 +161,7 @@ stock Handle:StartMessageAll(String:msgname[], flags=0) /** * Starts a simpler usermessage (network message) for one client. + * @note See StartMessage or StartMessageEx(). * * @param msgname Message name to start. * @param client Client to send to. diff --git a/public/IUserMessages.h b/public/IUserMessages.h index d25b2b8b..ce6e5919 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -110,6 +110,16 @@ namespace SourceMod */ virtual bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false) =0; + /** + * @brief Unhooks a user message. + * + * @param msg_id Message Id. + * @param pListener Pointer to an IUserMessageListener. + * @param intercept If true, removed message will from interception pool rather than normal hook pool. + * @return True on success, false otherwise. + */ + virtual bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false) =0; + /** * @brief Wrapper around UserMessageBegin for more options. * From 3f1051e83bfe87ca227b5ab8e0d692fd097c6031 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 17 Feb 2007 04:10:58 +0000 Subject: [PATCH 0484/1664] Corrected Vista information... I think --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40515 --- NOTICE.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index c596b069..35815e51 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -2,10 +2,10 @@ We now use svn:keywords "Id" on all .c/.cpp/.h/.sp/.inc files. Please make sure WINDOWS: Open your Application Data folder. - Windows XP/2000: C:\Documents and Settings\\Application Data - Windows Vista: C:\Users\\Application Data + Windows XP/2000: C:\Documents and Settings\\Application Data + Windows Vista: C:\Users\\AppData\Roaming - Under Application Data, go to Subversion. Open the "config" file with a text editor. + Now go to Subversion. Open the "config" file with a text editor. LINUX: Open ~/.subversion/config with your favorite text editor. From 314f3401c8a74c4afa1dfc21663cd9d1f2bd9c1f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 04:37:47 +0000 Subject: [PATCH 0485/1664] fixed a bug where determinate 1D arrays would not have correct sizeof() -- REALLY hacky fix :( fixed local arrays asserting on more than two dimensions with the last dimension being indeterminate --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40516 --- sourcepawn/compiler/sc.h | 1 + sourcepawn/compiler/sc1.c | 10 ++++++++++ sourcepawn/compiler/sc2.c | 12 +++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 95f61483..2b3783ac 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -823,6 +823,7 @@ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ SC_VDECL int pc_functag; /* global function tag */ SC_VDECL int pc_tag_string; /* global string tag */ +SC_VDECL int glbstringread; /* last global string read */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ SC_VDECL constvalue sc_state_tab; /* state table */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index b9e4ed34..fce03a4f 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -170,6 +170,7 @@ static int *wqptr; /* pointer to next entry */ static HWND hwndFinish = 0; #endif +SC_VDECL int glbstringread = 0; char g_tmpfile[_MAX_PATH] = {0}; /* "main" of the compiler @@ -2044,6 +2045,9 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst } /* if */ assert(litidx==0); /* literal queue should be empty (again) */ initials(ident,tag,&size,dim,numdim,enumroot);/* stores values in the literal queue */ + if (tag == pc_tag_string && (numdim == 1) && !dim[numdim-1]) { + slength = glbstringread; + } assert(size>=litidx); if (numdim==1) dim[0]=(int)size; @@ -2209,6 +2213,7 @@ static int declloc(int fstatic) do { ident=iVARIABLE; size=1; + slength=0; numdim=0; /* no dimensions */ tag=pc_addtag(NULL); if (lex(&val,&str)!=tSYMBOL) /* read in (new) token */ @@ -2304,7 +2309,12 @@ static int declloc(int fstatic) sc_alignnext=FALSE; } /* if */ cur_lit=litidx; /* save current index in the literal table */ + if (numdim && !dim[numdim-1]) + size = 0; initials(ident,tag,&size,dim,numdim,enumroot); + if (tag == pc_tag_string && (numdim == 1) && !dim[numdim-1]) { + slength = glbstringread; + } if (size==0) return ident; /* error message already given */ if (numdim==1) diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 2894e14c..a0609c6f 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1798,6 +1798,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) i=0; /* start at least significant byte */ val=0; + glbstringread=1; while (*lptr!='\"' && *lptr!='\0') { if (*lptr=='\a') { /* ignore '\a' (which was inserted at a line concatenation) */ lptr++; @@ -1807,6 +1808,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) if (c>=(ucell)(1 << sCHARBITS)) error(43); /* character constant exceeds range */ val |= (c << 8*i); + glbstringread++; if (i==sizeof(ucell)-(sCHARBITS/8)) { litadd(val); val=0; @@ -2821,10 +2823,14 @@ SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int for (level=0; leveldim.array.length=dim[level]; - if (tag == pc_tag_string && level == numdim - 1) - top->dim.array.slength=slength; - else + if (tag == pc_tag_string && level == numdim - 1) { + if (slength == 0) + top->dim.array.length=dim[level] * sizeof(cell); + else + top->dim.array.slength=slength; + } else { top->dim.array.slength=0; + } top->dim.array.level=(short)(numdim-level-1); top->x.tags.index=idxtag[level]; top->parent=parent; From e7759cabea8df3d69b710cea075adf043a8525e8 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 17 Feb 2007 05:33:31 +0000 Subject: [PATCH 0486/1664] Initial fixes to ensure static strings passed to new convars Also fixed minor warning in smn_bitbuffer.cpp --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40517 --- core/CConVarManager.cpp | 9 +++++++-- core/smn_bitbuffer.cpp | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 32cfd609..734379a0 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -97,7 +97,7 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) { ConVarInfo *info; - ConCommandBase *cvar = static_cast(object); + ConVar *cvar = static_cast(object); // Find convar in lookup trie sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); @@ -105,6 +105,11 @@ void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) // If convar was created by SourceMod plugin... if (info->sourceMod) { + // Delete string allocations + delete [] cvar->GetName(); + delete [] cvar->GetDefault(); + delete [] cvar->GetHelpText(); + // Then unregister it g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); } @@ -205,7 +210,7 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name } // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max); + cvar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); // Find plugin creating convar IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); diff --git a/core/smn_bitbuffer.cpp b/core/smn_bitbuffer.cpp index cc3adf9f..b6692069 100644 --- a/core/smn_bitbuffer.cpp +++ b/core/smn_bitbuffer.cpp @@ -12,10 +12,10 @@ * Version: $Id$ */ -#include -#include #include "sourcemod.h" #include "HandleSys.h" +#include +#include static cell_t smn_BfWriteBool(IPluginContext *pCtx, const cell_t *params) { From 49d96d4322baf0477c5f5227c5a7a26fd63d7e25 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 17 Feb 2007 07:31:14 +0000 Subject: [PATCH 0487/1664] Added GetUserMessageName() native spec to usermessages.inc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40518 --- core/msvc8/sourcemod_mm.vcproj | 22 +++++++++++++++++----- plugins/include/usermessages.inc | 10 ++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 79a348b2..954a50e2 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -273,6 +277,10 @@ RelativePath="..\CellRecipientFilter.h" > + + @@ -333,6 +341,10 @@ RelativePath="..\sourcemod.h" > + + - - + + diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 6afb1053..c6ad7395 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -36,6 +36,16 @@ enum UserMsg */ native UserMsg:GetUserMessageId(const String:msg[]); +/** + * Retrieves the name of a message by ID. + * + * @param msg_id Message index. + * @param msg Buffer to store the name of the message. + * @param maxlength Maximum length of string buffer. + * @return True if message index is valid, false otherwise. + */ +native bool:GetUserMessageName(UserMsg:msg_id, String:msg[], maxlength); + /** * Starts a usermessage (network message). * @note Only one message can be active at a time. From 6b28bec27fbffe6bdb9234d5140abad89416d4be Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 07:54:20 +0000 Subject: [PATCH 0488/1664] rewrote console command implementation internally admin commands on the way but still not done removed weird restriction --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40519 --- core/CConCmdManager.cpp | 317 +++++++++++++++++++++++++++++------- core/CConCmdManager.h | 53 +++++- plugins/include/console.inc | 3 +- 3 files changed, 299 insertions(+), 74 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index fd4123d8..75cca8b4 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -13,6 +13,7 @@ #include "CConCmdManager.h" #include "sm_srvcmds.h" +#include "AdminCache.h" #include "sm_stringutil.h" CConCmdManager g_ConCmds; @@ -23,19 +24,22 @@ SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int struct PlCmdInfo { ConCmdInfo *pInfo; + CmdHook *pHook; CmdType type; }; - typedef List CmdList; +void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info); -CConCmdManager::CConCmdManager() +CConCmdManager::CConCmdManager() : m_Strings(1024) { m_pCmds = sm_trie_create(); + m_pCmdGrps = sm_trie_create(); } CConCmdManager::~CConCmdManager() { sm_trie_destroy(m_pCmds); + sm_trie_destroy(m_pCmdGrps); } void CConCmdManager::OnSourceModAllInitialized() @@ -53,9 +57,23 @@ void CConCmdManager::OnSourceModShutdown() g_PluginSys.RemovePluginsListener(this); } -void CConCmdManager::OnPluginLoaded(IPlugin *plugin) +void CConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) { - /* Nothing yet... */ + List::iterator iter = cmdlist.begin(); + CmdHook *pHook; + + while (iter != cmdlist.end()) + { + pHook = (*iter); + if (pHook->pf->GetParentContext() == pContext) + { + delete pHook->pAdmin; + delete pHook; + iter = cmdlist.erase(iter); + } else { + iter++; + } + } } void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) @@ -64,36 +82,41 @@ void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) List removed; if (plugin->GetProperty("CommandList", (void **)&pList, true)) { + IPluginContext *pContext = plugin->GetBaseContext(); CmdList::iterator iter; + /* First pass! + * Only bother if there's an actual command list on this plugin... + */ for (iter=pList->begin(); - iter!=pList->end(); - iter++) + iter!=pList->end(); + iter++) { PlCmdInfo &cmd = (*iter); - if (cmd.type == Cmd_Server - || cmd.type == Cmd_Console) + ConCmdInfo *pInfo = cmd.pInfo; + + /* Has this chain already been fully cleaned/removed? */ + if (removed.find(pInfo) != removed.end()) { - ConCmdInfo *pInfo = cmd.pInfo; - /* See if this is being removed */ - if (removed.find(pInfo) != removed.end()) - { - continue; - } - /* See if there are still hooks */ - if (pInfo->srvhooks - && pInfo->srvhooks->GetFunctionCount()) - { - continue; - } - if (pInfo->conhooks - && pInfo->conhooks->GetFunctionCount()) - { - continue; - } - /* Remove the command */ - RemoveConCmd(pInfo); - removed.push_back(pInfo); + continue; } + + /* Remove any hooks from us on this command */ + RemoveConCmds(pInfo->conhooks, pContext); + RemoveConCmds(pInfo->srvhooks, pContext); + + /* See if there are still hooks */ + if (pInfo->srvhooks.size()) + { + continue; + } + if (pInfo->conhooks.size()) + { + continue; + } + + /* Remove the command, it should be safe now */ + RemoveConCmd(pInfo); + removed.push_back(pInfo); } delete pList; } @@ -118,15 +141,32 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo)) { cell_t result = type; - if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) + cell_t tempres = result; + List::iterator iter; + CmdHook *pHook; + for (iter=pInfo->conhooks.begin(); + iter!=pInfo->conhooks.end(); + iter++) { - pInfo->conhooks->PushCell(client); - pInfo->conhooks->PushCell(args); - pInfo->conhooks->Execute(&result); - } - if (result >= Pl_Stop) - { - return Pl_Stop; + pHook = (*iter); + if (pHook->pAdmin + && pHook->pAdmin->eflags) + { + /* :TODO: admin calculations */ + } + pHook->pf->PushCell(client); + pHook->pf->PushCell(args); + if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE) + { + if (tempres > result) + { + result = tempres; + } + if (result == Pl_Stop) + { + break; + } + } } type = (ResultType)result; } @@ -153,12 +193,30 @@ void CConCmdManager::InternalDispatch() cell_t result = Pl_Continue; int args = engine->Cmd_Argc() - 1; - if (m_CmdClient == 0) + List::iterator iter; + CmdHook *pHook; + + /* Execute server-only commands if viable */ + if (m_CmdClient == 0 && pInfo->srvhooks.size()) { - if (pInfo->srvhooks && pInfo->srvhooks->GetFunctionCount()) + cell_t tempres = result; + for (iter=pInfo->srvhooks.begin(); + iter!=pInfo->srvhooks.end(); + iter++) { - pInfo->srvhooks->PushCell(args); - pInfo->srvhooks->Execute(&result); + pHook = (*iter); + pHook->pf->PushCell(args); + if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE) + { + if (tempres > result) + { + result = tempres; + } + if (result == Pl_Stop) + { + break; + } + } } /* Check if there's an early stop */ @@ -172,12 +230,35 @@ void CConCmdManager::InternalDispatch() } } - /* Execute console command hooks */ - if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) + /* Execute console commands */ + if (pInfo->conhooks.size()) { - pInfo->conhooks->PushCell(m_CmdClient); - pInfo->conhooks->PushCell(args); - pInfo->conhooks->Execute(&result); + cell_t tempres = result; + for (iter=pInfo->conhooks.begin(); + iter!=pInfo->conhooks.end(); + iter++) + { + pHook = (*iter); + if (m_CmdClient + && pHook->pAdmin + && pHook->pAdmin->eflags) + { + /* :TODO: check admin stuff */ + } + pHook->pf->PushCell(m_CmdClient); + pHook->pf->PushCell(args); + if (pHook->pf->Execute(&tempres) != SP_ERROR_NONE) + { + if (tempres > result) + { + result = tempres; + } + if (result == Pl_Stop) + { + break; + } + } + } } if (result >= Pl_Handled) @@ -190,19 +271,25 @@ void CConCmdManager::InternalDispatch() } } +ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args) +{ + return Pl_Continue; +} + void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags) { ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + CmdHook *pHook = new CmdHook(); - if (!pInfo->conhooks) + pHook->pf = pFunction; + if (description && description[0]) { - pInfo->conhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_Cell); + pHook->helptext.assign(description); } - - pInfo->conhooks->AddFunction(pFunction); + pInfo->conhooks.push_back(pHook); /* Add to the plugin */ CmdList *pList; @@ -215,7 +302,79 @@ void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, PlCmdInfo info; info.pInfo = pInfo; info.type = Cmd_Console; - pList->push_back(info); + info.pHook = pHook; + AddToPlCmdList(pList, info); +} + +bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, + const char *name, + const char *group, + int adminflags, + const char *description, + int flags) +{ + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + + CmdHook *pHook = new CmdHook(); + AdminCmdInfo *pAdmin = new AdminCmdInfo(); + + pHook->pf = pFunction; + if (description && description[0]) + { + pHook->helptext.assign(description); + } + pHook->pAdmin = pAdmin; + + void *object; + int grpid; + if (!sm_trie_retrieve(m_pCmdGrps, group, (void **)&object)) + { + grpid = m_Strings.AddString(group); + sm_trie_insert(m_pCmdGrps, group, (void *)grpid); + } else { + grpid = (int)object; + } + + pAdmin->cmdGrpId = grpid; + pAdmin->flags = flags; + + /* First get the command group override, if any */ + bool override = g_Admins.GetCommandOverride(group, + Override_CommandGroup, + &(pAdmin->eflags)); + + /* Next get the command override, if any */ + if (g_Admins.GetCommandOverride(name, + Override_Command, + &(pAdmin->eflags))) + { + override = true; + } + + /* Assign normal flags if there were no overrides */ + if (!override) + { + pAdmin->eflags = pAdmin->flags; + } + + /* Finally, add the hook */ + pInfo->conhooks.push_back(pHook); + + /* Now add to the plugin */ + CmdList *pList; + IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + if (!pPlugin->GetProperty("CommandList", (void **)&pList)) + { + pList = new CmdList(); + pPlugin->SetProperty("CommandList", pList); + } + PlCmdInfo info; + info.pInfo = pInfo; + info.type = Cmd_Admin; + info.pHook = pHook; + AddToPlCmdList(pList, info); + + return true; } void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, @@ -225,13 +384,15 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, { ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + CmdHook *pHook = new CmdHook(); - if (!pInfo->srvhooks) + pHook->pf = pFunction; + if (description && description[0]) { - pInfo->srvhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_Cell); + pHook->helptext.assign(description); } - pInfo->srvhooks->AddFunction(pFunction); + pInfo->srvhooks.push_back(pHook); /* Add to the plugin */ CmdList *pList; @@ -244,7 +405,36 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, PlCmdInfo info; info.pInfo = pInfo; info.type = Cmd_Server; - pList->push_back(info); + info.pHook = pHook; + AddToPlCmdList(pList, info); +} + +void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info) +{ + CmdList::iterator iter = pList->begin(); + bool inserted = false; + const char *orig = NULL; + + orig = info.pInfo->pCmd->GetName(); + + /* Insert this into the help list, SORTED alphabetically. */ + while (iter != pList->end()) + { + PlCmdInfo &obj = (*iter); + const char *cmd = obj.pInfo->pCmd->GetName(); + if (strcmp(orig, cmd) < 0) + { + pList->insert(iter, info); + inserted = true; + break; + } + iter++; + } + + if (!inserted) + { + pList->push_back(info); + } } void CConCmdManager::AddToCmdList(ConCmdInfo *info) @@ -305,12 +495,8 @@ void CConCmdManager::RemoveConCmd(ConCmdInfo *info) /* Remove from list */ m_CmdList.remove(info); - - /* Free forwards */ - if (info->srvhooks) - { - g_Forwards.ReleaseForward(info->srvhooks); - } + + delete info; } ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) @@ -400,11 +586,16 @@ void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argc type = "server"; } else if (cmd.type == Cmd_Console) { type = "console"; - } else if (cmd.type == Cmd_Client) { - type = "client"; + } else if (cmd.type == Cmd_Admin) { + type = "admin"; } name = cmd.pInfo->pCmd->GetName(); - help = cmd.pInfo->pCmd->GetHelpText(); + if (cmd.pHook->helptext.size()) + { + help = cmd.pHook->helptext.c_str(); + } else { + help = cmd.pInfo->pCmd->GetHelpText(); + } g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); } diff --git a/core/CConCmdManager.h b/core/CConCmdManager.h index d924483c..0517b7a0 100644 --- a/core/CConCmdManager.h +++ b/core/CConCmdManager.h @@ -19,8 +19,11 @@ #include "sourcemm_api.h" #include "ForwardSys.h" #include "sm_trie.h" +#include "sm_memtable.h" #include +#include #include +#include using namespace SourceHook; @@ -28,7 +31,32 @@ enum CmdType { Cmd_Server, Cmd_Console, - Cmd_Client + Cmd_Admin, +}; + +struct AdminCmdInfo +{ + AdminCmdInfo() + { + cmdGrpId = -1; + flags = 0; + eflags = 0; + } + int cmdGrpId; /* index into cmdgroup string table */ + FlagBits flags; /* default flags */ + FlagBits eflags; /* effective flags */ +}; + +struct CmdHook +{ + CmdHook() + { + pf = NULL; + pAdmin = NULL; + } + IPluginFunction *pf; /* function hook */ + String helptext; /* help text */ + AdminCmdInfo *pAdmin; /* admin requirements, if any */ }; struct ConCmdInfo @@ -37,13 +65,11 @@ struct ConCmdInfo { sourceMod = false; pCmd = NULL; - srvhooks = NULL; - conhooks = NULL; } bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ ConCommand *pCmd; /**< Pointer to the command itself */ - IChangeableForward *srvhooks; /**< Hooks on this name as a server command */ - IChangeableForward *conhooks; /**< Hooks on this name as a console command */ + List srvhooks; /**< Hooks as a server command */ + List conhooks; /**< Hooks as a console command */ }; class CConCmdManager : @@ -59,24 +85,33 @@ public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: //IPluginsListener - void OnPluginLoaded(IPlugin *plugin); void OnPluginDestroyed(IPlugin *plugin); public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); + bool AddAdminCommand(IPluginFunction *pFunction, + const char *name, + const char *group, + int adminflags, + const char *description, + int flags); ResultType DispatchClientCommand(int client, ResultType type); private: void InternalDispatch(); + ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args); ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags); void SetCommandClient(int client); void AddToCmdList(ConCmdInfo *info); void RemoveConCmd(ConCmdInfo *info); + void RemoveConCmds(List &cmdlist, IPluginContext *pContext); private: - Trie *m_pCmds; - List m_CmdList; - int m_CmdClient; + Trie *m_pCmds; /* command lookup */ + Trie *m_pCmdGrps; /* command group lookup */ + List m_CmdList; /* command list, currently unused */ + int m_CmdClient; /* current client */ + BaseStringTable m_Strings; /* string table */ }; extern CConCmdManager g_ConCmds; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index ec0258a2..4810e37b 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -115,7 +115,7 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti #if 0 /** * Creates a console command as an administrative command. If the command does not exist, - * it is created. This command cannot be used to create duplicate admin commands. + * it is created. * * @param cmd String containing command to register. * @param callback A function to use as a callback for when the command is invoked. @@ -125,7 +125,6 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti * @param description Optional description to use for help. * @param flags Optional console flags. * @noreturn - * @error If this command has already been registered as an admin command. */ native RegAdminCmd(const String:cmd[], ConCmd:callback, From 9d0e33a71f0411dce1c9abf89997448e6dd8d444 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 08:59:52 +0000 Subject: [PATCH 0489/1664] added admin access checking added syncing between overrides (note: denial message is a todo) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40520 --- core/AdminCache.cpp | 11 ++- core/CConCmdManager.cpp | 141 ++++++++++++++++++++++++++++++++++-- core/CConCmdManager.h | 4 +- core/smn_console.cpp | 30 ++++++++ plugins/include/console.inc | 14 ++-- 5 files changed, 180 insertions(+), 20 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index b03f3110..e8557bc0 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -17,6 +17,7 @@ #include "ShareSys.h" #include "ForwardSys.h" #include "CPlayerManager.h" +#include "CConCmdManager.h" AdminCache g_Admins; @@ -93,6 +94,8 @@ void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits } sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags); + + g_ConCmds.UpdateAdminCmdFlags(cmd, type, flags); } bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags) @@ -138,9 +141,9 @@ void AdminCache::_UnsetCommandGroupOverride(const char *group) return; } - /* :TODO: Notify command system */ - sm_trie_delete(m_pCmdGrpOverrides, group); + + g_ConCmds.UpdateAdminCmdFlags(group, Override_CommandGroup, 0); } void AdminCache::_UnsetCommandOverride(const char *cmd) @@ -150,9 +153,9 @@ void AdminCache::_UnsetCommandOverride(const char *cmd) return; } - /* :TODO: Notify command system */ - sm_trie_delete(m_pCmdOverrides, cmd); + + g_ConCmds.UpdateAdminCmdFlags(cmd, Override_Command, 0); } void AdminCache::DumpCommandOverrideCache(OverrideType type) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 75cca8b4..9bc10721 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -15,6 +15,8 @@ #include "sm_srvcmds.h" #include "AdminCache.h" #include "sm_stringutil.h" +#include "CPlayerManager.h" +#include "CTranslator.h" CConCmdManager g_ConCmds; @@ -149,10 +151,13 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) iter++) { pHook = (*iter); - if (pHook->pAdmin - && pHook->pAdmin->eflags) + if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin)) { - /* :TODO: admin calculations */ + if (result < Pl_Handled) + { + result = Pl_Handled; + } + continue; } pHook->pf->PushCell(client); pHook->pf->PushCell(args); @@ -241,9 +246,13 @@ void CConCmdManager::InternalDispatch() pHook = (*iter); if (m_CmdClient && pHook->pAdmin - && pHook->pAdmin->eflags) + && !CheckAccess(m_CmdClient, cmd, pHook->pAdmin)) { - /* :TODO: check admin stuff */ + if (result < Pl_Handled) + { + result = Pl_Handled; + } + continue; } pHook->pf->PushCell(m_CmdClient); pHook->pf->PushCell(args); @@ -271,9 +280,67 @@ void CConCmdManager::InternalDispatch() } } -ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args) +bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin) { - return Pl_Continue; + FlagBits cmdflags = pAdmin->eflags; + if (cmdflags == 0) + { + return true; + } + + CPlayer *player = g_Players.GetPlayerByIndex(client); + if (!player) + { + return false; + } + + AdminId adm = player->GetAdminId(); + if (adm != INVALID_ADMIN_ID) + { + FlagBits bits = g_Admins.GetAdminFlags(adm, Access_Effective); + + /* root knows all, WHOA */ + if ((bits & ADMFLAG_ROOT) == ADMFLAG_ROOT) + { + return true; + } + + /* See if our other flags match */ + if ((bits & cmdflags) != cmdflags) + { + return true; + } + + /* Check for overrides */ + unsigned int groups = g_Admins.GetAdminGroupCount(adm); + GroupId gid; + OverrideRule rule; + bool override = false; + for (unsigned int i=0; i::iterator iter; + CmdHook *pHook; + + for (iter=pInfo->conhooks.begin(); iter!=pInfo->conhooks.end(); iter++) + { + pHook = (*iter); + if (pHook->pAdmin) + { + if (bits) + { + pHook->pAdmin->eflags = bits; + } else { + pHook->pAdmin->eflags = pHook->pAdmin->flags; + } + } + } + } else if (type == Override_CommandGroup) { + void *object; + if (!sm_trie_retrieve(m_pCmdGrps, cmd, &object)) + { + return; + } + int grpid = (int)object; + + /* This is bad :( loop through all commands */ + List::iterator iter; + CmdHook *pHook; + for (iter=m_CmdList.begin(); iter!=m_CmdList.end(); iter++) + { + pInfo = (*iter); + for (List::iterator citer=pInfo->conhooks.begin(); + citer!=pInfo->conhooks.end(); + citer++) + { + pHook = (*citer); + if (pHook->pAdmin && pHook->pAdmin->cmdGrpId == grpid) + { + if (bits) + { + pHook->pAdmin->eflags = bits; + } else { + pHook->pAdmin->eflags = pHook->pAdmin->flags; + } + } + } + } + } +} + void CConCmdManager::RemoveConCmd(ConCmdInfo *info) { /* Remove console-specific information diff --git a/core/CConCmdManager.h b/core/CConCmdManager.h index 0517b7a0..3f0198a6 100644 --- a/core/CConCmdManager.h +++ b/core/CConCmdManager.h @@ -98,6 +98,7 @@ public: const char *description, int flags); ResultType DispatchClientCommand(int client, ResultType type); + void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits); private: void InternalDispatch(); ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args); @@ -106,10 +107,11 @@ private: void AddToCmdList(ConCmdInfo *info); void RemoveConCmd(ConCmdInfo *info); void RemoveConCmds(List &cmdlist, IPluginContext *pContext); + bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); private: Trie *m_pCmds; /* command lookup */ Trie *m_pCmdGrps; /* command group lookup */ - List m_CmdList; /* command list, currently unused */ + List m_CmdList; /* command list */ int m_CmdClient; /* current client */ BaseStringTable m_Strings; /* string table */ }; diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 3651e4bf..9ccc5214 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -16,6 +16,7 @@ #include "HandleSys.h" #include "CConVarManager.h" #include "CConCmdManager.h" +#include "PluginSys.h" static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) { @@ -361,6 +362,35 @@ static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params) +{ + char *name,*help; + const char *group; + IPluginFunction *pFunction; + FlagBits flags = params[3]; + int cmdflags = params[6]; + + pContext->LocalToString(params[1], &name); + pContext->LocalToString(params[4], &help); + pContext->LocalToString(params[5], (char **)&group); + pFunction = pContext->GetFunctionById(params[2]); + + if (group[0] == '\0') + { + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + group = pPlugin->GetFilename(); + } + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags); + + return 1; +} + REGISTER_NATIVES(convarNatives) { {"CreateConVar", sm_CreateConVar}, diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 4810e37b..fb74edd5 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -112,7 +112,6 @@ functag ConCmd Action:public(client, argCount); */ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0); -#if 0 /** * Creates a console command as an administrative command. If the command does not exist, * it is created. @@ -126,13 +125,12 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti * @param flags Optional console flags. * @noreturn */ -native RegAdminCmd(const String:cmd[], - ConCmd:callback, - adminflags, - const String:group[]="", - const String:description[]="", - flags=0); -#endif +native RegAdminCmd(const String:cmd[], + ConCmd:callback, + adminflags, + const String:description[]="", + const String:group[]="", + flags=0); /** * Creates a new console variable. From b9451b6cc9780e2d8a57fef13cc6bcf422289183 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 09:00:14 +0000 Subject: [PATCH 0490/1664] exposed global translation file for core --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40521 --- core/CTranslator.cpp | 11 +++++++++++ core/CTranslator.h | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 059f1366..11a37c6f 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -22,6 +22,7 @@ #include "sourcemod.h" CTranslator g_Translator; +CPhraseFile *g_pCorePhrases = NULL; struct trans_t { @@ -574,6 +575,10 @@ const char *CPhraseFile::GetFilename() return m_File.c_str(); } +/************************** + ** MAIN TRANSLATOR CODE ** + **************************/ + CTranslator::CTranslator() { m_pStringTab = new BaseStringTable(2048); @@ -597,6 +602,12 @@ CTranslator::~CTranslator() delete m_pStringTab; } +void CTranslator::OnSourceModAllInitialized() +{ + unsigned int id = FindOrAddPhraseFile("core.cfg"); + g_pCorePhrases = GetFileByIndex(id); +} + bool CTranslator::GetLanguageByCode(const char *code, unsigned int *index) { void *_index; diff --git a/core/CTranslator.h b/core/CTranslator.h index a77e7405..a487198c 100644 --- a/core/CTranslator.h +++ b/core/CTranslator.h @@ -90,11 +90,15 @@ private: bool m_FileLogged; }; -class CTranslator : public ITextListener_SMC +class CTranslator : + public ITextListener_SMC, + public SMGlobalClass { public: CTranslator(); ~CTranslator(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); public: //ITextListener_SMC void ReadSMC_ParseStart(); SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); @@ -117,6 +121,7 @@ private: String m_CustomError; }; +extern CPhraseFile *g_pCorePhrases; extern CTranslator g_Translator; #endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_ From 2ba612fed7992390139c0415a993c707c7920e3c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 09:02:22 +0000 Subject: [PATCH 0491/1664] clientconnect now blocks properly when needed removed cruft --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40522 --- core/CPlayerManager.cpp | 10 +++------- core/CPlayerManager.h | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 91c74fb2..34b16afe 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -195,10 +195,11 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons { m_AuthQueue[++m_AuthQueue[0]] = client; g_SourceMod.SetAuthChecking(true); + } else { + RETURN_META_VALUE(MRES_SUPERCEDE, false); } - //:todo: this must meta return - return (res) ? true : false; + return true; } bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) @@ -257,11 +258,6 @@ void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playernam m_clputinserver->Execute(&res, NULL); } -void CPlayerManager::OnClientAuthorized() -{ - //:TODO: -} - void CPlayerManager::OnClientDisconnect(edict_t *pEntity) { cell_t res; diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index a621de88..afdbd884 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -82,7 +82,6 @@ public: void OnClientPutInServer(edict_t *pEntity, char const *playername); void OnClientDisconnect(edict_t *pEntity); void OnClientDisconnect_Post(edict_t *pEntity); - void OnClientAuthorized(); //:TODO: any args needed? void OnClientCommand(edict_t *pEntity); void OnClientSettingsChanged(edict_t *pEntity); public: //IPlayerManager From 43051a05714864e71be76433aba7a9eb967b968e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 09:12:21 +0000 Subject: [PATCH 0492/1664] added functions for getting arguments --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40523 --- core/smn_console.cpp | 26 ++++++++++++++++++++++++++ plugins/include/console.inc | 30 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 9ccc5214..aa27d180 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -391,6 +391,29 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params) +{ + return engine->Cmd_Argc() - 1; +} + +static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params) +{ + const char *arg = engine->Cmd_Argv(params[1]); + + pContext->StringToLocalUTF8(params[2], params[3], arg, NULL); + + return 1; +} + +static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params) +{ + const char *args = engine->Cmd_Args(); + + pContext->StringToLocalUTF8(params[1], params[2], args, NULL); + + return 1; +} + REGISTER_NATIVES(convarNatives) { {"CreateConVar", sm_CreateConVar}, @@ -413,5 +436,8 @@ REGISTER_NATIVES(convarNatives) {"ResetConVar", sm_ResetConVar}, {"RegServerCmd", sm_RegServerCmd}, {"RegConsoleCmd", sm_RegConsoleCmd}, + {"GetCmdArgString", sm_GetCmdArgString}, + {"GetCmdArgs", sm_GetCmdArgs}, + {"GetCmdArg", sm_GetCmdArg}, {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index fb74edd5..4bfb27b4 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -131,6 +131,36 @@ native RegAdminCmd(const String:cmd[], const String:description[]="", const String:group[]="", flags=0); + +/** + * Returns the number of arguments from the current console or server command. + * @note Unlike the HL2 engine call, this does not include the command itself. + * + * @return Number of arguments to the current command. + */ +native GetCmdArgs(); + +/** + * Retrieves a command argument given its index, from the current console or + * server command. + * @note Argument indexes start at 1; 0 retrieves the command name. + * + * @param argnum Argument number to retrieve. + * @param buffer Buffer to use for storing the string. + * @param maxlength Maximum length of the buffer. + * @noreturn + */ +native GetCmdArg(argnum, String:buffer[], maxlength); + +/** + * Retrieves the entire command argument string in one lump from the current + * console or server command. + * + * @param buffer Buffer to use for storing the string. + * @param maxlength Maximum length of the buffer. + * @noreturn + */ +native GetCmdArgString(String:buffer[], maxlength); /** * Creates a new console variable. From 03e70ebe16a67bd4ce1e3586b5a87ca57ce260a6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 17:25:50 +0000 Subject: [PATCH 0493/1664] reverted project file for now moved printing natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40524 --- core/msvc8/sourcemod_mm.vcproj | 8 ------ core/smn_console.cpp | 52 +++++++++++++++++++++++++++++++++- core/smn_player.cpp | 48 ------------------------------- 3 files changed, 51 insertions(+), 57 deletions(-) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 954a50e2..477f1b5b 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -199,10 +199,6 @@ RelativePath="..\CDbgReporter.cpp" > - - @@ -661,10 +657,6 @@ RelativePath="..\smn_datapacks.cpp" > - - diff --git a/core/smn_console.cpp b/core/smn_console.cpp index aa27d180..ed352fe1 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -17,6 +17,8 @@ #include "CConVarManager.h" #include "CConCmdManager.h" #include "PluginSys.h" +#include "sm_stringutil.h" +#include "CPlayerManager.h" static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) { @@ -414,7 +416,53 @@ static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params) return 1; } -REGISTER_NATIVES(convarNatives) +static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) +{ + char buffer[1024]; + char *fmt; + int arg = 2; + + pCtx->LocalToString(params[1], &fmt); + size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); + + buffer[res++] = '\n'; + buffer[res] = '\0'; + + META_CONPRINT(buffer); + + return 1; +} + +static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) +{ + int index = params[1]; + if ((index < 1) || (index > g_Players.GetMaxClients())) + { + return pCtx->ThrowNativeError("Invalid client index %d", index); + } + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); + if (!pPlayer->IsInGame()) + { + return pCtx->ThrowNativeError("Client %d is not in game", index); + } + + char buffer[1024]; + char *fmt; + int arg = 3; + + pCtx->LocalToString(params[2], &fmt); + size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); + + buffer[res++] = '\n'; + buffer[res] = '\0'; + + engine->ClientPrintf(pPlayer->GetEdict(), buffer); + + return 1; +} + +REGISTER_NATIVES(consoleNatives) { {"CreateConVar", sm_CreateConVar}, {"FindConVar", sm_FindConVar}, @@ -439,5 +487,7 @@ REGISTER_NATIVES(convarNatives) {"GetCmdArgString", sm_GetCmdArgString}, {"GetCmdArgs", sm_GetCmdArgs}, {"GetCmdArg", sm_GetCmdArg}, + {"PrintToServer", sm_PrintToServer}, + {"PrintToConsole", sm_PrintToConsole}, {NULL, NULL} }; diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 006cb0cf..c480bee4 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -159,23 +159,6 @@ static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) return (pPlayer->IsFakeClient()) ? 1 : 0; } -static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) -{ - char buffer[1024]; - char *fmt; - int arg = 2; - - pCtx->LocalToString(params[1], &fmt); - size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); - - buffer[res++] = '\n'; - buffer[res] = '\0'; - - META_CONPRINT(buffer); - - return 1; -} - static cell_t sm_GetClientInfo(IPluginContext *pContext, const cell_t *params) { int client = params[1]; @@ -202,35 +185,6 @@ static cell_t sm_GetClientInfo(IPluginContext *pContext, const cell_t *params) return 1; } -static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) -{ - int index = params[1]; - if ((index < 1) || (index > g_Players.GetMaxClients())) - { - return pCtx->ThrowNativeError("Invalid client index %d", index); - } - - CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); - if (!pPlayer->IsInGame()) - { - return pCtx->ThrowNativeError("Client %d is not in game", index); - } - - char buffer[1024]; - char *fmt; - int arg = 3; - - pCtx->LocalToString(params[2], &fmt); - size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg); - - buffer[res++] = '\n'; - buffer[res] = '\0'; - - engine->ClientPrintf(pPlayer->GetEdict(), buffer); - - return 1; -} - static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params) { int client = params[1]; @@ -402,8 +356,6 @@ REGISTER_NATIVES(playernatives) {"IsPlayerInGame", sm_IsPlayerIngame}, {"IsClientAuthorized", sm_IsPlayerAuthorized}, {"IsFakeClient", sm_IsPlayerFakeClient}, - {"PrintToServer", sm_PrintToServer}, - {"PrintToConsole", sm_PrintToConsole}, {"GetClientInfo", sm_GetClientInfo}, {"SetUserAdmin", SetUserAdmin}, {"GetUserAdmin", GetUserAdmin}, From 3be7988cd10248447d697746fa60bfcd2f6b093f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 17:35:09 +0000 Subject: [PATCH 0494/1664] fixed printtoconsole crashing on fake clients --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40525 --- core/smn_console.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index ed352fe1..410b6645 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -446,6 +446,12 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) { return pCtx->ThrowNativeError("Client %d is not in game", index); } + + /* Silent fail on bots, engine will crash */ + if (pPlayer->IsFakeClient()) + { + return 0; + } char buffer[1024]; char *fmt; From ae5dfd096601ceafacf0f7c9e8aaf1f227e6981c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Feb 2007 19:03:18 +0000 Subject: [PATCH 0495/1664] added helper a core translation helper to the translator regadmincmd is now officially done and tested, as are overrides printtoplayers now prints to the server on id==0 as a convenience fixed a crash bug in the admin system fixed up console.inc a bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40526 --- core/AdminCache.cpp | 15 +++++++---- core/AdminCache.h | 1 + core/CConCmdManager.cpp | 23 +++++++++++++--- core/CTranslator.cpp | 54 ++++++++++++++++++++++++++++++++++--- core/CTranslator.h | 11 +++++++- core/smn_console.cpp | 32 ++++++++++++++-------- core/sourcemod.cpp | 6 +++++ plugins/include/console.inc | 9 ++++--- 8 files changed, 124 insertions(+), 27 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index e8557bc0..0cc9e833 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -34,10 +34,12 @@ AdminCache::AdminCache() m_FirstGroup = -1; m_pAuthTables = sm_trie_create(); m_InvalidatingAdmins = false; + m_destroying = false; } AdminCache::~AdminCache() { + m_destroying = true; DumpAdminCache(AdminCache_Overrides, false); DumpAdminCache(AdminCache_Groups, false); @@ -549,7 +551,7 @@ bool AdminCache::InvalidateAdmin(AdminId id) return false; } - if (!m_InvalidatingAdmins) + if (!m_InvalidatingAdmins && !m_destroying) { g_Players.ClearAdminId(id); } @@ -749,7 +751,10 @@ void AdminCache::RegisterAuthIdentType(const char *name) void AdminCache::InvalidateAdminCache(bool unlink_admins) { m_InvalidatingAdmins = true; - g_Players.ClearAllAdmins(); + if (!m_destroying) + { + g_Players.ClearAllAdmins(); + } /* Wipe the identity cache first */ List::iterator iter; for (iter=m_AuthMethods.begin(); @@ -783,7 +788,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) { DumpCommandOverrideCache(Override_Command); DumpCommandOverrideCache(Override_CommandGroup); - if (rebuild) + if (rebuild && !m_destroying) { for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) { @@ -797,7 +802,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) if (part == AdminCache_Groups) { InvalidateGroupCache(); - if (rebuild) + if (rebuild && !m_destroying) { for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) { @@ -809,7 +814,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) } } InvalidateAdminCache(true); - if (rebuild) + if (rebuild && !m_destroying) { for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) { diff --git a/core/AdminCache.h b/core/AdminCache.h index 9d4eaae9..eb40a5cf 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -159,6 +159,7 @@ public: int m_LastUser; int m_FreeUserList; bool m_InvalidatingAdmins; + bool m_destroying; }; extern AdminCache g_Admins; diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 9bc10721..546fe4be 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -306,7 +306,7 @@ bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdm } /* See if our other flags match */ - if ((bits & cmdflags) != cmdflags) + if ((bits & cmdflags) == cmdflags) { return true; } @@ -338,8 +338,25 @@ bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdm } } + if (player->IsFakeClient() + || player->GetEdict() == NULL) + { + return false; + } + /* If we got here, the command failed... */ - /* :TODO: send a message to the client about this! */ + char buffer[128]; + if (g_Translator.CoreTrans(client, buffer, sizeof(buffer), "No Access", NULL, NULL) + != Trans_Okay) + { + snprintf(buffer, sizeof(buffer), "You do not have access to this command"); + } + + char fullbuffer[192]; + snprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer); + + engine->ClientPrintf(player->GetEdict(), fullbuffer); + return false; } @@ -403,7 +420,7 @@ bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, } pAdmin->cmdGrpId = grpid; - pAdmin->flags = flags; + pAdmin->flags = adminflags; /* First get the command group override, if any */ bool override = g_Admins.GetCommandOverride(group, diff --git a/core/CTranslator.cpp b/core/CTranslator.cpp index 11a37c6f..ce73c044 100644 --- a/core/CTranslator.cpp +++ b/core/CTranslator.cpp @@ -604,6 +604,7 @@ CTranslator::~CTranslator() void CTranslator::OnSourceModAllInitialized() { + AddLanguage("en", "English"); unsigned int id = FindOrAddPhraseFile("core.cfg"); g_pCorePhrases = GetFileByIndex(id); } @@ -735,17 +736,31 @@ SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key); } + AddLanguage(key, value); + + return SMCParse_Continue; +} + +bool CTranslator::AddLanguage(const char *langcode, const char *description) +{ + if (sm_trie_retrieve(m_pLCodeLookup, langcode, NULL)) + { + return false; + } + Language *pLanguage = new Language; unsigned int idx = m_Languages.size(); - strcpy(pLanguage->m_code2, key); - pLanguage->m_FullName = m_pStringTab->AddString(value); + pLanguage->m_code2[0] = langcode[0]; + pLanguage->m_code2[1] = langcode[1]; + pLanguage->m_code2[2] = langcode[2]; + pLanguage->m_FullName = m_pStringTab->AddString(description); - sm_trie_insert(m_pLCodeLookup, key, reinterpret_cast(idx)); + sm_trie_insert(m_pLCodeLookup, langcode, reinterpret_cast(idx)); m_Languages.push_back(pLanguage); - return SMCParse_Continue; + return true; } CPhraseFile *CTranslator::GetFileByIndex(unsigned int index) @@ -770,3 +785,34 @@ size_t CTranslator::Translate(char *buffer, size_t maxlength, void **params, con return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params); } + +TransError CTranslator::CoreTrans(int client, + char *buffer, + size_t maxlength, + const char *phrase, + void **params, + size_t *outlen) +{ + /* :TODO: do language stuff here */ + + if (!g_pCorePhrases) + { + return Trans_BadPhraseFile; + } + + Translation trans; + TransError err; + if ((err=g_pCorePhrases->GetTranslation(phrase, 0, &trans)) != Trans_Okay) + { + return err; + } + + size_t len = Translate(buffer, maxlength, params, &trans); + + if (outlen) + { + *outlen = len; + } + + return Trans_Okay; +} diff --git a/core/CTranslator.h b/core/CTranslator.h index a487198c..3138e91c 100644 --- a/core/CTranslator.h +++ b/core/CTranslator.h @@ -53,7 +53,8 @@ enum TransError Trans_Okay = 0, Trans_BadLanguage = 1, Trans_BadPhrase = 2, - Trans_BadPhraseLanguage = 3 + Trans_BadPhraseLanguage = 3, + Trans_BadPhraseFile = 4, }; class CPhraseFile : public ITextListener_SMC @@ -112,6 +113,14 @@ public: bool GetLanguageByCode(const char *code, unsigned int *index); size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans); CPhraseFile *GetFileByIndex(unsigned int index); + TransError CoreTrans(int client, + char *buffer, + size_t maxlength, + const char *phrase, + void **params, + size_t *outlen=NULL); +private: + bool AddLanguage(const char *langcode, const char *description); private: CVector m_Languages; CVector m_Files; diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 410b6645..acc09148 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -436,21 +436,25 @@ static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; - if ((index < 1) || (index > g_Players.GetMaxClients())) + if ((index < 0) || (index > g_Players.GetMaxClients())) { return pCtx->ThrowNativeError("Invalid client index %d", index); } - CPlayer *pPlayer = g_Players.GetPlayerByIndex(index); - if (!pPlayer->IsInGame()) + CPlayer *pPlayer = NULL; + if (index != 0) { - return pCtx->ThrowNativeError("Client %d is not in game", index); - } - - /* Silent fail on bots, engine will crash */ - if (pPlayer->IsFakeClient()) - { - return 0; + pPlayer = g_Players.GetPlayerByIndex(index); + if (!pPlayer->IsInGame()) + { + return pCtx->ThrowNativeError("Client %d is not in game", index); + } + + /* Silent fail on bots, engine will crash */ + if (pPlayer->IsFakeClient()) + { + return 0; + } } char buffer[1024]; @@ -463,7 +467,12 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) buffer[res++] = '\n'; buffer[res] = '\0'; - engine->ClientPrintf(pPlayer->GetEdict(), buffer); + if (index != 0) + { + engine->ClientPrintf(pPlayer->GetEdict(), buffer); + } else { + META_CONPRINT(buffer); + } return 1; } @@ -495,5 +504,6 @@ REGISTER_NATIVES(consoleNatives) {"GetCmdArg", sm_GetCmdArg}, {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, + {"RegAdminCmd", sm_RegAdminCmd}, {NULL, NULL} }; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 375844f8..c13b2a10 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -24,6 +24,7 @@ #include "AdminCache.h" #include "sm_stringutil.h" #include "CPlayerManager.h" +#include "CTranslator.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -190,6 +191,11 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_Logger.MapChange(pMapName); + /* Refresh language stuff */ + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg"); + g_Translator.RebuildLanguageDatabase(path); + DoGlobalPluginLoads(); m_IsMapLoading = false; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 4bfb27b4..74e10906 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -76,10 +76,11 @@ native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:... /** * Called when a server-only command is invoked. * + * @params args Number of arguments that were in the argument string. * @return A Result value. Not handling the command * means that Source will report it as "not found." */ -functag SrvCmd Action:public(argCount); +functag SrvCmd Action:public(args); /** * Creates a server-only console command, or hooks an already existing one. @@ -96,10 +97,11 @@ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:descriptio * Called when a generic console command is invoked. * * @param client Index of the client, or 0 from the server. + * @param args Number of arguments that were in the argument string. * @return A Result value. Not handling the command * means that Source will report it as "not found." */ -functag ConCmd Action:public(client, argCount); +functag ConCmd Action:public(client, args); /** * Creates a console command, or hooks an already existing one. @@ -114,7 +116,8 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti /** * Creates a console command as an administrative command. If the command does not exist, - * it is created. + * it is created. When this command is invoked, the access rights of the player are + * automatically checked before allowing it to continue. * * @param cmd String containing command to register. * @param callback A function to use as a callback for when the command is invoked. From eb9352b75d5b9f48916cfe83a84125976b28d62a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 20 Feb 2007 19:10:56 +0000 Subject: [PATCH 0496/1664] removed todo list since we have a task system now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40527 --- TODO.txt | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 TODO.txt diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index c504cadc..00000000 --- a/TODO.txt +++ /dev/null @@ -1,14 +0,0 @@ -things to do for a release, in priority - X finish plugin unloading - X URGENT: fix compiler's sizeof(), add cellsof - X do module api - X finish plugin pausing/unpausing, forwards must block execution - X do admin api - - finish cross extension dependencies (ShareSys::AddDepency) - X make "mapupdated" plugins work as intended (reload on mapchange if newer) - X add debugging output to logger - - finish ML api, expose through interface - X add error messages to format routine - X finish global unloading - - add hex format specifier - X linux building (oh god) From dc06ac650169dc044bd4e388d11c89902c866f44 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Feb 2007 22:05:25 +0000 Subject: [PATCH 0497/1664] added server command functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40528 --- core/smn_console.cpp | 38 +++++++++++++++++++++++++++++++++++++ plugins/include/console.inc | 24 +++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index acc09148..e1277d71 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -477,6 +477,41 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params) +{ + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1); + + /* One byte for null terminator, one for newline */ + buffer[len++] = '\n'; + buffer[len] = '\0'; + + engine->ServerCommand(buffer); + + return 1; +} + +static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params) +{ + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1); + + /* One byte for null terminator, one for newline */ + buffer[len++] = '\n'; + buffer[len] = '\0'; + + engine->InsertServerCommand(buffer); + + return 1; +} + +static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params) +{ + engine->ServerExecute(); + + return 1; +} + REGISTER_NATIVES(consoleNatives) { {"CreateConVar", sm_CreateConVar}, @@ -505,5 +540,8 @@ REGISTER_NATIVES(consoleNatives) {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, {"RegAdminCmd", sm_RegAdminCmd}, + {"ServerCommand", sm_ServerCommand}, + {"InsertServerCommand", sm_InsertServerCommand}, + {"ServerExecute", sm_ServerExecute}, {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 74e10906..9fa93148 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -52,6 +52,30 @@ #define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ #define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ +/** + * Executes a server command as if it were on the server console (or RCON) + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native ServerCommand(const String:format[], {Handle,Float,String,_}:...); + +/** + * Inserts a server command at the beginning of the server command buffer. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native InsertServerCommand(const String:format[], {Handle,Float,String,_}:...); + +/** + * Executes every command in the server's command buffer, rather than once per frame. + * + * @noreturn + */ +native ServerExecute(); /** * Sends a message to the server console. From d30525b8f839586b1f082a16f1ef38e57215811c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Feb 2007 22:05:44 +0000 Subject: [PATCH 0498/1664] put usermessages at the end of the include so it will compile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40529 --- plugins/include/sourcemod.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e01e8109..e6ad901b 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -34,7 +34,6 @@ struct Plugin #include #include #include -#include #include /** @@ -341,4 +340,5 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); */ native LogError(const String:format[], {Handle,Float,String,_}:...); +#include #include From 3de592d387f1c5136d74596c44a320cf6849ba40 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Feb 2007 22:09:05 +0000 Subject: [PATCH 0499/1664] added replicated version cvar --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40530 --- core/sm_srvcmds.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index c1347ea7..40e580c5 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -17,6 +17,8 @@ RootConsoleMenu g_RootMenu; +ConVar sourcemod_version("sourcemod_version", SOURCEMOD_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version"); + RootConsoleMenu::RootConsoleMenu() { m_pCommands = sm_trie_create(); From 8553f12d59f21b7d7177106d08604eee412e44b9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 22 Feb 2007 02:05:50 +0000 Subject: [PATCH 0500/1664] Corrected an API design flaw with pausing. Contexts can now be flagged as paused, and IsRunnable() is moved from IBaseContext to IPluginFunction. While this allows for per-function pausing, it is not intended that way. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40531 --- core/CConCmdManager.cpp | 12 ++++++++++++ core/systems/ForwardSys.cpp | 25 ++++++++----------------- core/systems/PluginSys.cpp | 17 +++++++++++------ core/vm/sp_vm_basecontext.cpp | 13 +------------ core/vm/sp_vm_basecontext.h | 3 --- core/vm/sp_vm_function.cpp | 19 +++++++++++++++++++ core/vm/sp_vm_function.h | 2 ++ public/sourcepawn/sp_vm_api.h | 14 +++++++------- public/sourcepawn/sp_vm_types.h | 1 + 9 files changed, 61 insertions(+), 45 deletions(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 546fe4be..2d19dad9 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -151,6 +151,10 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) iter++) { pHook = (*iter); + if (!pHook->pf->IsRunnable()) + { + continue; + } if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin)) { if (result < Pl_Handled) @@ -210,6 +214,10 @@ void CConCmdManager::InternalDispatch() iter++) { pHook = (*iter); + if (!pHook->pf->IsRunnable()) + { + continue; + } pHook->pf->PushCell(args); if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE) { @@ -244,6 +252,10 @@ void CConCmdManager::InternalDispatch() iter++) { pHook = (*iter); + if (!pHook->pf->IsRunnable()) + { + continue; + } if (m_CmdClient && pHook->pAdmin && !CheckAccess(m_CmdClient, cmd, pHook->pAdmin)) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 70536027..3ce93a1e 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -304,6 +304,11 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) { func = (*iter); + if (!func->IsRunnable()) + { + continue; + } + for (unsigned int i=0; i *lst; - if (func->GetParentContext()->IsRunnable()) - { - lst = &m_functions; - } else { - lst = &m_paused; - } - - for (iter=lst->begin(); iter!=lst->end(); iter++) + for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { if ((*iter) == func) { found = true; - lst->erase(iter); + m_functions.erase(iter); break; } } @@ -689,13 +686,7 @@ bool CForward::AddFunction(IPluginFunction *func) return false; } - //:IDEA: eventually we will tell the plugin we're using it [?] - if (func->GetParentContext()->IsRunnable()) - { - m_functions.push_back(func); - } else { - m_paused.push_back(func); - } + m_functions.push_back(func); return true; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 8651a455..5881a06e 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -202,7 +202,6 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) } m_ctx.base = new BaseContext(m_ctx.ctx); - m_ctx.base->SetRunnable(false); m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; m_status = Plugin_Created; @@ -222,9 +221,9 @@ void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); va_end(ap); - if (m_ctx.base) + if (m_ctx.ctx) { - m_ctx.base->SetRunnable(false); + m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED; } } @@ -310,7 +309,6 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) } m_status = Plugin_Loaded; - m_ctx.base->SetRunnable(true); int err; cell_t result; @@ -397,8 +395,6 @@ bool CPlugin::SetPauseState(bool paused) return false; } - m_status = (paused) ? Plugin_Paused : Plugin_Running; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange"); if (pFunction) { @@ -407,6 +403,15 @@ bool CPlugin::SetPauseState(bool paused) pFunction->Execute(&result); } + if (paused) + { + m_status = Plugin_Paused; + m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED; + } else { + m_status = Plugin_Running; + m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED; + } + g_PluginSys._SetPauseState(this, paused); return true; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 302fb186..d6c4393e 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -40,7 +40,6 @@ BaseContext::BaseContext(sp_context_t *_ctx) ctx->dbreak = GlobalDebugBreak; m_InExec = false; m_CustomMsg = false; - m_Runnable = true; m_funcsnum = ctx->vmbase->FunctionCount(ctx); m_priv_funcs = NULL; m_pub_funcs = NULL; @@ -153,7 +152,7 @@ IPluginDebugInfo *BaseContext::GetDebugInfo() int BaseContext::Execute(uint32_t code_addr, cell_t *result) { - if (!m_Runnable) + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) { return SP_ERROR_NOT_RUNNABLE; } @@ -928,14 +927,4 @@ void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) { m_pToken = token; } - -bool BaseContext::IsRunnable() -{ - return m_Runnable; -} - -void BaseContext::SetRunnable(bool runnable) -{ - m_Runnable = runnable; -} #endif diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 4c001a54..68651e3f 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -68,8 +68,6 @@ namespace SourcePawn #if defined SOURCEMOD_BUILD virtual SourceMod::IdentityToken_t *GetIdentity(); void SetIdentity(SourceMod::IdentityToken_t *token); - bool IsRunnable(); - void SetRunnable(bool runnable); #endif public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); @@ -88,7 +86,6 @@ namespace SourcePawn char m_MsgCache[1024]; bool m_CustomMsg; bool m_InExec; - bool m_Runnable; unsigned int m_funcsnum; CFunction **m_priv_funcs; CFunction **m_pub_funcs; diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index c4fc339f..c7f3b5a6 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -26,10 +26,21 @@ void CFunction::Set(uint32_t code_addr, IPluginContext *plugin) m_curparam = 0; m_errorstate = SP_ERROR_NONE; m_Invalid = false; + m_pCtx = plugin ? plugin->GetContext() : NULL; +} + +bool CFunction::IsRunnable() +{ + return ((m_pCtx->flags & SPFLAG_PLUGIN_PAUSED) != SPFLAG_PLUGIN_PAUSED); } int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { + if (!IsRunnable()) + { + return SP_ERROR_NOT_RUNNABLE; + } + while (num_params--) { m_pContext->PushCell(params[num_params]); @@ -48,6 +59,10 @@ CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : m_errorstate(SP_ERROR_NONE) { m_Invalid = false; + if (plugin) + { + m_pCtx = plugin->GetContext(); + } } int CFunction::PushCell(cell_t cell) @@ -201,6 +216,10 @@ void CFunction::Cancel() int CFunction::Execute(cell_t *result) { int err; + if (!IsRunnable()) + { + m_errorstate = SP_ERROR_NOT_RUNNABLE; + } if (m_errorstate != SP_ERROR_NONE) { err = m_errorstate; diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index 2eaaf229..4b13f66d 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -54,6 +54,7 @@ public: { m_Invalid = true; } + bool IsRunnable(); public: void Set(uint32_t code_addr, IPluginContext *plugin); private: @@ -66,6 +67,7 @@ private: private: uint32_t m_codeaddr; IPluginContext *m_pContext; + sp_context_t *m_pCtx; cell_t m_params[SP_MAX_EXEC_PARAMS]; ParamInfo m_info[SP_MAX_EXEC_PARAMS]; unsigned int m_curparam; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 99568264..cfdb5958 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -184,6 +184,13 @@ namespace SourcePawn * @return Address, or NULL if invalid parameter specified. */ virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; + + /** + * @brief Returns whether the parent plugin is paused. + * + * @return True if runnable, false otherwise. + */ + virtual bool IsRunnable() =0; }; @@ -534,13 +541,6 @@ namespace SourcePawn * @return Identity token. */ virtual SourceMod::IdentityToken_t *GetIdentity() =0; - - /** - * @brief Returns whether the identity is runnable. - * - * @return True if runnable, false otherwise. - */ - virtual bool IsRunnable() =0; #endif }; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 3440aa8a..9e04a143 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -229,6 +229,7 @@ typedef struct sp_debug_symbol_s typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); #define SPFLAG_PLUGIN_DEBUG (1<<0) /**< plugin is in debug mode */ +#define SPFLAG_PLUGIN_PAUSED (1<<1) /**< plugin is "paused" (blocked from executing) */ /** * @brief This is the heart of the VM. It contains all of the runtime From 81a6bc3288d7aa8c6b2e667d82594263f96c47b2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 22 Feb 2007 02:09:46 +0000 Subject: [PATCH 0501/1664] removed unnecessary code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40532 --- core/systems/ForwardSys.cpp | 66 +------------------------------------ core/systems/ForwardSys.h | 3 -- 2 files changed, 1 insertion(+), 68 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 3ce93a1e..376beaf3 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -179,33 +179,7 @@ CForward *CForwardManager::ForwardMake() void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused) { - List::iterator iter; - CForward *fwd; - - if (paused) - { - for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) - { - fwd = (*iter); - fwd->PushPausedFunctions(plugin); - } - for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) - { - fwd = (*iter); - fwd->PushPausedFunctions(plugin); - } - } else { - for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) - { - fwd = (*iter); - fwd->PopPausedFunctions(plugin); - } - for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) - { - fwd = (*iter); - fwd->PopPausedFunctions(plugin); - } - } + /* No longer used */ } /************************************* @@ -705,41 +679,3 @@ ExecType CForward::GetExecType() const { return m_ExecType; } - -void CForward::PushPausedFunctions(IPlugin *plugin) -{ - FuncIter iter; - IPluginFunction *func; - IPluginContext *pContext = plugin->GetBaseContext(); - - for (iter=m_functions.begin(); iter!=m_functions.end();) - { - func = (*iter); - if (func->GetParentContext() == pContext) - { - m_paused.push_back(func); - iter = m_functions.erase(iter); - } else { - iter++; - } - } -} - -void CForward::PopPausedFunctions(IPlugin *plugin) -{ - FuncIter iter; - IPluginFunction *func; - IPluginContext *pContext = plugin->GetBaseContext(); - - for (iter=m_paused.begin(); iter!=m_paused.end();) - { - func = (*iter); - if (func->GetParentContext() == pContext) - { - m_functions.push_back(func); - iter = m_paused.erase(iter); - } else { - iter++; - } - } -} diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index db283fde..27c5868b 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -70,8 +70,6 @@ public: unsigned int num_params, ParamType *types, va_list ap); - void PushPausedFunctions(IPlugin *plugin); - void PopPausedFunctions(IPlugin *plugin); private: void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags); @@ -85,7 +83,6 @@ protected: * Destroying these things and using new/delete for their members feels bad. */ mutable List m_functions; - List m_paused; /* Type and name information */ FwdParamInfo m_params[SP_MAX_EXEC_PARAMS]; From 8567d140d2c754bb7bdea3eaac3637bce81982d9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 22 Feb 2007 02:20:15 +0000 Subject: [PATCH 0502/1664] re-added this back, it was a good idea after all --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40533 --- core/systems/ForwardSys.cpp | 22 +++++++++++++++------- core/systems/ForwardSys.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 376beaf3..9f0f25ce 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -278,11 +278,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) { func = (*iter); - if (!func->IsRunnable()) - { - continue; - } - for (unsigned int i=0; i *lst; + + if (func->IsRunnable()) + { + lst = &m_functions; + } else { + lst = &m_paused; + } for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { if ((*iter) == func) { found = true; - m_functions.erase(iter); + lst->erase(iter); break; } } @@ -660,7 +663,12 @@ bool CForward::AddFunction(IPluginFunction *func) return false; } - m_functions.push_back(func); + if (func->IsRunnable()) + { + m_functions.push_back(func); + } else { + m_paused.push_back(func); + } return true; } diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 27c5868b..0582e3f9 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -83,6 +83,7 @@ protected: * Destroying these things and using new/delete for their members feels bad. */ mutable List m_functions; + mutable List m_paused; /* Type and name information */ FwdParamInfo m_params[SP_MAX_EXEC_PARAMS]; From e4fdaede321ffb93cbbe52b4ff17fa39a70318b5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 02:47:03 +0000 Subject: [PATCH 0503/1664] added per-handle security (untested) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40534 --- core/systems/HandleSys.cpp | 54 +++++++++++++++++++++++++++++++++++--- core/systems/HandleSys.h | 10 ++++++- core/systems/ShareSys.cpp | 6 ++++- public/IHandleSys.h | 19 +++++++++++++- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 7ef9cc1d..835bf3c9 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -283,6 +283,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, pHandle->serial = m_HSerial; pHandle->owner = owner; pHandle->ch_next = 0; + pHandle->access_special = false; /* Create the hash value */ Handle_t hash = pHandle->serial; @@ -336,8 +337,25 @@ void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pTok m_Types[type].typeSec.ident = pToken; } -Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity) +Handle_t HandleSystem::CreateHandleInt(HandleType_t type, + void *object, + const HandleSecurity *pSec, + HandleError *err, + const HandleAccess *pAccess, + bool identity) { + IdentityToken_t *ident; + IdentityToken_t *owner; + + if (pSec) + { + ident = pSec->pIdentity; + owner = pSec->pOwner; + } else { + ident = NULL; + owner = NULL; + } + if (!type || type >= HANDLESYS_TYPEARRAY_SIZE || m_Types[type].dispatch == NULL) @@ -376,15 +394,31 @@ Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityT return 0; } + if (pAccess) + { + pHandle->access_special = true; + pHandle->sec = *pAccess; + } + pHandle->object = object; pHandle->clone = 0; return handle; } +Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err) +{ + return CreateHandleInt(type, object, pSec, err, pAccess, false); +} + Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) { - return CreateHandleEx(type, object, owner, ident, err, false); + HandleSecurity sec; + + sec.pIdentity = ident; + sec.pOwner = owner; + + return CreateHandleEx(type, object, &sec, NULL, err); } bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) @@ -447,7 +481,14 @@ HandleError HandleSystem::GetHandle(Handle_t handle, bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity) { QHandleType *pType = &m_Types[pHandle->type]; - unsigned int access = pType->hndlSec.access[right]; + unsigned int access; + + if (pHandle->access_special) + { + access = pHandle->sec.access[right]; + } else { + access = pType->hndlSec.access[right]; + } /* Check if the type's identity matches */ if (access & HANDLE_RESTRICT_IDENTITY) @@ -487,6 +528,13 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand return err; } + /* Assign permissions from parent */ + if (pHandle->access_special) + { + pNewHandle->access_special = true; + pNewHandle->sec = pHandle->sec; + } + pNewHandle->clone = index; pHandle->refcount++; diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 97962562..0288abda 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -63,6 +63,8 @@ struct QHandle unsigned int refcount; /* Reference count for safe destruction */ unsigned int clone; /* If non-zero, this is our cloned parent index */ HandleSet set; /* Information about the handle's state */ + bool access_special; /* Whether or not access rules are special or type-derived */ + HandleAccess sec; /* Security rules */ /* The following variables are unrelated to the Handle array, and used * as an inlined chain of information */ unsigned int freeID; /* ID of a free handle in the free handle chain */ @@ -126,6 +128,12 @@ public: //IHandleSystem bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess); bool TypeCheck(HandleType_t intype, HandleType_t outtype); + + virtual Handle_t CreateHandleEx(HandleType_t type, + void *object, + const HandleSecurity *pSec, + const HandleAccess *pAccess, + HandleError *err); protected: /** * Decodes a handle with sanity and security checking. @@ -170,7 +178,7 @@ protected: HandleError FreeHandle(QHandle *pHandle, unsigned int index); void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index); HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner); - Handle_t CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity); + Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 95e7184d..b8649cea 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -104,7 +104,11 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) /* :TODO: Cache? */ IdentityToken_t *pToken = new IdentityToken_t; - pToken->ident = g_HandleSys.CreateHandleEx(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL, true); + + HandleSecurity sec; + sec.pOwner = sec.pIdentity = GetIdentRoot(); + + pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true); return pToken; } diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 92cf5a72..a1dc7b6f 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -39,7 +39,7 @@ #include #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" -#define SMINTERFACE_HANDLESYSTEM_VERSION 1 +#define SMINTERFACE_HANDLESYSTEM_VERSION 2 /** Specifies no Identity */ #define DEFAULT_IDENTITY NULL @@ -303,6 +303,23 @@ namespace SourceMod * @return True on success, false if version is unsupported. */ virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; + + /** + * @brief Creates a new handle. + * + * @param type Type to use on the handle. + * @param object Object to bind to the handle. + * @param pSec Security pointer; pOwner is written as the owner, + * pIdent is used as the parent identity for authorization. + * @param pAccess Access right descriptor for the Handle; NULL for type defaults. + * @param err Optional pointer to store an error code. + * @return A new Handle_t, or 0 on failure. + */ + virtual Handle_t CreateHandleEx(HandleType_t type, + void *object, + const HandleSecurity *pSec, + const HandleAccess *pAccess, + HandleError *err) =0; }; } From 0b8874e5ec9c8008e65140ae05b96c6dee68aadc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 02:51:14 +0000 Subject: [PATCH 0504/1664] fixed a series of crash bugs related to CreateForward() with a NULL typeset --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40535 --- core/systems/ForwardSys.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 9f0f25ce..2f6c39b2 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -209,6 +209,7 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu } else { for (unsigned int i=0; im_types[i] = types[i]; + pForward->m_types[i] = _types[i]; } - if (num_params && types[num_params-1] == Param_VarArgs) + if (num_params && _types[num_params-1] == Param_VarArgs) { pForward->m_varargs = num_params--; } else { From bb69a9f0d22646d277c4b7b48f7da45cd311f39b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 04:24:06 +0000 Subject: [PATCH 0505/1664] added random number natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40536 --- core/msvc8/sourcemod_mm.vcproj | 4 +++ core/smn_halflife.cpp | 45 ++++++++++++++++++++++++++++++++++ core/sourcemm_api.cpp | 2 ++ core/sourcemm_api.h | 2 ++ plugins/include/sourcemod.inc | 27 ++++++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 core/smn_halflife.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 477f1b5b..e79697fd 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -665,6 +665,10 @@ RelativePath="..\smn_float.cpp" > + + diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp new file mode 100644 index 00000000..32d7a6cb --- /dev/null +++ b/core/smn_halflife.cpp @@ -0,0 +1,45 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_globals.h" +#include "sourcemm_api.h" + +static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params) +{ + engrandom->SetSeed(params[1]); + + return 1; +} + +static cell_t GetRandomFloat(IPluginContext *pContext, const cell_t *params) +{ + float fMin = sp_ctof(params[1]); + float fMax = sp_ctof(params[2]); + + float fRandom = engrandom->RandomFloat(fMin, fMax); + + return sp_ftoc(fRandom); +} + +static cell_t GetRandomInt(IPluginContext *pContext, const cell_t *params) +{ + return engrandom->RandomInt(params[1], params[2]); +} + +REGISTER_NATIVES(halflifeNatives) +{ + {"SetRandomSeed", SetRandomSeed}, + {"GetRandomFloat", GetRandomFloat}, + {"GetRandomInt", GetRandomInt}, + {NULL, NULL}, +}; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index fedd22e8..10f003b0 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -24,6 +24,7 @@ ISmmPluginManager *g_pMMPlugins = NULL; CGlobalVars *gpGlobals = NULL; ICvar *icvar = NULL; IGameEventManager2 *gameevents = NULL; +IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -37,6 +38,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); GET_V_IFACE_CURRENT(engineFactory, icvar, ICvar, VENGINE_CVAR_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); + GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL) { diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 5acbfbe7..6a64614a 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -19,6 +19,7 @@ #include #include #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -52,6 +53,7 @@ extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; extern IGameEventManager2 *gameevents; extern SourceHook::CallClass *enginePatch; +extern IUniformRandomStream *engrandom; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e6ad901b..b0004cb0 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -340,5 +340,32 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); */ native LogError(const String:format[], {Handle,Float,String,_}:...); +/** + * Sets the seed value for the global Half-Life 2 Random Stream + * + * @param seed Seed value. + * @noreturn + */ +native SetRandomSeed(seed); + +/** + * Returns a random floating point number from the Half-Life 2 Random Stream + * + * @param fMin Minimum random bound. + * @param fMax Maximum random bound. + * @return A random number between (inclusive) fMin and fMax. + */ +native Float:GetRandomFloat(Float:fMin=0.0, Float:fMax=1.0); + +/** + * Returns a random number from the Half-Life 2 Random Stream + * + * @param nmin Minimum random bound. + * @param nmax Maximum random bound. + * @return A random number between (inclusive) nmin and nmax. + */ +native GetRandomInt(nmin, nmax); + + #include #include From 95e92b25aa83e90bef5924043f8a4ba88d562590 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 04:36:15 +0000 Subject: [PATCH 0506/1664] added a gameframe hook --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40537 --- core/sourcemod.cpp | 17 +++++++++++++++++ plugins/include/sourcemod.inc | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index c13b2a10..83823d46 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -25,6 +25,7 @@ #include "sm_stringutil.h" #include "CPlayerManager.h" #include "CTranslator.h" +#include "ForwardSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -40,6 +41,7 @@ IVirtualMachine *g_pVM; IdentityToken_t *g_pCoreIdent = NULL; float g_LastTime = 0.0f; float g_LastAuthCheck = 0.0f; +IForward *g_pOnGameFrame = NULL; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef unsigned int (*GETEXPORTCOUNT)(); @@ -203,6 +205,11 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_Admins.DumpAdminCache(AdminCache_Overrides, true); g_Admins.DumpAdminCache(AdminCache_Groups, true); + if (!g_pOnGameFrame) + { + g_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL); + } + RETURN_META_VALUE(MRES_IGNORED, true); } @@ -223,6 +230,11 @@ void SourceModBase::GameFrame(bool simulating) } g_LastTime = curtime; } + + if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount()) + { + g_pOnGameFrame->Execute(NULL); + } } void SourceModBase::LevelShutdown() @@ -296,6 +308,11 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c void SourceModBase::CloseSourceMod() { + if (g_pOnGameFrame) + { + g_Forwards.ReleaseForward(g_pOnGameFrame); + } + /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index b0004cb0..e62be797 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -148,6 +148,13 @@ forward OnClientSettingsChanged(client); */ forward OnClientAuthorized(client, const String:auth[]); +/** + * Called before every server frame. Note that you should avoid + * doing expensive computations here, and you should declare large + * local arrays using 'decl' instead of 'new'. + */ +forward OnGameFrame(); + /** * Returns the maximum number of clients allowed on the server. * From 1cc70a46eb4a34885153577d817aa09581172a19 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 05:26:54 +0000 Subject: [PATCH 0507/1664] added a crapload of random natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40538 --- core/smn_console.cpp | 23 +++++ core/smn_halflife.cpp | 162 +++++++++++++++++++++++++++++++++- core/sourcemm_api.cpp | 1 + core/sourcemm_api.h | 2 + core/sourcemod.cpp | 7 ++ plugins/include/console.inc | 12 +++ plugins/include/sourcemod.inc | 106 ++++++++++++++++++++++ 7 files changed, 312 insertions(+), 1 deletion(-) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index e1277d71..08c2461a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -512,6 +512,28 @@ static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + char buffer[256]; + g_SourceMod.FormatString(buffer, sizeof(buffer)-1, pContext, params, 2); + + engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer); + + return 1; +} + REGISTER_NATIVES(consoleNatives) { {"CreateConVar", sm_CreateConVar}, @@ -543,5 +565,6 @@ REGISTER_NATIVES(consoleNatives) {"ServerCommand", sm_ServerCommand}, {"InsertServerCommand", sm_InsertServerCommand}, {"ServerExecute", sm_ServerExecute}, + {"ClientCommand", sm_ClientCommand}, {NULL, NULL} }; diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 32d7a6cb..214d93db 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -12,7 +12,9 @@ */ #include "sm_globals.h" +#include "sourcemod.h" #include "sourcemm_api.h" +#include "CPlayerManager.h" static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params) { @@ -36,10 +38,168 @@ static cell_t GetRandomInt(IPluginContext *pContext, const cell_t *params) return engrandom->RandomInt(params[1], params[2]); } +static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params) +{ + char *map; + pContext->LocalToString(params[1], &map); + + return engine->IsMapValid(map); +} + +static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params) +{ + return engine->IsDedicatedServer(); +} + +static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params) +{ + return engine->GetEntityCount(); +} + +static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return 0; + } + + /* Shouldn't be necessary... not sure though */ + return pEdict->IsFree() ? 0 : 1; +} + +static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->CreateEdict(); + + if (!pEdict) + { + return 0; + } + + return engine->IndexOfEdict(pEdict); +} + +static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]); + } + + engine->RemoveEdict(pEdict); + + return 1; +} + +static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params) +{ + float fTime = engine->Time(); + return sp_ftoc(fTime); +} + +static cell_t GetGameTime(IPluginContext *pContext, const cell_t *params) +{ + return sp_ftoc(gpGlobals->curtime); +} + +static cell_t CreateFakeClient(IPluginContext *pContext, const cell_t *params) +{ + char *netname; + + pContext->LocalToString(params[1], &netname); + + edict_t *pEdict = engine->CreateFakeClient(netname); + + /* :TODO: does the engine fire forwards for us and whatnot? no idea... */ + + if (!pEdict) + { + return 0; + } + + return engine->IndexOfEdict(pEdict); +} + +static cell_t SetFakeClientConVar(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + if (!pPlayer->IsFakeClient()) + { + return pContext->ThrowNativeError("Player %d is not a fake client", params[1]); + } + + char *cvar, *value; + + pContext->LocalToString(params[2], &cvar); + pContext->LocalToString(params[3], &value); + + engine->SetFakeClientConVarValue(pPlayer->GetEdict(), cvar, value); + + return 1; +} + +static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params) +{ + const char *description; + + if (params[3]) + { + description = gamedll->GetGameDescription(); + } else { + description = SERVER_CALL(GetGameDescription)(); + } + + size_t numBytes; + + pContext->StringToLocalUTF8(params[1], params[2], description, &numBytes); + + return numBytes; +} + +static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) +{ + return gpGlobals->maxEntities; +} + +static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) +{ + size_t bytes; + pContext->StringToLocalUTF8(params[1], params[2], STRING(gpGlobals->mapname), &bytes); + return bytes; +} + REGISTER_NATIVES(halflifeNatives) { - {"SetRandomSeed", SetRandomSeed}, + {"CreateEdict", CreateEdict}, + {"CreateFakeClient", CreateFakeClient}, + {"GetCurrentMap", GetCurrentMap}, + {"GetEngineTime", GetEngineTime}, + {"GetEntityCount", GetEntityCount}, + {"GetGameDescription", GetGameDescription}, + {"GetGameTime", GetGameTime}, + {"GetMaxEntities", GetMaxEntities}, {"GetRandomFloat", GetRandomFloat}, {"GetRandomInt", GetRandomInt}, + {"IsDedicatedServer", IsDedicatedServer}, + {"IsMapValid", IsMapValid}, + {"IsValidEntity", IsValidEntity}, + {"RemoveEdict", RemoveEdict}, + {"SetFakeClientConVar", SetFakeClientConVar}, + {"SetRandomSeed", SetRandomSeed}, {NULL, NULL}, }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 10f003b0..3856b907 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -26,6 +26,7 @@ ICvar *icvar = NULL; IGameEventManager2 *gameevents = NULL; IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; +CallClass *gamedllPatch = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 6a64614a..317215d5 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -53,9 +53,11 @@ extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; extern IGameEventManager2 *gameevents; extern SourceHook::CallClass *enginePatch; +extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) +#define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 83823d46..950793d1 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -160,6 +160,7 @@ void SourceModBase::StartSourceMod(bool late) SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); enginePatch = SH_GET_CALLCLASS(engine); + gamedllPatch = SH_GET_CALLCLASS(gamedll); /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -345,6 +346,12 @@ void SourceModBase::CloseSourceMod() enginePatch = NULL; } + if (gamedllPatch) + { + SH_RELEASE_CALLCLASS(gamedllPatch); + gamedllPatch = NULL; + } + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 9fa93148..c9a20c20 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -77,6 +77,18 @@ native InsertServerCommand(const String:format[], {Handle,Float,String,_}:...); */ native ServerExecute(); +/** + * Executes a client command. Note that this will not work on clients unless + * they have cl_restrict_server_commands set to 0. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters/ + * @noreturn + * @error Invalid client index, or client not connected. + */ +native ClientCommand(client, const String:fmt[], {String,Float,Handle,_}:...); + /** * Sends a message to the server console. * diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e62be797..fcdd3eef 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -373,6 +373,112 @@ native Float:GetRandomFloat(Float:fMin=0.0, Float:fMax=1.0); */ native GetRandomInt(nmin, nmax); +/** + * Returns whether a map is valid or not. + * + * @param Map name, excluding .bsp extension. + * @return True if valid, false otherwise. + */ +native bool:IsMapValid(const String:map[]); + +/** + * Returns whether the server is dedicated. + * + * @return True if dedicated, false otherwise. + */ +native bool:IsDedicatedServer(); + +/** + * Returns the number of entities in the server. + * + * @return Number of entities in the server. + */ +native GetEntityCount(); + +/** + * Returns whether or not an entity is valid. + * + * @param entity Index of the entity. + * @return True if valid, false otherwise. + */ +native bool:IsValidEntity(entity); + +/** + * Creates a new edict (the basis of a networkable entity) + * + * @return Index of the entity, 0 on failure. + */ +native CreateEdict(); + +/** + * Removes an edict from the world. + * + * @param entity Index of the entity. + * @noreturn + * @error Invalid entity index. + */ +native RemoveEntity(entity); + +/** + * Returns a high-precision time value for profiling the engine. + * + * @return A floating point time value. + */ +native Float:GetEngineTime(); + +/** + * Returns the game time based on the game tick. + * + * @return Game tick time. + */ +native Float:GetGameTime(); + +/** + * Creates a fake client. + * + * @param name Name to use. + * @return Client index on success, 0 otherwise. + */ +native CreateFakeClient(const String:name[]); + +/** + * Sets a convar value on a fake client. + * + * @param client Client index. + * @param cvar ConVar name. + * @param value ConVar value. + * @noreturn + * @error Invalid client index, client not connected, + * or client not a fake client. + */ +native SetFakeClientConVar(client, const String:cvar[], const String:value[]); + +/** + * Returns the game description from the mod. + * + * @param buffer Buffer to store the description. + * @param maxlength Maximum size of the buffer. + * @param original If true, retrieves the original game description, + * ignoring any potential hooks from plugins. + * @return Number of bytes written to the buffer (UTF-8 safe). + */ +native GetGameDescription(String:buffer[], maxlength, bool:original=false); + +/** + * Returns the maximum number of entities. + * + * @return Maximum number of entities. + */ +native GetMaxEntities(); + +/** + * Returns the current map name. + * + * @param buffer Buffer to store map name. + * @param maxlength Maximum length of buffer. + * @return Number of bytes written (UTF-8 safe). + */ +native GetCurrentMap(String:buffer[], maxlength); #include #include From 8d412faf5c240e6a92c526de9f66fbb099b35458 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 07:43:50 +0000 Subject: [PATCH 0508/1664] fixed an assertion apparently being in the wrong place --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40539 --- sourcepawn/compiler/sctracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index b3bbc1a9..e0617c47 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -410,8 +410,8 @@ void popstacklist(int codegen) if (codegen) { _stack_genusage(stackusage, 1); + assert(stackusage->head==NULL); } - assert(stackusage->head==NULL); oldlist = stackusage->prev; free(stackusage); From fd32916b6e6ada96e4acfda92de4157049ad5a93 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 07:44:08 +0000 Subject: [PATCH 0509/1664] fixed a corruption bug where idxtags were not properly set --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40540 --- sourcepawn/compiler/sc1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index fce03a4f..3084df53 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2257,7 +2257,9 @@ static int declloc(int fstatic) pushreg(sPRI); } if (matchtoken(']')) { - dim[numdim++] = 0; + idxtag[numdim] = 0; + dim[numdim] = 0; + numdim++; continue; } dim_ident = doexpr2(TRUE,FALSE,FALSE,FALSE,&idxtag[numdim],&dim_sym,0,&dim_val); From 5cb299014acb0d509f697f947e155136831b6654 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 08:21:09 +0000 Subject: [PATCH 0510/1664] added sorting natives (phew) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40541 --- core/msvc8/sourcemod_mm.vcproj | 4 + core/sm_stringutil.cpp | 7 +- core/smn_sorting.cpp | 365 +++++++++++++++++++++++++++++++++ plugins/include/sorting.inc | 113 ++++++++++ plugins/include/sourcemod.inc | 1 + plugins/testsuite/sorttest.sp | 164 +++++++++++++++ 6 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 core/smn_sorting.cpp create mode 100644 plugins/include/sorting.inc create mode 100644 plugins/testsuite/sorttest.sp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index e79697fd..345569a5 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -681,6 +681,10 @@ RelativePath="..\smn_player.cpp" > + + diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 75db7263..47abe741 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -660,7 +660,12 @@ reswitch: { CHECK_ARGS(0); char *str; - pCtx->LocalToString(params[arg], &str); + int err; + if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, "Could not deference string"); + return 0; + } AddString(&buf_p, llen, str, width, prec); arg++; break; diff --git a/core/smn_sorting.cpp b/core/smn_sorting.cpp new file mode 100644 index 00000000..4807598b --- /dev/null +++ b/core/smn_sorting.cpp @@ -0,0 +1,365 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_globals.h" +#include +#include + +/*********************************** + * About the double array hack * + *************************** + + Double arrays in Pawn are vectors offset by the current offset. For example: + + new array[2][2] + + In this array, index 0 contains the offset from the current offset which + results in the final vector [2] (at [0][2]). Meaning, to dereference [1][2], + it is equivalent to: + + address = &array[1] + array[1] + 2 * sizeof(cell) + + The fact that each offset is from the _current_ position rather than the _base_ + position is very important. It means that if you to try to swap vector positions, + the offsets will no longer match, because their current position has changed. A + simple and ingenious way around this is to back up the positions in a separate array, + then to overwrite each position in the old array with absolute indices. Pseudo C++ code: + + cell *array; //assumed to be set to the 2+D array + cell *old_offsets = new cell[2]; + for (int i=0; i<2; i++) + { + old_offsets = array[i]; + array[i] = i; + } + + Now, you can swap the array indices with no problem, and do a reverse-lookup to find the original addresses. + After sorting/modification is done, you must relocate the new indices. For example, if the two vectors in our + demo array were swapped, array[0] would be 1 and array[1] would be 0. This is invalid to the virtual machine. + Luckily, this is also simple -- all the information is there. + + for (int i=0; i<2; i++) + { + //get the # of the vector we want to relocate in + cell vector_index = array[i]; + //get the real address of this vector + char *real_address = (char *)array + (vector_index * sizeof(cell)) + old_offsets[vector_index]; + //calc and store the new distance offset + array[i] = real_address - ( (char *)array + (vector_index + sizeof(cell)) ) + } + + Note that the inner expression can be heavily reduced; it is expanded for readability. + **********************************/ + +enum SortOrder +{ + Sort_Ascending = 0, + Sort_Descending = 1, +}; + +int sort_ints_asc(const void *int1, const void *int2) +{ + return (*(int *)int1) - (*(int *)int2); +} + +int sort_ints_desc(const void *int1, const void *int2) +{ + return (*(int *)int2) - (*(int *)int1); +} + +static cell_t sm_SortIntegers(IPluginContext *pContext, const cell_t *params) +{ + cell_t *array; + cell_t array_size = params[2]; + cell_t type = params[3]; + + pContext->LocalToPhysAddr(params[1], &array); + + if (type == Sort_Ascending) + { + qsort(array, array_size, sizeof(cell_t), sort_ints_asc); + } else { + qsort(array, array_size, sizeof(cell_t), sort_ints_desc); + } + + return 1; +} + +int sort_floats_asc(const void *float1, const void *float2) +{ + float r1 = *(float *)float1; + float r2 = *(float *)float2; + + if (r1 < r2) + { + return -1; + } else if (r2 < r1) { + return 1; + } else { + return 0; + } +} + +int sort_floats_desc(const void *float1, const void *float2) +{ + float r1 = *(float *)float1; + float r2 = *(float *)float2; + + if (r1 < r2) + { + return 1; + } else if (r2 < r1) { + return -1; + } else { + return 0; + } +} + +static cell_t sm_SortFloats(IPluginContext *pContext, const cell_t *params) +{ + cell_t *array; + cell_t array_size = params[2]; + cell_t type = params[3]; + + pContext->LocalToPhysAddr(params[1], &array); + + if (type == Sort_Ascending) + { + qsort(array, array_size, sizeof(cell_t), sort_floats_asc); + } else { + qsort(array, array_size, sizeof(cell_t), sort_floats_desc); + } + + return 1; +} + +static cell_t *g_CurStringArray = NULL; +static cell_t *g_CurRebaseMap = NULL; + +int sort_strings_asc(const void *blk1, const void *blk2) +{ + cell_t reloc1 = *(cell_t *)blk1; + cell_t reloc2 = *(cell_t *)blk2; + + char *str1 = ((char *)(&g_CurStringArray[reloc1]) + g_CurRebaseMap[reloc1]); + char *str2 = ((char *)(&g_CurStringArray[reloc2]) + g_CurRebaseMap[reloc2]); + + return strcmp(str1, str2); +} + +int sort_strings_desc(const void *blk1, const void *blk2) +{ + cell_t reloc1 = *(cell_t *)blk1; + cell_t reloc2 = *(cell_t *)blk2; + + char *str1 = ((char *)(&g_CurStringArray[reloc1]) + g_CurRebaseMap[reloc1]); + char *str2 = ((char *)(&g_CurStringArray[reloc2]) + g_CurRebaseMap[reloc2]); + + return strcmp(str2, str1); +} + +static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params) +{ + cell_t *array; + cell_t array_size = params[2]; + cell_t type = params[3]; + + pContext->LocalToPhysAddr(params[1], &array); + + /** HACKHACK - back up the old indices, replace the indices with something easier */ + cell_t amx_addr, *phys_addr; + int err; + if ((err=pContext->HeapAlloc(array_size, &amx_addr, &phys_addr)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, "Ran out of memory to sort"); + } + + g_CurStringArray = array; + g_CurRebaseMap = phys_addr; + + for (int i=0; iHeapPop(amx_addr); + + g_CurStringArray = NULL; + g_CurRebaseMap = NULL; + + return 1; +} + +struct sort_info +{ + IPluginFunction *pFunc; + Handle_t hndl; + cell_t array_addr; + cell_t *array_base; + cell_t *array_remap; +}; + +sort_info g_SortInfo; + +int sort1d_amx_custom(const void *elem1, const void *elem2) +{ + cell_t c1 = *(cell_t *)elem1; + cell_t c2 = *(cell_t *)elem2; + + cell_t result = 0; + IPluginFunction *pf = g_SortInfo.pFunc; + pf->PushCell(c1); + pf->PushCell(c2); + pf->PushCell(g_SortInfo.array_addr); + pf->PushCell(g_SortInfo.hndl); + pf->Execute(&result); + + return result; +} + +static cell_t sm_SortCustom1D(IPluginContext *pContext, const cell_t *params) +{ + cell_t *array; + cell_t array_size = params[2]; + + IPluginFunction *pFunction = pContext->GetFunctionById(params[3]); + if (!pFunction) + { + return pContext->ThrowNativeError("Function %x is not a valid function", params[3]); + } + + pContext->LocalToPhysAddr(params[1], &array); + + sort_info oldinfo = g_SortInfo; + + + g_SortInfo.hndl = params[4]; + g_SortInfo.array_addr = params[1]; + g_SortInfo.array_remap = NULL; + g_SortInfo.array_base = NULL; + g_SortInfo.pFunc = pFunction; + + qsort(array, array_size, sizeof(cell_t), sort1d_amx_custom); + + g_SortInfo = oldinfo; + + return 1; +} + +int sort2d_amx_custom(const void *elem1, const void *elem2) +{ + cell_t c1 = *(cell_t *)elem1; + cell_t c2 = *(cell_t *)elem2; + + cell_t c1_addr = g_SortInfo.array_addr + (c1 * sizeof(cell_t)) + g_SortInfo.array_remap[c1]; + cell_t c2_addr = g_SortInfo.array_addr + (c2 * sizeof(cell_t)) + g_SortInfo.array_remap[c2]; + + IPluginContext *pContext = g_SortInfo.pFunc->GetParentContext(); + cell_t *c1_r, *c2_r; + pContext->LocalToPhysAddr(c1_addr, &c1_r); + pContext->LocalToPhysAddr(c2_addr, &c2_r); + + cell_t result = 0; + g_SortInfo.pFunc->PushCell(c1_addr); + g_SortInfo.pFunc->PushCell(c2_addr); + g_SortInfo.pFunc->PushCell(g_SortInfo.array_addr); + g_SortInfo.pFunc->PushCell(g_SortInfo.hndl); + g_SortInfo.pFunc->Execute(&result); + + return result; +} + +static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params) +{ + cell_t *array; + cell_t array_size = params[2]; + IPluginFunction *pFunction; + + pContext->LocalToPhysAddr(params[1], &array); + + if ((pFunction=pContext->GetFunctionById(params[3])) == NULL) + { + return pContext->ThrowNativeError("Function %x is not a valid function", params[3]); + } + + /** back up the old indices, replace the indices with something easier */ + cell_t amx_addr, *phys_addr; + int err; + if ((err=pContext->HeapAlloc(array_size, &amx_addr, &phys_addr)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, "Ran out of memory to sort"); + return 0; + } + + sort_info oldinfo = g_SortInfo; + + g_SortInfo.pFunc = pFunction; + g_SortInfo.hndl = params[4]; + g_SortInfo.array_addr = params[1]; + + /** Same process as in strings, back up the old indices for later fixup */ + g_SortInfo.array_base = array; + g_SortInfo.array_remap = phys_addr; + + for (int i=0; iHeapPop(amx_addr); + + g_SortInfo = oldinfo; + + return 1; +} + +REGISTER_NATIVES(sortNatives) +{ + {"SortIntegers", sm_SortIntegers}, + {"SortFloats", sm_SortFloats}, + {"SortStrings", sm_SortStrings}, + {"SortCustom1D", sm_SortCustom1D}, + {"SortCustom2D", sm_SortCustom2D}, + {NULL, NULL}, +}; diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc new file mode 100644 index 00000000..14f689f2 --- /dev/null +++ b/plugins/include/sorting.inc @@ -0,0 +1,113 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + + +#if defined _sorting_included + #endinput +#endif +#define _sorting_included + +/** + * @brief Contains sorting orders. + */ +enum SortOrder +{ + Sort_Ascending = 0, /**< Ascending order */ + Sort_Descending = 1, /**< Descending order */ +}; + +/** + * Sorts an array of integers. + * + * @param array Array of integers to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + * @noreturn + */ +native SortIntegers(array[], array_size, SortOrder:order = Sort_Ascending); + +/** + * Sorts an array of float point numbers. + * + * @param array Array of floating point numbers to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + * @noreturn + */ +native SortFloats(Float:array[], array_size, SortOrder:order = Sort_Ascending); + +/** + * Sorts an array of strings. + * + * @param array Array of strings to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + * @noreturn + */ +native SortStrings(String:array[][], num_strings, SortOrder:order = Sort_Ascending); + +/** + * Sort comparison function for 1D array elements. + * @note You may need to use explicit tags in order to use data properly. + * + * @param elem1 First element to compare. + * @param elem2 Second element to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +functag SortFunc1D public(elem1, elem2, const array[], Handle:hndl); + +/** + * Sorts a custom 1D array. You must pass in a comparison function. + * + * @param array Array to sort. + * @param array_size Size of the array to sort. + * @param sortfunc Sort function. + * @param hndl Optional Handle to pass through the comparison calls. + * @noreturn + */ +native SortCustom1D(array[], array_size, SortFunc1D:sortfunc, Handle:hndl=INVALID_HANDLE); + +/** + * Sort comparison function for 2D array elements (sub-arrays). + * @note You may need to use explicit tags in order to use data properly. + * + * @param elem1 First array to compare. + * @param elem2 Second array to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +funcenum SortFunc2D +{ + public(array[], array[], const array[][], Handle:hndl), + public(String:array[], String:array[], const String:array[][], Handle:hndl), +}; + +/** + * Sorts a custom 2D array. You must pass in a comparison function. + * + * @param array Array to sort. + * @param array_size Size of the major array to sort (first index, outermost). + * @param sortfunc Sort comparison function to use. + * @param hndl Optional Handle to pass through the comparison calls. + * @noreturn + */ +native SortCustom2D(array[][], array_size, SortFunc2D:sortfunc, Handle:hndl=INVALID_HANDLE); \ No newline at end of file diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index fcdd3eef..4410d151 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -35,6 +35,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. diff --git a/plugins/testsuite/sorttest.sp b/plugins/testsuite/sorttest.sp new file mode 100644 index 00000000..1398a7d5 --- /dev/null +++ b/plugins/testsuite/sorttest.sp @@ -0,0 +1,164 @@ +#include + +public Plugin:myinfo = +{ + name = "Sorting Test", + author = "AlliedModders LLC", + description = "Tests sorting functions", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public OnPluginStart(Handle:myself) +{ + RegServerCmd("test_sort_ints", Command_TestSortInts) + RegServerCmd("test_sort_floats", Command_TestSortFloats) + RegServerCmd("test_sort_strings", Command_TestSortStrings) + RegServerCmd("test_sort_1d", Command_TestSort1D) + RegServerCmd("test_sort_2d", Command_TestSort2D) +} + +/***************** + * INTEGER TESTS * + *****************/ +// Note that integer comparison is just int1-int2 (or a variation therein) + +PrintIntegers(const array[], size) +{ + for (new i=0; i f2) + { + return -1; + } else if (f1 < f2) { + return 1; + } + + return 0; +} + +public Action:Command_TestSort1D(args) +{ + new Float:array[10] = {6.3, 7.6, 3.2, 2.1, 8.5, 5.2, 0.4, 1.7, 4.8, 8.2} + + SortCustom1D(_:array, 10, Custom1DSort) + PrintFloats(array, 10) + + return Plugin_Handled +} + +/*************************** + * String comparison tests * + ***************************/ + +PrintStrings(const String:array[][], size) +{ + for (new i=0; i Date: Mon, 26 Feb 2007 08:32:20 +0000 Subject: [PATCH 0511/1664] removed Handle:myself from OnPluginStart added GetMyHandle to get handle now, but there's no use... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40542 --- core/smn_handles.cpp | 7 +++++++ core/systems/PluginSys.cpp | 6 +++++- core/systems/PluginSys.h | 22 ++++++++++++---------- plugins/include/sourcemod.inc | 9 ++++++++- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 204c344f..4e818819 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -82,6 +82,13 @@ static cell_t sm_CloneHandle(IPluginContext *pContext, const cell_t *params) } } +static cell_t sm_GetMyHandle(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + return pPlugin->GetMyHandle(); +} + REGISTER_NATIVES(handles) { {"IsValidHandle", sm_IsValidHandle}, diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 5881a06e..63f09009 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -92,6 +92,11 @@ void CPlugin::InitIdentity() } } +Handle_t CPlugin::GetMyHandle() +{ + return m_handle; +} + CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) { char fullpath[PLATFORM_MAX_PATH+1]; @@ -280,7 +285,6 @@ void CPlugin::Call_OnPluginStart() return; } - pFunction->PushCell(m_handle); pFunction->Execute(&result); } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 2b46fed0..05838db0 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -182,34 +182,36 @@ public: bool IsRunnable() const; /** - * Adds a language file index to the plugin's list. - */ + * Adds a language file index to the plugin's list. + */ void AddLangFile(unsigned int index); /** - * Get language file count for this plugin. - */ + * Get language file count for this plugin. + */ size_t GetLangFileCount() const; /** - * Get language file index based on the vector index. - */ + * Get language file index based on the vector index. + */ unsigned int GetLangFileByIndex(unsigned int index) const; public: /** - * Returns the modification time during last plugin load. - */ + * Returns the modification time during last plugin load. + */ time_t GetTimeStamp() const; /** - * Returns the current modification time of the plugin file. - */ + * Returns the current modification time of the plugin file. + */ time_t GetFileTimeStamp(); /** * Returns true if the plugin was running, but is now invalid. */ bool WasRunning(); + + Handle_t GetMyHandle(); protected: void UpdateInfo(); void SetTimeStamp(time_t t); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 4410d151..cab69d2c 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -56,7 +56,7 @@ public Plugin:myinfo; * * @noreturn */ -forward OnPluginStart(Handle:myself); +forward OnPluginStart(); /** * Called before OnPluginStart, in case the plugin wants to check for load failure. @@ -156,6 +156,13 @@ forward OnClientAuthorized(client, const String:auth[]); */ forward OnGameFrame(); +/** + * Returns the calling plugin's Handle. + * + * @return Handle of the calling plugin. + */ +native Handle:GetMyHandle(); + /** * Returns the maximum number of clients allowed on the server. * From 38532ccdad20485f1a4b79ca8d1acc19df67c00b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 08:50:25 +0000 Subject: [PATCH 0512/1664] removed redundant float native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40543 --- core/smn_float.cpp | 14 -------------- plugins/include/float.inc | 8 -------- 2 files changed, 22 deletions(-) diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 4973a22f..9f72c38a 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -163,19 +163,6 @@ static cell_t sm_FloatRound(IPluginContext *pCtx, const cell_t *params) return static_cast(val); } -static cell_t sm_FloatStr(IPluginContext *pCtx, const cell_t *params) -{ - char *str; - - pCtx->LocalToString(params[1], &str); - if (!strlen(str)) - { - return 0; - } - - return sp_ftoc((float)atof(str)); -} - static cell_t sm_FloatFraction(IPluginContext *pCtx, const cell_t *params) { float val = sp_ctof(params[1]); @@ -244,7 +231,6 @@ static cell_t sm_ArcTangent2(IPluginContext *pCtx, const cell_t *params) REGISTER_NATIVES(floatnatives) { {"float", sm_float}, - {"FloatStr", sm_FloatStr}, {"FloatMul", sm_FloatMul}, {"FloatDiv", sm_FloatDiv}, {"FloatAdd", sm_FloatAdd}, diff --git a/plugins/include/float.inc b/plugins/include/float.inc index 0d9f8139..f71ac877 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -41,14 +41,6 @@ enum floatround_method */ native Float:float(value); -/** - * Converts a string into a floating point value. - * - * @param str String to convert. - * @return Converted floating point number. - */ -native Float:FloatStr(const String:str[]); - /** * Multiplies two floats together. * From 57a69562cf9d01bff18c69bfb970e146c17f9046 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 09:12:32 +0000 Subject: [PATCH 0513/1664] changed name output format --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40544 --- tools/builder/ABuilder.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs index f1a95b19..d1f7016f 100644 --- a/tools/builder/ABuilder.cs +++ b/tools/builder/ABuilder.cs @@ -154,12 +154,12 @@ namespace builder public string PackageBuildName(Package pkg) { return pkg.GetPackageName() - + "-" - + DateTime.Now.Day.ToString("00") - + DateTime.Now.Month.ToString("00") - + DateTime.Now.Year + "-r" - + GetRevsionOfPath(cfg.SourceBase); + + GetRevsionOfPath(cfg.SourceBase) + + "-" + + DateTime.Now.Year + + DateTime.Now.Month.ToString("00") + + DateTime.Now.Day.ToString("00"); } public void BuildPackage(Package pkg) From 52de18813cc8decd9bfc6749f991c4efdb00d39e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 09:21:08 +0000 Subject: [PATCH 0514/1664] fixed stupid export --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40545 --- core/smn_handles.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 4e818819..9d7b6dde 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -94,5 +94,6 @@ REGISTER_NATIVES(handles) {"IsValidHandle", sm_IsValidHandle}, {"CloseHandle", sm_CloseHandle}, {"CloneHandle", sm_CloneHandle}, + {"GetMyHandle", sm_GetMyHandle}, {NULL, NULL}, }; From 09887584f451f9df504d457daabcff1d44cc3cc3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 03:32:14 +0000 Subject: [PATCH 0515/1664] added functions for target immunity testing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40546 --- core/smn_admin.cpp | 6 ++++++ core/smn_player.cpp | 25 +++++++++++++++++++++++++ plugins/include/admin.inc | 21 +++++++++++++++++++++ plugins/include/sourcemod.inc | 11 +++++++++++ 4 files changed, 63 insertions(+) diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index 67f1addc..4f6e3ed6 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -418,6 +418,11 @@ static cell_t FlagBitsToArray(IPluginContext *pContext, const cell_t *params) } } +static cell_t CanAdminTarget(IPluginContext *pContext, const cell_t *params) +{ + return g_Admins.CanAdminTarget(params[1], params[2]) ? 1 : 0; +} + REGISTER_NATIVES(adminNatives) { {"DumpAdminCache", DumpAdminCache}, @@ -454,6 +459,7 @@ REGISTER_NATIVES(adminNatives) {"FlagBitArrayToBits", FlagBitArrayToBits}, {"FlagArrayToBits", FlagArrayToBits}, {"FlagBitsToArray", FlagBitsToArray}, + {"CanAdminTarget", CanAdminTarget}, /* -------------------------------------------------- */ {NULL, NULL}, }; diff --git a/core/smn_player.cpp b/core/smn_player.cpp index c480bee4..c520c01e 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -345,6 +345,30 @@ static cell_t GetClientUserId(IPluginContext *pContext, const cell_t *params) return engine->GetPlayerUserId(pPlayer->GetEdict()); } +static cell_t CanUserTarget(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + int target = params[2]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsConnected()) { + return pContext->ThrowNativeError("Player %d is not connected", client); + } + + CPlayer *pTarget = g_Players.GetPlayerByIndex(target); + if (!pTarget) + { + return pContext->ThrowNativeError("Player %d is not a valid client", target); + } else if (!pTarget->IsConnected()) { + return pContext->ThrowNativeError("Player %d is not connected", target); + } + + return g_Admins.CanAdminTarget(pPlayer->GetAdminId(), pTarget->GetAdminId()) ? 1 : 0; +} + REGISTER_NATIVES(playernatives) { {"GetMaxClients", sm_GetMaxClients}, @@ -364,6 +388,7 @@ REGISTER_NATIVES(playernatives) {"SetUserFlagBits", SetUserFlagBits}, {"GetUserFlagBits", GetUserFlagBits}, {"GetClientUserId", GetClientUserId}, + {"CanUserTarget", CanUserTarget}, {NULL, NULL} }; diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index d803edf3..6c929eb0 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -462,12 +462,33 @@ native FlagArrayToBits(const AdminFlag:array[], numFlags) =0; */ native FlagBitsToArray(bits, AdminFlag:array[], maxSize) =0; +/** + * Tests whether one admin can target another. + * + * @param admin Admin doing the targetting (may be INVALID_ADMIN_ID). + * @param target Target admin (may be INVALID_ADMIN_ID). + * @return True if targetable, false if immune. + */ +native CanAdminTarget(AdminId:admin, AdminId:target); +/** + * Converts a flag to its single bit. + * + * @param flag Flag to convert. + * @return Bit representation of the flag. + */ stock FlagToBit(AdminFlag:flag) { return (1<<_:flag); } +/** + * Converts a bit to an AdminFlag. + * + * @param bit Bit to convert. + * @param flag Stores the converted flag by reference. + * @return True on success, false otherwise. + */ stock bool:BitToFlag(bit, &AdminFlag:flag) { new AdminFlag:array[1]; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index cab69d2c..8080c4e4 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -328,6 +328,17 @@ native SetUserFlagBits(client, flags); */ native GetUserFlagBits(client); +/** + * Returns whether a user can target another user. + * This is a helper function for CanAdminTarget. + * + * @param client Player's index. + * @param target Target player's index. + * @return True if target is targettable by the player, false otherwise. + * @error Invalid or unconnected player indexers. + */ +native bool:CanUserTarget(client, target); + /** * Logs a generic message to the HL2 logs. * From 348f21b61a37d8aa18a52f0bb589a53ced3e9f9c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 07:31:55 +0000 Subject: [PATCH 0516/1664] renamed this function to avoid clashes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40547 --- public/IPlayerHelpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 3642409f..91142e90 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -116,7 +116,7 @@ namespace SourceMod class IClientListener { public: - virtual unsigned int GetInterfaceVersion() + virtual unsigned int GetClientListenerVersion() { return SMINTERFACE_PLAYERMANAGER_VERSION; } From 88023370eafe3e13efbf5a6234c360d0ce36006a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 08:21:01 +0000 Subject: [PATCH 0517/1664] implemented wrapper around BAT's AdminInterface --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40548 --- extensions/batsupport/BATInterface.h | 61 +++ extensions/batsupport/Makefile | 91 +++++ extensions/batsupport/extension.cpp | 235 +++++++++++ extensions/batsupport/extension.h | 46 +++ extensions/batsupport/msvc8/batsupport.sln | 20 + extensions/batsupport/msvc8/batsupport.vcproj | 380 ++++++++++++++++++ extensions/batsupport/smsdk_config.h | 33 ++ extensions/batsupport/smsdk_ext.cpp | 333 +++++++++++++++ extensions/batsupport/smsdk_ext.h | 196 +++++++++ 9 files changed, 1395 insertions(+) create mode 100644 extensions/batsupport/BATInterface.h create mode 100644 extensions/batsupport/Makefile create mode 100644 extensions/batsupport/extension.cpp create mode 100644 extensions/batsupport/extension.h create mode 100644 extensions/batsupport/msvc8/batsupport.sln create mode 100644 extensions/batsupport/msvc8/batsupport.vcproj create mode 100644 extensions/batsupport/smsdk_config.h create mode 100644 extensions/batsupport/smsdk_ext.cpp create mode 100644 extensions/batsupport/smsdk_ext.h diff --git a/extensions/batsupport/BATInterface.h b/extensions/batsupport/BATInterface.h new file mode 100644 index 00000000..7ed28961 --- /dev/null +++ b/extensions/batsupport/BATInterface.h @@ -0,0 +1,61 @@ +/* ======== Basic Admin tool ======== +* Copyright (C) 2004-2006 Erling K. Sæterdal +* No warranties of any kind +* +* License: zlib/libpng +* +* Author(s): Erling K. Sæterdal ( EKS ) +* Credits: +* Menu code based on code from CSDM ( http://www.tcwonline.org/~dvander/cssdm ) Created by BAILOPAN +* Helping on misc errors/functions: BAILOPAN,LDuke,sslice,devicenull,PMOnoTo,cybermind ( most who idle in #sourcemod on GameSurge realy ) +* ============================ */ + +#ifndef _INCLUDE_BATINTERFACE +#define _INCLUDE_BATINTERFACE +#include "ismmplugin.h" + +#define ADMININTERFACE_VERSION 0 +#define ADMININTERFACE_MAXACCESSLENGTHTEXT 50 // This is the maximum length of a "flag" access text. + +//#include "BATMenu.h" + +//extern menuId g_AdminMenu; +class AdminInterfaceListner +{ +public: + virtual void OnAdminInterfaceUnload()=0; + virtual void Client_Authorized(int id)=0; +}; + +class AdminInterface +{ +public: + virtual bool RegisterFlag(const char *Class,const char *Flag,const char *Description) = 0; // Registers a new admin access + virtual bool IsClient(int id) = 0; // returns false if client is bot, or NOT connected + virtual bool HasFlag(int id,const char *Flag) = 0; // returns true if the player has this access flag, lower case only + virtual int GetInterfaceVersion() = 0 ; // Returns the interface version of the admin mod + virtual const char* GetModName() = 0; // Returns the name of the current admin mod + virtual void AddEventListner(AdminInterfaceListner *ptr) = 0; // You should ALLWAYS set this, so you know when the "server" plugin gets unloaded + virtual void RemoveListner(AdminInterfaceListner *ptr) = 0; // You MUST CALL this function in your plugin unloads function, or the admin plugin will crash on next client connect. +}; + +class BATAdminInterface : public AdminInterface +{ +public: + bool RegisterFlag(const char *Class,const char *Flag,const char *Description); // Max 1 admin access at the time, returns true if done successfully + bool IsClient(int id); // returns false if client is bot, or NOT connected + bool HasFlag(int id,const char *Flag); // returns true if the player has this access flag + int GetInterfaceVersion() { return ADMININTERFACE_VERSION; } // Returns the interface version of the admin mod + const char* GetModName() { return "BAT"; } // Returns the name of the current admin mod + void AddEventListner(AdminInterfaceListner *ptr); // You should ALLWAYS set this, so you know when the "server" plugin gets unloaded + void RemoveListner(AdminInterfaceListner *ptr); +private: + char GetFlagFromInt(int CharIndex); + bool CustomAccessExistence(const char *Flag); +}; +class MyListener : public IMetamodListener +{ +public: + virtual void *OnMetamodQuery(const char *iface, int *ret); +}; +#endif \ No newline at end of file diff --git a/extensions/batsupport/Makefile b/extensions/batsupport/Makefile new file mode 100644 index 00000000..537e149c --- /dev/null +++ b/extensions/batsupport/Makefile @@ -0,0 +1,91 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = sample + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/extensions/batsupport/extension.cpp b/extensions/batsupport/extension.cpp new file mode 100644 index 00000000..96ef66cc --- /dev/null +++ b/extensions/batsupport/extension.cpp @@ -0,0 +1,235 @@ +// vim: set ts=4 : +#include +#include +#include "extension.h" + +BatSupport g_BatSupport; /**< Global singleton for your extension's main interface */ +IAdminSystem *admins = NULL; +IPlayerManager *players = NULL; +SMEXT_LINK(&g_BatSupport); + +bool BatSupport::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + SM_GET_IFACE(ADMINSYS, admins); + SM_GET_IFACE(PLAYERMANAGER, players); + + players->AddClientListener(this); + + return true; +} + +void BatSupport::SDK_OnUnload() +{ + players->RemoveClientListener(this); + + List::iterator iter; + AdminInterfaceListner *hook; + + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + hook = (*iter); + hook->OnAdminInterfaceUnload(); + } + + /* In case plugins don't do this */ + m_hooks.clear(); +} + +bool BatSupport::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +{ + g_SMAPI->AddListener(this, this); + + return true; +} + +void BatSupport::OnClientAuthorized(int client, const char *authstring) +{ + List::iterator iter; + AdminInterfaceListner *hook; + + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + hook = (*iter); + hook->Client_Authorized(client); + } +} + +const char *BatSupport::GetModName() +{ + return "SourceMod"; +} + +int BatSupport::GetInterfaceVersion() +{ + return ADMININTERFACE_VERSION; +} + +void *BatSupport::OnMetamodQuery(const char *iface, int *ret) +{ + if (strcmp(iface, "AdminInterface") == 0) + { + AdminInterface *pThis = this; + if (ret) + { + *ret = IFACE_OK; + } + return pThis; + } + + if (ret) + { + *ret = IFACE_FAILED; + } + + return NULL; +} + +bool BatSupport::RegisterFlag(const char *Class,const char *Flag,const char *Description) +{ + /* No empty flags */ + if (Flag[0] == '\0') + { + g_pSM->LogError(myself, "BAT AdminInterface support tried to register a blank flag"); + return false; + } + + /* We only support up to 6 custom flags for SourceMod */ + if (m_flags.size() >= 6) + { + g_pSM->LogError(myself, "BAT AdminInterface support reached maximum number of custom flags"); + return false; + } + + List::iterator iter; + for (iter=m_flags.begin(); iter!=m_flags.end(); iter++) + { + CustomFlag &cf = (*iter); + /* Ignore already registered, in case plugin is reloading */ + if (cf.name.compare(Flag) == 0) + { + return true; + } + } + + g_pSM->LogMessage(myself, + "BAT AdminInterface support registered Admin_Custom%d (class \"%s\") (flag \"%s\") (descr \"%s\")", + m_flags.size() + 1, + Class, + Flag, + Description); + + unsigned int f = (unsigned int)Admin_Custom1; + f += m_flags.size(); + + CustomFlag cf; + cf.bit = (1<GetGamePlayer(id); + + if (!pPlayer) + { + return false; + } + + if (!pPlayer->IsConnected()) + { + return false; + } + + if (pPlayer->IsFakeClient()) + { + return false; + } + + return true; +} + +void BatSupport::AddEventListner(AdminInterfaceListner *ptr) +{ + m_hooks.push_back(ptr); +} + +void BatSupport::RemoveListner(AdminInterfaceListner *ptr) +{ + m_hooks.remove(ptr); +} + +bool BatSupport::HasFlag(int id,const char *Flag) +{ + IGamePlayer *pPlayer = players->GetGamePlayer(id); + + if (!pPlayer || !pPlayer->IsConnected()) + { + return false; + } + + AdminId admin = pPlayer->GetAdminId(); + if (admin == INVALID_ADMIN_ID) + { + return false; + } + + FlagBits bits = admins->GetAdminFlags(admin, Access_Effective); + + /* Root has it all... except for immunity */ + if ((strcmp(Flag, "immunity") != 0) + && ((bits & ADMFLAG_ROOT) == ADMFLAG_ROOT)) + { + return true; + } + + if (!strcmp(Flag, "any")) + { + return ((bits & ~ADMFLAG_RESERVATION) != 0); + } else if (!strcmp(Flag, "kick")) { + return ((bits & ADMFLAG_KICK) == ADMFLAG_KICK); + } else if (!strcmp(Flag, "slap")) { + return ((bits & ADMFLAG_SLAY) == ADMFLAG_SLAY); + } else if (!strcmp(Flag, "slay")) { + return ((bits & ADMFLAG_SLAY) == ADMFLAG_SLAY); + } else if (!strcmp(Flag, "ban")) { + return ((bits & ADMFLAG_BAN) == ADMFLAG_BAN); + } else if (!strcmp(Flag, "chat")) { + return ((bits & ADMFLAG_CHAT) == ADMFLAG_CHAT); + } else if (!strcmp(Flag, "rcon")) { + return ((bits & ADMFLAG_RCON) == ADMFLAG_RCON); + } else if (!strcmp(Flag, "map")) { + return ((bits & ADMFLAG_CHANGEMAP) == ADMFLAG_CHANGEMAP); + } else if (!strcmp(Flag, "reservedslots")) { + return ((bits & ADMFLAG_RESERVATION) == ADMFLAG_RESERVATION); + } else if (!strcmp(Flag, "immunuty")) { + /* This is a bit different... */ + unsigned int count = admins->GetAdminGroupCount(admin); + for (unsigned int i=0; iGetAdminGroup(admin, i, NULL); + if (admins->GetGroupGenericImmunity(gid, Immunity_Default) + || admins->GetGroupGenericImmunity(gid, Immunity_Global)) + { + return true; + } + } + return false; + } + + List::iterator iter; + for (iter=m_flags.begin(); iter!=m_flags.end(); iter++) + { + CustomFlag &cf = (*iter); + if (cf.name.compare(Flag) == 0) + { + return ((bits & cf.bit) == cf.bit); + } + } + + return false; +} diff --git a/extensions/batsupport/extension.h b/extensions/batsupport/extension.h new file mode 100644 index 00000000..ce234f0a --- /dev/null +++ b/extensions/batsupport/extension.h @@ -0,0 +1,46 @@ +// vim: set ts=4 : +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +#include "smsdk_ext.h" +#include "BATInterface.h" +#include +#include + +using namespace SourceHook; + +struct CustomFlag +{ + String name; + AdminFlag flag; + FlagBits bit; +}; + +class BatSupport : + public SDKExtension, + public IMetamodListener, + public AdminInterface, + public IClientListener +{ +public: //SDKExtension + bool SDK_OnLoad(char *error, size_t err_max, bool late); + void SDK_OnUnload(); + bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); +public: //IMetamodListener + void *OnMetamodQuery(const char *iface, int *ret); +public: //AdminInterface + bool RegisterFlag(const char *Class,const char *Flag,const char *Description); + bool IsClient(int id); + bool HasFlag(int id,const char *Flag); + int GetInterfaceVersion(); + const char* GetModName(); + void AddEventListner(AdminInterfaceListner *ptr); + void RemoveListner(AdminInterfaceListner *ptr); +public: //IClientListener + void OnClientAuthorized(int client, const char *authstring); +private: + List m_hooks; + List m_flags; +}; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/batsupport/msvc8/batsupport.sln b/extensions/batsupport/msvc8/batsupport.sln new file mode 100644 index 00000000..6f8ed540 --- /dev/null +++ b/extensions/batsupport/msvc8/batsupport.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BatSupport", "BatSupport.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/batsupport/msvc8/batsupport.vcproj b/extensions/batsupport/msvc8/batsupport.vcproj new file mode 100644 index 00000000..43e91d83 --- /dev/null +++ b/extensions/batsupport/msvc8/batsupport.vcproj @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/batsupport/smsdk_config.h b/extensions/batsupport/smsdk_config.h new file mode 100644 index 00000000..0454a055 --- /dev/null +++ b/extensions/batsupport/smsdk_config.h @@ -0,0 +1,33 @@ +// vim: set ts=4 : +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "BAT Support" +#define SMEXT_CONF_DESCRIPTION "Adds support for BAT's AdminInterface" +#define SMEXT_CONF_VERSION "1.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "BATSUPPORT" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/batsupport/smsdk_ext.cpp b/extensions/batsupport/smsdk_ext.cpp new file mode 100644 index 00000000..2e060a7f --- /dev/null +++ b/extensions/batsupport/smsdk_ext.cpp @@ -0,0 +1,333 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + + if (SDK_OnLoad(error, err_max, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/extensions/batsupport/smsdk_ext.h b/extensions/batsupport/smsdk_ext.h new file mode 100644 index 00000000..8d23c32e --- /dev/null +++ b/extensions/batsupport/smsdk_ext.h @@ -0,0 +1,196 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ From ad5bc37912dc64e89a9be6c62709f43ba93a12a2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 08:32:29 +0000 Subject: [PATCH 0518/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40549 --- extensions/batsupport/BATInterface.h | 5 +++-- extensions/batsupport/Makefile | 6 +----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/extensions/batsupport/BATInterface.h b/extensions/batsupport/BATInterface.h index 7ed28961..7640f52b 100644 --- a/extensions/batsupport/BATInterface.h +++ b/extensions/batsupport/BATInterface.h @@ -12,7 +12,7 @@ #ifndef _INCLUDE_BATINTERFACE #define _INCLUDE_BATINTERFACE -#include "ismmplugin.h" +#include #define ADMININTERFACE_VERSION 0 #define ADMININTERFACE_MAXACCESSLENGTHTEXT 50 // This is the maximum length of a "flag" access text. @@ -58,4 +58,5 @@ class MyListener : public IMetamodListener public: virtual void *OnMetamodQuery(const char *iface, int *ret); }; -#endif \ No newline at end of file +#endif + diff --git a/extensions/batsupport/Makefile b/extensions/batsupport/Makefile index 537e149c..1e9d6a22 100644 --- a/extensions/batsupport/Makefile +++ b/extensions/batsupport/Makefile @@ -9,7 +9,7 @@ SOURCEMM = ../../../../sourcemm ### EDIT BELOW FOR OTHER PROJECTS ### ##################################### -PROJECT = sample +PROJECT = batsupport #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so @@ -60,14 +60,10 @@ endif BINARY = $(PROJECT).ext.so OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) -OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -$(BIN_DIR)/%.o: %.c - $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< - all: mkdir -p $(BIN_DIR) ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so From 5cccd9a242c3d66453e6ee31ec64cad5de468351 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 27 Feb 2007 21:30:04 +0000 Subject: [PATCH 0519/1664] Added hex format specifier (%X and %x) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40550 --- core/sm_stringutil.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 47abe741..3720da97 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -22,6 +22,7 @@ #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ +#define UPPERDIGITS 0x00000100 /* make alpha digits uppercase */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) @@ -358,6 +359,65 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags) *buf_p = buf; } +void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags) +{ + char text[32]; + int digits; + char *buf; + char digit; + int hexadjust; + + if (flags & UPPERDIGITS) + { + hexadjust = 'A' - '9' - 1; + } else { + hexadjust = 'a' - '9' - 1; + } + + digits = 0; + do + { + digit = ('0' + val % 16); + if (digit > '9') + { + digit += hexadjust; + } + + text[digits++] = digit; + val /= 16; + } while(val); + + buf = *buf_p; + + if (!(flags & LADJUST)) + { + while (digits < width && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + width--; + maxlen--; + } + } + + while (digits-- && maxlen) + { + *buf++ = text[digits]; + width--; + maxlen--; + } + + if (flags & LADJUST) + { + while (width-- && maxlen) + { + *buf++ = (flags & ZEROPAD) ? '0' : ' '; + maxlen--; + } + } + + *buf_p = buf; +} + size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args) { if (!buffer || !maxlen) @@ -486,6 +546,21 @@ reswitch: arg++; break; } + case 'X': + { + unsigned int *value = (unsigned int *)args[arg]; + flags |= UPPERDIGITS; + AddHex(&buf_p, llen, *value, width, flags); + arg++; + break; + } + case 'x': + { + unsigned int *value = (unsigned int *)args[arg]; + AddHex(&buf_p, llen, *value, width, flags); + arg++; + break; + } case '%': { if (!llen) @@ -704,6 +779,25 @@ reswitch: llen -= res; break; } + case 'X': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + flags |= UPPERDIGITS; + AddHex(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } + case 'x': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddHex(&buf_p, llen, static_cast(*value), width, flags); + arg++; + break; + } case '%': { if (!llen) From 9e98944097e9046781f66fda3c6c1778453505e2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 23:39:30 +0000 Subject: [PATCH 0520/1664] split sourcemod.inc into clients.inc and fixed some bugs --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40551 --- plugins/include/clients.inc | 276 ++++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 256 +------------------------------ 2 files changed, 277 insertions(+), 255 deletions(-) create mode 100644 plugins/include/clients.inc diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc new file mode 100644 index 00000000..8cd04cb2 --- /dev/null +++ b/plugins/include/clients.inc @@ -0,0 +1,276 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _clients_included + #endinput +#endif +#define _clients_included + +/** + * Called on client connection. + * + * @param client Player index. + * @param rejectmsg Buffer to store the rejection message when the connection is refused. + * @param maxlen Maximum number of characters for rejection buffer. + * @return True to validate client's connection, false to refuse it. + */ +forward bool:OnClientConnect(client, String:rejectmsg[], maxlen); + +/** + * Called when a client is entering to the game. + * + * @param client Player index. + * @noreturn + */ +forward OnClientPutInServer(client); + +/** + * Called when a client is disconnecting from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect(client); + +/** + * Called when a client is disconnected from the server. + * + * @param client Player index. + * @noreturn + */ +forward OnClientDisconnect_Post(client); + +/** + * Called when a client is sending a command. + * + * @param client Player index. + * @param args Number of arguments. + * @noreturn + */ +forward Action:OnClientCommand(client, args); + +/** + * Called whenever the client's settings are changed. + * + * @param client Player index. + * @noreturn + */ +forward OnClientSettingsChanged(client); + +/** + * Called when a client receives a Steam ID. + * @note This is called by bots, but the ID will be "BOT" + * + * @param client Player index. + * @param auth Player auth string. + */ +forward OnClientAuthorized(client, const String:auth[]); + +/** + * Returns the maximum number of clients allowed on the server. + * + * @return Maximum number of clients allowed. + */ +native GetMaxClients(); + +/** + * Returns the client count put in the server. + * + * @param inGameOnly If false connecting players are also counted. + * @return Client count in the server. + */ +native GetClientCount(bool:inGameOnly=true); + +/** + * Returns the client's name. + * + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. + */ +native bool:GetClientName(client, String:name[], maxlen); + +/** + * Retrieves a client's IP address. + * + * @param client Player index. + * @param name Buffer to store the client's ip address. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param remport Remove client's port from the ip string (true by default). + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); + +/** + * Retrieves a client's authentication string (SteamID). + * + * @param client Player index. + * @param auth Buffer to store the client's auth string. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +native bool:GetClientAuthString(client, String:auth[], maxlen); + +/** + * Retrieves a client's user id, which is an index incremented for every client + * that joins the server. + * + * @param client Player index. + * @return User id of the client. + * @error If the client is not connected or the index is invalid. + */ +native GetClientUserId(client); + +/** + * Returns if a certain player is connected. + * + * @param client Player index. + * @return True if player is connected to the server, false otherwise. + */ +native bool:IsClientConnected(client); + +/** + * Returns if a certain player has entered the game. + * + * @param client Player index. + * @return True if player has entered the game, false otherwise. + */ +native bool:IsPlayerInGame(client); + +/** + * Returns if a certain player has been authenticated. + * + * @param client Player index. + * @return True if player has been authenticated, false otherwise. + */ +native bool:IsClientAuthorized(client); + +/** + * Returns if a certain player is a fake client. + * + * @param client Player index. + * @return True if player is a fake client, false otherwise. + */ +native bool:IsFakeClient(client); + +/** + * Retrieves values from client replicated keys. + * + * @param client Player's index. + * @param key Key string. + * @param value Buffer to store value. + * @param maxlen Maximum length of valve (UTF-8 safe). + * @return True on success, false otherwise. + * @error Invalid client index, or client not connected. + */ +native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); + +/** + * Sets a client's AdminId. + * + * @param client Player's index. + * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. + * @param temp True if the id should be freed on disconnect. + * @noreturn + * @error Invalid client index, client not connected, or bogus AdminId. + */ +native SetUserAdmin(client, AdminId:id, bool:temp=false); + +/** + * Retrieves a client's AdminId. + * + * @param client Player's index. + * @return AdminId of the client, or INVALID_ADMIN_ID if none. + * @error Invalid client index, or client not connected. + */ +native AdminId:GetUserAdmin(client); + +/** + * Sets access flags on a client. If the client is not an admin, + * a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param ... Flags to set on the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native AddUserFlags(client, {AdminFlag}:...); + +/** + * Removes flags from a client. If the client is not an admin, + * this has no effect. + * + * @param client Player's index. + * @param ... Flags to remove from the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native RemoveUserFlags(client, {AdminFlag}:...); + +/** + * Sets access flags on a client using bits instead of flags. If the + * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param flags Bitstring of flags to set on client. + * @noreturn + */ +native SetUserFlagBits(client, flags); + +/** + * Returns client access flags. If the client is not an admin, + * the result is always 0. + * + * @param client Player's index. + * @return Flags + * @error Invalid client index, or client not connected. + */ +native GetUserFlagBits(client); + +/** + * Returns whether a user can target another user. + * This is a helper function for CanAdminTarget. + * + * @param client Player's index. + * @param target Target player's index. + * @return True if target is targettable by the player, false otherwise. + * @error Invalid or unconnected player indexers. + */ +native bool:CanUserTarget(client, target); + + +/** + * Creates a fake client. + * + * @param name Name to use. + * @return Client index on success, 0 otherwise. + */ +native CreateFakeClient(const String:name[]); + +/** + * Sets a convar value on a fake client. + * + * @param client Client index. + * @param cvar ConVar name. + * @param value ConVar value. + * @noreturn + * @error Invalid client index, client not connected, + * or client not a fake client. + */ +native SetFakeClientConVar(client, const String:cvar[], const String:value[]); \ No newline at end of file diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 8080c4e4..ae792fa0 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -36,6 +36,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -90,65 +91,6 @@ forward OnPluginEnd(); */ forward OnPluginPauseChange(bool:pause); -/** - * Called on client connection. - * - * @param client Player index. - * @param rejectmsg Buffer to store the rejection message when the connection is refused. - * @param maxlen Maximum number of characters for rejection buffer. - * @return True to validate client's connection, false to refuse it. - */ -forward bool:OnClientConnect(client, String:rejectmsg[], maxlen); - -/** - * Called when a client is entering to the game. - * - * @param client Player index. - * @noreturn - */ -forward OnClientPutInServer(client); - -/** - * Called when a client is disconnecting from the server. - * - * @param client Player index. - * @noreturn - */ -forward OnClientDisconnect(client); - -/** - * Called when a client is disconnected from the server. - * - * @param client Player index. - * @noreturn - */ -forward OnClientDisconnect_Post(client); - -/** - * Called when a client is sending a command. - * - * @param client Player index. - * @noreturn - */ -forward OnClientCommand(client, argCount); - -/** - * Called whenever the client's settings are changed. - * - * @param client Player index. - * @noreturn - */ -forward OnClientSettingsChanged(client); - -/** - * Called when a client receives a Steam ID. - * @note This is called by bots, but the ID will be "BOT" - * - * @param client Player index. - * @param auth Player auth string. - */ -forward OnClientAuthorized(client, const String:auth[]); - /** * Called before every server frame. Note that you should avoid * doing expensive computations here, and you should declare large @@ -163,182 +105,6 @@ forward OnGameFrame(); */ native Handle:GetMyHandle(); -/** - * Returns the maximum number of clients allowed on the server. - * - * @return Maximum number of clients allowed. - */ -native GetMaxClients(); - -/** - * Returns the client count put in the server. - * - * @param inGameOnly If false connecting players are also counted. - * @return Client count in the server. - */ -native GetClientCount(bool:inGameOnly=true); - -/** - * Returns the client's name. - * - * @param client Player index. - * @param name Buffer to store the client's name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. - */ -native bool:GetClientName(client, String:name[], maxlen); - -/** - * Retrieves a client's IP address. - * - * @param client Player index. - * @param name Buffer to store the client's ip address. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param remport Remove client's port from the ip string (true by default). - * @return True on success, false otherwise. - * @error If the client is not connected or the index is invalid. - */ -native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); - -/** - * Retrieves a client's authentication string (SteamID). - * - * @param client Player index. - * @param auth Buffer to store the client's auth string. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected or the index is invalid. - */ -native bool:GetClientAuthString(client, String:auth[], maxlen); - -/** - * Retrieves a client's user id, which is an index incremented for every client - * that joins the server. - * - * @param client Player index. - * @return User id of the client. - * @error If the client is not connected or the index is invalid. - */ -native GetClientUserId(client); - -/** - * Returns if a certain player is connected. - * - * @param client Player index. - * @return True if player is connected to the server, false otherwise. - */ -native bool:IsClientConnected(client); - -/** - * Returns if a certain player has entered the game. - * - * @param client Player index. - * @return True if player has entered the game, false otherwise. - */ -native bool:IsPlayerInGame(client); - -/** - * Returns if a certain player has been authenticated. - * - * @param client Player index. - * @return True if player has been authenticated, false otherwise. - */ -native bool:IsClientAuthorized(client); - -/** - * Returns if a certain player is a fake client. - * - * @param client Player index. - * @return True if player is a fake client, false otherwise. - */ -native bool:IsFakeClient(client); - -/** - * Retrieves values from client replicated keys. - * - * @param client Player's index. - * @param key Key string. - * @param value Buffer to store value. - * @param maxlen Maximum length of valve (UTF-8 safe). - * @return True on success, false otherwise. - * @error Invalid client index, or client not connected. - */ -native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); - -/** - * Sets a client's AdminId. - * - * @param client Player's index. - * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. - * @param temp True if the id should be freed on disconnect. - * @noreturn - * @error Invalid client index, client not connected, or bogus AdminId. - */ -native SetUserAdmin(client, AdminId:id, bool:temp=false); - -/** - * Retrieves a client's AdminId. - * - * @param client Player's index. - * @return AdminId of the client, or INVALID_ADMIN_ID if none. - * @error Invalid client index, or client not connected. - */ -native AdminId:GetUserAdmin(client); - -/** - * Sets access flags on a client. If the client is not an admin, - * a temporary, anonymous AdminId is given. - * - * @param client Player's index. - * @param ... Flags to set on the client. - * @noreturn - * @error Invalid client index, or client not connected. - */ -native AddUserFlags(client, {AdminFlag}:...); - -/** - * Removes flags from a client. If the client is not an admin, - * this has no effect. - * - * @param client Player's index. - * @param ... Flags to remove from the client. - * @noreturn - * @error Invalid client index, or client not connected. - */ -native RemoveUserFlags(client, {AdminFlag}:...); - -/** - * Sets access flags on a client using bits instead of flags. If the - * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. - * - * @param client Player's index. - * @param flags Bitstring of flags to set on client. - * @noreturn - */ -native SetUserFlagBits(client, flags); - -/** - * Returns client access flags. If the client is not an admin, - * the result is always 0. - * - * @param client Player's index. - * @return Flags - * @error Invalid client index, or client not connected. - */ -native GetUserFlagBits(client); - -/** - * Returns whether a user can target another user. - * This is a helper function for CanAdminTarget. - * - * @param client Player's index. - * @param target Target player's index. - * @return True if target is targettable by the player, false otherwise. - * @error Invalid or unconnected player indexers. - */ -native bool:CanUserTarget(client, target); - /** * Logs a generic message to the HL2 logs. * @@ -452,26 +218,6 @@ native Float:GetEngineTime(); */ native Float:GetGameTime(); -/** - * Creates a fake client. - * - * @param name Name to use. - * @return Client index on success, 0 otherwise. - */ -native CreateFakeClient(const String:name[]); - -/** - * Sets a convar value on a fake client. - * - * @param client Client index. - * @param cvar ConVar name. - * @param value ConVar value. - * @noreturn - * @error Invalid client index, client not connected, - * or client not a fake client. - */ -native SetFakeClientConVar(client, const String:cvar[], const String:value[]); - /** * Returns the game description from the mod. * From 3fec219433cabc97e09c47e1077c3b5072329ea9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Feb 2007 23:51:38 +0000 Subject: [PATCH 0521/1664] fixed bug where Plugin_Handled didn't block commands --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40552 --- core/CConCmdManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 2d19dad9..6ce12a22 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -268,7 +268,7 @@ void CConCmdManager::InternalDispatch() } pHook->pf->PushCell(m_CmdClient); pHook->pf->PushCell(args); - if (pHook->pf->Execute(&tempres) != SP_ERROR_NONE) + if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE) { if (tempres > result) { From 8d29b2c02ecf5b5948cb8469ae2fb8e9cc48c159 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 01:02:47 +0000 Subject: [PATCH 0522/1664] initial import of game compatibility backend --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40553 --- configs/gamedata/core.games.txt | 14 ++ core/CConCmdManager.cpp | 22 +- core/CGameConfigs.cpp | 363 ++++++++++++++++++++++++++++++++ core/CGameConfigs.h | 85 ++++++++ core/CHalfLife2.cpp | 111 ++++++++++ core/CHalfLife2.h | 49 +++++ core/msvc8/sourcemod_mm.vcproj | 18 +- public/IGameConfigs.h | 118 +++++++++++ 8 files changed, 768 insertions(+), 12 deletions(-) create mode 100644 configs/gamedata/core.games.txt create mode 100644 core/CGameConfigs.cpp create mode 100644 core/CGameConfigs.h create mode 100644 core/CHalfLife2.cpp create mode 100644 core/CHalfLife2.h create mode 100644 public/IGameConfigs.h diff --git a/configs/gamedata/core.games.txt b/configs/gamedata/core.games.txt new file mode 100644 index 00000000..910da115 --- /dev/null +++ b/configs/gamedata/core.games.txt @@ -0,0 +1,14 @@ +"Games" +{ + "*" + { + "Offsets" + { + "GetDataDescMap" + { + "windows" "13" + "linux" "14" + } + } + } +} diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 6ce12a22..4e56d4cc 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -1,15 +1,15 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "CConCmdManager.h" #include "sm_srvcmds.h" diff --git a/core/CGameConfigs.cpp b/core/CGameConfigs.cpp new file mode 100644 index 00000000..fa390991 --- /dev/null +++ b/core/CGameConfigs.cpp @@ -0,0 +1,363 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "CGameConfigs.h" +#include "CTextParsers.h" +#include "sm_stringutil.h" +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "CHalfLife2.h" +#include "CLogger.h" +#include "ShareSys.h" + +CGameConfigManager g_GameConfigs; +IGameConfig *g_pGameConf = NULL; +char g_mod[255]; + +#define PSTATE_NONE 0 +#define PSTATE_GAMES 1 +#define PSTATE_GAMEDEFS 2 +#define PSTATE_GAMEDEFS_OFFSETS 3 +#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4 + +#if defined PLATFORM_WINDOWS +#define PLATFORM_NAME "windows" +#elif defined PLATFORM_LINUX +#define PLATFORM_NAME "linux" +#endif + +CGameConfig::CGameConfig(const char *file) +{ + m_pFile = sm_strdup(file); + m_pOffsets = sm_trie_create(); + m_pProps = sm_trie_create(); +} + +CGameConfig::~CGameConfig() +{ + sm_trie_destroy(m_pOffsets); + sm_trie_destroy(m_pProps); + delete [] m_pFile; +} + +SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes) +{ + if (m_IgnoreLevel) + { + m_IgnoreLevel++; + return SMCParse_Continue; + } + switch (m_ParseState) + { + case PSTATE_NONE: + { + if (strcmp(name, "Games") == 0) + { + m_ParseState = PSTATE_GAMES; + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMES: + { + if ((strcmp(name, "*") == 0) + || (strcmp(name, g_mod) == 0)) + { + m_ParseState = PSTATE_GAMEDEFS; + strncopy(m_mod, name, sizeof(m_mod)); + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMEDEFS: + { + if (strcmp(name, "Offsets") == 0) + { + m_ParseState = PSTATE_GAMEDEFS_OFFSETS; + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMEDEFS_OFFSETS: + { + m_prop[0] = '\0'; + m_class[0] = '\0'; + strncopy(m_offset, name, sizeof(m_offset)); + m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; + break; + } + /* No sub-sections allowed: + case PSTATE_GAMEDEFS_OFFSETS_OFFSET: + */ + default: + { + /* If we don't know what we got, start ignoring */ + m_IgnoreLevel++; + break; + } + } + + return SMCParse_Continue; +} + +SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) +{ + if (m_IgnoreLevel) + { + return SMCParse_Continue; + } + + if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET) + { + if (strcmp(key, "class") == 0) + { + strncopy(m_class, value, sizeof(m_class)); + } else if (strcmp(key, "prop") == 0) { + strncopy(m_prop, value, sizeof(m_prop)); + } else if (strcmp(key, PLATFORM_NAME) == 0) { + int val = atoi(value); + sm_trie_insert(m_pOffsets, m_offset, (void *)val); + } + } + + return SMCParse_Continue; +} + +SMCParseResult CGameConfig::ReadSMC_LeavingSection() +{ + if (m_IgnoreLevel) + { + m_IgnoreLevel--; + return SMCParse_Continue; + } + + switch (m_ParseState) + { + case PSTATE_GAMES: + { + m_ParseState = PSTATE_NONE; + break; + } + case PSTATE_GAMEDEFS: + { + m_ParseState = PSTATE_GAMES; + break; + } + case PSTATE_GAMEDEFS_OFFSETS: + { + m_ParseState = PSTATE_GAMEDEFS; + break; + } + case PSTATE_GAMEDEFS_OFFSETS_OFFSET: + { + /* Parse the offset... */ + if (m_class[0] != '\0' + && m_prop[0] != '\0') + { + SendProp *pProp = g_HL2.FindInSendTable(m_class, m_prop); + if (pProp) + { + int val = pProp->GetOffset(); + sm_trie_insert(m_pOffsets, m_offset, (void *)val); + sm_trie_insert(m_pProps, m_offset, pProp); + } else { + /* Check if it's a non-default game and no offsets exist */ + if ((strcmp(m_mod, "*") != 0) + && (!sm_trie_retrieve(m_pOffsets, m_offset, NULL))) + { + g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", + m_class, + m_prop, + m_pFile, + m_mod); + } + } + } + m_ParseState = PSTATE_GAMEDEFS_OFFSETS; + break; + } + } + + return SMCParse_Continue; +} + +bool CGameConfig::Reparse(char *error, size_t maxlength) +{ + SMCParseError err; + + char path[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile); + + /* Initialize states */ + m_IgnoreLevel = 0; + m_ParseState = PSTATE_NONE; + sm_trie_clear(m_pOffsets); + + if ((err=g_TextParser.ParseFile_SMC(path, this, NULL, NULL)) + != SMCParse_Okay) + { + if (error && (err != SMCParse_Custom)) + { + const char *str = g_TextParser.GetSMCErrorString(err); + snprintf(error, maxlength, "%s", err); + } + return false; + } + + return true; +} + +bool CGameConfig::GetOffset(const char *key, int *value) +{ + void *obj; + + if (!sm_trie_retrieve(m_pOffsets, key, &obj)) + { + return false; + } + + *value = (int)obj; + + return true; +} + +const char *CGameConfig::GetKeyValue(const char *key) +{ + /* :TODO: implement */ + return false; +} + +SendProp *CGameConfig::GetSendProp(const char *key) +{ + SendProp *pProp; + + if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp)) + { + return NULL; + } + + return pProp; +} + +void CGameConfig::IncRefCount() +{ + m_RefCount++; +} + +unsigned int CGameConfig::DecRefCount() +{ + m_RefCount--; + return m_RefCount; +} + +CGameConfigManager::CGameConfigManager() +{ + m_pLookup = sm_trie_create(); +} + +CGameConfigManager::~CGameConfigManager() +{ + sm_trie_destroy(m_pLookup); +} + +void CGameConfigManager::OnSourceModStartup(bool late) +{ + LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); + + char mod[255]; + engine->GetGameDir(mod, sizeof(mod)); + + g_mod[0] = '\0'; + size_t len = strlen(mod); + for (size_t i=len-1; i>=0 && iReparse(error, sizeof(error))) + { + /* :TODO: log */ + } + + g_ShareSys.AddInterface(NULL, this); +} + +void CGameConfigManager::OnSourceModAllShutdown() +{ + CloseGameConfigFile(g_pGameConf); +} + +bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) +{ + CGameConfig *pConfig; + + if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig)) + { + pConfig->IncRefCount(); + *_pConfig = pConfig; + return true; + } + + pConfig = new CGameConfig(file); + + /* :HACKHACK: Don't parse the main config file */ + bool retval = true; + if (_pConfig != &g_pGameConf) + { + retval = pConfig->Reparse(error, maxlength); + } + + m_cfgs.push_back(pConfig); + sm_trie_insert(m_pLookup, file, pConfig); + + pConfig->IncRefCount(); + + *_pConfig = pConfig; + + return retval; +} + +void CGameConfigManager::CloseGameConfigFile(IGameConfig *cfg) +{ + CGameConfig *pConfig = (CGameConfig *)cfg; + + if (pConfig->DecRefCount() == 0) + { + delete pConfig; + } +} diff --git a/core/CGameConfigs.h b/core/CGameConfigs.h new file mode 100644 index 00000000..dcfb994f --- /dev/null +++ b/core/CGameConfigs.h @@ -0,0 +1,85 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ +#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ + +#include +#include +#include +#include "sm_trie.h" +#include "sm_globals.h" + +using namespace SourceMod; +using namespace SourceHook; + +class SendProp; + +class CGameConfig : + public ITextListener_SMC, + public IGameConfig +{ +public: + CGameConfig(const char *file); + ~CGameConfig(); +public: + bool Reparse(char *error, size_t maxlength); +public: //ITextListener_SMC + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); + SMCParseResult ReadSMC_LeavingSection(); +public: //IGameConfig + const char *GetKeyValue(const char *key); + bool GetOffset(const char *key, int *value); + SendProp *GetSendProp(const char *key); +public: + void IncRefCount(); + unsigned int DecRefCount(); +private: + char *m_pFile; + Trie *m_pOffsets; + Trie *m_pProps; + unsigned int m_RefCount; + /* Parse states */ + int m_ParseState; + unsigned int m_IgnoreLevel; + char m_class[64]; + char m_prop[64]; + char m_offset[64]; + char m_mod[255]; +}; + +class CGameConfigManager : + public IGameConfigManager, + public SMGlobalClass +{ +public: + CGameConfigManager(); + ~CGameConfigManager(); +public: //IGameConfigManager + bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength); + void CloseGameConfigFile(IGameConfig *cfg); +public: //SMGlobalClass + void OnSourceModStartup(bool late); + void OnSourceModAllInitialized(); + void OnSourceModAllShutdown(); +private: + List m_cfgs; + Trie *m_pLookup; +}; + +extern CGameConfigManager g_GameConfigs; +extern IGameConfig *g_pGameConf; + +#endif //_INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ diff --git a/core/CHalfLife2.cpp b/core/CHalfLife2.cpp new file mode 100644 index 00000000..2a724b3f --- /dev/null +++ b/core/CHalfLife2.cpp @@ -0,0 +1,111 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "CHalfLife2.h" +#include "sourcemm_api.h" + +CHalfLife2 g_HL2; + +CHalfLife2::CHalfLife2() +{ + m_pClasses = sm_trie_create(); +} + +CHalfLife2::~CHalfLife2() +{ + sm_trie_destroy(m_pClasses); + + List::iterator iter; + DataTableInfo *pInfo; + for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++) + { + pInfo = (*iter); + sm_trie_destroy(pInfo->lookup); + delete pInfo; + } + + m_Tables.clear(); +} + +#if 0 +void CHalfLife2::OnSourceModStartup(bool late) +{ +} + +void CHalfLife2::OnSourceModAllShutdown() +{ +} +#endif + +SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name) +{ + const char *pname; + int props = pTable->GetNumProps(); + SendProp *prop; + + for (int i=0; iGetProp(i); + pname = prop->GetName(); + if (pname && strcmp(name, pname) == 0) + { + return prop; + } + if (prop->GetDataTable()) + { + if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL) + { + return prop; + } + } + } + + return NULL; +} + +SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) +{ + DataTableInfo *pInfo = NULL; + + if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo)) + { + ServerClass *sc = gamedll->GetAllServerClasses(); + while (sc) + { + if (strcmp(classname, sc->GetName()) == 0) + { + pInfo = new DataTableInfo; + pInfo->lookup = sm_trie_create(); + pInfo->sc = sc; + sm_trie_insert(m_pClasses, classname, pInfo); + break; + } + sc = sc->m_pNext; + } + if (!pInfo) + { + return NULL; + } + } + + SendProp *pProp; + if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp)) + { + if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL) + { + sm_trie_insert(pInfo->lookup, offset, pProp); + } + } + + return pProp; +} diff --git a/core/CHalfLife2.h b/core/CHalfLife2.h new file mode 100644 index 00000000..f540d670 --- /dev/null +++ b/core/CHalfLife2.h @@ -0,0 +1,49 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CHALFLIFE2_H_ +#define _INCLUDE_SOURCEMOD_CHALFLIFE2_H_ + +#include +#include "sm_trie.h" +#include "sm_globals.h" +#include "dt_send.h" +#include "server_class.h" + +using namespace SourceHook; + +struct DataTableInfo +{ + ServerClass *sc; + Trie *lookup; +}; + +class CHalfLife2 +{ +public: + CHalfLife2(); + ~CHalfLife2(); +public: + /*void OnSourceModStartup(bool late); + void OnSourceModAllShutdown();*/ +public: + SendProp *FindInSendTable(const char *classname, const char *offset); +public: + Trie *m_pClasses; + List m_Tables; +}; + +extern CHalfLife2 g_HL2; + +#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 345569a5..11888d8b 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -199,6 +199,14 @@ RelativePath="..\CDbgReporter.cpp" > + + + + @@ -274,7 +282,11 @@ > + + + + diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h new file mode 100644 index 00000000..8823c53f --- /dev/null +++ b/public/IGameConfigs.h @@ -0,0 +1,118 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. +* All rights reserved. +* =============================================================== +* +* This file is part of the SourceMod/SourcePawn SDK. This file may only be +* used or modified under the Terms and Conditions of its License Agreement, +* which is found in public/licenses/LICENSE.txt. As of this notice, derivative +* works must be licensed under the GNU General Public License (version 2 or +* greater). A copy of the GPL is included under public/licenses/GPL.txt. +* +* To view the latest information, see: http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ + +#include + +/** + * @file IGameConfig.h + * @brief Abstracts game private data configuration. + */ + +#define SMINTERFACE_GAMECONFIG_NAME "IGameConfigManager" +#define SMINTERFACE_GAMECONFIG_VERSION 1 + +class SendProp; + +namespace SourceMod +{ + /** + * @brief Details the property types. + */ + enum PropType + { + PropType_Unknown = 0, /**< Property type is not known */ + PropType_Send = 1, /**< Property type is a networkable property */ + PropType_Data = 2, /**< Property type is a data/save property */ + }; + + enum PropError + { + PropError_Okay = 0, /**< No error */ + PropError_NotSet, /**< Property is not set in the config file */ + PropError_NotFound, /**< Property was not found in the game */ + }; + + #define INVALID_PROPERTY_VALUE -1 /**< Property value is not valid */ + + /** + * @brief Describes a game private data config file + */ + class IGameConfig + { + public: + /** + * @brief Returns an offset value. + * + * @param key Key to retrieve from the offset section. + * @param value Pointer to store the offset value in. + * @return True if found, false otherwise. + */ + virtual bool GetOffset(const char *key, int *value) =0; + + /** + * @brief Returns information about a property. + * + * @param key Key to retrieve from the property section. + * @param value Pointer to store the offset value. Will be -1 on failure. + * @return A PropError error code. + */ + virtual SendProp *GetSendProp(const char *key) =0; + }; + + /** + * @brief Manages game config files + */ + class IGameConfigManager : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_GAMECONFIG_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_GAMECONFIG_VERSION; + } + public: + /** + * @brief Loads or finds an already loaded game config file. + * + * @param file File to load. The path must be relative to the 'gamedata' + * folder under the config folder, and the extension should be ommitted. + * @param pConfig Pointer to store the game config pointer. Pointer will be valid even on failure. + * @param error Optional error message buffer. + * @param maxlength Maximum length of the error buffer. + * @return True on success, false if the file failed. + */ + virtual bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength) =0; + + /** + * @brief Closes an IGameConfig pointer. Since a file can be loaded more than once, + * the file will not actually be removed from memory until it is closed once for each + * call to LoadGameConfigfile(). + * + * @param cfg Pointer to the IGameConfig to close. + */ + virtual void CloseGameConfigFile(IGameConfig *cfg) =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ From d893af2ea4a72c2c76e6a6bac1708e04f9a7754c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 03:58:18 +0000 Subject: [PATCH 0523/1664] added keys to game config files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40554 --- core/CGameConfigs.cpp | 26 +++++++++++++++++++++++--- core/CGameConfigs.h | 3 +++ public/IGameConfigs.h | 10 +++++++++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/core/CGameConfigs.cpp b/core/CGameConfigs.cpp index fa390991..31daf969 100644 --- a/core/CGameConfigs.cpp +++ b/core/CGameConfigs.cpp @@ -31,6 +31,7 @@ char g_mod[255]; #define PSTATE_GAMEDEFS 2 #define PSTATE_GAMEDEFS_OFFSETS 3 #define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4 +#define PSTATE_GAMEDEFS_KEYS 5 #if defined PLATFORM_WINDOWS #define PLATFORM_NAME "windows" @@ -43,13 +44,17 @@ CGameConfig::CGameConfig(const char *file) m_pFile = sm_strdup(file); m_pOffsets = sm_trie_create(); m_pProps = sm_trie_create(); + m_pKeys = sm_trie_create(); + m_pStrings = new BaseStringTable(512); } CGameConfig::~CGameConfig() { sm_trie_destroy(m_pOffsets); sm_trie_destroy(m_pProps); + sm_trie_destroy(m_pKeys); delete [] m_pFile; + delete m_pStrings; } SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes) @@ -88,6 +93,8 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes if (strcmp(name, "Offsets") == 0) { m_ParseState = PSTATE_GAMEDEFS_OFFSETS; + } else if (strcmp(name, "Keys") == 0) { + m_ParseState = PSTATE_GAMEDEFS_KEYS; } else { m_IgnoreLevel++; } @@ -103,6 +110,7 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes } /* No sub-sections allowed: case PSTATE_GAMEDEFS_OFFSETS_OFFSET: + case PSTATE_GAMEDEFS_KEYS: */ default: { @@ -133,6 +141,9 @@ SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value, int val = atoi(value); sm_trie_insert(m_pOffsets, m_offset, (void *)val); } + } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) { + int id = m_pStrings->AddString(value); + sm_trie_insert(m_pKeys, key, (void *)id); } return SMCParse_Continue; @@ -158,6 +169,7 @@ SMCParseResult CGameConfig::ReadSMC_LeavingSection() m_ParseState = PSTATE_GAMES; break; } + case PSTATE_GAMEDEFS_KEYS: case PSTATE_GAMEDEFS_OFFSETS: { m_ParseState = PSTATE_GAMEDEFS; @@ -203,10 +215,14 @@ bool CGameConfig::Reparse(char *error, size_t maxlength) char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile); - /* Initialize states */ + /* Initialize parse states */ m_IgnoreLevel = 0; m_ParseState = PSTATE_NONE; + /* Reset cached data */ + m_pStrings->Reset(); sm_trie_clear(m_pOffsets); + sm_trie_clear(m_pProps); + sm_trie_clear(m_pKeys); if ((err=g_TextParser.ParseFile_SMC(path, this, NULL, NULL)) != SMCParse_Okay) @@ -238,8 +254,12 @@ bool CGameConfig::GetOffset(const char *key, int *value) const char *CGameConfig::GetKeyValue(const char *key) { - /* :TODO: implement */ - return false; + void *obj; + if (!sm_trie_retrieve(m_pKeys, key, &obj)) + { + return NULL; + } + return m_pStrings->GetString((int)obj); } SendProp *CGameConfig::GetSendProp(const char *key) diff --git a/core/CGameConfigs.h b/core/CGameConfigs.h index dcfb994f..5b55cfb6 100644 --- a/core/CGameConfigs.h +++ b/core/CGameConfigs.h @@ -20,6 +20,7 @@ #include #include "sm_trie.h" #include "sm_globals.h" +#include "sm_memtable.h" using namespace SourceMod; using namespace SourceHook; @@ -47,9 +48,11 @@ public: void IncRefCount(); unsigned int DecRefCount(); private: + BaseStringTable *m_pStrings; char *m_pFile; Trie *m_pOffsets; Trie *m_pProps; + Trie *m_pKeys; unsigned int m_RefCount; /* Parse states */ int m_ParseState; diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h index 8823c53f..988f2824 100644 --- a/public/IGameConfigs.h +++ b/public/IGameConfigs.h @@ -68,13 +68,21 @@ namespace SourceMod virtual bool GetOffset(const char *key, int *value) =0; /** - * @brief Returns information about a property. + * @brief Returns information about a dynamic offset. * * @param key Key to retrieve from the property section. * @param value Pointer to store the offset value. Will be -1 on failure. * @return A PropError error code. */ virtual SendProp *GetSendProp(const char *key) =0; + + /** + * @brief Returns the value of a key from the "Keys" section. + * + * @param key Key to retrieve from the Keys section. + * @return String containing the value, or NULL if not found. + */ + virtual const char *GetKeyValue(const char *key) =0; }; /** From 124f9ba0490951685036b3d6ec09c2cc3d61f08a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 04:18:23 +0000 Subject: [PATCH 0524/1664] slight reorganization for future expansion --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40555 --- core/CHalfLife2.cpp | 25 ++++++++++++++++++++++++- core/CHalfLife2.h | 5 ++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/core/CHalfLife2.cpp b/core/CHalfLife2.cpp index 2a724b3f..ca07c45f 100644 --- a/core/CHalfLife2.cpp +++ b/core/CHalfLife2.cpp @@ -73,7 +73,18 @@ SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name) return NULL; } -SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) +ServerClass *CHalfLife2::FindServerClass(const char *classname) +{ + DataTableInfo *pInfo = _FindServerClass(classname); + if (!pInfo) + { + return NULL; + } + + return pInfo->sc; +} + +DataTableInfo *CHalfLife2::_FindServerClass(const char *classname) { DataTableInfo *pInfo = NULL; @@ -98,6 +109,18 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) } } + return pInfo; +} + +SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) +{ + DataTableInfo *pInfo = _FindServerClass(classname); + + if (!pInfo) + { + return NULL; + } + SendProp *pProp; if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp)) { diff --git a/core/CHalfLife2.h b/core/CHalfLife2.h index f540d670..3f03ff99 100644 --- a/core/CHalfLife2.h +++ b/core/CHalfLife2.h @@ -39,7 +39,10 @@ public: void OnSourceModAllShutdown();*/ public: SendProp *FindInSendTable(const char *classname, const char *offset); -public: + ServerClass *FindServerClass(const char *classname); +private: + DataTableInfo *_FindServerClass(const char *classname); +private: Trie *m_pClasses; List m_Tables; }; From 27f239b639f2a020f898bed6074a993e02d65308 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 04:41:41 +0000 Subject: [PATCH 0525/1664] fixed a codegen bug in the compiler (amb53) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40556 --- sourcepawn/compiler/sc3.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 1828a47b..de5620ad 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1266,7 +1266,7 @@ static int hier14(value *lval1) * (a() ? return_array() : return_array()) ? return_array() : return_array() */ -void dynarray_from_heaplist(memuse_list_t *heap) +long dynarray_from_heaplist(memuse_list_t *heap) { memuse_t *use=heap->head; memuse_t *tmp; @@ -1281,6 +1281,7 @@ void dynarray_from_heaplist(memuse_list_t *heap) free(heap); if (total) setheap_save(-total*sizeof(cell)); + return total; } static int hier13(value *lval) @@ -1291,6 +1292,7 @@ static int hier13(value *lval) int flab2=getlabel(); value lval2={0}; int array1,array2; + long total1,total2; memuse_list_t *heap; pushheaplist(); @@ -1309,7 +1311,7 @@ static int hier13(value *lval) ldconst(lval->constval,sPRI); sc_allowtags=(short)POPSTK_I(); /* restore */ heap=popsaveheaplist(); - dynarray_from_heaplist(heap); + total1=dynarray_from_heaplist(heap); pushheaplist(); jumplabel(flab2); setlabel(flab1); @@ -1331,9 +1333,9 @@ static int hier13(value *lval) if (!matchtag(lval->tag,lval2.tag,FALSE)) error(213); /* tagname mismatch ('true' and 'false' expressions) */ heap=popsaveheaplist(); - dynarray_from_heaplist(heap); + total2=dynarray_from_heaplist(heap); setlabel(flab2); - if (array1 && array2) { + if ((array1 && array2) && (total1 && total2)) { markheap(MEMUSE_DYNAMIC, 0); } if (lval->ident==iARRAY) From f7df18f6fdc8edf49bf240f4c2005a2f088c76a3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 16:35:06 +0000 Subject: [PATCH 0526/1664] fixed crash when gamedata is missing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40557 --- core/CGameConfigs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CGameConfigs.cpp b/core/CGameConfigs.cpp index 31daf969..048704cc 100644 --- a/core/CGameConfigs.cpp +++ b/core/CGameConfigs.cpp @@ -230,7 +230,7 @@ bool CGameConfig::Reparse(char *error, size_t maxlength) if (error && (err != SMCParse_Custom)) { const char *str = g_TextParser.GetSMCErrorString(err); - snprintf(error, maxlength, "%s", err); + snprintf(error, maxlength, "%s", str); } return false; } From 7ebe3f33cd1ae00c2c102dbfc69aea43b63c126e Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 1 Mar 2007 22:49:08 +0000 Subject: [PATCH 0527/1664] initial implementation of message hooks --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40558 --- core/CMsgIdPool.h | 63 ------- core/CMsgListenerWrapper.h | 144 ++++++++++++++ core/CUserMessages.cpp | 314 +++++++++++++++++++++++++++++++ core/CUserMessages.h | 72 +++++++ core/CellRecipientFilter.h | 7 +- core/msvc8/sourcemod_mm.vcproj | 16 +- core/smn_usermsgs.cpp | 269 +++++++++++++++++++------- plugins/include/usermessages.inc | 40 ++-- public/IUserMessages.h | 16 +- 9 files changed, 770 insertions(+), 171 deletions(-) delete mode 100644 core/CMsgIdPool.h create mode 100644 core/CMsgListenerWrapper.h create mode 100644 core/CUserMessages.cpp create mode 100644 core/CUserMessages.h diff --git a/core/CMsgIdPool.h b/core/CMsgIdPool.h deleted file mode 100644 index de84ce4d..00000000 --- a/core/CMsgIdPool.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ - -#ifndef _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ -#define _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ - -#include "sm_trie.h" -#include "sourcemm_api.h" - -#define INVALID_MESSAGE_ID -1 - -class CMessageIdPool -{ -public: - CMessageIdPool() - { - m_Names = sm_trie_create(); - } - ~CMessageIdPool() - { - sm_trie_destroy(m_Names); - } -public: - int GetMessageId(const char *name) - { - int msgid; - if (!sm_trie_retrieve(m_Names, name, reinterpret_cast(&msgid))) - { - char buf[255]; - int dummy; - msgid = 0; - - while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy)) - { - if (strcmp(name, buf) == 0) - { - sm_trie_insert(m_Names, name, reinterpret_cast(msgid)); - return msgid; - } - msgid++; - } - - return INVALID_MESSAGE_ID; - } - - return msgid; - } -private: - Trie *m_Names; -}; - -#endif //_INCLUDE_SOURCEMOD_CMSGIDPOOL_H_ diff --git a/core/CMsgListenerWrapper.h b/core/CMsgListenerWrapper.h new file mode 100644 index 00000000..254d24b9 --- /dev/null +++ b/core/CMsgListenerWrapper.h @@ -0,0 +1,144 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ +#define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ + +extern int g_MsgPlayers[256]; + +class MsgListenerWrapper : public IUserMessageListener +{ +public: + void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); + bool IsInterceptHook() const; + int GetMessageId() const; + IPluginFunction *GetHookedFunction() const; + IPluginFunction *GetNotifyFunction() const; +public: //IUserMessageListener + void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); + ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); + void OnUserMessageSent(int msg_id); +private: + size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter); +private: + IPluginFunction *m_Hook; + IPluginFunction *m_Intercept; + IPluginFunction *m_Notify; + bool m_IsInterceptHook; + int m_MsgId; +}; + +inline size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter) +{ + size_t size = static_cast(pFilter->GetRecipientCount()); + + for (size_t i=0; iGetRecipientIndex(i); + } + + return size; +} + +inline bool MsgListenerWrapper::IsInterceptHook() const +{ + return m_IsInterceptHook; +} + +inline int MsgListenerWrapper::GetMessageId() const +{ + return m_MsgId; +} + +inline IPluginFunction *MsgListenerWrapper::GetHookedFunction() const +{ + if (m_Hook) + { + return m_Hook; + } else { + return m_Intercept; + } +} + +inline IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const +{ + return m_Notify; +} + +inline void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept) +{ + if (intercept) + { + m_Intercept = hook; + m_Hook = NULL; + } else { + m_Hook = hook; + m_Intercept = NULL; + } + + if (notify) + { + m_Notify = notify; + } else { + m_Notify = NULL; + } + + m_MsgId = msgid; + m_IsInterceptHook = intercept; +} + +inline void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +{ + cell_t res; + size_t size = PreparePlArray(g_MsgPlayers, pFilter); + + m_Hook->PushCell(msg_id); + m_Hook->PushCell(0); //:TODO: push handle! + m_Hook->PushArray(g_MsgPlayers, size, NULL); + m_Hook->PushCell(size); + m_Hook->PushCell(pFilter->IsReliable()); + m_Hook->PushCell(pFilter->IsInitMessage()); + m_Hook->Execute(&res); +} + +inline ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +{ + cell_t res = static_cast(Pl_Continue); + size_t size = PreparePlArray(g_MsgPlayers, pFilter); + + m_Intercept->PushCell(msg_id); + m_Intercept->PushCell(0); //:TODO: push handle! + m_Intercept->PushArray(g_MsgPlayers, size, NULL); + m_Intercept->PushCell(size); + m_Intercept->PushCell(pFilter->IsReliable()); + m_Intercept->PushCell(pFilter->IsInitMessage()); + m_Intercept->Execute(&res); + + return static_cast(res); +} + +inline void MsgListenerWrapper::OnUserMessageSent(int msg_id) +{ + cell_t res; + + if (!m_Notify) + { + return; + } + + m_Notify->PushCell(msg_id); + m_Notify->Execute(&res); +} + +#endif //_INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ diff --git a/core/CUserMessages.cpp b/core/CUserMessages.cpp new file mode 100644 index 00000000..3048faa3 --- /dev/null +++ b/core/CUserMessages.cpp @@ -0,0 +1,314 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "CUserMessages.h" + +CUserMessages g_UserMsgs; + +SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); +SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); + +CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500) +{ + m_Names = sm_trie_create(); + m_HookCount = 0; + m_InExec = false; + m_InHook = false; + m_CurFlags = 0; + m_CurId = INVALID_MESSAGE_ID; +} + +CUserMessages::~CUserMessages() +{ + sm_trie_destroy(m_Names); +} + +void CUserMessages::OnSourceModAllShutdown() +{ + if (m_HookCount) + { + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + } + m_HookCount = 0; +} + +int CUserMessages::GetMessageIndex(const char *msg) +{ + int msgid; + if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid))) + { + char buf[255]; + int dummy; + msgid = 0; + + while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy)) + { + if (strcmp(msg, buf) == 0) + { + sm_trie_insert(m_Names, msg, reinterpret_cast(msgid)); + return msgid; + } + msgid++; + } + + return INVALID_MESSAGE_ID; + } + + return msgid; +} + +bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) +{ + bf_write *buffer; + + if (m_InExec) + { + return NULL; + } + if (msg_id < 0 || msg_id >= 255) + { + return NULL; + } + + m_CellRecFilter.SetRecipientPtr(players, playersNum); + + m_CurFlags = flags; + if (m_CurFlags & USERMSG_INITMSG) + { + m_CellRecFilter.SetInitMessage(true); + } + if (m_CurFlags & USERMSG_RELIABLE) + { + m_CellRecFilter.SetReliable(true); + } + + m_InExec = true; + + if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) + { + buffer = engine->UserMessageBegin(static_cast(&m_CellRecFilter), msg_id); + } else { + buffer = ENGINE_CALL(UserMessageBegin)(static_cast(&m_CellRecFilter), msg_id); + } + + return buffer; +} + +bool CUserMessages::EndMessage() +{ + if (!m_InExec) + { + return false; + } + + if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) + { + engine->MessageEnd(); + } else { + ENGINE_CALL(MessageEnd)(); + } + + m_InExec = false; + m_CurFlags = 0; + m_CellRecFilter.ResetFilter(); + + return true; +} + +bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) +{ + if (msg_id < 0 || msg_id >= 255) + { + return false; + } + + if (!m_HookCount++) + { + SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + } + + if (intercept) + { + m_msgIntercepts[msg_id].push_back(pListener); + } else { + m_msgHooks[msg_id].push_back(pListener); + } + + return true; +} + +bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) +{ + //:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess + List *lst; + IUserMessageListener *listener; + MsgIter iter; + bool deleted = false; + + if (msg_id < 0 || msg_id >= 255) + { + return false; + } + + lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id]; + for (iter=lst->begin(); iter!=lst->end(); iter++) + { + listener = (*iter); + if (listener == pListener) + { + lst->erase(iter); + deleted = true; + break; + } + } + + if (deleted && !(--m_HookCount)) + { + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + } + + return (deleted) ? true : false; +} + +bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type) +{ + bool is_intercept_empty = m_msgIntercepts[msg_type].empty(); + bool is_hook_empty = m_msgHooks[msg_type].empty(); + + if (is_intercept_empty && is_hook_empty) + { + m_InHook = false; + RETURN_META_VALUE(MRES_IGNORED, NULL); + } + + if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL)) + { + m_InHook = false; + RETURN_META_VALUE(MRES_IGNORED, NULL); + } + + m_CurId = msg_type; + m_CurRecFilter = filter; + m_InterceptBuffer.Reset(); + m_InHook = true; + + if (!is_intercept_empty) + { + RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer); + } + + RETURN_META_VALUE(MRES_IGNORED, NULL); +} + +bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type) +{ + if (!m_InHook) + { + RETURN_META_VALUE(MRES_IGNORED, NULL); + } + + m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *); + + RETURN_META_VALUE(MRES_IGNORED, NULL); +} + +void CUserMessages::OnMessageEnd_Post() +{ + if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE)) + { + RETURN_META(MRES_IGNORED); + } + + List *lst; + IUserMessageListener *listener; + MsgIter iter; + + lst = &m_msgIntercepts[m_CurId]; + for (iter=lst->begin(); iter!=lst->end(); iter++) + { + listener = (*iter); + listener->OnUserMessageSent(m_CurId); + } + + lst = &m_msgHooks[m_CurId]; + for (iter=lst->begin(); iter!=lst->end(); iter++) + { + listener = (*iter); + listener->OnUserMessageSent(m_CurId); + } +} + +void CUserMessages::OnMessageEnd_Pre() +{ + if (!m_InHook) + { + RETURN_META(MRES_IGNORED); + } + + List *lst; + IUserMessageListener *listener; + bf_write *engine_bfw; + MsgIter iter; + ResultType res; + bool intercepted = false; + bool handled = false; + + lst = &m_msgIntercepts[m_CurId]; + for (iter=lst->begin(); iter!=lst->end(); iter++) + { + listener = (*iter); + res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter); + if (res == Pl_Stop) + { + goto supercede; + } else if (res == Pl_Handled) { + handled = true; + } + intercepted = true; + } + + if (handled) + { + goto supercede; + } + + if (intercepted) + { + engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId); + m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten()); + engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten()); + ENGINE_CALL(MessageEnd)(); + goto supercede; + } + + lst = &m_msgHooks[m_CurId]; + for (iter=lst->begin(); iter!=lst->end(); iter++) + { + listener = (*iter); + listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter); + } + + RETURN_META(MRES_IGNORED); +supercede: + RETURN_META(MRES_SUPERCEDE); +} diff --git a/core/CUserMessages.h b/core/CUserMessages.h new file mode 100644 index 00000000..c995e886 --- /dev/null +++ b/core/CUserMessages.h @@ -0,0 +1,72 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ +#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ + +#include "sm_globals.h" +#include +#include +#include "sourcemm_api.h" +#include "sm_trie.h" +#include "CellRecipientFilter.h" + +using namespace SourceHook; +using namespace SourceMod; + +#define INVALID_MESSAGE_ID -1 + +typedef List::iterator MsgIter; + +class CUserMessages : + public IUserMessages, + public SMGlobalClass +{ +public: + CUserMessages(); + ~CUserMessages(); +public: //SMGlobalClass + void OnSourceModAllShutdown(); +public: //IUserMessages + int GetMessageIndex(const char *msg); + bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); + bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); + bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags); + bool EndMessage(); +public: + bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type); + bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type); + void OnMessageEnd_Pre(); + void OnMessageEnd_Post(); +private: + List m_msgHooks[255]; + List m_msgIntercepts[255]; + unsigned char m_pBase[2500]; + IRecipientFilter *m_CurRecFilter; + bf_write m_InterceptBuffer; + bf_write *m_OrigBuffer; + bf_read m_ReadBuffer; + size_t m_HookCount; + bool m_InHook; + + Trie *m_Names; + CellRecipientFilter m_CellRecFilter; + bool m_InExec; + int m_CurFlags; + int m_CurId; +}; + +extern CUserMessages g_UserMsgs; + +#endif //_INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ diff --git a/core/CellRecipientFilter.h b/core/CellRecipientFilter.h index 1a082088..243855c2 100644 --- a/core/CellRecipientFilter.h +++ b/core/CellRecipientFilter.h @@ -21,7 +21,7 @@ class CellRecipientFilter : public IRecipientFilter { public: - CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0), m_CellRecipients(NULL) {} + CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0) {} ~CellRecipientFilter() {} public: //IRecipientFilter bool IsReliable() const; @@ -34,10 +34,10 @@ public: void SetInitMessage(bool isinitmsg); void ResetFilter(); private: + cell_t m_CellRecipients[255]; bool m_Reliable; bool m_InitMessage; size_t m_Size; - cell_t *m_CellRecipients; }; inline void CellRecipientFilter::ResetFilter() @@ -45,7 +45,6 @@ inline void CellRecipientFilter::ResetFilter() m_Reliable = false; m_InitMessage = false; m_Size = 0; - m_CellRecipients = NULL; } inline bool CellRecipientFilter::IsReliable() const @@ -84,7 +83,7 @@ inline void CellRecipientFilter::SetReliable(bool isreliable) inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count) { - m_CellRecipients = ptr; + memcpy(m_CellRecipients, ptr, count * sizeof(cell_t)); m_Size = count; } diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 11888d8b..d8fce4ff 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -294,7 +298,7 @@ > + + @@ -409,6 +417,10 @@ RelativePath="..\..\public\ITextParsers.h" > + + m_FreeListeners; }; +void UsrMessageNatives::OnSourceModAllInitialized() +{ + g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_PluginSys.AddPluginsListener(this); +} + +void UsrMessageNatives::OnSourceModShutdown() +{ + g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent); + g_PluginSys.RemovePluginsListener(this); + g_WrBitBufType = 0; +} +void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) +{ +} + +void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin) +{ + List *wrapper_list; + + if (plugin->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list), true)) + { + List::iterator iter; + MsgListenerWrapper *listener; + + for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) + { + listener = (*iter); + if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook())) + { + m_FreeListeners.push(listener); + } + } + + delete wrapper_list; + } +} + +MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx) +{ + MsgListenerWrapper *listener_wrapper; + + if (m_FreeListeners.empty()) + { + listener_wrapper = new MsgListenerWrapper; + } else { + listener_wrapper = m_FreeListeners.front(); + m_FreeListeners.pop(); + } + + List *wrapper_list; + IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); + + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + { + wrapper_list = new List; + pl->SetProperty("MsgListeners", wrapper_list); + } + + wrapper_list->push_back(listener_wrapper); + + return listener_wrapper; +} + +MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept) +{ + MsgListenerWrapper *listener; + List *wrapper_list; + List::iterator iter; + IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); + bool found = false; + + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + { + return NULL; + } + + for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) + { + listener = (*iter); + if ((msgid == listener->GetMessageId()) + && (intercept == listener->IsInterceptHook()) + && (pHook == listener->GetHookedFunction())) + { + found = true; + break; + } + } + + return (found) ? listener : NULL; +} +bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept) +{ + List *wrapper_list; + IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); + + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + { + return false; + } + + wrapper_list->remove(listener); + m_FreeListeners.push(listener); + + return true; +} + +/************************************** +* * +* USER MESSAGE NATIVE IMPLEMENTATIONS * +* * +***************************************/ + +static UsrMessageNatives s_UsrMessageNatives; + static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) { char *msgname; @@ -57,7 +165,7 @@ static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) return 0; } - return g_MessageIds.GetMessageId(msgname); + return g_UserMsgs.GetMessageIndex(msgname); } static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) @@ -78,30 +186,14 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) return 0; } - if ((msgid=g_MessageIds.GetMessageId(msgname)) == INVALID_MESSAGE_ID) + if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID) { return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname); } pCtx->LocalToPhysAddr(params[2], &cl_array); - g_CurMsgFlags = params[4]; - g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]); - if (g_CurMsgFlags & USERMSG_INITMSG) - { - g_MsgRecFilter.SetInitMessage(true); - } - if (g_CurMsgFlags & USERMSG_RELIABLE) - { - g_MsgRecFilter.SetReliable(true); - } - - if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages - { - pBitBuf = engine->UserMessageBegin(static_cast(&g_MsgRecFilter), msgid); - } else { - pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast(&g_MsgRecFilter), msgid); - } + pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); g_IsMsgInExec = true; @@ -120,30 +212,14 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress"); } - if (msgid < 0 || msgid > 255) + if (msgid < 0 || msgid >= 255) { return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid); } pCtx->LocalToPhysAddr(params[2], &cl_array); - g_CurMsgFlags = params[4]; - g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]); - if (g_CurMsgFlags & USERMSG_INITMSG) - { - g_MsgRecFilter.SetInitMessage(true); - } - if (g_CurMsgFlags & USERMSG_RELIABLE) - { - g_MsgRecFilter.SetReliable(true); - } - - if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages - { - pBitBuf = engine->UserMessageBegin(static_cast(&g_MsgRecFilter), msgid); - } else { - pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast(&g_MsgRecFilter), msgid); - } + pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); g_IsMsgInExec = true; @@ -160,25 +236,78 @@ static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Unable to end message, no message is in progress"); } - if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) - { - engine->MessageEnd(); - } else { - ENGINE_CALL(MessageEnd)(); - } + g_UserMsgs.EndMessage(); sec.pOwner = pCtx->GetIdentity(); sec.pIdentity = g_pCoreIdent; g_HandleSys.FreeHandle(g_CurMsgHandle, &sec); g_IsMsgInExec = false; - g_CurMsgFlags = 0; - g_MsgRecFilter.ResetFilter(); return 1; } -static UsrMessageNatives s_UsrMessageNatives; +static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) +{ + IPluginFunction *pHook, *pNotify; + MsgListenerWrapper *listener; + bool intercept; + int msgid = params[1]; + + if (msgid < 0 || msgid >= 255) + { + return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid); + } + + pHook = pCtx->GetFunctionById(params[2]); + if (!pHook) + { + return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); + } + pNotify = pCtx->GetFunctionById(params[4]); + + intercept = (params[3]) ? true : false; + listener = s_UsrMessageNatives.GetNewListener(pCtx); + listener->InitListener(msgid, pHook, pNotify, intercept); + g_UserMsgs.HookUserMessage(msgid, listener, intercept); + + return 1; +} + +static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params) +{ + IPluginFunction *pFunc; + MsgListenerWrapper *listener; + bool intercept; + int msgid = params[1]; + + if (msgid < 0 || msgid >= 255) + { + return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid); + } + + pFunc = pCtx->GetFunctionById(params[2]); + if (!pFunc) + { + return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + intercept = (params[3]) ? true : false; + listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept); + if (!listener) + { + return pCtx->ThrowNativeError("Unable to unhook the current user message"); + } + + if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept)) + { + return pCtx->ThrowNativeError("Unable to unhook the current user message"); + } + + s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept); + + return 1; +} REGISTER_NATIVES(usrmsgnatives) { @@ -186,5 +315,7 @@ REGISTER_NATIVES(usrmsgnatives) {"StartMessage", smn_StartMessage}, {"StartMessageEx", smn_StartMessageEx}, {"EndMessage", smn_EndMessage}, + {"HookUserMessage", smn_HookUserMessage}, + {"UnHookUserMessage", smn_UnHookUserMessage}, {NULL, NULL} }; diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index c6ad7395..29d38ed1 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -85,6 +85,7 @@ native EndMessage(); * @brief Called when a message is hooked * * @param msg_id Message index. + * @param bf Handle to the input bit buffer of the message. * @param players Array containing player indexes. * @param playersNum Number of players in the array. * @param reliable True if message is reliable, false otherwise. @@ -92,7 +93,14 @@ native EndMessage(); * @return Ignored for normal hooks. For intercept hooks, false blocks * the message from being sent, and true continues. */ -functag MsgHook bool:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); +functag MsgHook Action:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); + +/** + * @brief Called when a message is finished sending. + * + * @param msg_id Message index. + */ +functag MsgSentNotify public(UserMsg:msg_id); /** * @brief Hooks a user message. @@ -102,10 +110,11 @@ functag MsgHook bool:public(UserMsg:msg_id, Handle:bf, const players[], playersN * @param intercept If intercept is true, message will be fully intercepted, * allowing the user to block the message. Otherwise, * the hook is normal and ignores the return value. + * @param notify Notification function. * @noreturn * @error Invalid message index. */ -native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); +native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgSentNotify:notify=MsgSentNotify:-1); /** * @brief Removes one usermessage hook. @@ -118,33 +127,6 @@ native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); */ native UnHookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); -/** - * @brief Called when a message is finished sending. - * - * @param msg_id Message index. - */ -functag MsgSentNotify public(UserMsg:msg_id); - -/** - * @brief Notifies when a message has finished sending. - * - * @param msg_id Message index. - * @param notify Notification function. - * @noreturn - * @error Invalid message index. - */ -native NotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify); - -/** - * @brief Removes a user message notification. - * - * @param msg_id Message index. - * @param notify Notification function. - * @noreturn - * @error Invalid message index. - */ -native RemoveNotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify); - /** * Starts a usermessage (network message) that broadcasts to all clients. * @note See StartMessage or StartMessageEx(). diff --git a/public/IUserMessages.h b/public/IUserMessages.h index ce6e5919..6307c336 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -19,7 +19,9 @@ #ifndef _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_ #define _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_ +#include #include +#include #include #include @@ -59,9 +61,9 @@ namespace SourceMod * @param pFtiler Recipient filter. * @return True to allow message, false to scrap it. */ - virtual bool InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) + virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) { - return true; + return Pl_Continue; } /** @@ -73,6 +75,11 @@ namespace SourceMod } }; + #define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */ + #define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */ + #define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */ + #define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */ + /** * @brief Contains functions for hooking user messages. */ @@ -127,14 +134,15 @@ namespace SourceMod * @param players Array containing player indexes. * @param playersNum Number of players in the array. * @param flags Flags to use for sending the message. - * @return bf_write structure to write message with. + * @return bf_write structure to write message with, or NULL on failure. */ virtual bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) =0; /** * @brief Wrapper around UserMessageEnd for use with StartMessage(). + * @return True on success, false otherwise. */ - virtual void EndMessage() =0; + virtual bool EndMessage() =0; }; } From 3b207f2cc927edbda4c8177fce6aa747bc72bf16 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 1 Mar 2007 23:44:27 +0000 Subject: [PATCH 0528/1664] implemented GetUserMessageName native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40559 --- core/CUserMessages.cpp | 9 +++++++++ core/CUserMessages.h | 1 + core/smn_usermsgs.cpp | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/core/CUserMessages.cpp b/core/CUserMessages.cpp index 3048faa3..25bc3ee2 100644 --- a/core/CUserMessages.cpp +++ b/core/CUserMessages.cpp @@ -19,6 +19,8 @@ CUserMessages g_UserMsgs; SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); +//:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time + CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500) { m_Names = sm_trie_create(); @@ -71,6 +73,13 @@ int CUserMessages::GetMessageIndex(const char *msg) return msgid; } +bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const +{ + int dummy; + + return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy); +} + bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) { bf_write *buffer; diff --git a/core/CUserMessages.h b/core/CUserMessages.h index c995e886..3c79965e 100644 --- a/core/CUserMessages.h +++ b/core/CUserMessages.h @@ -40,6 +40,7 @@ public: //SMGlobalClass void OnSourceModAllShutdown(); public: //IUserMessages int GetMessageIndex(const char *msg); + bool GetMessageName(int msgid, char *buffer, size_t maxlen) const; bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags); diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 3cb62ebe..c9eff762 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -52,6 +52,7 @@ void UsrMessageNatives::OnSourceModShutdown() g_PluginSys.RemovePluginsListener(this); g_WrBitBufType = 0; } + void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) { } @@ -131,6 +132,7 @@ MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *p return (found) ? listener : NULL; } + bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept) { List *wrapper_list; @@ -168,6 +170,21 @@ static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) return g_UserMsgs.GetMessageIndex(msgname); } +static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params) +{ + char *msgname; + + pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname); + + if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3])) + { + msgname = ""; + return 0; + } + + return 1; +} + static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) { char *msgname; @@ -269,6 +286,7 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) intercept = (params[3]) ? true : false; listener = s_UsrMessageNatives.GetNewListener(pCtx); listener->InitListener(msgid, pHook, pNotify, intercept); + g_UserMsgs.HookUserMessage(msgid, listener, intercept); return 1; @@ -312,6 +330,7 @@ static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params) REGISTER_NATIVES(usrmsgnatives) { {"GetUserMessageId", smn_GetUserMessageId}, + {"GetUserMessageName", smn_GetUserMessageName}, {"StartMessage", smn_StartMessage}, {"StartMessageEx", smn_StartMessageEx}, {"EndMessage", smn_EndMessage}, From 16eab8a0911a63e1daa51e44232f887087fd7958 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 00:52:55 +0000 Subject: [PATCH 0529/1664] internal reorganization renamed edict to entity where appropriate --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40560 --- core/msvc8/sourcemod_mm.vcproj | 6 +++- core/smn_halflife.cpp | 54 ---------------------------- plugins/include/entity.inc | 66 ++++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 39 +------------------- 4 files changed, 72 insertions(+), 93 deletions(-) create mode 100644 plugins/include/entity.inc diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d8fce4ff..7b30ebd9 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 214d93db..93c00cd0 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -51,50 +51,6 @@ static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params) return engine->IsDedicatedServer(); } -static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params) -{ - return engine->GetEntityCount(); -} - -static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) -{ - edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); - - if (!pEdict) - { - return 0; - } - - /* Shouldn't be necessary... not sure though */ - return pEdict->IsFree() ? 0 : 1; -} - -static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params) -{ - edict_t *pEdict = engine->CreateEdict(); - - if (!pEdict) - { - return 0; - } - - return engine->IndexOfEdict(pEdict); -} - -static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) -{ - edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); - - if (!pEdict) - { - return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]); - } - - engine->RemoveEdict(pEdict); - - return 1; -} - static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params) { float fTime = engine->Time(); @@ -171,11 +127,6 @@ static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params) return numBytes; } -static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) -{ - return gpGlobals->maxEntities; -} - static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) { size_t bytes; @@ -185,20 +136,15 @@ static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) REGISTER_NATIVES(halflifeNatives) { - {"CreateEdict", CreateEdict}, {"CreateFakeClient", CreateFakeClient}, {"GetCurrentMap", GetCurrentMap}, {"GetEngineTime", GetEngineTime}, - {"GetEntityCount", GetEntityCount}, {"GetGameDescription", GetGameDescription}, {"GetGameTime", GetGameTime}, - {"GetMaxEntities", GetMaxEntities}, {"GetRandomFloat", GetRandomFloat}, {"GetRandomInt", GetRandomInt}, {"IsDedicatedServer", IsDedicatedServer}, {"IsMapValid", IsMapValid}, - {"IsValidEntity", IsValidEntity}, - {"RemoveEdict", RemoveEdict}, {"SetFakeClientConVar", SetFakeClientConVar}, {"SetRandomSeed", SetRandomSeed}, {NULL, NULL}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc new file mode 100644 index 00000000..03f40cc4 --- /dev/null +++ b/plugins/include/entity.inc @@ -0,0 +1,66 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _entity_included + #endinput +#endif +#define _entity_included + +/** + * Returns the maximum number of entities. + * + * @return Maximum number of entities. + */ +native GetMaxEntities(); + +/** + * Returns the number of entities in the server. + * + * @return Number of entities in the server. + */ +native GetEntityCount(); + +/** + * Returns whether or not an entity is valid. Returns false + * if there is no matching CBaseEntity for this edict index. + * + * @param edict Index of the entity. + * @return True if valid, false otherwise. + */ +native bool:IsValidEntity(edict); + +/** + * Returns whether or not an edict index is valid. + * + * @param edict Index of the edict. + * @return True if valid, false otherwise. + */ +native bool:IsValidEdict(edict); + +/** + * Creates a new edict (the basis of a networkable entity) + * + * @return Index of the entity, 0 on failure. + */ +native CreateEdict(); + +/** + * Removes an edict from the world. + * + * @param edict Index of the entity. + * @noreturn + * @error Invalid entity index. + */ +native RemoveEdict(edict); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index ae792fa0..fb0d3299 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -37,6 +37,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -173,37 +174,6 @@ native bool:IsMapValid(const String:map[]); */ native bool:IsDedicatedServer(); -/** - * Returns the number of entities in the server. - * - * @return Number of entities in the server. - */ -native GetEntityCount(); - -/** - * Returns whether or not an entity is valid. - * - * @param entity Index of the entity. - * @return True if valid, false otherwise. - */ -native bool:IsValidEntity(entity); - -/** - * Creates a new edict (the basis of a networkable entity) - * - * @return Index of the entity, 0 on failure. - */ -native CreateEdict(); - -/** - * Removes an edict from the world. - * - * @param entity Index of the entity. - * @noreturn - * @error Invalid entity index. - */ -native RemoveEntity(entity); - /** * Returns a high-precision time value for profiling the engine. * @@ -229,13 +199,6 @@ native Float:GetGameTime(); */ native GetGameDescription(String:buffer[], maxlength, bool:original=false); -/** - * Returns the maximum number of entities. - * - * @return Maximum number of entities. - */ -native GetMaxEntities(); - /** * Returns the current map name. * From a0ae2a5b16d9c6a1eba1b70062d1be230dc661fa Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 01:21:43 +0000 Subject: [PATCH 0530/1664] added a few new entity natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40561 --- core/smn_entities.cpp | 145 +++++++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 51 ++++++++++++- 2 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 core/smn_entities.cpp diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp new file mode 100644 index 00000000..11e374bd --- /dev/null +++ b/core/smn_entities.cpp @@ -0,0 +1,145 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_globals.h" +#include "sourcemod.h" +#include "sourcemm_api.h" + +inline edict_t *GetEdict(cell_t num) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(num); + if (!pEdict || pEdict->IsFree()) + { + return NULL; + } + return pEdict; +} + +static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) +{ + return gpGlobals->maxEntities; +} + +static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->CreateEdict(); + + if (!pEdict) + { + return 0; + } + + return engine->IndexOfEdict(pEdict); +} + +static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]); + } + + engine->RemoveEdict(pEdict); + + return 1; +} + +static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return 0; + } + + /* Shouldn't be necessary... not sure though */ + return pEdict->IsFree() ? 0 : 1; +} + +static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict || pEdict->IsFree()) + { + return 0; + } + + IServerUnknown *pUnknown = pEdict->GetUnknown(); + if (!pUnknown) + { + return 0; + } + + CBaseEntity *pEntity = pUnknown->GetBaseEntity(); + return (pEntity != NULL) ? 1 : 0; +} + +static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict || pEdict->IsFree()) + { + return 0; + } + + return (pEdict->GetNetworkable() != NULL) ? 1 : 0; +} + +static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params) +{ + return engine->GetEntityCount(); +} + +static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = GetEdict(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid edict (%d)", params[1]); + } + + return pEdict->m_fStateFlags; +} + +static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = GetEdict(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid edict (%d)", params[1]); + } + + pEdict->m_fStateFlags = params[2]; + + return 1; +} + +REGISTER_NATIVES(entityNatives) +{ + {"CreateEdict", CreateEdict}, + {"GetEdictFlags", GetEdictFlags}, + {"GetEntityCount", GetEntityCount}, + {"GetMaxEntities", GetMaxEntities}, + {"IsEntNetworkable", IsEntNetworkable}, + {"IsValidEdict", IsValidEdict}, + {"IsValidEntity", IsValidEntity}, + {"RemoveEdict", RemoveEdict}, + {"SetEdictFlags", SetEdictFlags}, +}; diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 03f40cc4..4d6709bd 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -18,6 +18,22 @@ #endif #define _entity_included + +/** + * For more information on these, see the HL2SDK (public/edict.h) + */ +#define FL_EDICT_CHANGED (1<<0) /**< Game DLL sets this when the entity state changes + Mutually exclusive with FL_EDICT_PARTIAL_CHANGE. */ +#define FL_EDICT_FREE (1<<1) /**< this edict if free for reuse */ +#define FL_EDICT_FULL (1<<2) /**< this is a full server entity */ +#define FL_EDICT_FULLCHECK (0<<0) /**< call ShouldTransmit() each time, this is a fake flag */ +#define FL_EDICT_ALWAYS (1<<3) /**< always transmit this entity */ +#define FL_EDICT_DONTSEND (1<<4) /**< don't transmit this entity */ +#define FL_EDICT_PVSCHECK (1<<5) /**< always transmit entity, but cull against PVS */ +#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) +#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) +#define FL_FULL_EDICT_CHANGED (1<<8) + /** * Returns the maximum number of entities. * @@ -36,7 +52,7 @@ native GetEntityCount(); * Returns whether or not an entity is valid. Returns false * if there is no matching CBaseEntity for this edict index. * - * @param edict Index of the entity. + * @param edict Index of the entity/edict. * @return True if valid, false otherwise. */ native bool:IsValidEntity(edict); @@ -49,18 +65,45 @@ native bool:IsValidEntity(edict); */ native bool:IsValidEdict(edict); +/** + * Returns whether or not an entity is a valid networkable edict. + * + * @param edict Index of the edict. + * @return True if networkable, false if invalid or not networkable. + */ +native bool:IsEntNetworkable(edict); + /** * Creates a new edict (the basis of a networkable entity) * - * @return Index of the entity, 0 on failure. + * @return Index of the edict, 0 on failure. */ native CreateEdict(); /** * Removes an edict from the world. * - * @param edict Index of the entity. + * @param edict Index of the edict. * @noreturn - * @error Invalid entity index. + * @error Invalid edict index. */ native RemoveEdict(edict); + +/** + * Returns the flags on an edict. These are not the same as entity flags. + * + * @param edict Index of the entity. + * @return Edict flags. + * @error Invalid edict index. + */ +native GetEdictFlags(edict); + +/** + * Sets the flags on an edict. These are not the same as entity flags. + * + * @param edict Index of the entity. + * @param flags Flags to set. + * @noreturn + * @error Invalid edict index. + */ +native SetEdictFlags(edict, flags); \ No newline at end of file From bbb373297f554b47605500d1ded0a62b4de1786e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 01:56:56 +0000 Subject: [PATCH 0531/1664] fixed some bugs with edicts and players added classname retrieval functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40562 --- core/smn_entities.cpp | 66 ++++++++++++++++++++++++++++++++++---- plugins/include/entity.inc | 24 +++++++++++++- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 11e374bd..3c58a47c 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -14,6 +14,8 @@ #include "sm_globals.h" #include "sourcemod.h" #include "sourcemm_api.h" +#include "server_class.h" +#include "CPlayerManager.h" inline edict_t *GetEdict(cell_t num) { @@ -22,6 +24,14 @@ inline edict_t *GetEdict(cell_t num) { return NULL; } + if (num > 0 && num < g_Players.GetMaxClients()) + { + CPlayer *pPlayer = g_Players.GetPlayerByIndex(num); + if (!pPlayer || !pPlayer->IsConnected()) + { + return NULL; + } + } return pEdict; } @@ -58,7 +68,7 @@ static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params) { - edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + edict_t *pEdict = GetEdict(params[1]); if (!pEdict) { @@ -71,9 +81,9 @@ static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params) static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) { - edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + edict_t *pEdict = GetEdict(params[1]); - if (!pEdict || pEdict->IsFree()) + if (!pEdict) { return 0; } @@ -90,9 +100,9 @@ static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params) { - edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + edict_t *pEdict = GetEdict(params[1]); - if (!pEdict || pEdict->IsFree()) + if (!pEdict) { return 0; } @@ -131,11 +141,55 @@ static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = GetEdict(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid edict (%d)", params[1]); + } + + const char *cls = pEdict->GetClassName(); + + if (!cls || cls[0] == '\0') + { + return 0; + } + + pContext->StringToLocal(params[2], params[3], cls); + + return 1; +} + +static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = GetEdict(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid edict (%d)", params[1]); + } + + IServerNetworkable *pNet = pEdict->GetNetworkable(); + if (!pNet) + { + return 0; + } + + ServerClass *pClass = pNet->GetServerClass(); + + pContext->StringToLocal(params[2], params[3], pClass->GetName()); + + return 1; +} + REGISTER_NATIVES(entityNatives) { {"CreateEdict", CreateEdict}, + {"GetEdictClassname", GetEdictClassname}, {"GetEdictFlags", GetEdictFlags}, - {"GetEntityCount", GetEntityCount}, + {"GetEntityNetClass", GetEntityNetClass}, {"GetMaxEntities", GetMaxEntities}, {"IsEntNetworkable", IsEntNetworkable}, {"IsValidEdict", IsValidEdict}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 4d6709bd..6870d62d 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -106,4 +106,26 @@ native GetEdictFlags(edict); * @noreturn * @error Invalid edict index. */ -native SetEdictFlags(edict, flags); \ No newline at end of file +native SetEdictFlags(edict, flags); + +/** + * Retrieves an edict classname. + * + * @param edict Index of the entity. + * @param clsname Buffer to store the classname. + * @param maxlength Maximum length of the buffer. + * @return True on success, false if there is no classname set. + */ +native bool:GetEdictClassname(edict, String:clsname[], maxlength); + +/** + * Retrieves an entity's networkable serverclass name. + * This is not the same as the classname and is used for networkable state changes. + * + * @param edict Index of the entity. + * @param clsname Buffer to store the serverclass name. + * @param maxlength Maximum lnegth of the buffer. + * @return True on success, false if the edict is not networkable. + * @error Invalid edict index. + */ +native bool:GetEntityNetClass(edict, String:clsname[], maxlength); From ec62fb6892b11a4a299ec040ad4afc389c86c35c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 08:00:45 +0000 Subject: [PATCH 0532/1664] added initial private offset functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40563 --- core/smn_entities.cpp | 261 +++++++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 120 +++++++++++++++++ 2 files changed, 381 insertions(+) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 3c58a47c..77fa4d89 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -35,6 +35,30 @@ inline edict_t *GetEdict(cell_t num) return pEdict; } +inline edict_t *GetEntity(cell_t num, CBaseEntity **pData) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(num); + if (!pEdict || pEdict->IsFree()) + { + return NULL; + } + if (num > 0 && num < g_Players.GetMaxClients()) + { + CPlayer *pPlayer = g_Players.GetPlayerByIndex(num); + if (!pPlayer || !pPlayer->IsConnected()) + { + return NULL; + } + } + IServerUnknown *pUnk; + if ((pUnk=pEdict->GetUnknown()) == NULL) + { + return NULL; + } + *pData = pUnk->GetBaseEntity(); + return pEdict; +} + static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) { return gpGlobals->maxEntities; @@ -184,11 +208,244 @@ static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t GetEntData(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + switch (params[3]) + { + case 4: + return *(int *)((uint8_t *)pEntity + offset); + case 2: + return *(short *)((uint8_t *)pEntity + offset); + case 1: + return *((uint8_t *)pEntity + offset); + default: + return pContext->ThrowNativeError("Integer size %d is invalid", params[3]); + } +} + +static cell_t SetEntData(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + switch (params[4]) + { + case 4: + { + *(int *)((uint8_t *)pEntity + offset) = params[3]; + break; + } + case 2: + { + *(short *)((uint8_t *)pEntity + offset) = params[3]; + break; + } + case 1: + { + *((uint8_t *)pEntity + offset) = params[3]; + break; + } + default: + return pContext->ThrowNativeError("Integer size %d is invalid", params[4]); + } + + return 1; +} + +static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + float f = *(float *)((uint8_t *)pEntity + offset); + + return sp_ftoc(f); +} + +static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]); + + return 1; +} + +static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + Vector *v = (Vector *)((uint8_t *)pEntity + offset); + + cell_t *vec; + pContext->LocalToPhysAddr(params[3], &vec); + + vec[0] = v->x; + vec[1] = v->y; + vec[2] = v->z; + + return 1; +} + +static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + Vector *v = (Vector *)((uint8_t *)pEntity + offset); + + cell_t *vec; + pContext->LocalToPhysAddr(params[3], &vec); + + v->x = vec[0]; + v->y = vec[1]; + v->z = vec[2]; + + return 1; +} + +static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset); + + if (!hndl.IsValid()) + { + return 0; + } + + /* :TODO: check serial no.? */ + + return hndl.GetEntryIndex(); +} + +static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset); + + if (params[3] == 0) + { + hndl.Set(NULL); + } else { + edict_t *pEdict = GetEdict(params[3]); + if (!pEdict) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[3]); + } + IServerEntity *pEntOther = pEdict->GetIServerEntity(); + hndl.Set(pEntOther); + } + + return 1; +} + REGISTER_NATIVES(entityNatives) { {"CreateEdict", CreateEdict}, {"GetEdictClassname", GetEdictClassname}, {"GetEdictFlags", GetEdictFlags}, + {"GetEntData", GetEntData}, + {"GetEntDataEnt", GetEntDataEnt}, + {"GetEntDataFloat", GetEntDataFloat}, + {"GetEntDataVector", GetEntDataVector}, {"GetEntityNetClass", GetEntityNetClass}, {"GetMaxEntities", GetMaxEntities}, {"IsEntNetworkable", IsEntNetworkable}, @@ -196,4 +453,8 @@ REGISTER_NATIVES(entityNatives) {"IsValidEntity", IsValidEntity}, {"RemoveEdict", RemoveEdict}, {"SetEdictFlags", SetEdictFlags}, + {"SetEntData", SetEntData}, + {"SetEntDataEnt", SetEntDataEnt}, + {"SetEntDataFloat", SetEntDataFloat}, + {"SetEntDataVector", SetEntDataVector}, }; diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 6870d62d..9277a6c9 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -129,3 +129,123 @@ native bool:GetEdictClassname(edict, String:clsname[], maxlength); * @error Invalid edict index. */ native bool:GetEntityNetClass(edict, String:clsname[], maxlength); + +/** + * @section Entity offset functions + * + * Offsets should be specified in byte distance from the CBaseEntity + * structure, not short (double byte) or integer (four byte) multiples. + * It is somewhat common practice to use offsets aligned to their final + * type, and thus make sure you are not falling to this error in SourceMod. + * For example, if your "integer-aligned" offset was 119, your byte-aligned + * offset is 119*4, or 476. + + * Specifying incorrect offsets or the incorrect data type for an offset + * can have fatal consequences. If you are hardcoding offsets, and the + * layout of CBaseEntity does not match, you can easily crash the server. + * + * The reasonable bounds for offsets is greater than or equal to 0 and + * below 32768. Offsets out of these bounds will throw an error. However, + * this does not represent any real range, it is simply a sanity check for + * illegal values. Any range outside of the CBaseEntity structure's private + * size will cause undefined behaviour or even crash. + */ + +/** + * Peeks into an entity's object data and retrieves the integer value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param size Number of bytes to read (valid values are 1, 2, or 4). + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + */ +native GetEntData(entity, offset, size=4); + +/** + * Peeks into an entity's object data and sets the integer value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + * @noreturn + */ +native SetEntData(entity, offset, value, size=4); + +/** + * Peeks into an entity's object data and retrieves the float value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + */ +native Float:GetEntDataFloat(entity, offset); + +/** + * Peeks into an entity's object data and sets the integer value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + * @noreturn + */ +native SetEntDataFloat(entity, offset, Float:value); + +/** + * Peeks into an entity's object data and retrieves the entity handle + * info at the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Entity index at the given location, or 0 if none. + * @error Invalid entity or offset out of reasonable bounds. + */ +native GetEntDataEnt(entity, offset); + +/** + * Peeks into an entity's object data and sest the entity handle info + * at the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param other Entity index to set, or 0 to clear. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +native SetEntDataEnt(entity, offset, other); + +/** + * Peeks into an entity's object data and retrieves the vector at the + * given offset. + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param vec Vector buffer to store data in. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +native GetEntDataVector(entity, offset, Float:vec[3]); + +/** + * Peeks into an entity's object data and sets the vector at the given + * offset. + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param vec Vector to set. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +native SetEntDataVector(entity, offset, const Float:vec[3]); From de588c77b9338c962a242dcf13a1a15cf9be1a6b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 08:34:13 +0000 Subject: [PATCH 0533/1664] added state change function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40564 --- core/smn_entities.cpp | 32 ++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 13 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 77fa4d89..f39fd55f 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -437,8 +437,40 @@ static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) return 1; } +IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() +{ + return engine->GetChangeAccessor( (const edict_t *)this ); +} + +CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; + +static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = GetEdict(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Edict %d is invalid", params[1]); + } + + if (!g_pSharedChangeInfo) + { + g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); + } + + if (params[2]) + { + pEdict->StateChanged(params[2]); + } else { + pEdict->StateChanged(); + } + + return 1; +} + REGISTER_NATIVES(entityNatives) { + {"ChangeEdictState", ChangeEdictState}, {"CreateEdict", CreateEdict}, {"GetEdictClassname", GetEdictClassname}, {"GetEdictFlags", GetEdictFlags}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 9277a6c9..6cb4f5e4 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -150,6 +150,19 @@ native bool:GetEntityNetClass(edict, String:clsname[], maxlength); * illegal values. Any range outside of the CBaseEntity structure's private * size will cause undefined behaviour or even crash. */ + +/** + * Marks an entity as state changed. This can be useful if you set an offset + * and wish for it to be immediately changed over the network. By default this + * is not done for offset setting functions. + * + * @param edict Index to the edict. + * @param offset Offset to mark as changed. If 0, + * the entire edict is marked as changed. + * @noreturn + * @error Invalid entity or offset out of bounds. + */ +native ChangeEdictState(edict, offset = 0); /** * Peeks into an entity's object data and retrieves the integer value at From 9de900d3eb0260ca50f496878cdaab2949a4aef5 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 2 Mar 2007 09:15:54 +0000 Subject: [PATCH 0534/1664] Made this const for great justice --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40565 --- core/systems/ForwardSys.cpp | 6 +++--- core/systems/ForwardSys.h | 6 +++--- public/IForwardSys.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 2f6c39b2..2103b1d6 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -43,7 +43,7 @@ void CForwardManager::OnSourceModShutdown() g_PluginSys.RemovePluginsListener(this); } -IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...) +IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...) { CForward *fwd; va_list ap; @@ -61,7 +61,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned return fwd; } -IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...) +IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...) { CForward *fwd; va_list ap; @@ -186,7 +186,7 @@ void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused) * ACTUAL FORWARD API IMPLEMENTATION * *************************************/ -CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap) +CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap) { ParamType _types[SP_MAX_EXEC_PARAMS]; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 0582e3f9..e0ce371b 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -68,7 +68,7 @@ public: static CForward *CreateForward(const char *name, ExecType et, unsigned int num_params, - ParamType *types, + const ParamType *types, va_list ap); private: void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags); @@ -108,12 +108,12 @@ public: //IForwardManager IForward *CreateForward(const char *name, ExecType et, unsigned int num_params, - ParamType *types, + const ParamType *types, ...); IChangeableForward *CreateForwardEx(const char *name, ExecType et, int num_params, - ParamType *types, + const ParamType *types, ...); IForward *FindForward(const char *name, IChangeableForward **ifchng); void ReleaseForward(IForward *forward); diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 97ed2b9a..fc903fe4 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -289,7 +289,7 @@ namespace SourceMod virtual IForward *CreateForward(const char *name, ExecType et, unsigned int num_params, - ParamType *types, + const ParamType *types, ...) =0; /** @@ -309,7 +309,7 @@ namespace SourceMod virtual IChangeableForward *CreateForwardEx(const char *name, ExecType et, int num_params, - ParamType *types, + const ParamType *types, ...) =0; /** From 66b244011e1f36f63f30ffe91d1a5c8494ab3ed9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 19:10:44 +0000 Subject: [PATCH 0535/1664] added ThrowError() a la amxmodx's abort() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40566 --- core/msvc8/sourcemod_mm.vcproj | 4 ++++ core/smn_core.cpp | 35 +++++++++++++++++++++++++++++++++ core/vm/sp_vm_engine.cpp | 3 ++- plugins/include/sourcemod.inc | 14 ++++++++++++- public/sourcepawn/sp_vm_types.h | 1 + 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 core/smn_core.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7b30ebd9..c05a59b0 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -681,6 +681,10 @@ RelativePath="..\smn_console.cpp" > + + diff --git a/core/smn_core.cpp b/core/smn_core.cpp new file mode 100644 index 00000000..bc7b342a --- /dev/null +++ b/core/smn_core.cpp @@ -0,0 +1,35 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_globals.h" +#include "sourcemod.h" + +static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) +{ + char buffer[512]; + + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); + + if (pContext->GetContext()->n_err == SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer); + } + + return 0; +} + +REGISTER_NATIVES(coreNatives) +{ + {"ThrowError", ThrowError}, + {NULL, NULL}, +}; diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index 49d6fa25..9f884da1 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -31,7 +31,7 @@ using namespace SourcePawn; -#define ERROR_MESSAGE_MAX 23 +#define ERROR_MESSAGE_MAX 25 static const char *g_ErrorMsgTable[] = { NULL, @@ -59,6 +59,7 @@ static const char *g_ErrorMsgTable[] = "Maximum number of parameters reached", "Native detected error", "Plugin not runnable", + "Call was aborted", }; SourcePawnEngine::SourcePawnEngine() diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index fb0d3299..64ccb7db 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -37,7 +37,6 @@ struct Plugin #include #include #include -#include /** * Declare this as a struct in your plugin to expose its information. @@ -106,6 +105,18 @@ forward OnGameFrame(); */ native Handle:GetMyHandle(); + +/** + * Aborts the current callback and throws an error. This function + * does not return in that no code is executed following it. + * + * @param format String format. + * @param ... Format arguments. + * @noreturn + * @error Always! + */ +native ThrowError(const String:fmt[], {Handle,Float,String,_}:...); + /** * Logs a generic message to the HL2 logs. * @@ -210,3 +221,4 @@ native GetCurrentMap(String:buffer[], maxlength); #include #include +#include diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 9e04a143..2ba21ffd 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -62,6 +62,7 @@ typedef uint32_t funcid_t; /**< Function index code */ #define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */ #define SP_ERROR_NATIVE 23 /**< Error originates from a native */ #define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ +#define SP_ERROR_ABORTED 25 /**< Function call was aborted */ //Hey you! Update the string table if you add to the end of me! */ /********************************************** From 791cbc985f7dca8edad6f55d431a013301441741 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 19:11:04 +0000 Subject: [PATCH 0536/1664] added entity functions and stocks for send props --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40567 --- core/smn_entities.cpp | 38 ++++++++ plugins/include/entity.inc | 195 ++++++++++++++++++++++++++++++++++++- 2 files changed, 229 insertions(+), 4 deletions(-) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index f39fd55f..97b624fe 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -16,6 +16,7 @@ #include "sourcemm_api.h" #include "server_class.h" #include "CPlayerManager.h" +#include "CHalfLife2.h" inline edict_t *GetEdict(cell_t num) { @@ -253,6 +254,11 @@ static cell_t SetEntData(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Offset %d is invalid", offset); } + if (params[5]) + { + pEdict->StateChanged(offset); + } + switch (params[4]) { case 4: @@ -316,6 +322,11 @@ static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params) *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]); + if (params[4]) + { + pEdict->StateChanged(offset); + } + return 1; } @@ -372,6 +383,11 @@ static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params) v->y = vec[1]; v->z = vec[2]; + if (params[4]) + { + pEdict->StateChanged(offset); + } + return 1; } @@ -434,6 +450,11 @@ static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) hndl.Set(pEntOther); } + if (params[4]) + { + pEdict->StateChanged(offset); + } + return 1; } @@ -468,10 +489,27 @@ static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params) +{ + char *cls, *prop; + pContext->LocalToString(params[1], &cls); + pContext->LocalToString(params[2], &prop); + + SendProp *pSend = g_HL2.FindInSendTable(cls, prop); + + if (!pSend) + { + return -1; + } + + return pSend->GetOffset(); +} + REGISTER_NATIVES(entityNatives) { {"ChangeEdictState", ChangeEdictState}, {"CreateEdict", CreateEdict}, + {"FindSendPropOffs", FindSendPropOffs}, {"GetEdictClassname", GetEdictClassname}, {"GetEdictFlags", GetEdictFlags}, {"GetEntData", GetEntData}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 6cb4f5e4..31b922d9 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -183,11 +183,12 @@ native GetEntData(entity, offset, size=4); * @param entity Edict index. * @param offset Offset to use. * @param size Number of bytes to write (valid values are 1, 2, or 4). + * @param changeState If true, change will be sent over the network. * @return Value at the given memory location. * @error Invalid entity or offset out of reasonable bounds. * @noreturn */ -native SetEntData(entity, offset, value, size=4); +native SetEntData(entity, offset, value, size=4, bool:changeState=false); /** * Peeks into an entity's object data and retrieves the float value at @@ -206,11 +207,12 @@ native Float:GetEntDataFloat(entity, offset); * * @param entity Edict index. * @param offset Offset to use. + * @param changeState If true, change will be sent over the network. * @return Value at the given memory location. * @error Invalid entity or offset out of reasonable bounds. * @noreturn */ -native SetEntDataFloat(entity, offset, Float:value); +native SetEntDataFloat(entity, offset, Float:value, bool:changeState=false); /** * Peeks into an entity's object data and retrieves the entity handle @@ -230,10 +232,11 @@ native GetEntDataEnt(entity, offset); * @param entity Edict index. * @param offset Offset to use. * @param other Entity index to set, or 0 to clear. + * @param changeState If true, change will be sent over the network. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -native SetEntDataEnt(entity, offset, other); +native SetEntDataEnt(entity, offset, other, bool:changeState=false); /** * Peeks into an entity's object data and retrieves the vector at the @@ -258,7 +261,191 @@ native GetEntDataVector(entity, offset, Float:vec[3]); * @param entity Edict index. * @param offset Offset to use. * @param vec Vector to set. + * @param changeState If true, change will be sent over the network. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -native SetEntDataVector(entity, offset, const Float:vec[3]); +native SetEntDataVector(entity, offset, const Float:vec[3], bool:changeState=false); + +/** + * Given a ServerClass name, finds a networkable send property offset. + * This information is cached for future calls. + * + * @param cls Classname. + * @param prop Property name. + * @return An offset, or -1 on failure. + */ +native FindSendPropOffs(const String:cls[], const String:prop[]); + +/** + * Wrapper function for finding a send property for a particular entity. + * + * @param ent Entity index. + * @param prop Property name. + * @return An offset, or -1 on failure. + */ +stock GetEntSendPropOffs(ent, const String:prop[]) +{ + decl String:cls[64]; + + if (!GetEntityNetClass(ent, cls, sizeof(cls))) + { + return -1; + } + + return FindSendPropOffs(cls, prop); +} + +/** + * Gets a network property as an integer; wrapper around GetEntData(). + * + * @param entity Edict index. + * @param prop Property to use. + * @param size Number of bytes to read (valid values are 1, 2, or 4). + * @return Value at the given property offset. + * @error Invalid entity or property not found. + */ +stock GetEntProp(entity, const String:prop[], size=4) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return GetEntData(entity, offs, size); +} + +/** + * Sets a network property as an integer; wrapper around GetEntData(). + * + * @param entity Edict index. + * @param prop Property to use. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * @error Invalid entity or offset out of reasonable bounds. + * @noreturn + */ +stock SetEntProp(entity, const String:prop[], value, size=4) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return SetEntData(entity, offs, value, size, true); +} + +/** + * Gets a network property as a float; wrapper around GetEntDataFloat(). + * + * @param entity Edict index. + * @param prop Property to use. + * @return Value at the given property offset.. + * @error Invalid entity or offset out of reasonable bounds. + */ +stock Float:GetEntPropFloat(entity, const String:prop[]) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return GetEntDataFloat(entity, offs); +} + +/** + * Sets a network property as a float; wrapper around SetEntDataFloat(). + * + * @param entity Edict index. + * @param prop Property to use. + * @param value Value to set. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +stock SetEntPropFloat(entity, const String:prop[], Float:value) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return SetEntDataFloat(entity, offs, value, true); +} + +/** + * Gets a network property as a handle entity; wrapper around GetEntDataEnt(). + * + * @param entity Edict index. + * @param prop Property to use. + * @return Entity index at the given property, or 0 if none. + * @error Invalid entity or offset out of reasonable bounds. + */ +stock GetEntPropEnt(entity, const String:prop[]) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return GetEntDataEnt(entity, offs); +} + +/** + * Sets a network property as a handle entity; wrapper around SetEntDataEnt(). + * + * @param entity Edict index. + * @param prop Property to use. + * @param other Entity index to set, or 0 to unset. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +stock SetEntPropEnt(entity, const String:prop[], other) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return SetEntDataEnt(entity, offs, other, true); +} + +/** + * Gets a network property as a vector; wrapper around GetEntDataVector(). + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param prop Property to use. + * @param vec Vector buffer to store data in. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +stock GetEntPropVector(entity, const String:prop[], Float:vec[3]) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return GetEntDataVector(entity, offs, vec); +} + +/** + * Sets a network property as a vector; wrapper around SetEntDataVector(). + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param prop Property to use. + * @param vec Vector to set. + * @noreturn + * @error Invalid entity or offset out of reasonable bounds. + */ +stock SetEntPropVector(entity, const String:prop[], const Float:vec[3]) +{ + new offs = GetEntSendPropOffs(entity, prop); + if (offs == -1) + { + ThrowError("Property \"%s\" not found for entity %d", prop, entity); + } + return SetEntDataVector(entity, offs, vec, true); +} From fd5c410153e34ed7fdbc730332e162cf35a3d314 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 19:11:29 +0000 Subject: [PATCH 0537/1664] aligned header spaces properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40568 --- core/smn_console.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 08c2461a..0c7e4570 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -1,15 +1,15 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "sm_globals.h" #include "sourcemm_api.h" From 25891bdaba08584561e846e486a1578e2ad3ced3 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 2 Mar 2007 23:23:13 +0000 Subject: [PATCH 0538/1664] Typo fix: initialler -> initializer --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40569 --- sourcepawn/compiler/sc1.c | 8 +- sourcepawn/compiler/sc5.scp | 146 ++++++++++++++++++------------------ 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 3084df53..5c22032a 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -2576,7 +2576,7 @@ static void initials(int ident,int tag,cell *size,int dim[],int numdim, /* now initialize the sub-arrays */ memset(counteddim,0,sizeof counteddim); initarray(ident,tag,dim,numdim,0,curlit,counteddim,&lastdim,enumroot,&errorfound); - /* check the specified array dimensions with the initialler counts */ + /* check the specified array dimensions with the initializer counts */ for (idx=0; idxsymfield->dim.array.length) - error(228); /* length of initialler exceeds size of the enum field */ + error(228); /* length of initializer exceeds size of the enum field */ if (ellips) { step=prev1-prev2; } else { diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index 1af2cd33..c6759275 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -27,12 +27,12 @@ SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned ch /*-*SCPACK start of pair table, do not change or remove this line */ unsigned char errstr_table[][2] = { {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {116,105}, {100,32}, {115,32}, {101,114}, {101,110}, {133,129}, {97,108}, {37,115}, {34,140}, {141,34}, {117,110}, - {114,101}, {110,111}, {115,105}, {97,116}, {121,32}, {97,110}, {111,114}, {109,98}, {32,142}, {100,101}, {115,116}, {109,137}, {41,10}, {101,134}, {138,32}, {98,108}, + {114,101}, {110,111}, {115,105}, {97,116}, {121,32}, {97,110}, {111,114}, {109,98}, {32,142}, {100,101}, {115,116}, {41,10}, {109,137}, {101,134}, {138,32}, {98,108}, {145,130}, {111,108}, {114,97}, {143,99}, {118,139}, {102,163}, {115,121}, {166,151}, {167,161}, {117,115}, {97,32}, {115,146}, {97,159}, {132,162}, {103,32}, {136,32}, - {150,32}, {103,117}, {105,134}, {177,155}, {164,178}, {132,179}, {111,102}, {101,120}, {165,158}, {131,180}, {99,104}, {116,104}, {105,135}, {153,102}, {101,100}, {118,132}, + {150,32}, {103,117}, {105,134}, {177,156}, {164,178}, {132,179}, {111,102}, {101,120}, {165,158}, {131,180}, {99,104}, {116,104}, {105,135}, {153,102}, {101,100}, {118,132}, {168,152}, {182,32}, {105,172}, {191,194}, {101,135}, {173,148}, {109,97}, {116,111}, {99,129}, {115,10}, {112,144}, {116,97}, {181,130}, {98,128}, {154,147}, {44,32}, - {40,192}, {132,97}, {169,130}, {189,131}, {152,10}, {101,10}, {208,156}, {109,210}, {195,128}, {34,32}, {129,32}, {139,32}, {104,97}, {105,99}, {100,105}, {146,122}, - {109,147}, {110,32}, {101,108}, {117,108}, {99,111}, {108,111}, {111,112}, {116,136}, {200,154}, {58,212}, {102,105}, {97,115}, {108,128}, {230,136}, {232,149}, {149,32}, + {40,192}, {132,97}, {169,130}, {189,131}, {152,10}, {101,10}, {208,155}, {109,210}, {195,128}, {34,32}, {129,32}, {139,32}, {104,97}, {105,99}, {146,122}, {109,147}, + {110,32}, {100,105}, {101,108}, {117,108}, {99,111}, {108,111}, {111,112}, {116,136}, {200,154}, {58,212}, {102,105}, {97,115}, {108,128}, {230,136}, {232,149}, {149,32}, {202,171}, {131,174}, {203,174}, {215,205}, {119,105}, {109,112}, {183,240}, {110,117}, {118,128}, {165,138}, {247,151}, {198,148}, {102,150}, {111,32}, {131,32} }; /*-*SCPACK end of pair table, do not change or remove this line */ @@ -136,97 +136,97 @@ static char *errmsg[] = { /*095*/ "cannot have required parameters after optional parameters\n" #else "\267pect\235\307k\211:\230\317bu\202fo\217\206\216\012", - "\201l\224\252s\203g\354\316e\233\202(\260\366\201) c\357f\241\345w ea\272 \042c\353e\042\012", + "\201l\224\252s\203g\354\316e\234\202(\260\366\201) c\357f\241\345w ea\272 \042c\353e\042\012", "\231cl\321\236\301\252\345c\333\330\327appe\204 \376\252\344\365o\217\206\237ock\012", - "\371\230 \274\240i\365le\233t\276\012", + "\371\230 \274\240i\365le\234t\276\012", "\270\373\240\334\370\265t\311", "\363a\253gn\235\307 \357\255y\012", "\355\223\260c\225\240\315\220\323\276\012", "\363\252\356\202\366\201; \353sum\235z\210o\012", - "\271\305\337\200(nega\205ve\317z\210\375\260ou\202\301bo\217ds\234", + "\271\305\336\200(nega\205ve\317z\210\375\260ou\202\301bo\217ds\233", "\271\270\260\231cl\321\212\012", "\271out\222d\200\371\311", "\271\270c\213l\317\240\252\264add\220s\311", - "\221 \211tr\224po\203\202(\221 pu\237\335 \371s\234", - "\271\316e\233t; \240\376s\364t\272\012", - "\042\275a\343t\331c\353\200\363\273\200l\353\202c\353\200\376s\364t\272 \316e\233t\012", + "\221 \211tr\224po\203\202(\221 pu\237\335 \371s\233", + "\271\316e\234t; \240\376s\364t\272\012", + "\042\275a\343t\331c\353\200\363\273\200l\353\202c\353\200\376s\364t\272 \316e\234t\012", "m\343\205p\354\275a\343t\207\376\042s\364t\272\042\012", "\217\323\235\300\012", - "\203i\205\213iza\236d\223\252\267ce\276\207\231cl\204\235\337\325", + "\203i\205\213iza\236d\223\252\267ce\276\207\231cl\204\235\336\325", "\240\252lab\342\351", "\271\250 nam\200\216\012", "\250 \213\220ad\224\323\276\351", - "\363l\244u\200(n\201-\356t\234", - "\305a\253gn\233\202\363\222\365\354a\253gn\233t\012", + "\363l\244u\200(n\201-\356t\233", + "\305a\253gn\234\202\363\222\365\354a\253gn\234t\012", "\042b\220ak\331\260\042\310t\203ue\331\274ou\202\301\310t\267t\012", - "\270head\361\336ff\210\207from pro\307typ\325", - "\221 \340\272\361\042#if...\042\012", + "\270head\361\341ff\210\207from pro\307typ\325", + "\221 \337\272\361\042#if...\042\012", "\271\272\321ct\257\356t\012", "\271subscrip\202(\240\357\305\260\307\375m\225\224subscripts)\351", "\271\366\201\317\353sum\235z\210o\012", - "\344\365o\217\206\316e\233\202\240c\345s\235a\202\273\200\211\206\301\352\354(\232\204t\235a\202l\203\200%d\234", - "\217k\221w\341\336\220c\205v\325", - "\305\203\231x ou\202\301bo\217d\207(\330\216\234", - "\305\363\203\231x\235(\330\216\234", - "\314do\304\240\334\370\252\275a\343\202\244u\200(\314%d\234", - "\314typ\200mis\340\272 (\314%d\234", - "e\365t\224\316e\233t\012", - "\271\232r\361(po\253\237\224n\201-\347m\203\223\235\232r\203g\234", + "\344\365o\217\206\316e\234\202\240c\345s\235a\202\273\200\211\206\301\352\354(\232\204t\235a\202l\203\200%d\233", + "\217k\221w\340\341\220c\205v\325", + "\305\203\231x ou\202\301bo\217d\207(\330\216\233", + "\305\363\203\231x\235(\330\216\233", + "\314do\304\240\334\370\252\275a\343\202\244u\200(\314%d\233", + "\314typ\200mis\337\272 (\314%d\233", + "e\365t\224\316e\234t\012", + "\271\232r\361(po\253\237\224n\201-\347m\203\223\235\232r\203g\233", "\267t\242 \272\321c\347\207\332l\203\325", - "\356\202\250 \334\207\221 \337\325", - "dupl\335\223\200\042c\353e\331lab\342 (\244u\200%d\234", - "\271\342lip\222s\317\305\337\200\274\240k\221wn\012", + "\356\202\250 \334\207\221 \336\325", + "dupl\335\223\200\042c\353e\331lab\342 (\244u\200%d\233", + "\271\342lip\222s\317\305\336\200\274\240k\221wn\012", "\271\344\227\203a\236\301cl\353\207speci\352\210\311", "\272\321ct\257\356\202\267ce\276\207r\225g\200f\260pack\235\232r\203g\012", "po\222\212\333p\321me\347\207\327\312c\276\200\213l nam\235p\321me\347\311", "\307\375m\225\224\270\265t\311", - "\217k\221w\341\305\337\200(\330\216\234", - "\305\337\304d\375\240\340\272\317\260\231\232\203a\236\305\274\307\375sm\213l\012", - "\305\336\233\222\201\207d\375\240\340\272\012", + "\217k\221w\340\305\336\200(\330\216\233", + "\305\336\304d\375\240\337\272\317\260\231\232\203a\236\305\274\307\375sm\213l\012", + "\305(\207d\375\240\337\272\012", "\271l\203\200\310t\203ua\212\012", "\271r\225g\325", - "\271subscript\317\251\200\042[ ]\331\355\223\226\207\332\306j\260\336\233\222\201\311", - "m\343\205-\336\233\222\201\333\255y\207\363f\343l\224\203i\205\213iz\276\012", - "\267ce\276\361\306ximum \372\257\301\336\233\222\201\311", - "\217\340\272\235c\345s\361b\242c\200(\042}\042\234", + "\271subscript\317\251\200\042[ ]\331\355\223\226\207\332\306j\260\341\234\222\201\311", + "m\343\205-\341\234\222\201\333\255y\207\363f\343l\224\203i\205\213iz\276\012", + "\267ce\276\361\306ximum \372\257\301\341\234\222\201\311", + "\217\337\272\235c\345s\361b\242c\200(\042}\042\233", "\232\204\202\301\270bod\224\364\273ou\202\270head\210\012", - "\255ys\317\345c\333\303\304\225\206\270\265t\207c\225\240\315pu\237\335 (\330\216\234", - "\217f\203ish\235\366\332be\374\200\344\365il\257\336\220c\205v\325", + "\255ys\317\345c\333\303\304\225\206\270\265t\207c\225\240\315pu\237\335 (\330\216\233", + "\217f\203ish\235\366\332be\374\200\344\365il\257\341\220c\205v\325", "dupl\335\223\200\265t; sam\200\314\274p\353s\235tw\335\325", - "\270\314\373\240\334\370\252\275a\343\202\244u\200(\330\216\234", - "m\343\205p\354\042#\342se\331\336\220c\205v\304betwe\211 \042#if ... #\211\336f\042\012", - "\042#\342seif\331\336\220c\205\370f\241\345w\207\357\042#\342se\331\336\220c\205v\325", + "\270\314\373\240\334\370\252\275a\343\202\244u\200(\330\216\233", + "m\343\205p\354\042#\342se\331\341\220c\205v\304betwe\211 \042#if ... #\211\341f\042\012", + "\042#\342seif\331\341\220c\205\370f\241\345w\207\357\042#\342se\331\341\220c\205v\325", "\372\257\301\355\225d\207do\304\240\352\202\273\200\355\223\226\012", "\270\220s\343\202\362\301\355\223\226\230 \363\216\012", "c\225\240\272\225g\200\312\323\235\355\223\226\311", - "\270\314\373\201l\224\334\370\252s\203g\354\362(\314%d\234", - "\270\314\373\240\315\252\220f\210\211c\200\314\260\357\305(\314\216\234", - "\330c\225\240\315bo\273 \252\220f\210\211c\200\225\206\357\305(\330\216\234", + "\270\314\373\201l\224\334\370\252s\203g\354\362(\314%d\233", + "\270\314\373\240\315\252\220f\210\211c\200\314\260\357\305(\314\216\233", + "\330c\225\240\315bo\273 \252\220f\210\211c\200\225\206\357\305(\330\216\233", "\271\242\212\333\372\257\312ci\222\332\376#p\242g\306\012", "\242\212\333\372\257\374\306\202\213\220ad\224\323\276\012", "\242\212\333\372\257supp\226\202wa\207\240\211\254\276\012", - "\251\210-\323\235\355\223\260\363\231cl\204\235be\374\200\251\200(\371\230\234", - "\042\337e\266\331\355\223\260\274\271\332\042\371\331\250\311", - "\270\314\363\357\305(\314\216\234", - "#\323\200p\223\347\341\327\232\204\202\364\273 \357\213p\334be\205c \272\321c\347\012", - "\203pu\202l\203\200\307\375l\201\256(aft\257subs\205tu\212s\234", + "\251\210-\323\235\355\223\260\363\231cl\204\235be\374\200\251\200(\371\230\233", + "\042\336e\266\331\355\223\260\274\271\332\042\371\331\250\311", + "\270\314\363\357\305(\314\216\233", + "#\323\200p\223\347\340\327\232\204\202\364\273 \357\213p\334be\205c \272\321c\347\012", + "\203pu\202l\203\200\307\375l\201\256(aft\257subs\205tu\212s\233", "\246n\313x \210r\260\376\273\200\366\201\317\260\271\270c\213l\012", "m\213\374m\235UTF-8 \211\344d\203g\317\260c\226rupt\235\352le: \214\012", - "\270\251\304bo\273 \042\220turn\331\225\206\042\220tur\341<\244ue>\042\012", - "\203\310\222\232\211\202\220tur\341typ\304(\305& n\201-\255y\234", - "\217k\221w\341\250\317\260\240\252\356\202\250 \326", + "\270\251\304bo\273 \042\220turn\331\225\206\042\220tur\340<\244ue>\042\012", + "\203\310\222\232\211\202\220tur\340typ\304(\305& n\201-\255y\233", + "\217k\221w\340\250\317\260\240\252\356\202\250 \326", "c\225\240\313k\200\252\362a\207\252\275a\343\202\244u\200f\260\357\203\231x\235\305p\321met\257\326", "\251\210-\323\235\355\223\226\207\225\206na\205\370\371\207\373\240\334\370\316e\311", - "\252\270\260\330\373\201l\224b\342\201\256\307 \252s\203g\354au\307\340\332\326", - "\316\200\310fl\335t: \201\200\301\273\200\316\304\274\213\220ad\224a\253gn\235\307 a\221\273\257i\365le\233\313\236\326", + "\252\270\260\330\373\201l\224b\342\201\256\307 \252s\203g\354au\307\337\332\326", + "\316\200\310fl\335t: \201\200\301\273\200\316\304\274\213\220ad\224a\253gn\235\307 a\221\273\257i\365le\234\313\236\326", "\221 \316\304\204\200\323\235f\260\300\012", - "\217k\221w\341au\307\340\201\324", - "\217k\221w\341\316\200\216 f\260au\307\340\201\324", + "\217k\221w\340au\307\337\201\324", + "\217k\221w\340\316\200\216 f\260au\307\337\201\324", "pu\237\335 \303\304\225\206\345c\333\303\304\373\240\334\370\316\304\326", "\316\200\303\304\373\240\315\203i\205\213iz\235\326", - "pu\237\335 \371\207\373\240\220tur\341\255y\207\326", + "pu\237\335 \371\207\373\240\220tur\340\255y\207\326", "a\227i\261ou\207\356t; \362ov\210rid\200\274\220qui\220\206\326", - "\372\257\301\265t\207do\304\240\340\272 \323i\212\012", + "\372\257\301\265t\207do\304\240\337\272 \323i\212\012", "\267pect\235\362nam\200id\211\205\352\210\012", "\270\211um\210a\236\220qui\220\207\217iqu\200\313g\012", "c\225\240\334\370\220qui\220\206p\321me\347\207aft\257\346\212\333p\321me\347\311" @@ -260,7 +260,7 @@ static char *fatalmsg[] = { "\203suff\335i\211\202mem\226y\012", "\271\353se\227l\257\203\232ruc\212\324", "\367m\210\335 ov\210f\345w\317\267ce\276\361capacity\012", - "\344\365il\235scrip\202\267ce\276\207\273\200\306ximum mem\226\224\337\200(%l\206bytes\234", + "\344\365il\235scrip\202\267ce\276\207\273\200\306ximum mem\226\224\336\200(%l\206bytes\233", "\307\375m\225\224\210r\260messag\304\332\201\200l\203\325", "\344\231pag\200\306pp\361\352\354\240fo\217d\012", "\271p\223h\351", @@ -298,8 +298,8 @@ static char *warnmsg[] = { /*224*/ "indeterminate array size in \"sizeof\" expression (symbol \"%s\")\n", /*225*/ "unreachable code\n", /*226*/ "a variable is assigned to itself (symbol \"%s\")\n", -/*227*/ "more initiallers than enum fields\n", -/*228*/ "length of initialler exceeds size of the enum field\n", +/*227*/ "more initializers than enum fields\n", +/*228*/ "length of initializer exceeds size of the enum field\n", /*229*/ "index tag mismatch (symbol \"%s\")\n", /*230*/ "no implementation for state \"%s\" in function \"%s\", no fall-back\n", /*231*/ "state specification on forward declaration is ignored\n", @@ -311,40 +311,40 @@ static char *warnmsg[] = { #else "\300 \274tr\243\223\235\307 %\206\272\321c\347\311", "\220\323i\236\301\356t/\306cr\375\326", - "\372\257\301\265t\207do\304\240\340\272 \323i\212\012", + "\372\257\301\265t\207do\304\240\337\272 \323i\212\012", "\250 \274nev\257\251\276\351", "\250 \274a\253gn\235\252\244u\200\273a\202\274nev\257\251\276\351", "\220d\217d\225\202\344\231: \356\202\366\332\274z\210o\012", "\220d\217d\225\202te\232: \356\202\366\332\274n\201-z\210o\012", - "\217k\221w\341#p\242g\306\012", + "\217k\221w\340#p\242g\306\012", "\270\364\273 \362\220s\343\202\251\235be\374\200\323i\212\317\374c\361\220p\204s\325", - "\371\230 sho\343\206\220tur\341\252\244u\325", + "\371\230 sho\343\206\220tur\340\252\244u\325", "po\253\237\200\251\200\301\250 be\374\200\203i\205\213iza\212\351", - "po\253\237\224\217\203t\211\231\206a\253gn\233t\012", + "po\253\237\224\217\203t\211\231\206a\253gn\234t\012", "po\253\237\224\217\203t\211\231\206bit\364s\200\355a\212\012", - "\362mis\340\272\012", + "\362mis\337\272\012", "po\253\237\224\252\042\350\331\305\314wa\207\203t\211\231d\351", "\366\332\334\207\221 effect\012", - "ne\232\235\344m\233t\012", + "ne\232\235\344m\234t\012", "\345os\200\203d\211\313\212\012", "\241\206\232y\354pro\307typ\304\251\235\364\273 \346\212\333sem\335\241umn\311", "\345c\333\330\216 s\334dow\207\252\330a\202\252\312c\276\361lev\342\012", "\366\332\364\273 \362ov\210rid\200\327appe\204 betwe\211 p\204\211\273ese\311", "lab\342 nam\200\216 s\334dow\207\362nam\325", - "\372\257\301\336git\207\267ce\276\207\242\212\333\372\257\312ci\222\201\012", - "\220d\217d\225\202\042\337e\266\042: \314\337\200\274\213way\2071 \326", - "\203\231\347m\203\223\200\305\337\200\376\042\337e\266\331\366\332\326", + "\372\257\301\341git\207\267ce\276\207\242\212\333\372\257\312ci\222\201\012", + "\220d\217d\225\202\042\336e\266\042: \314\336\200\274\213way\2071 \326", + "\203\231\347m\203\223\200\305\336\200\376\042\336e\266\331\366\332\326", "\217\220a\272\254\200\344\231\012", "\252\330\274a\253gn\235\307 its\342f \326", - "m\226\200\203i\205\213l\210\207\273\357\211um \352\342d\311", - "l\211g\273 \301\203i\205\213l\257\267ce\276\207\337\200\301\273\200\211um \352\342d\012", - "\203\231x \362mis\340\272 \326", - "\221 i\365le\233\313\236f\260\316\200\216 \376\371\230\317\221 f\213l-back\012", + "m\226\200\203i\205\213iz\210\207\273\357\211um \352\342d\311", + "l\211g\273 \301\203i\205\213iz\257\267ce\276\207\336\200\301\273\200\211um \352\342d\012", + "\203\231x \362mis\337\272 \326", + "\221 i\365le\234\313\236f\260\316\200\216 \376\371\230\317\221 f\213l-back\012", "\316\200specif\335a\236\332\374w\204\206\231cl\321\236\274ig\221\220d\012", - "outpu\202\352\354\274writt\211\317bu\202\364\273 \344\365ac\202\211\344d\361\336s\254\276\012", + "outpu\202\352\354\274writt\211\317bu\202\364\273 \344\365ac\202\211\344d\361\341s\254\276\012", "\316\200\330\216 s\334dow\207\252g\345b\333\303\325", "\270\274\231\312c\223\235\320) \214\012", "pu\237\335 \270lack\207\374w\204\206\231cl\321\236\326", - "\217k\221w\341p\321met\257\376subs\205tu\236(\203c\226\220c\202#\323\200p\223\347n\234" + "\217k\221w\340p\321met\257\376subs\205tu\236(\203c\226\220c\202#\323\200p\223\347n\233" #endif }; From 52e8a1fa7646bff08119947b937f8b1bd9567ae6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Mar 2007 23:54:26 +0000 Subject: [PATCH 0539/1664] initial sketch of the timer system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40570 --- public/ITimerSystem.h | 109 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 public/ITimerSystem.h diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h new file mode 100644 index 00000000..2291087f --- /dev/null +++ b/public/ITimerSystem.h @@ -0,0 +1,109 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ + +#include + +//:TODO: this is a placeholder and not yet implemented +//remove these lines and uncomment once we're done! +//#define SMINTERFACE_TIMERSYS_NAME "ITimerSys" +//#define SMINTERFACE_TIMERSYS_VERSION 1 + +namespace SourceMod +{ + class ITimer; + + /** + * @brief Event callbacks for when a timer is executed. + */ + class ITimedEvent + { + public: + /** + * @brief Called when a timer is executed. + * + * @param pTimer Pointer to the timer instance. + * @param pData Private pointer passed from host. + * @return Pl_Handle to stop timer, Pl_Continue to continue. + * Passing Pl_Continue when a timer's repeat count + * has been exhausted will not extend it. + */ + virtual ResultType OnTimer(ITimer *pTimer, void *pData) =0; + + /** + * @brief Called when the timer has been killed. + * + * @param pTimer Pointer to the timer instance. + * @param pData Private data pointer passed from host. + */ + virtual void OnTimerEnd() =0; + }; + + #define TIMER_FLAG_REPEAT (1<<0) + + class ITimerSystem : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_TIMERSYS_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_TIMERSYS_VERSION; + } + public: + /** + * @brief Creates a timed event. + * + * @param pCallbacks Pointer to ITimedEvent callbacks. + * @param fInterval Interval, in seconds, of the timed event to occur. + * The smallest allowed interval is 0.1 seconds. + * @param pData Private data to pass on to the timer. + * @param flags Extra flags to pass on to the timer. + * @return An ITimer pointer on success, NULL on failure. + */ + virtual ITimer *CreateTimer(ITimedEvent *pCallbacks, + float fInterval, + void *pData, + int flags) =0; + + /** + * @brief Kills a timer. + * + * @param pTimer Pointer to the ITimer structure. + * @return + */ + virtual void KillTimer(ITimer *pTimer) =0; + + /** + * @brief Arbitrarily fires a timer. If the timer is not a repeating + * timer, this will also kill the timer. + * + * @param pTimer Pointer to the ITimer structure. + * @param delayExec If true, and the timer is repeating, the + * next execution will be delayed by its interval. + * @return + */ + virtual void FireTimerOnce(ITimer *pTimer, bool delayExec=false) =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ From 4499f4df7570469daa263639f8e7052ba7ffabff Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 3 Mar 2007 00:56:01 +0000 Subject: [PATCH 0540/1664] exposed the message interface --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40571 --- core/CUserMessages.cpp | 5 +++++ core/CUserMessages.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/CUserMessages.cpp b/core/CUserMessages.cpp index 25bc3ee2..d675b737 100644 --- a/core/CUserMessages.cpp +++ b/core/CUserMessages.cpp @@ -36,6 +36,11 @@ CUserMessages::~CUserMessages() sm_trie_destroy(m_Names); } +void CUserMessages::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, this); +} + void CUserMessages::OnSourceModAllShutdown() { if (m_HookCount) diff --git a/core/CUserMessages.h b/core/CUserMessages.h index 3c79965e..d18ce29a 100644 --- a/core/CUserMessages.h +++ b/core/CUserMessages.h @@ -15,9 +15,8 @@ #ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ #define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ -#include "sm_globals.h" +#include "ShareSys.h" #include -#include #include "sourcemm_api.h" #include "sm_trie.h" #include "CellRecipientFilter.h" @@ -37,6 +36,7 @@ public: CUserMessages(); ~CUserMessages(); public: //SMGlobalClass + void OnSourceModAllInitialized(); void OnSourceModAllShutdown(); public: //IUserMessages int GetMessageIndex(const char *msg); From ddfb56c34d40986ccbb0d86f43033a7462dfd5cd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 07:50:01 +0000 Subject: [PATCH 0541/1664] new versioning stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40572 --- core/CLogger.cpp | 6 +++--- core/msvc8/sourcemod_mm.vcproj | 4 ---- core/sm_srvcmds.cpp | 4 ++-- core/sm_version.h | 10 ++-------- core/sm_version.tpl | 24 ++++++++++++++++++++++++ core/sourcemm_api.cpp | 2 +- core/svn_version.h | 11 ----------- core/version.rc | 4 ++-- modules.versions | 14 ++++++++++++++ sourcepawn/jit/x86/jit_version.h | 5 ++--- sourcepawn/jit/x86/jit_version.tpl | 21 +++++++++++++++++++++ sourcepawn/jit/x86/jit_x86.cpp | 2 +- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 4 ---- sourcepawn/jit/x86/svn_version.h | 11 ----------- sourcepawn/jit/x86/version.rc | 4 ++-- 15 files changed, 74 insertions(+), 52 deletions(-) create mode 100644 core/sm_version.tpl delete mode 100644 core/svn_version.h create mode 100644 modules.versions create mode 100644 sourcepawn/jit/x86/jit_version.tpl delete mode 100644 sourcepawn/jit/x86/svn_version.h diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 04962c68..545256dc 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -71,7 +71,7 @@ void CLogger::_NewMapFile() } else { char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); - fprintf(fp, "L %s: SourceMod log file started (file \"logs_%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION); + fprintf(fp, "L %s: SourceMod log file started (file \"logs_%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SVN_FULL_VERSION); fclose(fp); } } @@ -218,8 +218,8 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_DailyPrintHdr) { m_DailyPrintHdr = false; - fprintf(fp, "L %s: SourceMod log file session started (file \"logs_%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION); - } + fprintf(fp, "L %s: SourceMod log file session started (file \"logs_%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SVN_FULL_VERSION); + } fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); } else { diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index c05a59b0..ca4676c8 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -357,10 +357,6 @@ RelativePath="..\sourcemod.h" > - - GetVMName(), g_pVM->GetVersionString()); ConsolePrint(" JIT Settings: %s", g_pVM->GetCPUOptimizations()); ConsolePrint(" http://www.sourcemod.net/"); diff --git a/core/sm_version.h b/core/sm_version.h index ca273dd3..f43e3372 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -18,13 +18,7 @@ * @file Contains SourceMod version information. */ -#include "svn_version.h" - -#define SOURCEMOD_V_MAJOR 1 -#define SOURCEMOD_V_MINOR 0 -#define SOURCEMOD_V_REV 0 - -#define SOURCEMOD_VERSION "1.0.0." SVN_REVISION_STRING -#define SOURCEMOD_FILEVERS 1,0,0,0 +#define SVN_FULL_VERSION "1.0.0.571" +#define SVN_FILE_VERSION 1,0,0,571 #endif //_INCLUDE_SOURCEMOD_VERSION_H_ diff --git a/core/sm_version.tpl b/core/sm_version.tpl new file mode 100644 index 00000000..a0f33049 --- /dev/null +++ b/core/sm_version.tpl @@ -0,0 +1,24 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_VERSION_H_ +#define _INCLUDE_SOURCEMOD_VERSION_H_ + +/** + * @file Contains SourceMod version information. + */ + +#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$GLOBAL_BUILD$" +#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$GLOBAL_BUILD$ + +#endif //_INCLUDE_SOURCEMOD_VERSION_H_ diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 3856b907..1374bba5 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -102,7 +102,7 @@ const char *SourceMod_Core::GetLicense() const char *SourceMod_Core::GetVersion() { - return SOURCEMOD_VERSION; + return SVN_FULL_VERSION; } const char *SourceMod_Core::GetDate() diff --git a/core/svn_version.h b/core/svn_version.h deleted file mode 100644 index 97147a48..00000000 --- a/core/svn_version.h +++ /dev/null @@ -1,11 +0,0 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 468 -#define SVN_REVISION_STRING "468" -#define SVN_FILE_VERSION 1,0,0,468 - -#endif //_INCLUDE_SVN_VERSION_H_ - diff --git a/core/version.rc b/core/version.rc index 5e6c1bfe..2a9e0860 100644 --- a/core/version.rc +++ b/core/version.rc @@ -47,12 +47,12 @@ BEGIN BEGIN VALUE "Comments", "SourceMod" VALUE "FileDescription", "SourceMod Core" - VALUE "FileVersion", SVN_REVISION_STRING + VALUE "FileVersion", SVN_FULL_VERSION VALUE "InternalName", "sourcemod" VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" VALUE "OriginalFilename", "sourcemod_mm.dll" VALUE "ProductName", "SourceMod" - VALUE "ProductVersion", SOURCEMOD_VERSION + VALUE "ProductVersion", SVN_FULL_VERSION END END BLOCK "VarFileInfo" diff --git a/modules.versions b/modules.versions new file mode 100644 index 00000000..671cb640 --- /dev/null +++ b/modules.versions @@ -0,0 +1,14 @@ +[PRODUCT] +major = 1 +minor = 0 +revision = 0 + +[core] +folder = core +in = sm_version.tpl +out = sm_version.h + +[jitx86] +folder = sourcepawn/jit/x86 +in = jit_version.tpl +out = jit_version.h diff --git a/sourcepawn/jit/x86/jit_version.h b/sourcepawn/jit/x86/jit_version.h index 01b7f602..f0db73f2 100644 --- a/sourcepawn/jit/x86/jit_version.h +++ b/sourcepawn/jit/x86/jit_version.h @@ -15,8 +15,7 @@ #ifndef _INCLUDE_JIT_VERSION_H_ #define _INCLUDE_JIT_VERSION_H_ -#include "svn_version.h" - -#define JIT_VERSION "1.0.0." SVN_REVISION_STRING +#define SVN_FULL_VERSION "1.0.0.431" +#define SVN_FILE_VERSION 1,0,0,431 #endif //_INCLUDE_JIT_VERSION_H_ diff --git a/sourcepawn/jit/x86/jit_version.tpl b/sourcepawn/jit/x86/jit_version.tpl new file mode 100644 index 00000000..6b7c221b --- /dev/null +++ b/sourcepawn/jit/x86/jit_version.tpl @@ -0,0 +1,21 @@ +/** + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + + +#ifndef _INCLUDE_JIT_VERSION_H_ +#define _INCLUDE_JIT_VERSION_H_ + +#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$LOCAL_BUILD$" +#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$ + +#endif //_INCLUDE_JIT_VERSION_H_ diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 35da47a2..7c9e5e89 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2332,7 +2332,7 @@ unsigned int JITX86::FunctionCount(const sp_context_t *ctx) const char *JITX86::GetVersionString() { - return JIT_VERSION; + return SVN_FULL_VERSION; } const char *JITX86::GetCPUOptimizations() diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index 8a44c16f..f2972a94 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -220,10 +220,6 @@ RelativePath="..\opcode_helpers.h" > - - diff --git a/sourcepawn/jit/x86/svn_version.h b/sourcepawn/jit/x86/svn_version.h deleted file mode 100644 index 27a49005..00000000 --- a/sourcepawn/jit/x86/svn_version.h +++ /dev/null @@ -1,11 +0,0 @@ -/** This file is autogenerated by build scripts */ - -#ifndef _INCLUDE_SVN_VERSION_H_ -#define _INCLUDE_SVN_VERSION_H_ - -#define SVN_REVISION 408 -#define SVN_REVISION_STRING "408" -#define SVN_FILE_VERSION 1,0,0,408 - -#endif //_INCLUDE_SVN_VERSION_H_ - diff --git a/sourcepawn/jit/x86/version.rc b/sourcepawn/jit/x86/version.rc index f3caeb14..60a7087f 100644 --- a/sourcepawn/jit/x86/version.rc +++ b/sourcepawn/jit/x86/version.rc @@ -46,12 +46,12 @@ BEGIN BEGIN VALUE "Comments", "SourcePawn JIT" VALUE "FileDescription", "SourcePawn JIT/Virtual Machine" - VALUE "FileVersion", SVN_REVISION_STRING + VALUE "FileVersion", SVN_FULL_VERSION VALUE "InternalName", "sourcemod" VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" VALUE "OriginalFilename", "sourcepawn.jit.x86.dll" VALUE "ProductName", "SourcePawn JIT" - VALUE "ProductVersion", JIT_VERSION + VALUE "ProductVersion", SVN_FULL_VERSION END END BLOCK "VarFileInfo" From b9da5d8a23ee34bf8330d26cc5541489a90a38a7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 07:54:32 +0000 Subject: [PATCH 0542/1664] added the holy version changer script! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40573 --- tools/versionchanger.pl | 166 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 tools/versionchanger.pl diff --git a/tools/versionchanger.pl b/tools/versionchanger.pl new file mode 100644 index 00000000..63004d38 --- /dev/null +++ b/tools/versionchanger.pl @@ -0,0 +1,166 @@ +#!/usr/bin/perl + +our %arguments = +( + 'config' => 'modules.versions', + 'major' => '1', + 'minor' => '0', + 'revision' => '0', + 'build' => undef, + 'svnrev' => 'global', + 'path' => '', +); + +my $arg; +foreach $arg (@ARGV) +{ + $arg =~ s/--//; + @arg = split(/=/, $arg); + $arguments{$arg[0]} = $arg[1]; +} + +#Set up path info +if ($arguments{'path'} ne "") +{ + if (!(-d $arguments{'path'})) + { + die "Unable to find path: " . $arguments{'path'} ."\n"; + } + chdir($arguments{'path'}); +} + +if (!open(CONFIG, $arguments{'config'})) +{ + die "Unable to open config file for reading: " . $arguments{'config'} . "\n"; +} + +our %modules; +my $cur_module = undef; +my $line; +while () +{ + chomp; + $line = $_; + if ($line =~ /^\[([^\]]+)\]$/) + { + $cur_module = $1; + next; + } + if (!$cur_module) + { + next; + } + if ($line =~ /^([^=]+) = (.+)$/) + { + $modules{$cur_module}{$1} = $2; + } +} + +close(CONFIG); + +#Copy global configuration options... +if (exists($modules{'PRODUCT'})) +{ + if (exists($modules{'PRODUCT'}{'major'})) + { + $arguments{'major'} = $modules{'PRODUCT'}{'major'}; + } + if (exists($modules{'PRODUCT'}{'minor'})) + { + $arguments{'minor'} = $modules{'PRODUCT'}{'minor'}; + } + if (exists($modules{'PRODUCT'}{'revision'})) + { + $arguments{'revision'} = $modules{'PRODUCT'}{'revision'}; + } + if (exists($modules{'PRODUCT'}{'svnrev'})) + { + $arguments{'svnrev'} = $modules{'PRODUCT'}{'svnrev'}; + } +} + +#Get the global SVN revision if we have none +my $rev; +if ($arguments{'build'} == undef) +{ + $rev = GetRevision(undef); +} else { + $rev = int($arguments{'build'}); +} + +my $major = $arguments{'major'}; +my $minor = $arguments{'minor'}; +my $revision = $arguments{'revision'}; +my $svnrev = $arguments{'svnrev'}; + +#Go through everything now +my $mod_i; +while ( ($cur_module, $mod_i) = each(%modules) ) +{ + #Skip the magic one + if ($cur_module eq "PRODUCT") + { + next; + } + #Prepare path + my %mod = %{$mod_i}; + my $infile = $mod{'in'}; + my $outfile = $mod{'out'}; + if ($mod{'folder'}) + { + if (!(-d $mod{'folder'})) + { + die "Folder " . $mod{'folder'} . " not found.\n"; + } + $infile = $mod{'folder'} . '/' . $infile; + $outfile = $mod{'folder'} . '/' . $outfile; + } + if (!(-f $infile)) + { + die "File $infile is not a file.\n"; + } + my $global_rev = $rev; + my $local_rev = GetRevision($mod{'folder'}); + if ($arguments{'svnrev'} eq 'local') + { + $global_rev = $local_rev; + } + #Start rewriting + open(INFILE, $infile) or die "Could not open file for reading: $infile\n"; + open(OUTFILE, '>'.$outfile) or die "Could not open file for writing: $outfile\n"; + while () + { + s/\$PMAJOR\$/$major/g; + s/\$PMINOR\$/$minor/g; + s/\$PREVISION\$/$revision/g; + s/\$GLOBAL_BUILD\$/$rev/g; + s/\$LOCAL_BUILD\$/$local_rev/g; + print OUTFILE $_; + } + close(OUTFILE); + close(INFILE); +} + +sub GetRevision +{ + my ($path)=(@_); + my $rev; + if (!$path) + { + $rev = `svnversion --committed`; + } else { + $rev = `svnversion --committed $path`; + } + print "$path $rev\n"; + if ($rev =~ /exported/) + { + die "Path specified is not a working copy\n"; + } elsif ($rev =~ /(\d+):(\d+)/) { + $rev = int($2); + } elsif ($rev =~ /(\d+)/) { + $rev = int($1); + } else { + die "Unknown svnversion response: $rev\n"; + } + return $rev; +} From 30a8e3237a6b039a32a6f7d29ae39a13e7a4fc26 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 08:11:40 +0000 Subject: [PATCH 0543/1664] removed Metamod from the build list, it was pointless --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40574 --- public/sample_ext/msvc8/sdk.sln | 6 -- public/sample_ext/msvc8/sdk.vcproj | 155 ----------------------------- 2 files changed, 161 deletions(-) diff --git a/public/sample_ext/msvc8/sdk.sln b/public/sample_ext/msvc8/sdk.sln index 99656471..a7b266be 100644 --- a/public/sample_ext/msvc8/sdk.sln +++ b/public/sample_ext/msvc8/sdk.sln @@ -5,18 +5,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk.vcproj", "{B3E79 EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug - Metamod|Win32 = Debug - Metamod|Win32 Debug|Win32 = Debug|Win32 - Release - Metamod|Win32 = Release - Metamod|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.ActiveCfg = Debug - Metamod|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.Build.0 = Debug - Metamod|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.ActiveCfg = Release - Metamod|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.Build.0 = Release - Metamod|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection diff --git a/public/sample_ext/msvc8/sdk.vcproj b/public/sample_ext/msvc8/sdk.vcproj index 4e0b3fca..cb06fd34 100644 --- a/public/sample_ext/msvc8/sdk.vcproj +++ b/public/sample_ext/msvc8/sdk.vcproj @@ -169,161 +169,6 @@ Name="VCPostBuildEventTool" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 868d9d4ba1df7233b0a9e5d02c0e7a945df00442 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 08:34:11 +0000 Subject: [PATCH 0544/1664] removed weird and bad lines from the Makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40575 --- public/sample_ext/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/public/sample_ext/Makefile b/public/sample_ext/Makefile index 537e149c..22ff9208 100644 --- a/public/sample_ext/Makefile +++ b/public/sample_ext/Makefile @@ -60,14 +60,10 @@ endif BINARY = $(PROJECT).ext.so OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) -OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -$(BIN_DIR)/%.o: %.c - $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< - all: mkdir -p $(BIN_DIR) ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so From 98a010efc16e1ae590b4be9d1c033d9a0e850dad Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 08:40:01 +0000 Subject: [PATCH 0545/1664] added versioning to geoip --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40576 --- extensions/geoip/msvc8/geoip.vcproj | 8 +++ extensions/geoip/smsdk_config.h | 4 +- extensions/geoip/svn_version.h | 12 ++++ extensions/geoip/svn_version.tpl | 12 ++++ extensions/geoip/version.rc | 104 ++++++++++++++++++++++++++++ modules.versions | 5 ++ tools/versionchanger.pl | 1 - 7 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 extensions/geoip/svn_version.h create mode 100644 extensions/geoip/svn_version.tpl create mode 100644 extensions/geoip/version.rc diff --git a/extensions/geoip/msvc8/geoip.vcproj b/extensions/geoip/msvc8/geoip.vcproj index d9132994..313793a6 100644 --- a/extensions/geoip/msvc8/geoip.vcproj +++ b/extensions/geoip/msvc8/geoip.vcproj @@ -214,12 +214,20 @@ RelativePath="..\smsdk_ext.h" > + + + + diff --git a/extensions/geoip/smsdk_config.h b/extensions/geoip/smsdk_config.h index 3356afb2..8e77d2ac 100644 --- a/extensions/geoip/smsdk_config.h +++ b/extensions/geoip/smsdk_config.h @@ -20,10 +20,12 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#include "svn_version.h" + /* Basic information exposed publically */ #define SMEXT_CONF_NAME "GeoIP" #define SMEXT_CONF_DESCRIPTION "NO IDEA WHAT THIS MODULE DOES" //:TODO: -#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_VERSION SVN_FULL_VERSION #define SMEXT_CONF_AUTHOR "AlliedModders" #define SMEXT_CONF_URL "http://www.sourcemod.net/" #define SMEXT_CONF_LOGTAG "GEOIP" diff --git a/extensions/geoip/svn_version.h b/extensions/geoip/svn_version.h new file mode 100644 index 00000000..e7226735 --- /dev/null +++ b/extensions/geoip/svn_version.h @@ -0,0 +1,12 @@ +/** + * Autogenerated by build scripts + */ + +#ifndef _INCLUDE_GEOIP_VERSION_H_ +#define _INCLUDE_GEOIP_VERSION_H_ + + +#define SVN_FULL_VERSION "1.0.0.431" +#define SVN_FILE_VERSION 1,0,0,431 + +#endif //_INCLUDE_GEOIP_VERSION_H_ diff --git a/extensions/geoip/svn_version.tpl b/extensions/geoip/svn_version.tpl new file mode 100644 index 00000000..3574844e --- /dev/null +++ b/extensions/geoip/svn_version.tpl @@ -0,0 +1,12 @@ +/** + * Autogenerated by build scripts + */ + +#ifndef _INCLUDE_GEOIP_VERSION_H_ +#define _INCLUDE_GEOIP_VERSION_H_ + + +#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$LOCAL_BUILD$" +#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$ + +#endif //_INCLUDE_GEOIP_VERSION_H_ diff --git a/extensions/geoip/version.rc b/extensions/geoip/version.rc new file mode 100644 index 00000000..5bf02ef0 --- /dev/null +++ b/extensions/geoip/version.rc @@ -0,0 +1,104 @@ +// Microsoft Visual C++ generated resource script. +// +//#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +#include "svn_version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION SVN_FILE_VERSION + PRODUCTVERSION SVN_FILE_VERSION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "GeoIP Extension" + VALUE "FileDescription", "SourceMod GeoIP Extension" + VALUE "FileVersion", SVN_FULL_VERSION + VALUE "InternalName", "sourceMod GeoIP Extension" + VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" + VALUE "OriginalFilename", "geoip.ext.dll" + VALUE "ProductName", "SourceMod GeoIP Extension" + VALUE "ProductVersion", SVN_FULL_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/modules.versions b/modules.versions index 671cb640..bc75a4a1 100644 --- a/modules.versions +++ b/modules.versions @@ -12,3 +12,8 @@ out = sm_version.h folder = sourcepawn/jit/x86 in = jit_version.tpl out = jit_version.h + +[geoip] +folder = extensions/geoip +in = svn_version.tpl +out = svn_version.h diff --git a/tools/versionchanger.pl b/tools/versionchanger.pl index 63004d38..a8457e93 100644 --- a/tools/versionchanger.pl +++ b/tools/versionchanger.pl @@ -151,7 +151,6 @@ sub GetRevision } else { $rev = `svnversion --committed $path`; } - print "$path $rev\n"; if ($rev =~ /exported/) { die "Path specified is not a working copy\n"; From 3118427af330016ca2c0c0d053a481adc52924f0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 08:43:48 +0000 Subject: [PATCH 0546/1664] added threader to versioning --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40577 --- extensions/geoip/version.rc | 2 +- extensions/threader/msvc8/threader.vcproj | 8 ++ extensions/threader/smsdk_config.h | 4 +- extensions/threader/svn_version.h | 12 +++ extensions/threader/svn_version.tpl | 12 +++ extensions/threader/version.rc | 104 ++++++++++++++++++++++ modules.versions | 5 ++ 7 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 extensions/threader/svn_version.h create mode 100644 extensions/threader/svn_version.tpl create mode 100644 extensions/threader/version.rc diff --git a/extensions/geoip/version.rc b/extensions/geoip/version.rc index 5bf02ef0..d89d3701 100644 --- a/extensions/geoip/version.rc +++ b/extensions/geoip/version.rc @@ -48,7 +48,7 @@ BEGIN VALUE "Comments", "GeoIP Extension" VALUE "FileDescription", "SourceMod GeoIP Extension" VALUE "FileVersion", SVN_FULL_VERSION - VALUE "InternalName", "sourceMod GeoIP Extension" + VALUE "InternalName", "SourceMod GeoIP Extension" VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" VALUE "OriginalFilename", "geoip.ext.dll" VALUE "ProductName", "SourceMod GeoIP Extension" diff --git a/extensions/threader/msvc8/threader.vcproj b/extensions/threader/msvc8/threader.vcproj index ed8e16c7..0d33669f 100644 --- a/extensions/threader/msvc8/threader.vcproj +++ b/extensions/threader/msvc8/threader.vcproj @@ -192,12 +192,20 @@ RelativePath="..\extension.h" > + + + + Date: Sat, 3 Mar 2007 08:51:47 +0000 Subject: [PATCH 0547/1664] added versioning to plugins --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40578 --- modules.versions | 5 +++++ plugins/include/core.inc | 6 +++++- plugins/include/version.inc | 25 +++++++++++++++++++++++++ plugins/include/version.tpl | 25 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 plugins/include/version.inc create mode 100644 plugins/include/version.tpl diff --git a/modules.versions b/modules.versions index b402d737..a0d7008c 100644 --- a/modules.versions +++ b/modules.versions @@ -8,6 +8,11 @@ folder = core in = sm_version.tpl out = sm_version.h +[plugins] +folder = plugins/include +in = version.tpl +out = version.inc + [jitx86] folder = sourcepawn/jit/x86 in = jit_version.tpl diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 5c867e7f..f5aed571 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -18,10 +18,13 @@ #endif #define _core_included -#define SOURCEMOD_PLUGINAPI_VERSION 1 +#include + +#define SOURCEMOD_PLUGINAPI_VERSION 2 struct PlVers { version, + String:filevers[], }; /** @@ -37,6 +40,7 @@ enum Action public PlVers:__version = { version = SOURCEMOD_PLUGINAPI_VERSION, + filevers = SOURCEMOD_VERSION }; struct Extension diff --git a/plugins/include/version.inc b/plugins/include/version.inc new file mode 100644 index 00000000..cad96bad --- /dev/null +++ b/plugins/include/version.inc @@ -0,0 +1,25 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _version_included + #endinput +#endif +#define _version_included + +#define SOURCEMOD_V_MAJOR 1 +#define SOURCEMOD_V_MINOR 0 +#define SOURCEMOD_V_RELEASE 0 + +#define SOURCEMOD_VERSION "1.0.0.577" diff --git a/plugins/include/version.tpl b/plugins/include/version.tpl new file mode 100644 index 00000000..37bc352c --- /dev/null +++ b/plugins/include/version.tpl @@ -0,0 +1,25 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _version_included + #endinput +#endif +#define _version_included + +#define SOURCEMOD_V_MAJOR $PMAJOR$ +#define SOURCEMOD_V_MINOR $PMINOR$ +#define SOURCEMOD_V_RELEASE $PREVISION$ + +#define SOURCEMOD_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$GLOBAL_BUILD$" From 60a37530fc42dd4c8d9e3efca3b7e6cc5909a97b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 08:56:45 +0000 Subject: [PATCH 0548/1664] excluded version.tpl from package builds --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40579 --- tools/builder/PkgCore.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 0c54e565..9dde3b0a 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -59,6 +59,9 @@ namespace builder string [] plugin_omits = new string[1]; plugin_omits[0] = "spcomp.exe"; + string [] include_omits = new string[1]; + include_omits[1] = "version.tpl"; + builder.CopyFolder(this, "plugins", "scripting", plugin_omits); builder.CopyFolder(this, "plugins/include", "scripting/include", null); builder.CopyFolder(this, "translations", "translations", null); From 300926b87dff5b879bc17157e37093407aea51cf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 3 Mar 2007 09:37:47 +0000 Subject: [PATCH 0549/1664] removed svn_version file updating --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40580 --- tools/builder/ABuilder.cs | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs index d1f7016f..0d198ca1 100644 --- a/tools/builder/ABuilder.cs +++ b/tools/builder/ABuilder.cs @@ -54,40 +54,6 @@ namespace builder return rev; } - public void UpdateRevisionInfo(Package pkg, Library lib) - { - string path = Config.PathFormat("{0}/{1}", cfg.SourceBase, lib.LocalPath); - string file = Config.PathFormat("{0}/svn_version.h", path); - - if (File.Exists(file)) - { - UpdateRevisionInfo(path, file); - } - } - - public void UpdateRevisionInfo(string path, string file) - { - string vers = cfg.ProductVersion.Replace(".", ","); - string rev = GetRevsionOfPath(path); - - File.Delete(file); - StreamWriter sw = File.CreateText(file); - - sw.WriteLine("/** This file is autogenerated by build scripts */"); - sw.WriteLine(""); - sw.WriteLine("#ifndef _INCLUDE_SVN_VERSION_H_"); - sw.WriteLine("#define _INCLUDE_SVN_VERSION_H_"); - sw.WriteLine(""); - sw.WriteLine("#define SVN_REVISION {0}", rev); - sw.WriteLine("#define SVN_REVISION_STRING \"{0}\"", rev); - sw.WriteLine("#define SVN_FILE_VERSION {0},{1}", vers, rev); - sw.WriteLine(""); - sw.WriteLine("#endif //_INCLUDE_SVN_VERSION_H_"); - sw.WriteLine(""); - - sw.Close(); - } - public bool CopyFile(Package pkg, string source, string dest) { string from = Config.PathFormat("{0}/{1}", @@ -191,7 +157,6 @@ namespace builder string bin = null, binpath = null; for (int i=0; i Date: Sat, 3 Mar 2007 09:46:36 +0000 Subject: [PATCH 0550/1664] fixed really stupid bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40581 --- tools/builder/PkgCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 9dde3b0a..1190cd24 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -60,10 +60,10 @@ namespace builder plugin_omits[0] = "spcomp.exe"; string [] include_omits = new string[1]; - include_omits[1] = "version.tpl"; + include_omits[0] = "version.tpl"; builder.CopyFolder(this, "plugins", "scripting", plugin_omits); - builder.CopyFolder(this, "plugins/include", "scripting/include", null); + builder.CopyFolder(this, "plugins/include", "scripting/include", include_omits); builder.CopyFolder(this, "translations", "translations", null); builder.CopyFolder(this, "public/licenses", null, null); } From 68f40e96f2618f33991d7cab56173d9cd0869b9a Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 4 Mar 2007 04:05:03 +0000 Subject: [PATCH 0551/1664] Initial import of event stuff: Natives to hook and fire game events Also made some minor internal changes to convars --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40582 --- core/CConVarManager.cpp | 78 +++---- core/CConVarManager.h | 10 +- core/EventManager.cpp | 363 +++++++++++++++++++++++++++++++++ core/EventManager.h | 119 +++++++++++ core/msvc8/sourcemod_mm.vcproj | 12 ++ core/smn_console.cpp | 90 ++++---- core/smn_events.cpp | 337 ++++++++++++++++++++++++++++++ plugins/include/console.inc | 2 +- plugins/include/events.inc | 205 +++++++++++++++++++ plugins/include/sourcemod.inc | 3 +- 10 files changed, 1128 insertions(+), 91 deletions(-) create mode 100644 core/EventManager.cpp create mode 100644 core/EventManager.h create mode 100644 core/smn_events.cpp create mode 100644 plugins/include/events.inc diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 734379a0..5c6e6f02 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -88,7 +88,7 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) CVector *cvarList; // If plugin has a convar list, free its memory - if (plugin->GetProperty("ConVar", reinterpret_cast(&cvarList), true)) + if (plugin->GetProperty("ConVarList", reinterpret_cast(&cvarList), true)) { delete cvarList; } @@ -97,21 +97,21 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) { ConVarInfo *info; - ConVar *cvar = static_cast(object); + ConVar *pConVar = static_cast(object); // Find convar in lookup trie - sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); + sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info)); // If convar was created by SourceMod plugin... if (info->sourceMod) { // Delete string allocations - delete [] cvar->GetName(); - delete [] cvar->GetDefault(); - delete [] cvar->GetHelpText(); + delete [] pConVar->GetName(); + delete [] pConVar->GetDefault(); + delete [] pConVar->GetHelpText(); - // Then unregister it - g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); + // Then unlink it from SourceMM + g_SMAPI->UnregisterConCmdBase(g_PLAPI, pConVar); } } @@ -151,8 +151,8 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc // Iterate convar list and display each one for (size_t i = 0; i < cvarList->size(); i++, id++) { - ConVar *cvar = (*cvarList)[i]; - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); + ConVar *pConVar = (*cvarList)[i]; + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, pConVar->GetName(), pConVar->GetString()); } return; @@ -164,16 +164,16 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) { - ConVar *cvar = NULL; + ConVar *pConVar = NULL; ConVarInfo *info = NULL; CVector *cvarList = NULL; Handle_t hndl = 0; // Find out if the convar exists already - cvar = icvar->FindVar(name); + pConVar = icvar->FindVar(name); // If the convar already exists... - if (cvar != NULL) + if (pConVar != NULL) { // First check if we already have a handle to it if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) @@ -182,13 +182,13 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name return info->handle; } else { // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; info->sourceMod = false; info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); + info->origCallback = pConVar->GetCallback(); m_ConVars.push_back(info); @@ -210,27 +210,27 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name } // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - cvar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); + pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); // Find plugin creating convar IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); // Get convar list from 'ConVar' property of plugin - pl->GetProperty("ConVar", reinterpret_cast(&cvarList)); + pl->GetProperty("ConVarList", reinterpret_cast(&cvarList)); // If 'ConVar' property doesn't exist... if (cvarList == NULL) { // Then create it cvarList = new CVector; - pl->SetProperty("ConVar", cvarList); + pl->SetProperty("ConVarList", cvarList); } // Add new convar to plugin's list - cvarList->push_back(cvar); + cvarList->push_back(pConVar); // Create a handle from the new convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; @@ -248,15 +248,15 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name Handle_t CConVarManager::FindConVar(const char *name) { - ConVar *cvar = NULL; + ConVar *pConVar = NULL; ConVarInfo *info = NULL; Handle_t hndl = 0; // Search for convar - cvar = icvar->FindVar(name); + pConVar = icvar->FindVar(name); // If it doesn't exist, then return an invalid handle - if (cvar == NULL) + if (pConVar == NULL) { return BAD_HANDLE; } @@ -269,13 +269,13 @@ Handle_t CConVarManager::FindConVar(const char *name) } // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; info->sourceMod = false; info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); + info->origCallback = pConVar->GetCallback(); m_ConVars.push_back(info); @@ -285,7 +285,7 @@ Handle_t CConVarManager::FindConVar(const char *name) return hndl; } -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -300,7 +300,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu } // Create a forward name - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", pConVar->GetName()); // First find out if the forward already exists g_Forwards.FindForward(fwdName, &fwd); @@ -315,13 +315,13 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) { // Set the convar's forward to the newly created one info->changeForward = fwd; // Set the convar's callback to our static one - cvar->InstallChangeCallback(OnConVarChanged); + pConVar->InstallChangeCallback(OnConVarChanged); } } @@ -329,7 +329,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu fwd->AddFunction(func); } -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -343,7 +343,7 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, } // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) { // Get the forward fwd = info->changeForward; @@ -351,14 +351,14 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, // If the forward doesn't exist, we can't unhook anything if (fwd == NULL) { - pContext->ThrowNativeError("Convar \"%s\" has no active hook", cvar->GetName()); + pContext->ThrowNativeError("Convar \"%s\" has no active hook", pConVar->GetName()); return; } // Remove the function from the forward's list if (!fwd->RemoveFunction(func)) { - pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", cvar->GetName()); + pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", pConVar->GetName()); return; } @@ -370,15 +370,15 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, info->changeForward = NULL; // Put the back the original convar callback - cvar->InstallChangeCallback(info->origCallback); + pConVar->InstallChangeCallback(info->origCallback); } } } -void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) +void CConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) { // If the values are the same... - if (strcmp(cvar->GetString(), oldValue) == 0) + if (strcmp(pConVar->GetString(), oldValue) == 0) { // Exit early in order to not trigger callbacks return; @@ -388,7 +388,7 @@ void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) ConVarInfo *info; // Find the convar in the lookup trie - sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); + sm_trie_retrieve(cache, pConVar->GetName(), reinterpret_cast(&info)); FnChangeCallback origCallback = info->origCallback; IChangeableForward *fwd = info->changeForward; @@ -396,12 +396,12 @@ void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) // If there was a change callback installed previously, call it if (origCallback) { - origCallback(cvar, oldValue); + origCallback(pConVar, oldValue); } // Now call forwards in plugins that have hooked this fwd->PushCell(info->handle); - fwd->PushString(cvar->GetString()); + fwd->PushString(pConVar->GetString()); fwd->PushString(oldValue); fwd->Execute(NULL); } diff --git a/core/CConVarManager.h b/core/CConVarManager.h index 80a05dda..aeecbf74 100644 --- a/core/CConVarManager.h +++ b/core/CConVarManager.h @@ -85,17 +85,17 @@ public: /** * Add a function to call when the specified convar changes. */ - void HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); + void HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); /** * Remove a function from the forward that will be called when the specified convar changes. */ - void UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); + void UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); private: /** - * Static callback that Valve's ConVar class executes when the convar's value changes. - */ - static void OnConVarChanged(ConVar *cvar, const char *oldValue); + * Static callback that Valve's ConVar class executes when the convar's value changes. + */ + static void OnConVarChanged(ConVar *pConVar, const char *oldValue); private: HandleType_t m_ConVarType; List m_ConVars; diff --git a/core/EventManager.cpp b/core/EventManager.cpp new file mode 100644 index 00000000..bf70b97f --- /dev/null +++ b/core/EventManager.cpp @@ -0,0 +1,363 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "EventManager.h" +#include "ForwardSys.h" +#include "HandleSys.h" +#include "PluginSys.h" +#include "sm_stringutil.h" + +EventManager g_EventManager; + +SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool); + +typedef List EventHookList; + +const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; + +EventManager::EventManager() : m_EventCopy(NULL), m_NotifyState(true) +{ + /* Create an event lookup trie */ + m_EventHooks = sm_trie_create(); +} + +EventManager::~EventManager() +{ + sm_trie_destroy(m_EventHooks); +} + +void EventManager::OnSourceModAllInitialized() +{ + /* Add a hook for IGameEventManager2::FireEvent() */ + SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false); + SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true); + + HandleAccess sec; + + /* Handle access security for 'GameEvent' handle type */ + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + /* Create the 'GameEvent' handle type */ + m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL); +} + +void EventManager::OnSourceModShutdown() +{ + /* Remove hook for IGameEventManager2::FireEvent() */ + SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false); + SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true); + + /* Remove the 'GameEvent' handle type */ + g_HandleSys.RemoveType(m_EventType, g_pCoreIdent); + + /* Remove ourselves as listener for events */ + gameevents->RemoveListener(this); +} + +void EventManager::OnHandleDestroy(HandleType_t type, void *object) +{ + if (type == m_EventType) + { + EventInfo *pInfo = static_cast(object); + + if (pInfo->canDelete) + { + gameevents->FreeEvent(pInfo->pEvent); + delete pInfo; + } + } +} + +void EventManager::OnPluginUnloaded(IPlugin *plugin) +{ + EventHookList *pHookList; + EventHook *pHook; + + // If plugin has an event hook list... + if (plugin->GetProperty("EventHooks", reinterpret_cast(&pHookList), true)) + { + for (EventHookList::iterator iter = pHookList->begin(); iter != pHookList->end(); iter++) + { + pHook = (*iter); + + if (--pHook->refCount == 0) + { + if (pHook->pPreHook) + { + g_Forwards.ReleaseForward(pHook->pPreHook); + } + + if (pHook->pPostHook) + { + g_Forwards.ReleaseForward(pHook->pPostHook); + } + + delete pHook; + } + } + + delete pHookList; + } +} + +/* IGameEventListener2::FireGameEvent */ +void EventManager::FireGameEvent(IGameEvent *pEvent) +{ + /* Not going to do anything here. + Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */ +} + +EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode) +{ + EventHook *pHook; + + /* If we aren't listening to this event... */ + if (!gameevents->FindListener(this, name)) + { + /* Then add ourselves */ + if (!gameevents->AddListener(this, name, true)) + { + /* If event doesn't exist... */ + return EventHookErr_InvalidEvent; + } + } + + /* If a hook structure does not exist... */ + if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook)) + { + EventHookList *pHookList; + IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + + /* Check plugin for an existing EventHook list */ + if (!plugin->GetProperty("EventHooks", (void **)&pHookList)) + { + pHookList = new EventHookList(); + plugin->SetProperty("EventHooks", pHookList); + } + + /* Create new GameEventHook structure */ + pHook = new EventHook(); + + if (mode == EventHookMode_Pre) + { + /* Create forward for a pre hook */ + pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS); + /* Add to forward list */ + pHook->pPreHook->AddFunction(pFunction); + } else { + /* Create forward for a post hook */ + pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); + /* Should we copy data from a pre hook to the post hook? */ + pHook->postCopy = (mode == EventHookMode_Post); + /* Add to forward list */ + pHook->pPostHook->AddFunction(pFunction); + } + + /* Increase reference count */ + pHook->refCount++; + + /* Add hook structure to hook lists */ + pHookList->push_back(pHook); + sm_trie_insert(m_EventHooks, name, pHook); + + return EventHookErr_Okay; + } + + /* Hook structure already exists at this point */ + + if (mode == EventHookMode_Pre) + { + /* Create pre hook forward if necessary */ + if (!pHook->pPreHook) + { + pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS); + } + + /* Add plugin function to forward list */ + pHook->pPreHook->AddFunction(pFunction); + } else { + /* Create post hook forward if necessary */ + if (!pHook->pPostHook) + { + pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); + } + + /* If postCopy is false, then we may want to set it to true */ + if (!pHook->postCopy) + { + pHook->postCopy = (mode == EventHookMode_Post); + } + + /* Add plugin function to forward list */ + pHook->pPostHook->AddFunction(pFunction); + } + + /* Increase reference count */ + pHook->refCount++; + + return EventHookErr_Okay; +} + +EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode) +{ + EventHook *pHook; + IChangeableForward **pEventForward; + + /* If hook does not exist at all */ + if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook)) + { + return EventHookErr_NotActive; + } + + /* One forward to rule them all */ + if (mode == EventHookMode_Pre) + { + pEventForward = &pHook->pPreHook; + } else { + pEventForward = &pHook->pPostHook; + } + + /* Remove function from forward's list */ + if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction)) + { + return EventHookErr_InvalidCallback; + } + + /* If forward's list contains 0 functions now, free it */ + if ((*pEventForward)->GetFunctionCount() == 0) + { + g_Forwards.ReleaseForward(*pEventForward); + *pEventForward = NULL; + } + + /* Decrement reference count */ + if (--pHook->refCount == 0) + { + /* If reference count is now 0, free hook structure */ + + EventHookList *pHookList; + IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + + /* Get plugin's event hook list */ + plugin->GetProperty("EventHooks", (void**)&pHookList); + + /* Remove current structure from plugin's list */ + pHookList->remove(pHook); + + /* Delete entry in trie */ + sm_trie_delete(m_EventHooks, name); + + /* And finally free structure memory */ + delete pHook; + } + + return EventHookErr_Okay; +} + +/* IGameEventManager2::FireEvent hook */ +bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) +{ + EventHook *pHook; + IChangeableForward *pForward; + cell_t res = Pl_Continue; + + if (!m_NotifyState) + { + RETURN_META_VALUE(MRES_IGNORED, true); + } + + /* Get the event name, we're going to need this for passing to post hooks */ + m_EventName = pEvent->GetName(); + + if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + { + pForward = pHook->pPreHook; + + if (pForward) + { + EventInfo info = {pEvent, false}; + + Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); + pForward->PushCell(hndl); + pForward->PushString(m_EventName); + pForward->PushCell(bDontBroadcast); + pForward->Execute(&res, NULL); + + HandleSecurity sec = { NULL, g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + } + + if (pHook->postCopy) + { + m_EventCopy = gameevents->DuplicateEvent(pEvent); + } + + if (res) + { + gameevents->FreeEvent(pEvent); + RETURN_META_VALUE(MRES_SUPERCEDE, false); + } + } + + RETURN_META_VALUE(MRES_IGNORED, true); +} + +/* IGameEventManager2::FireEvent post hook */ +bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) +{ + EventHook *pHook; + IChangeableForward *pForward; + Handle_t hndl; + + if (!m_NotifyState) + { + m_NotifyState = true; + RETURN_META_VALUE(MRES_IGNORED, true); + } + + if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + { + pForward = pHook->pPostHook; + + if (pForward) + { + if (pHook->postCopy) + { + EventInfo info = {m_EventCopy, false}; + hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); + pForward->PushCell(hndl); + } else { + pForward->PushCell(BAD_HANDLE); + } + + pForward->PushString(m_EventName); + pForward->PushCell(bDontBroadcast); + pForward->Execute(NULL); + + if (pHook->postCopy) + { + /* Free handle */ + HandleSecurity sec = { NULL, g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + /* Free event structure */ + gameevents->FreeEvent(m_EventCopy); + m_EventCopy = NULL; + } + } + } + + RETURN_META_VALUE(MRES_IGNORED, true); +} diff --git a/core/EventManager.h b/core/EventManager.h new file mode 100644 index 00000000..7b67cb00 --- /dev/null +++ b/core/EventManager.h @@ -0,0 +1,119 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "sm_trie.h" +#include +#include +#include +#include + +using namespace SourceHook; + +//#define EVENT_PASSTHRU (1<<0) +#define EVENT_PASSTHRU_ALL (1<<1) + +struct EventInfo +{ + IGameEvent *pEvent; + bool canDelete; +}; + +struct EventHook +{ + EventHook() + { + pPreHook = NULL; + pPostHook = NULL; + postCopy = false; + refCount = 0; + } + IChangeableForward *pPreHook; + IChangeableForward *pPostHook; + bool postCopy; + unsigned int refCount; +}; + +enum EventHookMode +{ + EventHookMode_Pre, + EventHookMode_Post, + EventHookMode_PostNoCopy +}; + +enum EventHookError +{ + EventHookErr_Okay = 0, /**< No error */ + EventHookErr_InvalidEvent, /**< Specified event does not exist */ + EventHookErr_NotActive, /**< Specified event has no active hook */ + EventHookErr_InvalidCallback, /**< Specified event does not fire specified callback */ +}; + +class EventManager : + public SMGlobalClass, + public IHandleTypeDispatch, + public IPluginsListener, + public IGameEventListener2 +{ +public: + EventManager(); + ~EventManager(); +public: // SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: // IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: // IPluginsListener + void OnPluginUnloaded(IPlugin *plugin); +public: // IGameEventListener2 + void FireGameEvent(IGameEvent *pEvent); +public: + /** + * Get the 'GameEvent' handle type ID. + */ + inline HandleType_t GetHandleType() + { + return EventManager::m_EventType; + } + + /** + * Sets the current SourceMod event notification state. + * + * If notify is set to true, SourceMod plugins will be notified of events. If false, they will not. + * This is temporarily used to make EVENT_PASSTHRU work when firing events from plugins. + */ + inline void SetNotifyState(bool notify) + { + m_NotifyState = notify; + } +public: + EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); + EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); +private: // IGameEventManager2 hooks + bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); + bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); +private: + HandleType_t m_EventType; + Trie *m_EventHooks; + bool m_NotifyState; + IGameEvent *m_EventCopy; + const char *m_EventName; +}; + +extern EventManager g_EventManager; + +#endif // _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index ca4676c8..f6986fa9 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -227,6 +227,10 @@ RelativePath="..\CUserMessages.cpp" > + + @@ -317,6 +321,10 @@ RelativePath="..\CUserMessages.h" > + + @@ -689,6 +697,10 @@ RelativePath="..\smn_entities.cpp" > + + diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 0c7e4570..b0889ddf 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -62,15 +62,15 @@ static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - g_ConVarManager.HookConVarChange(pContext, cvar, static_cast(params[2])); + g_ConVarManager.HookConVarChange(pContext, pConVar, static_cast(params[2])); return 1; } @@ -79,15 +79,15 @@ static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *para { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - g_ConVarManager.UnhookConVarChange(pContext, cvar, static_cast(params[2])); + g_ConVarManager.UnhookConVarChange(pContext, pConVar, static_cast(params[2])); return 1; } @@ -96,30 +96,30 @@ static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetBool(); + return pConVar->GetBool(); } static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetInt(); + return pConVar->GetInt(); } /* This handles both SetConVarBool() and SetConVarInt() */ @@ -127,15 +127,15 @@ static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->SetValue(params[2]); + pConVar->SetValue(params[2]); return 1; } @@ -144,15 +144,15 @@ static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - float value = cvar->GetFloat(); + float value = pConVar->GetFloat(); return sp_ftoc(value); } @@ -161,16 +161,16 @@ static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } float value = sp_ctof(params[2]); - cvar->SetValue(value); + pConVar->SetValue(value); return 1; } @@ -179,15 +179,15 @@ static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - pContext->StringToLocalUTF8(params[2], params[3], cvar->GetString(), NULL); + pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL); return 1; } @@ -196,9 +196,9 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -207,7 +207,7 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) char *value; pContext->LocalToString(params[2], &value); - cvar->SetValue(value); + pConVar->SetValue(value); return 1; } @@ -216,30 +216,30 @@ static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetFlags(); + return pConVar->GetFlags(); } static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->SetFlags(params[2]); + pConVar->SetFlags(params[2]); return 1; } @@ -248,9 +248,9 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -262,7 +262,7 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[2], &addr); - hasMin = cvar->GetMin(min); + hasMin = pConVar->GetMin(min); *addr = sp_ftoc(min); return hasMin; @@ -272,9 +272,9 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -286,7 +286,7 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[2], &addr); - hasMax = cvar->GetMax(max); + hasMax = pConVar->GetMax(max); *addr = sp_ftoc(max); return hasMax; @@ -296,15 +296,15 @@ static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - pContext->StringToLocalUTF8(params[2], params[3], cvar->GetName(), NULL); + pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL); return 1; } @@ -313,15 +313,15 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->Revert(); + pConVar->Revert(); return 1; } diff --git a/core/smn_events.cpp b/core/smn_events.cpp new file mode 100644 index 00000000..edc3b471 --- /dev/null +++ b/core/smn_events.cpp @@ -0,0 +1,337 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "HandleSys.h" +#include "EventManager.h" + +static cell_t sm_HookEvent(IPluginContext *pContext, const cell_t *params) +{ + char *name; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + if (g_EventManager.HookEvent(name, pFunction, static_cast(params[3])) == EventHookErr_InvalidEvent) + { + return pContext->ThrowNativeError("Game event \"%s\" does not exist", name); + } + + return 1; +} + +static cell_t sm_UnhookEvent(IPluginContext *pContext, const cell_t *params) +{ + char *name; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + EventHookError err = g_EventManager.UnhookEvent(name, pFunction, static_cast(params[3])); + + /* Possible errors that UnhookGameEvent can return */ + if (err == EventHookErr_NotActive) + { + return pContext->ThrowNativeError("Game event \"%s\" has no active hook", name); + } else if (err == EventHookErr_InvalidCallback) { + return pContext->ThrowNativeError("Invalid hook callback specified for game event \"%s\"", name); + } + + return 1; +} + +static cell_t sm_CreateEvent(IPluginContext *pContext, const cell_t *params) +{ + IGameEvent *pEvent; + EventInfo *pInfo; + char *name; + + pContext->LocalToString(params[1], &name); + + pEvent = gameevents->CreateEvent(name, true); + + if (pEvent) + { + pInfo = new EventInfo; + pInfo->pEvent = pEvent; + pInfo->canDelete = true; + + return g_HandleSys.CreateHandle(g_EventManager.GetHandleType(), pInfo, pContext->GetIdentity(), g_pCoreIdent, NULL); + } + + return BAD_HANDLE; +} + +static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + if ((params[3] & EVENT_PASSTHRU_ALL) == false) + { + /* Set whether or not SourceMod plugins should be notified */ + g_EventManager.SetNotifyState(false); + } + + /* Fire game event */ + gameevents->FireEvent(pInfo->pEvent, params[2] ? true : false); + + pInfo->canDelete = false; + + /* Free handle on game event */ + HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + /* Free EventInfo memory */ + delete pInfo; + + return 1; +} + +static cell_t sm_CancelCreatedEvent(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + gameevents->FreeEvent(pInfo->pEvent); + + // Free GameEventInfo memory + delete pInfo; + + // Free handle on game event + HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + return 1; +} + +static cell_t sm_GetEventName(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + pContext->StringToLocalUTF8(params[2], params[3], pInfo->pEvent->GetName(), NULL); + + return 1; +} + +static cell_t sm_GetEventBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + return pInfo->pEvent->GetBool(key); +} + +static cell_t sm_GetEventInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + return pInfo->pEvent->GetInt(key); +} + +static cell_t sm_GetEventFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + float value = pInfo->pEvent->GetFloat(key); + + return sp_ftoc(value); +} + +static cell_t sm_GetEventString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pContext->StringToLocalUTF8(params[3], params[4], pInfo->pEvent->GetString(key), NULL); + + return 1; +} + +static cell_t sm_SetEventBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pInfo->pEvent->SetBool(key, params[3] ? true : false); + + return 1; +} + +static cell_t sm_SetEventInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pInfo->pEvent->SetInt(key, params[3]); + + return 1; +} + +static cell_t sm_SetEventFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + float value = sp_ctof(params[3]); + pInfo->pEvent->SetFloat(key, value); + + return 1; +} + +static cell_t sm_SetEventString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key, *value; + pContext->LocalToString(params[2], &key); + pContext->LocalToString(params[3], &value); + + pInfo->pEvent->SetString(key, value); + + return 1; +} + +REGISTER_NATIVES(gameEventNatives) +{ + {"HookEvent", sm_HookEvent}, + {"UnhookEvent", sm_UnhookEvent}, + {"CreateEvent", sm_CreateEvent}, + {"FireEvent", sm_FireEvent}, + {"CancelCreatedEvent", sm_CancelCreatedEvent}, + {"GetEventName", sm_GetEventName}, + {"GetEventBool", sm_GetEventBool}, + {"GetEventInt", sm_GetEventInt}, + {"GetEventFloat", sm_GetEventFloat}, + {"GetEventString", sm_GetEventString}, + {"SetEventBool", sm_SetEventBool}, + {"SetEventInt", sm_SetEventInt}, + {"SetEventFloat", sm_SetEventFloat}, + {"SetEventString", sm_SetEventString}, + {NULL, NULL} +}; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index c9a20c20..24fe8ef6 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -207,7 +207,7 @@ native GetCmdArgString(String:buffer[], maxlength); * @param name Name of new convar. * @param defaultValue String containing the default value of new convar. * @param helpText Optional description of the convar. - * @param flags Optional bitstream of flags determining how the convar should be handled. (See FCVAR_* constants for more details) + * @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. * @param hasMin Optional boolean that determines if the convar has a minimum value. * @param min Minimum floating point value that the convar can have if hasMin is true. * @param hasMax Optional boolean that determines if the convar has a maximum value. diff --git a/plugins/include/events.inc b/plugins/include/events.inc new file mode 100644 index 00000000..3b4cadb9 --- /dev/null +++ b/plugins/include/events.inc @@ -0,0 +1,205 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _events_included + #endinput +#endif +#define _events_included + +/** + * Flags for firing game events + */ +#define EVENT_PASSTHRU_ALL (1<<1) /**< Event will pass through other SourceMM plugins AND SourceMod */ + +/** + * Event hook modes determining how hooking should be handled + */ +enum EventHookMode +{ + EventHookMode_Pre, /**< Hook callback fired before event is fired */ + EventHookMode_Post, /**< Hook callback fired after event is fired */ + EventHookMode_PostNoCopy /**< Hook callback fired after event is fired, but event data won't be copied */ +}; + +funcenum EventHook +{ + /** + * Called when a game event is fired. + * + * @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + * this event has set the hook mode EventHookMode_PostNoCopy. + * @param name String containing the name of the event. + * @param dontBroadcast True if event was not broadcast to clients, false otherwise. + * @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre. + */ + Action:public(Handle:event, const String:name[], bool:dontBroadcast), + /** + * Called when a game event is fired. + * + * @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + * this event has set the hook mode EventHookMode_PostNoCopy. + * @param name String containing the name of the event. + * @param dontBroadcast True if event was not broadcast to clients, false otherwise. + * @noreturn + */ + public(Handle:event, const String:name[], bool:dontBroadcast), +}; + +/** + * Creates a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @noreturn + * @error Invalid event name or invalid callback function. + */ +native HookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); + +/** + * Removes a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @noreturn + * @error Invalid callback function or no active hook for specified event. + */ +native UnhookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); + +/** + * Creates a game event to be fired later. + * + * @param name Name of event. + * @return Handle to event or INVALID_HANDLE if event doesn't exist. + */ +native Handle:CreateEvent(const String:name[]); + +/** + * Fires a game event. + * + * @param event Handle to the event. + * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. + * @param flags Optional bitstring flags. See EVENT_* constants for more details. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native FireEvent(Handle:event, bool:dontBroadcast=false, flags=0); + +/** + * Cancels a previously created game event that has not been fired. + * + * @param event Handled to the event. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native CancelCreatedEvent(Handle:event); + +/** + * Returns the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The boolean value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native bool:GetEventBool(Handle:event, const String:key[]); + +/** + * Sets the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New boolean value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventBool(Handle:event, const String:key[], bool:value); + +/** + * Returns the integer value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The integer value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native GetEventInt(Handle:event, const String:key[]); + +/** + * Sets the integer value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New integer value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventInt(Handle:event, const String:key[], value); + +/** + * Returns the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The floating point value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native Float:GetEventFloat(Handle:event, const String:key[]); + +/** + * Sets the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New floating point value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventFloat(Handle:event, const String:key[], Float:value); + +/** + * Retrieves the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value Buffer to store the value of the specified event key. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetEventString(Handle:event, const String:key[], String:value[], maxlength); + +/** + * Sets the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New string value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventString(Handle:event, const String:key[], const String:value[]); + +/** + * Retrieves the name of a game event. + * + * @param event Handle to the event. + * @param value Buffer to store the name of the event. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetEventName(Handle:event, String:name[], maxlength); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 64ccb7db..4143dfb6 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -37,6 +37,8 @@ struct Plugin #include #include #include +#include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -219,6 +221,5 @@ native GetGameDescription(String:buffer[], maxlength, bool:original=false); */ native GetCurrentMap(String:buffer[], maxlength); -#include #include #include From dbb74a612d008fc23b30e992e48355b4c482090f Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 04:50:30 +0000 Subject: [PATCH 0552/1664] Creating/Firing/Canceling events now use CStack to avoid the need to use new when possible --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40583 --- core/EventManager.cpp | 76 ++++++++++++++++++++++++++++++++------ core/EventManager.h | 23 ++++-------- core/smn_events.cpp | 40 ++++++++------------ core/sourcemm_api.h | 1 - plugins/include/events.inc | 4 +- 5 files changed, 89 insertions(+), 55 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index bf70b97f..587a20d5 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -25,7 +25,7 @@ typedef List EventHookList; const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; -EventManager::EventManager() : m_EventCopy(NULL), m_NotifyState(true) +EventManager::EventManager() : m_EventCopy(NULL), m_NotifyPlugins(true) { /* Create an event lookup trie */ m_EventHooks = sm_trie_create(); @@ -34,6 +34,15 @@ EventManager::EventManager() : m_EventCopy(NULL), m_NotifyState(true) EventManager::~EventManager() { sm_trie_destroy(m_EventHooks); + + /* Free memory used by EventInfo structs if any */ + CStack::iterator iter; + for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++) + { + delete (*iter); + } + + m_FreeEvents.popall(); } void EventManager::OnSourceModAllInitialized() @@ -68,15 +77,16 @@ void EventManager::OnSourceModShutdown() void EventManager::OnHandleDestroy(HandleType_t type, void *object) { - if (type == m_EventType) - { - EventInfo *pInfo = static_cast(object); + EventInfo *pInfo = static_cast(object); - if (pInfo->canDelete) - { - gameevents->FreeEvent(pInfo->pEvent); - delete pInfo; - } + /* Should only free event when created by a plugin */ + if (pInfo->pOwner) + { + /* Free IGameEvent */ + gameevents->FreeEvent(pInfo->pEvent); + + /* Add EventInfo struct to free event stack */ + m_FreeEvents.push(pInfo); } } @@ -266,6 +276,46 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun return EventHookErr_Okay; } +EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name) +{ + EventInfo *pInfo; + IGameEvent *pEvent = gameevents->CreateEvent(name, true); + + if (pEvent) + { + if (m_FreeEvents.empty()) + { + pInfo = new EventInfo(); + } else { + pInfo = m_FreeEvents.front(); + m_FreeEvents.pop(); + } + + + pInfo->pEvent = pEvent; + pInfo->pOwner = pContext->GetIdentity(); + + return pInfo; + } + + return NULL; +} + +void EventManager::FireEvent(IPluginContext *pContext, EventInfo *pInfo, int flags, bool bDontBroadcast) +{ + /* Should SourceMod plugins be notified of this event? */ + m_NotifyPlugins = (flags & EVENT_PASSTHRU_ALL) ? true : false; + + /* Actually fire event now */ + gameevents->FireEvent(pInfo->pEvent, bDontBroadcast); + + /* IGameEvent is free at this point, so no one owns this */ + pInfo->pOwner = NULL; + + /* Add EventInfo struct to free event stack */ + m_FreeEvents.push(pInfo); +} + /* IGameEventManager2::FireEvent hook */ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) { @@ -273,7 +323,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) IChangeableForward *pForward; cell_t res = Pl_Continue; - if (!m_NotifyState) + if (!m_NotifyPlugins) { RETURN_META_VALUE(MRES_IGNORED, true); } @@ -321,9 +371,11 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) IChangeableForward *pForward; Handle_t hndl; - if (!m_NotifyState) + if (!m_NotifyPlugins) { - m_NotifyState = true; + /* Reset plugin notification state */ + m_NotifyPlugins = true; + RETURN_META_VALUE(MRES_IGNORED, true); } diff --git a/core/EventManager.h b/core/EventManager.h index 7b67cb00..360a9201 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -8,7 +8,7 @@ * in whole or significant part. * For information, see LICENSE.txt or http://www.sourcemod.net/license.php * -* Version: $$ +* Version: $Id$ */ #ifndef _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ @@ -18,6 +18,7 @@ #include "sourcemm_api.h" #include "sm_trie.h" #include +#include #include #include #include @@ -30,7 +31,7 @@ using namespace SourceHook; struct EventInfo { IGameEvent *pEvent; - bool canDelete; + IdentityToken_t *pOwner; }; struct EventHook @@ -87,31 +88,23 @@ public: */ inline HandleType_t GetHandleType() { - return EventManager::m_EventType; - } - - /** - * Sets the current SourceMod event notification state. - * - * If notify is set to true, SourceMod plugins will be notified of events. If false, they will not. - * This is temporarily used to make EVENT_PASSTHRU work when firing events from plugins. - */ - inline void SetNotifyState(bool notify) - { - m_NotifyState = notify; + return m_EventType; } public: EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); + EventInfo *CreateEvent(IPluginContext *pContext, const char *name); + void FireEvent(IPluginContext *pContext, EventInfo *pInfo, int flags=0, bool bDontBroadcast=false); private: // IGameEventManager2 hooks bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); private: HandleType_t m_EventType; Trie *m_EventHooks; - bool m_NotifyState; + bool m_NotifyPlugins; IGameEvent *m_EventCopy; const char *m_EventName; + CStack m_FreeEvents; }; extern EventManager g_EventManager; diff --git a/core/smn_events.cpp b/core/smn_events.cpp index edc3b471..7e8814e9 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -65,20 +65,15 @@ static cell_t sm_UnhookEvent(IPluginContext *pContext, const cell_t *params) static cell_t sm_CreateEvent(IPluginContext *pContext, const cell_t *params) { - IGameEvent *pEvent; - EventInfo *pInfo; char *name; + EventInfo *pInfo; pContext->LocalToString(params[1], &name); - pEvent = gameevents->CreateEvent(name, true); + pInfo = g_EventManager.CreateEvent(pContext, name); - if (pEvent) + if (pInfo) { - pInfo = new EventInfo; - pInfo->pEvent = pEvent; - pInfo->canDelete = true; - return g_HandleSys.CreateHandle(g_EventManager.GetHandleType(), pInfo, pContext->GetIdentity(), g_pCoreIdent, NULL); } @@ -97,24 +92,18 @@ static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); } - if ((params[3] & EVENT_PASSTHRU_ALL) == false) + /* If identities do not match, don't fire event */ + if (pContext->GetIdentity() != pInfo->pOwner) { - /* Set whether or not SourceMod plugins should be notified */ - g_EventManager.SetNotifyState(false); + return pContext->ThrowNativeError("Game event \"%s\" could not be fired because it was not created by this plugin", pInfo->pEvent->GetName()); } - /* Fire game event */ - gameevents->FireEvent(pInfo->pEvent, params[2] ? true : false); - - pInfo->canDelete = false; + g_EventManager.FireEvent(pContext, pInfo, params[2], params[3] ? true : false); /* Free handle on game event */ - HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + HandleSecurity sec = {pContext->GetIdentity(), g_pCoreIdent}; g_HandleSys.FreeHandle(hndl, &sec); - /* Free EventInfo memory */ - delete pInfo; - return 1; } @@ -130,13 +119,14 @@ static cell_t sm_CancelCreatedEvent(IPluginContext *pContext, const cell_t *para return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); } - gameevents->FreeEvent(pInfo->pEvent); + /* If identities do not match, don't cancel event */ + if (pContext->GetIdentity() != pInfo->pOwner) + { + return pContext->ThrowNativeError("Game event \"%s\" could not be canceled because it was not created by this plugin", pInfo->pEvent->GetName()); + } - // Free GameEventInfo memory - delete pInfo; - - // Free handle on game event - HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + /* Free handle on game event */ + HandleSecurity sec = {pContext->GetIdentity(), g_pCoreIdent}; g_HandleSys.FreeHandle(hndl, &sec); return 1; diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 317215d5..138b02e1 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -17,7 +17,6 @@ #include "convar_sm.h" #include #include -#include #include #include diff --git a/plugins/include/events.inc b/plugins/include/events.inc index 3b4cadb9..349517cb 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -91,12 +91,12 @@ native Handle:CreateEvent(const String:name[]); * Fires a game event. * * @param event Handle to the event. - * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. * @param flags Optional bitstring flags. See EVENT_* constants for more details. + * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. * @noreturn * @error Invalid or corrupt Handle. */ -native FireEvent(Handle:event, bool:dontBroadcast=false, flags=0); +native FireEvent(Handle:event, flags=0, bool:dontBroadcast=false); /** * Cancels a previously created game event that has not been fired. From ac9051ab710e394bb68411f2c23040ad95d3838f Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 04:53:14 +0000 Subject: [PATCH 0553/1664] Oh, this isn't needed anymore --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40584 --- core/EventManager.cpp | 2 +- core/EventManager.h | 2 +- core/smn_events.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 587a20d5..91cde171 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -301,7 +301,7 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name) return NULL; } -void EventManager::FireEvent(IPluginContext *pContext, EventInfo *pInfo, int flags, bool bDontBroadcast) +void EventManager::FireEvent(EventInfo *pInfo, int flags, bool bDontBroadcast) { /* Should SourceMod plugins be notified of this event? */ m_NotifyPlugins = (flags & EVENT_PASSTHRU_ALL) ? true : false; diff --git a/core/EventManager.h b/core/EventManager.h index 360a9201..8e91bc86 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -94,7 +94,7 @@ public: EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventInfo *CreateEvent(IPluginContext *pContext, const char *name); - void FireEvent(IPluginContext *pContext, EventInfo *pInfo, int flags=0, bool bDontBroadcast=false); + void FireEvent(EventInfo *pInfo, int flags=0, bool bDontBroadcast=false); private: // IGameEventManager2 hooks bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 7e8814e9..cc35a804 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -98,7 +98,7 @@ static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Game event \"%s\" could not be fired because it was not created by this plugin", pInfo->pEvent->GetName()); } - g_EventManager.FireEvent(pContext, pInfo, params[2], params[3] ? true : false); + g_EventManager.FireEvent(pInfo, params[2], params[3] ? true : false); /* Free handle on game event */ HandleSecurity sec = {pContext->GetIdentity(), g_pCoreIdent}; From 70ec3db66c82b6c4769fd44406d9f3855a0c2d46 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 06:15:19 +0000 Subject: [PATCH 0554/1664] Commands with the same name as an existing convar can no longer be created --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40585 --- .../{CConCmdManager.cpp => ConCmdManager.cpp} | 74 +++++++++++++------ core/{CConCmdManager.h => ConCmdManager.h} | 19 +++-- core/msvc8/sourcemod_mm.vcproj | 16 ++-- core/smn_console.cpp | 17 ++++- plugins/include/console.inc | 5 +- 5 files changed, 84 insertions(+), 47 deletions(-) rename core/{CConCmdManager.cpp => ConCmdManager.cpp} (86%) rename core/{CConCmdManager.h => ConCmdManager.h} (86%) diff --git a/core/CConCmdManager.cpp b/core/ConCmdManager.cpp similarity index 86% rename from core/CConCmdManager.cpp rename to core/ConCmdManager.cpp index 4e56d4cc..90939efd 100644 --- a/core/CConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -11,14 +11,14 @@ * Version: $Id$ */ -#include "CConCmdManager.h" +#include "ConCmdManager.h" #include "sm_srvcmds.h" #include "AdminCache.h" #include "sm_stringutil.h" #include "CPlayerManager.h" #include "CTranslator.h" -CConCmdManager g_ConCmds; +ConCmdManager g_ConCmds; SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false); SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int); @@ -32,34 +32,34 @@ struct PlCmdInfo typedef List CmdList; void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info); -CConCmdManager::CConCmdManager() : m_Strings(1024) +ConCmdManager::ConCmdManager() : m_Strings(1024) { m_pCmds = sm_trie_create(); m_pCmdGrps = sm_trie_create(); } -CConCmdManager::~CConCmdManager() +ConCmdManager::~ConCmdManager() { sm_trie_destroy(m_pCmds); sm_trie_destroy(m_pCmdGrps); } -void CConCmdManager::OnSourceModAllInitialized() +void ConCmdManager::OnSourceModAllInitialized() { g_PluginSys.AddPluginsListener(this); g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); } -void CConCmdManager::OnSourceModShutdown() +void ConCmdManager::OnSourceModShutdown() { /* All commands should already be removed by the time we're done */ - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); g_RootMenu.RemoveRootConsoleCommand("cmds", this); g_PluginSys.RemovePluginsListener(this); } -void CConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) +void ConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) { List::iterator iter = cmdlist.begin(); CmdHook *pHook; @@ -78,7 +78,7 @@ void CConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pCo } } -void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) +void ConCmdManager::OnPluginDestroyed(IPlugin *plugin) { CmdList *pList; List removed; @@ -129,12 +129,12 @@ void CommandCallback() g_ConCmds.InternalDispatch(); } -void CConCmdManager::SetCommandClient(int client) +void ConCmdManager::SetCommandClient(int client) { m_CmdClient = client + 1; } -ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) +ResultType ConCmdManager::DispatchClientCommand(int client, ResultType type) { const char *cmd = engine->Cmd_Argv(0); int args = engine->Cmd_Argc() - 1; @@ -183,7 +183,7 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type) return type; } -void CConCmdManager::InternalDispatch() +void ConCmdManager::InternalDispatch() { /** * Note: Console commands will EITHER go through IServerGameDLL::ClientCommand, @@ -292,7 +292,7 @@ void CConCmdManager::InternalDispatch() } } -bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin) +bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin) { FlagBits cmdflags = pAdmin->eflags; if (cmdflags == 0) @@ -372,12 +372,18 @@ bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdm return false; } -void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, +bool ConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags) { ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + + if (!pInfo) + { + return false; + } + CmdHook *pHook = new CmdHook(); pHook->pf = pFunction; @@ -400,9 +406,11 @@ void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, info.type = Cmd_Console; info.pHook = pHook; AddToPlCmdList(pList, info); + + return true; } -bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, +bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, const char *name, const char *group, int adminflags, @@ -411,6 +419,11 @@ bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, { ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + if (!pInfo) + { + return false; + } + CmdHook *pHook = new CmdHook(); AdminCmdInfo *pAdmin = new AdminCmdInfo(); @@ -473,13 +486,19 @@ bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, return true; } -void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, +bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags) { ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + + if (!pInfo) + { + return false; + } + CmdHook *pHook = new CmdHook(); pHook->pf = pFunction; @@ -503,6 +522,8 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, info.type = Cmd_Server; info.pHook = pHook; AddToPlCmdList(pList, info); + + return true; } void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info) @@ -533,7 +554,7 @@ void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info) } } -void CConCmdManager::AddToCmdList(ConCmdInfo *info) +void ConCmdManager::AddToCmdList(ConCmdInfo *info) { List::iterator iter = m_CmdList.begin(); ConCmdInfo *pInfo; @@ -563,7 +584,7 @@ void CConCmdManager::AddToCmdList(ConCmdInfo *info) } } -void CConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits) +void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits) { ConCmdInfo *pInfo; @@ -623,7 +644,7 @@ void CConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Fla } } -void CConCmdManager::RemoveConCmd(ConCmdInfo *info) +void ConCmdManager::RemoveConCmd(ConCmdInfo *info) { /* Remove console-specific information * This should always be true as of right now @@ -655,7 +676,7 @@ void CConCmdManager::RemoveConCmd(ConCmdInfo *info) delete info; } -ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) +ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) { ConCmdInfo *pInfo; if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo)) @@ -666,9 +687,14 @@ ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *descr ConCommand *pCmd = NULL; while (pBase) { - if (pBase->IsCommand() - && (strcmp(pBase->GetName(), name) == 0)) + if (strcmp(pBase->GetName(), name) == 0) { + /* Don't want to return convar with same name */ + if (!pBase->IsCommand()) + { + return NULL; + } + pCmd = (ConCommand *)pBase; break; } @@ -701,7 +727,7 @@ ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *descr return pInfo; } -void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount) { if (argcount >= 3) { diff --git a/core/CConCmdManager.h b/core/ConCmdManager.h similarity index 86% rename from core/CConCmdManager.h rename to core/ConCmdManager.h index 3f0198a6..e14ec711 100644 --- a/core/CConCmdManager.h +++ b/core/ConCmdManager.h @@ -12,8 +12,8 @@ * Version: $Id$ */ -#ifndef _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ -#define _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ +#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ #include "sm_globals.h" #include "sourcemm_api.h" @@ -72,15 +72,15 @@ struct ConCmdInfo List conhooks; /**< Hooks as a console command */ }; -class CConCmdManager : +class ConCmdManager : public SMGlobalClass, public IRootConsoleCommand, public IPluginsListener { friend void CommandCallback(); public: - CConCmdManager(); - ~CConCmdManager(); + ConCmdManager(); + ~ConCmdManager(); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); @@ -89,8 +89,8 @@ public: //IPluginsListener public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: - void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); - void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); + bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); + bool AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); bool AddAdminCommand(IPluginFunction *pFunction, const char *name, const char *group, @@ -116,7 +116,6 @@ private: BaseStringTable m_Strings; /* string table */ }; -extern CConCmdManager g_ConCmds; - -#endif // _INCLUDE_SOURCEMOD_CCONCMDMANAGER_H_ +extern ConCmdManager g_ConCmds; +#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index f6986fa9..f46797f1 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -183,10 +183,6 @@ RelativePath="..\AdminCache.cpp" > - - @@ -211,6 +207,10 @@ RelativePath="..\CLogger.cpp" > + + @@ -269,10 +269,6 @@ RelativePath="..\AdminCache.h" > - - @@ -305,6 +301,10 @@ RelativePath="..\CMsgListenerWrapper.h" > + + diff --git a/core/smn_console.cpp b/core/smn_console.cpp index b0889ddf..497e93f7 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -15,7 +15,7 @@ #include "sourcemm_api.h" #include "HandleSys.h" #include "CConVarManager.h" -#include "CConCmdManager.h" +#include "ConCmdManager.h" #include "PluginSys.h" #include "sm_stringutil.h" #include "CPlayerManager.h" @@ -340,7 +340,10 @@ static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); } - g_ConCmds.AddServerCommand(pFunction, name, help, params[4]); + if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4])) + { + return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); + } return 1; } @@ -359,7 +362,10 @@ static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); } - g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]); + if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4])) + { + return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); + } return 1; } @@ -388,7 +394,10 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); } - g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags); + if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags)) + { + return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); + } return 1; } diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 24fe8ef6..426ce51d 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -126,6 +126,7 @@ functag SrvCmd Action:public(args); * @param description Optional description to use for command creation. * @param flags Optional flags to use for command creation. * @noreturn + * @error Command name is the same as an existing convar. */ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:description[]="", flags=0); @@ -147,6 +148,7 @@ functag ConCmd Action:public(client, args); * @param description Optional description to use for command creation. * @param flags Optional flags to use for command creation. * @noreturn + * @error Command name is the same as an existing convar. */ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]="", flags=0); @@ -163,6 +165,7 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti * @param description Optional description to use for help. * @param flags Optional console flags. * @noreturn + * @error Command name is the same as an existing convar. */ native RegAdminCmd(const String:cmd[], ConCmd:callback, @@ -213,7 +216,7 @@ native GetCmdArgString(String:buffer[], maxlength); * @param hasMax Optional boolean that determines if the convar has a maximum value. * @param max Maximum floating point value that the convar can have if hasMax is true. * @return A handle to the newly created convar. If the convar already exists, INVALID_HANDLE is returned. - * @error Convar name is blank or is the same as a console command. + * @error Convar name is blank or is the same as an existing console command. */ native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:helpText[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); From c256741488caac06ad79288b8aacc665ce429cfa Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 06:49:35 +0000 Subject: [PATCH 0555/1664] Renamed CConVarManager to ConVarManager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40586 --- .../{CConVarManager.cpp => ConVarManager.cpp} | 34 +++++++++---------- core/{CConVarManager.h => ConVarManager.h} | 14 ++++---- core/msvc8/sourcemod_mm.vcproj | 16 ++++----- core/smn_console.cpp | 2 +- 4 files changed, 33 insertions(+), 33 deletions(-) rename core/{CConVarManager.cpp => ConVarManager.cpp} (87%) rename core/{CConVarManager.h => ConVarManager.h} (88%) diff --git a/core/CConVarManager.cpp b/core/ConVarManager.cpp similarity index 87% rename from core/CConVarManager.cpp rename to core/ConVarManager.cpp index 5c6e6f02..5f4b50e7 100644 --- a/core/CConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -11,7 +11,7 @@ * Version: $Id$ */ -#include "CConVarManager.h" +#include "ConVarManager.h" #include "PluginSys.h" #include "ForwardSys.h" #include "HandleSys.h" @@ -19,31 +19,31 @@ #include "sm_stringutil.h" #include -CConVarManager g_ConVarManager; +ConVarManager g_ConVarManager; -CConVarManager::CConVarManager() : m_ConVarType(0) +ConVarManager::ConVarManager() : m_ConVarType(0) { // Create a convar lookup trie m_ConVarCache = sm_trie_create(); } -CConVarManager::~CConVarManager() +ConVarManager::~ConVarManager() { - List::iterator i; + List::iterator iter; // Destroy our convar lookup trie sm_trie_destroy(m_ConVarCache); // Destroy all the ConVarInfo structures - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) + for (iter = m_ConVars.begin(); iter != m_ConVars.end(); iter++) { - delete (*i); + delete (*iter); } m_ConVars.clear(); } -void CConVarManager::OnSourceModAllInitialized() +void ConVarManager::OnSourceModAllInitialized() { HandleAccess sec; @@ -59,7 +59,7 @@ void CConVarManager::OnSourceModAllInitialized() g_RootMenu.AddRootConsoleCommand("convars", "View convars created by a plugin", this); } -void CConVarManager::OnSourceModShutdown() +void ConVarManager::OnSourceModShutdown() { IChangeableForward *fwd; List::iterator i; @@ -83,7 +83,7 @@ void CConVarManager::OnSourceModShutdown() g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } -void CConVarManager::OnPluginDestroyed(IPlugin *plugin) +void ConVarManager::OnPluginDestroyed(IPlugin *plugin) { CVector *cvarList; @@ -94,7 +94,7 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) } } -void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) +void ConVarManager::OnHandleDestroy(HandleType_t type, void *object) { ConVarInfo *info; ConVar *pConVar = static_cast(object); @@ -115,7 +115,7 @@ void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) } } -void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) +void ConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount) { if (argcount >= 3) { @@ -162,7 +162,7 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.ConsolePrint("[SM] Usage: sm convars "); } -Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) +Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) { ConVar *pConVar = NULL; ConVarInfo *info = NULL; @@ -246,7 +246,7 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name return hndl; } -Handle_t CConVarManager::FindConVar(const char *name) +Handle_t ConVarManager::FindConVar(const char *name) { ConVar *pConVar = NULL; ConVarInfo *info = NULL; @@ -285,7 +285,7 @@ Handle_t CConVarManager::FindConVar(const char *name) return hndl; } -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) +void ConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -329,7 +329,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, fwd->AddFunction(func); } -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) +void ConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -375,7 +375,7 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVa } } -void CConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) +void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) { // If the values are the same... if (strcmp(pConVar->GetString(), oldValue) == 0) diff --git a/core/CConVarManager.h b/core/ConVarManager.h similarity index 88% rename from core/CConVarManager.h rename to core/ConVarManager.h index aeecbf74..1ac8b1f9 100644 --- a/core/CConVarManager.h +++ b/core/ConVarManager.h @@ -11,8 +11,8 @@ * Version: $Id$ */ -#ifndef _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ -#define _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ +#ifndef _INCLUDE_SOURCEMOD_CONVARMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CONVARMANAGER_H_ #include "sm_globals.h" #include "sourcemm_api.h" @@ -36,15 +36,15 @@ struct ConVarInfo FnChangeCallback origCallback; /**< The original callback function */ }; -class CConVarManager : +class ConVarManager : public SMGlobalClass, public IHandleTypeDispatch, public IPluginsListener, public IRootConsoleCommand { public: - CConVarManager(); - ~CConVarManager(); + ConVarManager(); + ~ConVarManager(); public: // SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); @@ -102,7 +102,7 @@ private: Trie *m_ConVarCache; }; -extern CConVarManager g_ConVarManager; +extern ConVarManager g_ConVarManager; -#endif // _INCLUDE_SOURCEMOD_CCONVARMANAGER_H_ +#endif // _INCLUDE_SOURCEMOD_CONVARMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index f46797f1..5ee357db 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -183,10 +183,6 @@ RelativePath="..\AdminCache.cpp" > - - @@ -211,6 +207,10 @@ RelativePath="..\ConCmdManager.cpp" > + + @@ -269,10 +269,6 @@ RelativePath="..\AdminCache.h" > - - @@ -305,6 +301,10 @@ RelativePath="..\ConCmdManager.h" > + + diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 497e93f7..b0de00c0 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -14,7 +14,7 @@ #include "sm_globals.h" #include "sourcemm_api.h" #include "HandleSys.h" -#include "CConVarManager.h" +#include "ConVarManager.h" #include "ConCmdManager.h" #include "PluginSys.h" #include "sm_stringutil.h" From e6a127ac17592207249546f7d8cfa573f725cd45 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 07:38:19 +0000 Subject: [PATCH 0556/1664] Redid case on some error messages Really minor things in EventManager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40587 --- core/EventManager.cpp | 2 +- core/EventManager.h | 4 ++-- core/smn_console.cpp | 30 +++++++++++++++--------------- core/smn_events.cpp | 22 +++++++++++----------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 91cde171..f40a1f2c 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -25,7 +25,7 @@ typedef List EventHookList; const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; -EventManager::EventManager() : m_EventCopy(NULL), m_NotifyPlugins(true) +EventManager::EventManager() : m_EventType(0), m_NotifyPlugins(true), m_EventCopy(NULL) { /* Create an event lookup trie */ m_EventHooks = sm_trie_create(); diff --git a/core/EventManager.h b/core/EventManager.h index 8e91bc86..a6a923e7 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -100,10 +100,10 @@ private: // IGameEventManager2 hooks bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); private: HandleType_t m_EventType; - Trie *m_EventHooks; bool m_NotifyPlugins; - IGameEvent *m_EventCopy; const char *m_EventName; + IGameEvent *m_EventCopy; + Trie *m_EventHooks; CStack m_FreeEvents; }; diff --git a/core/smn_console.cpp b/core/smn_console.cpp index b0de00c0..e76b6273 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -67,7 +67,7 @@ static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } g_ConVarManager.HookConVarChange(pContext, pConVar, static_cast(params[2])); @@ -84,7 +84,7 @@ static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *para if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } g_ConVarManager.UnhookConVarChange(pContext, pConVar, static_cast(params[2])); @@ -101,7 +101,7 @@ static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } return pConVar->GetBool(); @@ -116,7 +116,7 @@ static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } return pConVar->GetInt(); @@ -132,7 +132,7 @@ static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } pConVar->SetValue(params[2]); @@ -149,7 +149,7 @@ static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } float value = pConVar->GetFloat(); @@ -166,7 +166,7 @@ static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } float value = sp_ctof(params[2]); @@ -184,7 +184,7 @@ static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL); @@ -201,7 +201,7 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } char *value; @@ -221,7 +221,7 @@ static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } return pConVar->GetFlags(); @@ -236,7 +236,7 @@ static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } pConVar->SetFlags(params[2]); @@ -253,7 +253,7 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } cell_t *addr; @@ -277,7 +277,7 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } cell_t *addr; @@ -301,7 +301,7 @@ static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL); @@ -318,7 +318,7 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } pConVar->Revert(); diff --git a/core/smn_events.cpp b/core/smn_events.cpp index cc35a804..96e52598 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -89,7 +89,7 @@ static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } /* If identities do not match, don't fire event */ @@ -116,7 +116,7 @@ static cell_t sm_CancelCreatedEvent(IPluginContext *pContext, const cell_t *para if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } /* If identities do not match, don't cancel event */ @@ -141,7 +141,7 @@ static cell_t sm_GetEventName(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } pContext->StringToLocalUTF8(params[2], params[3], pInfo->pEvent->GetName(), NULL); @@ -158,7 +158,7 @@ static cell_t sm_GetEventBool(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -176,7 +176,7 @@ static cell_t sm_GetEventInt(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -194,7 +194,7 @@ static cell_t sm_GetEventFloat(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -214,7 +214,7 @@ static cell_t sm_GetEventString(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -234,7 +234,7 @@ static cell_t sm_SetEventBool(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -254,7 +254,7 @@ static cell_t sm_SetEventInt(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -274,7 +274,7 @@ static cell_t sm_SetEventFloat(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key; @@ -295,7 +295,7 @@ static cell_t sm_SetEventString(IPluginContext *pContext, const cell_t *params) if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) != HandleError_None) { - return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + return pContext->ThrowNativeError("Invalid game event handle %x (error %d)", hndl, err); } char *key, *value; From 0b25b6d66702b40a905c18265b5f6f746e78202e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 6 Mar 2007 23:59:25 +0000 Subject: [PATCH 0557/1664] Many things: 1) General code clean-up in convar manager 2) Fixed bug where convar handles were not being cached for pre-existing convars 3) Fixed bug where a convar's old value and new value were switched in the ConVarChanged hooks 4) Made convar and concmd listings more consistent, I think 5) Alphabetized convar listing 6) Minor clean-up in event manager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40588 --- core/ConCmdManager.cpp | 14 +- core/ConVarManager.cpp | 357 ++++++++++++++++++------------------ core/ConVarManager.h | 15 +- core/EventManager.cpp | 6 +- core/EventManager.h | 6 +- core/sm_stringutil.h | 2 + core/smn_console.cpp | 35 +++- core/systems/PluginSys.cpp | 3 +- plugins/include/console.inc | 10 +- 9 files changed, 235 insertions(+), 213 deletions(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 90939efd..094e3619 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -741,15 +741,18 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco return; } + const sm_plugininfo_t *plinfo = pPlugin->GetPublicInfo(); + const char *plname = IS_STR_FILLED(plinfo->name) ? plinfo->name : pPlugin->GetFilename(); + CmdList *pList; if (!pPlugin->GetProperty("CommandList", (void **)&pList)) { - g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename()); + g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname); return; } if (!pList->size()) { - g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename()); + g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname); return; } @@ -757,10 +760,11 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco const char *type = NULL; const char *name; const char *help; - g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]"); + g_RootMenu.ConsolePrint("[SM] Listing %d commands for: %s", pList->size(), plname); + g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]"); for (iter=pList->begin(); iter!=pList->end(); - iter++) + iter++, id++) { PlCmdInfo &cmd = (*iter); if (cmd.type == Cmd_Server) @@ -778,7 +782,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco } else { help = cmd.pInfo->pCmd->GetHelpText(); } - g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); + g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); } return; diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 5f4b50e7..1daf4aeb 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -21,9 +21,12 @@ ConVarManager g_ConVarManager; +const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String}; +typedef List ConVarList; + ConVarManager::ConVarManager() : m_ConVarType(0) { - // Create a convar lookup trie + /* Create a convar lookup trie */ m_ConVarCache = sm_trie_create(); } @@ -31,10 +34,10 @@ ConVarManager::~ConVarManager() { List::iterator iter; - // Destroy our convar lookup trie + /* Destroy our convar lookup trie */ sm_trie_destroy(m_ConVarCache); - // Destroy all the ConVarInfo structures + /* Destroy all the ConVarInfo structures */ for (iter = m_ConVars.begin(); iter != m_ConVars.end(); iter++) { delete (*iter); @@ -47,15 +50,15 @@ void ConVarManager::OnSourceModAllInitialized() { HandleAccess sec; - // Set up access rights for the 'ConVar' handle type + /* Set up access rights for the 'ConVar' handle type */ sec.access[HandleAccess_Read] = 0; sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - // Create the 'ConVar' handle type + /* Create the 'ConVar' handle type */ m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); - // Add the 'cvars' option to the 'sm' console command + /* Add the 'convars' option to the 'sm' console command */ g_RootMenu.AddRootConsoleCommand("convars", "View convars created by a plugin", this); } @@ -64,33 +67,33 @@ void ConVarManager::OnSourceModShutdown() IChangeableForward *fwd; List::iterator i; - // Iterate list of ConVarInfo structures + /* Iterate list of ConVarInfo structures */ for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) { fwd = (*i)->changeForward; - // Free any convar-change forwards that still exist + /* Free any convar-change forwards that still exist */ if (fwd) { g_Forwards.ReleaseForward(fwd); } } - // Remove the 'cvars' option from the 'sm' console command + /* Remove the 'convars' option from the 'sm' console command */ g_RootMenu.RemoveRootConsoleCommand("convars", this); - // Remove the 'ConVar' handle type + /* Remove the 'ConVar' handle type */ g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } -void ConVarManager::OnPluginDestroyed(IPlugin *plugin) +void ConVarManager::OnPluginUnloaded(IPlugin *plugin) { - CVector *cvarList; + ConVarList *pConVarList; - // If plugin has a convar list, free its memory - if (plugin->GetProperty("ConVarList", reinterpret_cast(&cvarList), true)) + /* If plugin has a convar list, free its memory */ + if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true)) { - delete cvarList; + delete pConVarList; } } @@ -99,18 +102,18 @@ void ConVarManager::OnHandleDestroy(HandleType_t type, void *object) ConVarInfo *info; ConVar *pConVar = static_cast(object); - // Find convar in lookup trie + /* Find convar in lookup trie */ sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info)); - // If convar was created by SourceMod plugin... + /* If convar was created by SourceMod plugin... */ if (info->sourceMod) { - // Delete string allocations + /* Delete string allocations */ delete [] pConVar->GetName(); delete [] pConVar->GetDefault(); delete [] pConVar->GetHelpText(); - // Then unlink it from SourceMM + /* Then unlink it from SourceMM */ g_SMAPI->UnregisterConCmdBase(g_PLAPI, pConVar); } } @@ -119,78 +122,80 @@ void ConVarManager::OnRootConsoleCommand(const char *command, unsigned int argco { if (argcount >= 3) { - int id = 1; - - // Get plugin index that was passed - int num = atoi(g_RootMenu.GetArgument(2)); + /* Get plugin index that was passed */ + int id = atoi(g_RootMenu.GetArgument(2)); - // If invalid plugin index... - if (num < 1 || num > (int)g_PluginSys.GetPluginCount()) + /* Get plugin object */ + CPlugin *plugin = g_PluginSys.GetPluginByOrder(id); + + if (!plugin) { - g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", num); + g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id); return; } - // Get plugin object - CPlugin *pl = g_PluginSys.GetPluginByOrder(num); + /* Get plugin name */ + const sm_plugininfo_t *plinfo = plugin->GetPublicInfo(); + const char *plname = IS_STR_FILLED(plinfo->name) ? plinfo->name : plugin->GetFilename(); - CVector *cvarList = NULL; + ConVarList *pConVarList; + ConVarList::iterator iter; - // Get convar list from 'ConVar' property - pl->GetProperty("ConVar", reinterpret_cast(&cvarList)); - - // If no cvar list... - if (cvarList == NULL) + /* If no convar list... */ + if (!plugin->GetProperty("ConVarList", (void **)&pConVarList)) { - g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name); + g_RootMenu.ConsolePrint("[SM] No convars found for: %s", plname); return; } - g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\"", pl->GetPublicInfo()->name); + g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname); + g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]"); - // Iterate convar list and display each one - for (size_t i = 0; i < cvarList->size(); i++, id++) + /* Iterate convar list and display each one */ + for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++) { - ConVar *pConVar = (*cvarList)[i]; - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, pConVar->GetName(), pConVar->GetString()); + const ConVar *pConVar = (*iter); + g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString()); } return; } - // Display usage of subcommand + /* Display usage of subcommand */ g_RootMenu.ConsolePrint("[SM] Usage: sm convars "); } -Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) +Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *description, int flags, bool hasMin, float min, bool hasMax, float max) { ConVar *pConVar = NULL; - ConVarInfo *info = NULL; - CVector *cvarList = NULL; + ConVarInfo *pInfo = NULL; + ConVarList *pConVarList = NULL; Handle_t hndl = 0; - // Find out if the convar exists already + /* Find out if the convar exists already */ pConVar = icvar->FindVar(name); - // If the convar already exists... - if (pConVar != NULL) + /* If the convar already exists... */ + if (pConVar) { - // First check if we already have a handle to it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + /* First find out if we already have a handle to it */ + if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo)) { - // If we do, then return that handle - return info->handle; + return pInfo->handle; } else { - // If we don't, then create a new handle from the convar + /* If we don't, then create a new handle from the convar */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = pConVar->GetCallback(); + /* Create and initialize ConVarInfo structure */ + pInfo = new ConVarInfo(); + pInfo->handle = hndl; + pInfo->sourceMod = false; + pInfo->changeForward = NULL; + pInfo->origCallback = pConVar->GetCallback(); - m_ConVars.push_back(info); + /* Insert struct into caches */ + m_ConVars.push_back(pInfo); + sm_trie_insert(m_ConVarCache, name, pInfo); return hndl; } @@ -201,47 +206,33 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, while (pBase) { - if (strcmp(pBase->GetName(), name) == 0) + if (pBase->IsCommand() && strcmp(pBase->GetName(), name) == 0) { - return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); + return BAD_HANDLE; } pBase = const_cast(pBase->GetNext()); } - // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); + /* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */ + pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max); - // Find plugin creating convar - IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); + /* Add convar to plugin's list */ + AddConVarToPluginList(pContext, pConVar); - // Get convar list from 'ConVar' property of plugin - pl->GetProperty("ConVarList", reinterpret_cast(&cvarList)); - - // If 'ConVar' property doesn't exist... - if (cvarList == NULL) - { - // Then create it - cvarList = new CVector; - pl->SetProperty("ConVarList", cvarList); - } - - // Add new convar to plugin's list - cvarList->push_back(pConVar); - - // Create a handle from the new convar + /* Create a handle from the new convar */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = true; - info->changeForward = NULL; - info->origCallback = NULL; + /* Create and initialize ConVarInfo structure */ + pInfo = new ConVarInfo(); + pInfo->handle = hndl; + pInfo->sourceMod = true; + pInfo->changeForward = NULL; + pInfo->origCallback = NULL; - m_ConVars.push_back(info); - - // Insert the handle into our lookup trie - sm_trie_insert(m_ConVarCache, name, info); + /* Insert struct into caches */ + m_ConVars.push_back(pInfo); + sm_trie_insert(m_ConVarCache, name, pInfo); return hndl; } @@ -249,159 +240,165 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, Handle_t ConVarManager::FindConVar(const char *name) { ConVar *pConVar = NULL; - ConVarInfo *info = NULL; - Handle_t hndl = 0; + ConVarInfo *pInfo; + Handle_t hndl; - // Search for convar + /* Search for convar */ pConVar = icvar->FindVar(name); - // If it doesn't exist, then return an invalid handle - if (pConVar == NULL) + /* If it doesn't exist, then return an invalid handle */ + if (!pConVar) { return BAD_HANDLE; } - // At this point, convar exists, so find out if we already have a handle for it - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) + /* At this point, the convar exists. So, find out if we already have a handle */ + if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo)) { - // If we do, then return that handle - return info->handle; + return pInfo->handle; } - // If we don't, then create a new handle from the convar + /* If we don't have a handle, then create a new one */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); - info = new ConVarInfo; - info->handle = hndl; - info->sourceMod = false; - info->changeForward = NULL; - info->origCallback = pConVar->GetCallback(); + /* Create and initilize ConVarInfo structure */ + pInfo = new ConVarInfo(); + pInfo->handle = hndl; + pInfo->sourceMod = false; + pInfo->changeForward = NULL; + pInfo->origCallback = pConVar->GetCallback(); - m_ConVars.push_back(info); - - // Insert the handle into our cache - sm_trie_insert(m_ConVarCache, name, info); + /* Insert struct into our caches */ + m_ConVars.push_back(pInfo); + sm_trie_insert(m_ConVarCache, name, pInfo); return hndl; } -void ConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) +void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction) { - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - char fwdName[64]; - ConVarInfo *info = NULL; + ConVarInfo *pInfo; + IChangeableForward *pForward; - // This shouldn't happen... - if (func == NULL) + /* Find the convar in the lookup trie */ + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo)) { - pContext->ThrowNativeError("Invalid function specified"); - return; - } + /* Get the forward */ + pForward = pInfo->changeForward; - // Create a forward name - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", pConVar->GetName()); - - // First find out if the forward already exists - g_Forwards.FindForward(fwdName, &fwd); - - // If the forward doesn't exist... - if (fwd == NULL) - { - // This is the forward's parameter type list - ParamType p[] = {Param_Cell, Param_String, Param_String}; - - // Create the forward - fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); - - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) + /* If forward does not exist, create it */ + if (!pForward) { - // Set the convar's forward to the newly created one - info->changeForward = fwd; + pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS); + pInfo->changeForward = pForward; - // Set the convar's callback to our static one + /* Install our own callback */ pConVar->InstallChangeCallback(OnConVarChanged); } - } - // Add the function to the forward's list - fwd->AddFunction(func); + /* Add function to forward's list */ + pForward->AddFunction(pFunction); + } } -void ConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) +void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction) { - IPluginFunction *func = pContext->GetFunctionById(funcid); - IChangeableForward *fwd = NULL; - ConVarInfo *info = NULL; + ConVarInfo *pInfo; + IChangeableForward *pForward; + IPluginContext *pContext = pFunction->GetParentContext(); - // This shouldn't happen... - if (func == NULL) + /* Find the convar in the lookup trie */ + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo)) { - pContext->ThrowNativeError("Invalid function specified"); - return; - } + /* Get the forward */ + pForward = pInfo->changeForward; - // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) - { - // Get the forward - fwd = info->changeForward; - - // If the forward doesn't exist, we can't unhook anything - if (fwd == NULL) + /* If the forward doesn't exist, we can't unhook anything */ + if (!pForward) { pContext->ThrowNativeError("Convar \"%s\" has no active hook", pConVar->GetName()); return; } - // Remove the function from the forward's list - if (!fwd->RemoveFunction(func)) + /* Remove the function from the forward's list */ + if (!pForward->RemoveFunction(pFunction)) { pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", pConVar->GetName()); return; } - // If the forward now has 0 functions in it... - if (fwd->GetFunctionCount() == 0) + /* If the forward now has 0 functions in it... */ + if (pForward->GetFunctionCount() == 0) { - // Free this forward - g_Forwards.ReleaseForward(fwd); - info->changeForward = NULL; + /* Free this forward */ + g_Forwards.ReleaseForward(pForward); + pInfo->changeForward = NULL; - // Put the back the original convar callback - pConVar->InstallChangeCallback(info->origCallback); + /* Put back the original convar callback */ + pConVar->InstallChangeCallback(pInfo->origCallback); } } } +void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar) +{ + ConVarList *pConVarList; + ConVarList::iterator iter; + bool inserted = false; + const char *orig = pConVar->GetName(); + + IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + + /* Check plugin for an existing convar list */ + if (!plugin->GetProperty("ConVarList", (void **)&pConVarList)) + { + pConVarList = new ConVarList(); + plugin->SetProperty("ConVarList", pConVarList); + } + + /* Insert convar into list which is sorted alphabetically */ + for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++) + { + if (strcmp(orig, (*iter)->GetName()) < 0) + { + pConVarList->insert(iter, pConVar); + inserted = true; + break; + } + } + + if (!inserted) + { + pConVarList->push_back(pConVar); + } +} + void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) { - // If the values are the same... + /* If the values are the same, exit early in order to not trigger callbacks */ if (strcmp(pConVar->GetString(), oldValue) == 0) { - // Exit early in order to not trigger callbacks return; } - Trie *cache = g_ConVarManager.GetConVarCache(); - ConVarInfo *info; + Trie *pCache = g_ConVarManager.GetConVarCache(); + ConVarInfo *pInfo; - // Find the convar in the lookup trie - sm_trie_retrieve(cache, pConVar->GetName(), reinterpret_cast(&info)); + /* Find the convar in the lookup trie */ + sm_trie_retrieve(pCache, pConVar->GetName(), (void **)&pInfo); - FnChangeCallback origCallback = info->origCallback; - IChangeableForward *fwd = info->changeForward; + FnChangeCallback origCallback = pInfo->origCallback; + IChangeableForward *pForward = pInfo->changeForward; - // If there was a change callback installed previously, call it + /* If there was a change callback installed previously, call it */ if (origCallback) { origCallback(pConVar, oldValue); } - // Now call forwards in plugins that have hooked this - fwd->PushCell(info->handle); - fwd->PushString(pConVar->GetString()); - fwd->PushString(oldValue); - fwd->Execute(NULL); + /* Now call forwards in plugins that have hooked this */ + pForward->PushCell(pInfo->handle); + pForward->PushString(oldValue); + pForward->PushString(pConVar->GetString()); + pForward->Execute(NULL); } diff --git a/core/ConVarManager.h b/core/ConVarManager.h index 1ac8b1f9..59ecfffe 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -51,7 +51,7 @@ public: // SMGlobalClass public: // IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); public: // IPluginsListener - void OnPluginDestroyed(IPlugin *plugin); + void OnPluginUnloaded(IPlugin *plugin); public: //IRootConsoleCommand void OnRootConsoleCommand(const char *command, unsigned int argcount); public: @@ -74,8 +74,8 @@ public: /** * Create a convar and return a handle to it. */ - Handle_t CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, - int flags, bool hasMin, float min, bool hasMax, float max); + Handle_t CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, + const char *description, int flags, bool hasMin, float min, bool hasMax, float max); /** * Searches for a convar and returns a handle to it @@ -85,13 +85,18 @@ public: /** * Add a function to call when the specified convar changes. */ - void HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); + void HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction); /** * Remove a function from the forward that will be called when the specified convar changes. */ - void UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); + void UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction); private: + /** + * Adds a convar to a plugin's list. + */ + static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar); + /** * Static callback that Valve's ConVar class executes when the convar's value changes. */ diff --git a/core/EventManager.cpp b/core/EventManager.cpp index f40a1f2c..13561e5a 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -21,9 +21,8 @@ EventManager g_EventManager; SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool); -typedef List EventHookList; - const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; +typedef List EventHookList; EventManager::EventManager() : m_EventType(0), m_NotifyPlugins(true), m_EventCopy(NULL) { @@ -93,12 +92,13 @@ void EventManager::OnHandleDestroy(HandleType_t type, void *object) void EventManager::OnPluginUnloaded(IPlugin *plugin) { EventHookList *pHookList; + EventHookList::iterator iter; EventHook *pHook; // If plugin has an event hook list... if (plugin->GetProperty("EventHooks", reinterpret_cast(&pHookList), true)) { - for (EventHookList::iterator iter = pHookList->begin(); iter != pHookList->end(); iter++) + for (iter = pHookList->begin(); iter != pHookList->end(); iter++) { pHook = (*iter); diff --git a/core/EventManager.h b/core/EventManager.h index a6a923e7..5d9df54b 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -11,8 +11,8 @@ * Version: $Id$ */ -#ifndef _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ -#define _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ +#ifndef _INCLUDE_SOURCEMOD_EVENTMANAGER_H_ +#define _INCLUDE_SOURCEMOD_EVENTMANAGER_H_ #include "sm_globals.h" #include "sourcemm_api.h" @@ -109,4 +109,4 @@ private: extern EventManager g_EventManager; -#endif // _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ +#endif // _INCLUDE_SOURCEMOD_EVENTMANAGER_H_ diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 5189f7e5..2991aae2 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -22,6 +22,8 @@ using namespace SourcePawn; #define LANG_SERVER 0 +#define IS_STR_FILLED(var) (var[0] != '\0') + size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); diff --git a/core/smn_console.cpp b/core/smn_console.cpp index e76b6273..ab81ca9a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -29,7 +29,7 @@ static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) // While the engine seems to accept a blank convar name, it causes a crash upon server quit if (name == NULL || strcmp(name, "") == 0) { - return pContext->ThrowNativeError("Null or blank convar name is not allowed"); + return pContext->ThrowNativeError("Convar with blank name is not permitted"); } pContext->LocalToString(params[2], &defaultVal); @@ -40,7 +40,14 @@ static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) float min = sp_ctof(params[6]); float max = sp_ctof(params[8]); - return g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max); + Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max); + + if (hndl == BAD_HANDLE) + { + return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name); + } + + return hndl; } static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params) @@ -49,12 +56,6 @@ static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params) pContext->LocalToString(params[1], &name); - // While the engine seems to accept a blank convar name, it causes a crash upon server quit - if (name == NULL || strcmp(name, "") == 0) - { - return BAD_HANDLE; - } - return g_ConVarManager.FindConVar(name); } @@ -70,7 +71,14 @@ static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } - g_ConVarManager.HookConVarChange(pContext, pConVar, static_cast(params[2])); + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + g_ConVarManager.HookConVarChange(pConVar, pFunction); return 1; } @@ -87,7 +95,14 @@ static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *para return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } - g_ConVarManager.UnhookConVarChange(pContext, pConVar, static_cast(params[2])); + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + g_ConVarManager.UnhookConVarChange(pConVar, pFunction); return 1; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 63f09009..c4d575e5 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1415,7 +1415,6 @@ const char *CPluginManager::GetStatusText(PluginStatus st) } } -#define IS_STR_FILLED(var) (var[0] != '\0') void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argcount) { if (argcount >= 3) @@ -1432,7 +1431,7 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc g_RootMenu.ConsolePrint("[SM] No plugins loaded"); return; } else { - g_RootMenu.ConsolePrint("[SM] Displaying %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : ""); + g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : ""); } IPluginIterator *iter = GetPluginIterator(); diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 426ce51d..e84d68f4 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -209,7 +209,7 @@ native GetCmdArgString(String:buffer[], maxlength); * * @param name Name of new convar. * @param defaultValue String containing the default value of new convar. - * @param helpText Optional description of the convar. + * @param description Optional description of the convar. * @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. * @param hasMin Optional boolean that determines if the convar has a minimum value. * @param min Minimum floating point value that the convar can have if hasMin is true. @@ -218,7 +218,7 @@ native GetCmdArgString(String:buffer[], maxlength); * @return A handle to the newly created convar. If the convar already exists, INVALID_HANDLE is returned. * @error Convar name is blank or is the same as an existing console command. */ -native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:helpText[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); +native Handle:CreateConVar(const String:name[], const String:defaultValue[], const String:description[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); /** * Searches for a console variable. @@ -236,7 +236,7 @@ native Handle:FindConVar(const String:name[]); * @param newValue String containing the new value of the convar. * @noreturn */ -functag OnConVarChanged public(Handle:convar, const String:oldValue[], const String:newValue[]); +functag ConVarChanged public(Handle:convar, const String:oldValue[], const String:newValue[]); /** * Creates a hook for when a console variable's value is changed. @@ -246,7 +246,7 @@ functag OnConVarChanged public(Handle:convar, const String:oldValue[], const Str * @noreturn * @error Invalid or corrupt Handle or invalid callback function. */ -native HookConVarChange(Handle:convar, OnConVarChanged:callback); +native HookConVarChange(Handle:convar, ConVarChanged:callback); /** * Removes a hook for when a console variable's value is changed. @@ -256,7 +256,7 @@ native HookConVarChange(Handle:convar, OnConVarChanged:callback); * @noreturn * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. */ -native UnhookConVarChange(Handle:convar, OnConVarChanged:callback); +native UnhookConVarChange(Handle:convar, ConVarChanged:callback); /** * Returns the boolean value of a console variable. From 876e3da8e334052242afeb0fff64d4b07c5ccb3c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Mar 2007 16:41:12 +0000 Subject: [PATCH 0558/1664] fixed the build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40589 --- core/AdminCache.cpp | 2 +- core/CPlayerManager.cpp | 2 +- core/ConVarManager.cpp | 1 - core/Makefile | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 0cc9e833..3db94043 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -17,7 +17,7 @@ #include "ShareSys.h" #include "ForwardSys.h" #include "CPlayerManager.h" -#include "CConCmdManager.h" +#include "ConCmdManager.h" AdminCache g_Admins; diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 34b16afe..8e4776ba 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -15,7 +15,7 @@ #include "ForwardSys.h" #include "ShareSys.h" #include "AdminCache.h" -#include "CConCmdManager.h" +#include "ConCmdManager.h" CPlayerManager g_Players; diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 1daf4aeb..0eb448b3 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -169,7 +169,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, { ConVar *pConVar = NULL; ConVarInfo *pInfo = NULL; - ConVarList *pConVarList = NULL; Handle_t hndl = 0; /* Find out if the convar exists already */ diff --git a/core/Makefile b/core/Makefile index 5d0a8835..7d744920 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,9 +19,9 @@ BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk -OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp CConVarManager.cpp CDataPack.cpp \ +OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp ConVarManager.cpp CDataPack.cpp \ CDbgReporter.cpp CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ - CConCmdManager.cpp \ + ConCmdManager.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ smn_player.cpp smn_string.cpp smn_textparse.cpp smn_console.cpp smn_admin.cpp \ From dfed71eb28ee85e8ffdf2774c159b9c3527067dd Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 7 Mar 2007 18:24:09 +0000 Subject: [PATCH 0559/1664] Breakage alert :\ ThrowNativeErrorEx now returns 0 for convenience PushCellByRef and PushFloatByRef no longer have a flags parameter because it was almost pointless --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40590 --- core/systems/ForwardSys.cpp | 10 +++++----- core/systems/ForwardSys.h | 4 ++-- core/vm/sp_vm_basecontext.cpp | 6 ++++-- core/vm/sp_vm_basecontext.h | 2 +- core/vm/sp_vm_function.cpp | 8 ++++---- core/vm/sp_vm_function.h | 4 ++-- public/sourcepawn/sp_vm_api.h | 7 ++++--- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 2103b1d6..404e2fef 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -297,7 +297,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) { func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags); } else if (type == Param_Float || type == Param_Cell) { - func->PushCellByRef(¶m->val, 0); + func->PushCellByRef(¶m->val); } else { func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags); assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef); @@ -434,7 +434,7 @@ int CForward::PushFloat(float number) return SP_ERROR_NONE; } -int CForward::PushCellByRef(cell_t *cell, int flags) +int CForward::PushCellByRef(cell_t *cell) { if (m_curparam < m_numparams) { @@ -452,13 +452,13 @@ int CForward::PushCellByRef(cell_t *cell, int flags) m_params[m_curparam].pushedas = Param_CellByRef; } - _Int_PushArray(cell, 1, flags); + _Int_PushArray(cell, 1, SM_PARAM_COPYBACK); m_curparam++; return SP_ERROR_NONE; } -int CForward::PushFloatByRef(float *num, int flags) +int CForward::PushFloatByRef(float *num) { if (m_curparam < m_numparams) { @@ -476,7 +476,7 @@ int CForward::PushFloatByRef(float *num, int flags) m_params[m_curparam].pushedas = Param_FloatByRef; } - _Int_PushArray((cell_t *)num, 1, flags); + _Int_PushArray((cell_t *)num, 1, SM_PARAM_COPYBACK); m_curparam++; return SP_ERROR_NONE; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index e0ce371b..287b5eff 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -47,9 +47,9 @@ class CForward : public IChangeableForward { public: //ICallable virtual int PushCell(cell_t cell); - virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushCellByRef(cell_t *cell); virtual int PushFloat(float number); - virtual int PushFloatByRef(float *number, int flags); + virtual int PushFloatByRef(float *number); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index d6c4393e..eb6a52b7 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -212,11 +212,11 @@ void BaseContext::SetErrorMessage(const char *msg, va_list ap) vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); } -void BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) +cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) { if (!m_InExec) { - return; + return 0; } ctx->n_err = error; @@ -228,6 +228,8 @@ void BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) SetErrorMessage(msg, ap); va_end(ap); } + + return 0; } cell_t BaseContext::ThrowNativeError(const char *msg, ...) diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 68651e3f..43d6d511 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -61,7 +61,7 @@ namespace SourcePawn virtual int BindNative(const sp_nativeinfo_t *native); virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); virtual int Execute(uint32_t code_addr, cell_t *result); - virtual void ThrowNativeErrorEx(int error, const char *msg, ...); + virtual cell_t ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index c7f3b5a6..49f6a483 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -79,14 +79,14 @@ int CFunction::PushCell(cell_t cell) return SP_ERROR_NONE; } -int CFunction::PushCellByRef(cell_t *cell, int flags) +int CFunction::PushCellByRef(cell_t *cell) { if (m_curparam >= SP_MAX_EXEC_PARAMS) { return SetError(SP_ERROR_PARAMS_MAX); } - return PushArray(cell, 1, NULL, flags); + return PushArray(cell, 1, NULL, SM_PARAM_COPYBACK); } int CFunction::PushFloat(float number) @@ -96,9 +96,9 @@ int CFunction::PushFloat(float number) return PushCell(val); } -int CFunction::PushFloatByRef(float *number, int flags) +int CFunction::PushFloatByRef(float *number) { - return PushCellByRef((cell_t *)number, flags); + return PushCellByRef((cell_t *)number); } int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback) diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index 4b13f66d..da8713be 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -35,9 +35,9 @@ public: CFunction(uint32_t code_addr, IPluginContext *pContext); public: virtual int PushCell(cell_t cell); - virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushCellByRef(cell_t *cell); virtual int PushFloat(float number); - virtual int PushFloatByRef(float *number, int flags); + virtual int PushFloatByRef(float *number); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index cfdb5958..67111d94 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -70,7 +70,7 @@ namespace SourcePawn * @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushCellByRef(cell_t *cell, int flags) =0; + virtual int PushCellByRef(cell_t *cell) =0; /** * @brief Pushes a float onto the current call. @@ -91,7 +91,7 @@ namespace SourcePawn & @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushFloatByRef(float *number, int flags) =0; + virtual int PushFloatByRef(float *number) =0; /** * @brief Pushes an array of cells onto the current call. @@ -505,8 +505,9 @@ namespace SourcePawn * @param error The error number to set. * @param msg Custom error message format. NULL to use default. * @param ... Message format arguments, if any. + * @return 0 for convenience. */ - virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; + virtual cell_t ThrowNativeErrorEx(int error, const char *msg, ...) =0; /** * @brief Throws a generic native error and halts any current execution. From 949b83c99b31a57bc7ed9105a5cff3f69109ae69 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 7 Mar 2007 18:37:41 +0000 Subject: [PATCH 0560/1664] Reverted change where flags param was removed on PushCellByRef and PushFloatByRef. Instead set the param to a default value of SM_PARAM_COPYBACK. (DS, how dare you!) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40591 --- core/systems/ForwardSys.cpp | 8 ++++---- core/systems/ForwardSys.h | 4 ++-- core/vm/sp_vm_function.cpp | 8 ++++---- core/vm/sp_vm_function.h | 4 ++-- public/sourcepawn/sp_vm_api.h | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 404e2fef..d43c15d9 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -434,7 +434,7 @@ int CForward::PushFloat(float number) return SP_ERROR_NONE; } -int CForward::PushCellByRef(cell_t *cell) +int CForward::PushCellByRef(cell_t *cell, int flags) { if (m_curparam < m_numparams) { @@ -452,13 +452,13 @@ int CForward::PushCellByRef(cell_t *cell) m_params[m_curparam].pushedas = Param_CellByRef; } - _Int_PushArray(cell, 1, SM_PARAM_COPYBACK); + _Int_PushArray(cell, 1, flags); m_curparam++; return SP_ERROR_NONE; } -int CForward::PushFloatByRef(float *num) +int CForward::PushFloatByRef(float *num, int flags) { if (m_curparam < m_numparams) { @@ -476,7 +476,7 @@ int CForward::PushFloatByRef(float *num) m_params[m_curparam].pushedas = Param_FloatByRef; } - _Int_PushArray((cell_t *)num, 1, SM_PARAM_COPYBACK); + _Int_PushArray((cell_t *)num, 1, flags); m_curparam++; return SP_ERROR_NONE; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 287b5eff..e0ce371b 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -47,9 +47,9 @@ class CForward : public IChangeableForward { public: //ICallable virtual int PushCell(cell_t cell); - virtual int PushCellByRef(cell_t *cell); + virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); - virtual int PushFloatByRef(float *number); + virtual int PushFloatByRef(float *number, int flags); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 49f6a483..c7f3b5a6 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -79,14 +79,14 @@ int CFunction::PushCell(cell_t cell) return SP_ERROR_NONE; } -int CFunction::PushCellByRef(cell_t *cell) +int CFunction::PushCellByRef(cell_t *cell, int flags) { if (m_curparam >= SP_MAX_EXEC_PARAMS) { return SetError(SP_ERROR_PARAMS_MAX); } - return PushArray(cell, 1, NULL, SM_PARAM_COPYBACK); + return PushArray(cell, 1, NULL, flags); } int CFunction::PushFloat(float number) @@ -96,9 +96,9 @@ int CFunction::PushFloat(float number) return PushCell(val); } -int CFunction::PushFloatByRef(float *number) +int CFunction::PushFloatByRef(float *number, int flags) { - return PushCellByRef((cell_t *)number); + return PushCellByRef((cell_t *)number, flags); } int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback) diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index da8713be..4b13f66d 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -35,9 +35,9 @@ public: CFunction(uint32_t code_addr, IPluginContext *pContext); public: virtual int PushCell(cell_t cell); - virtual int PushCellByRef(cell_t *cell); + virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); - virtual int PushFloatByRef(float *number); + virtual int PushFloatByRef(float *number, int flags); virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 67111d94..7ec0ace2 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -70,7 +70,7 @@ namespace SourcePawn * @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushCellByRef(cell_t *cell) =0; + virtual int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK) =0; /** * @brief Pushes a float onto the current call. @@ -91,7 +91,7 @@ namespace SourcePawn & @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushFloatByRef(float *number) =0; + virtual int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK) =0; /** * @brief Pushes an array of cells onto the current call. From bda756f3ff7a4a06ee525fc9e200af86eb3e327f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 10 Mar 2007 05:52:51 +0000 Subject: [PATCH 0561/1664] fixed a really dumb bug - shouldn't compilers be checking this? --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40592 --- core/vm/sp_vm_function.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index c7f3b5a6..1fe2f25b 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -135,7 +135,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr *phys_addr = info->phys_addr; } - return true; + return SP_ERROR_NONE; } int CFunction::PushString(const char *string) From 5fe8bed25673db3f6b30b4e4dbce016e504f6151 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 10 Mar 2007 13:16:19 +0000 Subject: [PATCH 0562/1664] Added timer system implementation --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40593 --- core/CTimerSys.cpp | 199 +++++++++++++++++++++++++++++++++ core/CTimerSys.h | 65 +++++++++++ core/msvc8/sourcemod_mm.vcproj | 14 ++- core/sourcemod.cpp | 8 +- public/ITimerSystem.h | 13 +-- 5 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 core/CTimerSys.cpp create mode 100644 core/CTimerSys.h diff --git a/core/CTimerSys.cpp b/core/CTimerSys.cpp new file mode 100644 index 00000000..166b54ed --- /dev/null +++ b/core/CTimerSys.cpp @@ -0,0 +1,199 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "CTimerSys.h" + +CTimerSystem g_Timers; + +void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags) +{ + m_Listener = pCallbacks; + m_Interval = fInterval; + m_ToExec = fToExec; + m_pData = pData; + m_Flags = flags; + m_InExec = false; + m_KillMe = false; +} + +void CTimerSystem::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, this); +} + +void CTimerSystem::RunFrame() +{ + ITimer *pTimer; + TimerIter iter; + + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); ) + { + pTimer = (*iter); + if (gpGlobals->curtime >= pTimer->m_ToExec) + { + pTimer->m_InExec = true; + pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); + if (pTimer->m_KillMe) + { + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + } + iter = m_SingleTimers.erase(iter); + m_FreeTimers.push(pTimer); + } else { + break; + } + } + + ResultType res; + for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); ) + { + pTimer = (*iter); + if (gpGlobals->curtime >= pTimer->m_ToExec) + { + pTimer->m_InExec = true; + res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); + if (pTimer->m_KillMe || (res == Pl_Stop)) + { + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + iter = m_LoopTimers.erase(iter); + m_FreeTimers.push(pTimer); + continue; + } + pTimer->m_InExec = false; + pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + } + iter++; + } + + m_LastExecTime = gpGlobals->curtime; +} + +ITimer *CTimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) +{ + ITimer *pTimer; + TimerIter iter; + float to_exec = gpGlobals->curtime + fInterval; + + if (m_FreeTimers.empty()) + { + pTimer = new ITimer; + } else { + pTimer = m_FreeTimers.front(); + m_FreeTimers.pop(); + } + + pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags); + + if (flags & TIMER_FLAG_REPEAT) + { + m_LoopTimers.push_back(pTimer); + goto return_timer; + } + + if (m_SingleTimers.size() >= 1) + { + iter = --m_SingleTimers.end(); + if ((*iter)->m_ToExec <= to_exec) + { + goto insert_end; + } + } + + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) + { + if ((*iter)->m_ToExec >= to_exec) + { + m_SingleTimers.insert(iter, pTimer); + goto return_timer; + } + } + +insert_end: + m_SingleTimers.push_back(pTimer); + +return_timer: + return pTimer; +} + +void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) +{ + ResultType res; + + if (pTimer->m_InExec) + { + return; + } + + pTimer->m_InExec = true; + res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); + + if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT)) + { + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + m_SingleTimers.remove(pTimer); + m_FreeTimers.push(pTimer); + } else { + if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe) + { + pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + pTimer->m_InExec = false; + return; + } + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + m_LoopTimers.remove(pTimer); + m_FreeTimers.push(pTimer); + } +} + +void CTimerSystem::KillTimer(ITimer *pTimer) +{ + TimerList *pList; + + if (pTimer->m_KillMe) + { + return; + } + + if (pTimer->m_InExec) + { + pTimer->m_KillMe = true; + return; + } + + pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */ + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + + pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers; + + pList->remove(pTimer); + m_FreeTimers.push(pTimer); +} + +void CTimerSystem::MapChange() +{ + ITimer *pTimer; + TimerIter iter; + + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) + { + pTimer = (*iter); + pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime; + } + + for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++) + { + pTimer = (*iter); + pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime; + } +} diff --git a/core/CTimerSys.h b/core/CTimerSys.h new file mode 100644 index 00000000..520a33f1 --- /dev/null +++ b/core/CTimerSys.h @@ -0,0 +1,65 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_ +#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_ + +#include "ShareSys.h" +#include +#include +#include +#include "sourcemm_api.h" + +using namespace SourceHook; +using namespace SourceMod; + +typedef List TimerList; +typedef List::iterator TimerIter; + +class SourceMod::ITimer +{ +public: + void Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags); + ITimedEvent *m_Listener; + void *m_pData; + float m_Interval; + float m_ToExec; + int m_Flags; + bool m_InExec; + bool m_KillMe; +}; + +class CTimerSystem : + public ITimerSystem, + public SMGlobalClass +{ +public: //SMGlobalClass + void OnSourceModAllInitialized(); +public: //ITimerSystem + ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags); + void KillTimer(ITimer *pTimer); + void FireTimerOnce(ITimer *pTimer, bool delayExec=false); +public: + void RunFrame(); + void MapChange(); +private: + List m_SingleTimers; + List m_LoopTimers; + CStack m_FreeTimers; + float m_LastExecTime; +}; + +extern CTimerSystem g_Timers; + +#endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 5ee357db..76298884 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -313,6 +317,10 @@ RelativePath="..\CTextParsers.h" > + + @@ -421,6 +429,10 @@ RelativePath="..\..\public\ITextParsers.h" > + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 950793d1..4271d6d3 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -26,6 +26,7 @@ #include "CPlayerManager.h" #include "CTranslator.h" #include "ForwardSys.h" +#include "CTimerSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -193,6 +194,7 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_LastAuthCheck = 0.0f; g_Logger.MapChange(pMapName); + g_Timers.MapChange(); /* Refresh language stuff */ char path[PLATFORM_MAX_PATH]; @@ -221,7 +223,7 @@ void SourceModBase::GameFrame(bool simulating) * precious CPU cycles. */ float curtime = gpGlobals->curtime; - if (curtime - g_LastTime > 0.1f) + if (curtime - g_LastTime >= 0.1f) { if (m_CheckingAuth && (gpGlobals->curtime - g_LastAuthCheck > 0.7f)) @@ -229,9 +231,11 @@ void SourceModBase::GameFrame(bool simulating) g_LastAuthCheck = gpGlobals->curtime; g_Players.RunAuthChecks(); } + + g_Timers.RunFrame(); g_LastTime = curtime; } - + if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount()) { g_pOnGameFrame->Execute(NULL); diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index 2291087f..23d19353 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -20,11 +20,10 @@ #define _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ #include +#include -//:TODO: this is a placeholder and not yet implemented -//remove these lines and uncomment once we're done! -//#define SMINTERFACE_TIMERSYS_NAME "ITimerSys" -//#define SMINTERFACE_TIMERSYS_VERSION 1 +#define SMINTERFACE_TIMERSYS_NAME "ITimerSys" +#define SMINTERFACE_TIMERSYS_VERSION 1 namespace SourceMod { @@ -41,9 +40,7 @@ namespace SourceMod * * @param pTimer Pointer to the timer instance. * @param pData Private pointer passed from host. - * @return Pl_Handle to stop timer, Pl_Continue to continue. - * Passing Pl_Continue when a timer's repeat count - * has been exhausted will not extend it. + * @return Pl_Stop to stop timer, Pl_Continue to continue. */ virtual ResultType OnTimer(ITimer *pTimer, void *pData) =0; @@ -53,7 +50,7 @@ namespace SourceMod * @param pTimer Pointer to the timer instance. * @param pData Private data pointer passed from host. */ - virtual void OnTimerEnd() =0; + virtual void OnTimerEnd(ITimer *pTimer, void *pData) =0; }; #define TIMER_FLAG_REPEAT (1<<0) From f592744d8787d76c23da42e8af7d073e7e1eded0 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 10 Mar 2007 13:36:38 +0000 Subject: [PATCH 0563/1664] NULL'ed this or something --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40594 --- core/smn_entities.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 97b624fe..f8b2f458 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -527,4 +527,5 @@ REGISTER_NATIVES(entityNatives) {"SetEntDataEnt", SetEntDataEnt}, {"SetEntDataFloat", SetEntDataFloat}, {"SetEntDataVector", SetEntDataVector}, + {NULL, NULL} }; From 38c94838b98e216f9ef5b5c933a974c535819852 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 10 Mar 2007 21:02:40 +0000 Subject: [PATCH 0564/1664] IPluginFunction implementation is re-entrant across native calls, as heap allocations are delayed until execution removed ICallable::GetAddressOfPushedParam removed phys_addr from ICallable::PushArray fixed a bug where sp_context_t::n_idx was overwritten upon re-entrant calls --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40595 --- core/CMsgListenerWrapper.h | 4 +- core/systems/ForwardSys.cpp | 9 +- core/systems/ForwardSys.h | 2 +- core/vm/sp_vm_basecontext.cpp | 3 + core/vm/sp_vm_function.cpp | 191 ++++++++++++++++++---------------- core/vm/sp_vm_function.h | 8 +- public/IForwardSys.h | 16 +-- public/sourcepawn/sp_vm_api.h | 28 ++--- 8 files changed, 137 insertions(+), 124 deletions(-) diff --git a/core/CMsgListenerWrapper.h b/core/CMsgListenerWrapper.h index 254d24b9..d06fe8e2 100644 --- a/core/CMsgListenerWrapper.h +++ b/core/CMsgListenerWrapper.h @@ -105,7 +105,7 @@ inline void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipie m_Hook->PushCell(msg_id); m_Hook->PushCell(0); //:TODO: push handle! - m_Hook->PushArray(g_MsgPlayers, size, NULL); + m_Hook->PushArray(g_MsgPlayers, size); m_Hook->PushCell(size); m_Hook->PushCell(pFilter->IsReliable()); m_Hook->PushCell(pFilter->IsInitMessage()); @@ -119,7 +119,7 @@ inline ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write m_Intercept->PushCell(msg_id); m_Intercept->PushCell(0); //:TODO: push handle! - m_Intercept->PushArray(g_MsgPlayers, size, NULL); + m_Intercept->PushArray(g_MsgPlayers, size); m_Intercept->PushCell(size); m_Intercept->PushCell(pFilter->IsReliable()); m_Intercept->PushCell(pFilter->IsInitMessage()); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index d43c15d9..bbbee3f5 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -299,7 +299,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) } else if (type == Param_Float || type == Param_Cell) { func->PushCellByRef(¶m->val); } else { - func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags); + func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags); assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef); } } else { @@ -489,7 +489,7 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) m_params[m_curparam].byref.orig_addr = inarray; } -int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags) +int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags) { /* We don't allow this here */ if (!inarray) @@ -513,11 +513,6 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, m_params[m_curparam].pushedas = Param_Array; } - if (phys_addr) - { - *phys_addr = NULL; - } - _Int_PushArray(inarray, cells, flags); m_curparam++; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index e0ce371b..2dbde5c8 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -50,7 +50,7 @@ public: //ICallable virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); virtual int PushFloatByRef(float *number, int flags); - virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags); + virtual int PushArray(cell_t *inarray, unsigned int cells, int flags); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual void Cancel(); diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index eb6a52b7..0c35b182 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -167,6 +167,7 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) cell_t save_sp = ctx->sp; cell_t save_hp = ctx->hp; + uint32_t n_idx = ctx->n_idx; bool wasExec = m_InExec; @@ -202,6 +203,8 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) ctx->hp = save_hp; } + ctx->n_idx = n_idx; + return err; } diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 1fe2f25b..9ee3d29a 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -86,7 +86,7 @@ int CFunction::PushCellByRef(cell_t *cell, int flags) return SetError(SP_ERROR_PARAMS_MAX); } - return PushArray(cell, 1, NULL, flags); + return PushArray(cell, 1, flags); } int CFunction::PushFloat(float number) @@ -101,7 +101,7 @@ int CFunction::PushFloatByRef(float *number, int flags) return PushCellByRef((cell_t *)number, flags); } -int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback) +int CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback) { if (m_curparam >= SP_MAX_EXEC_PARAMS) { @@ -109,32 +109,15 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr } ParamInfo *info = &m_info[m_curparam]; - int err; - - if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) - { - return SetError(err); - } info->flags = inarray ? copyback : 0; info->marked = true; - info->size = cells * sizeof(cell_t); - m_params[m_curparam] = info->local_addr; + info->size = cells; + info->str.is_sz = false; + info->orig_addr = inarray; + m_curparam++; - if (inarray) - { - memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells); - info->orig_addr = inarray; - } else { - info->orig_addr = info->phys_addr; - } - - if (phys_addr) - { - *phys_addr = info->phys_addr; - } - return SP_ERROR_NONE; } @@ -157,39 +140,15 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ ParamInfo *info = &m_info[m_curparam]; size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); - int err; - - if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) - { - return SetError(err); - } info->marked = true; - m_params[m_curparam] = info->local_addr; - m_curparam++; /* Prevent a leak */ - - if (!(sz_flags & SM_PARAM_STRING_COPY)) - { - goto skip_localtostr; - } - - if (sz_flags & SM_PARAM_STRING_UTF8) - { - if ((err=m_pContext->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) - { - return SetError(err); - } - } else { - if ((err=m_pContext->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) - { - return SetError(err); - } - } - -skip_localtostr: - info->flags = cp_flags; info->orig_addr = (cell_t *)string; + info->flags = cp_flags; info->size = len; + info->str.sz_flags = sz_flags; + info->str.is_sz = true; + + m_curparam++; return SP_ERROR_NONE; } @@ -201,21 +160,13 @@ void CFunction::Cancel() return; } - while (m_curparam--) - { - if (m_info[m_curparam].marked) - { - m_pContext->HeapRelease(m_info[m_curparam].local_addr); - m_info[m_curparam].marked = false; - } - } - m_errorstate = SP_ERROR_NONE; + m_curparam = 0; } int CFunction::Execute(cell_t *result) { - int err; + int err = SP_ERROR_NONE; if (!IsRunnable()) { m_errorstate = SP_ERROR_NOT_RUNNABLE; @@ -231,56 +182,122 @@ int CFunction::Execute(cell_t *result) cell_t temp_params[SP_MAX_EXEC_PARAMS]; ParamInfo temp_info[SP_MAX_EXEC_PARAMS]; unsigned int numparams = m_curparam; + unsigned int i; bool docopies = true; if (numparams) { //Save the info locally, then reset it for re-entrant calls. - memcpy(temp_params, m_params, numparams * sizeof(cell_t)); memcpy(temp_info, m_info, numparams * sizeof(ParamInfo)); } m_curparam = 0; - if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE) + /* Browse the parameters and build arrays */ + for (i=0; iHeapAlloc(temp_info[i].size, + &(temp_info[i].local_addr), + &(temp_info[i].phys_addr))) + != SP_ERROR_NONE) + { + break; + } + if (temp_info[i].orig_addr) + { + memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size); + } + } else { + /* Calculate cells required for the string */ + size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t); + + /* Allocate the buffer */ + if ((err=m_pContext->HeapAlloc(cells, + &(temp_info[i].local_addr), + &(temp_info[i].phys_addr))) + != SP_ERROR_NONE) + { + break; + } + /* Copy original string if necessary */ + if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL)) + { + if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) + { + if ((err=m_pContext->StringToLocalUTF8(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr, + NULL)) + != SP_ERROR_NONE) + { + break; + } + } else { + if ((err=m_pContext->StringToLocal(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr)) + != SP_ERROR_NONE) + { + break; + } + } + } + } /* End array/string calculation */ + /* Update the pushed parameter with the byref local address */ + temp_params[i] = temp_info[i].local_addr; + } else { + /* Just copy the value normally */ + temp_params[i] = m_params[i]; + } + } + + /* Make the call if we can */ + if (err == SP_ERROR_NONE) + { + if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE) + { + docopies = false; + } + } else { docopies = false; } - while (numparams--) + /* i should be equal to the last valid parameter + 1 */ + while (i--) { - if (!temp_info[numparams].marked) + if (!temp_info[i].marked) { continue; } - if (docopies && temp_info[numparams].flags) + if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) { - if (temp_info[numparams].orig_addr) + if (temp_info[i].orig_addr) { - if (temp_info[numparams].size == sizeof(cell_t)) + if (temp_info[i].str.is_sz) { - *temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr; + memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size); } else { - memcpy(temp_info[numparams].orig_addr, - temp_info[numparams].phys_addr, - temp_info[numparams].size); + if (temp_info[i].size == 1) + { + *temp_info[i].orig_addr = *(temp_info[i].phys_addr); + } else { + memcpy(temp_info[i].orig_addr, + temp_info[i].phys_addr, + temp_info[i].size * sizeof(cell_t)); + } } } } - m_pContext->HeapPop(temp_info[numparams].local_addr); - temp_info[numparams].marked = false; + if ((err=m_pContext->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE) + { + return err; + } } return err; } - -cell_t *CFunction::GetAddressOfPushedParam(unsigned int param) -{ - if (m_errorstate != SP_ERROR_NONE - || param >= m_curparam - || !m_info[param].marked) - { - return NULL; - } - - return m_info[param].phys_addr; -} diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index 4b13f66d..56d91b67 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -24,6 +24,11 @@ struct ParamInfo cell_t *phys_addr; /* Physical address of our copy */ cell_t *orig_addr; /* Original address to copy back to */ ucell_t size; /* Size of array in bytes */ + struct + { + bool is_sz; /* is a string */ + int sz_flags; /* has sz flags */ + } str; }; class CPlugin; @@ -38,10 +43,9 @@ public: virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushFloat(float number); virtual int PushFloatByRef(float *number, int flags); - virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); + virtual int PushArray(cell_t *inarray, unsigned int cells, int copyback); virtual int PushString(const char *string); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); - virtual cell_t *GetAddressOfPushedParam(unsigned int param); virtual int Execute(cell_t *result); virtual void Cancel(); virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); diff --git a/public/IForwardSys.h b/public/IForwardSys.h index fc903fe4..a6e9b018 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -37,7 +37,7 @@ using namespace SourcePawn; #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" -#define SMINTERFACE_FORWARDMANAGER_VERSION 1 +#define SMINTERFACE_FORWARDMANAGER_VERSION 2 /* * There is some very important documentation at the bottom of this file. @@ -177,14 +177,10 @@ namespace SourceMod * * @param inarray Array to copy. Cannot be NULL, unlike ICallable's version. * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Unused. If a value is passed, it will be filled with NULL. * @param flags Whether or not changes should be copied back to the input array. * @return Error code, if any. */ - virtual int PushArray(cell_t *inarray, - unsigned int cells, - cell_t **phys_addr, - int flags=0) =0; + virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0; }; /** @@ -270,6 +266,14 @@ namespace SourceMod { return SMINTERFACE_FORWARDMANAGER_VERSION; } + virtual bool IsVersionCompatible(unsigned int version) + { + if (version < 2 || version > GetInterfaceVersion()) + { + return false; + } + return true; + } public: /** * @brief Creates a managed forward. This forward exists globally. diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 7ec0ace2..3db0b0bc 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -94,23 +94,21 @@ namespace SourcePawn virtual int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK) =0; /** - * @brief Pushes an array of cells onto the current call. - * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back - * is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. + * @brief Pushes an array of cells onto the current call. + * + * On Execute, the pointer passed will be modified if non-NULL and copy-back + * is enabled. + * + * By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. * * @param inarray Array to copy, NULL if no initial array should be copied. * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Optional return address for physical array, if one was made. * @param flags Whether or not changes should be copied back to the input array. * @return Error code, if any. */ - virtual int PushArray(cell_t *inarray, - unsigned int cells, - cell_t **phys_addr, - int flags=0) =0; + virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0; /** * @brief Pushes a string onto the current call. @@ -177,14 +175,6 @@ namespace SourcePawn */ virtual IPluginContext *GetParentContext() =0; - /** - * @brief Returns the physical address of a by-reference parameter. - * - * @param param Parameter index to read (beginning at 0). - * @return Address, or NULL if invalid parameter specified. - */ - virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; - /** * @brief Returns whether the parent plugin is paused. * From 5228c86e2c4854848af68412efbc89f772117667 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 10 Mar 2007 21:12:40 +0000 Subject: [PATCH 0565/1664] reorganized this a bit --HG-- rename : core/CMsgListenerWrapper.h => core/smn_usermsgs.h extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40596 --- core/CMsgListenerWrapper.h | 144 --------------------------------- core/msvc8/sourcemod_mm.vcproj | 10 +-- core/smn_usermsgs.cpp | 120 +++++++++++++++++++++++++-- core/smn_usermsgs.h | 42 ++++++++++ 4 files changed, 161 insertions(+), 155 deletions(-) delete mode 100644 core/CMsgListenerWrapper.h create mode 100644 core/smn_usermsgs.h diff --git a/core/CMsgListenerWrapper.h b/core/CMsgListenerWrapper.h deleted file mode 100644 index d06fe8e2..00000000 --- a/core/CMsgListenerWrapper.h +++ /dev/null @@ -1,144 +0,0 @@ -/** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ - -#ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ -#define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ - -extern int g_MsgPlayers[256]; - -class MsgListenerWrapper : public IUserMessageListener -{ -public: - void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); - bool IsInterceptHook() const; - int GetMessageId() const; - IPluginFunction *GetHookedFunction() const; - IPluginFunction *GetNotifyFunction() const; -public: //IUserMessageListener - void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); - ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); - void OnUserMessageSent(int msg_id); -private: - size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter); -private: - IPluginFunction *m_Hook; - IPluginFunction *m_Intercept; - IPluginFunction *m_Notify; - bool m_IsInterceptHook; - int m_MsgId; -}; - -inline size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter) -{ - size_t size = static_cast(pFilter->GetRecipientCount()); - - for (size_t i=0; iGetRecipientIndex(i); - } - - return size; -} - -inline bool MsgListenerWrapper::IsInterceptHook() const -{ - return m_IsInterceptHook; -} - -inline int MsgListenerWrapper::GetMessageId() const -{ - return m_MsgId; -} - -inline IPluginFunction *MsgListenerWrapper::GetHookedFunction() const -{ - if (m_Hook) - { - return m_Hook; - } else { - return m_Intercept; - } -} - -inline IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const -{ - return m_Notify; -} - -inline void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept) -{ - if (intercept) - { - m_Intercept = hook; - m_Hook = NULL; - } else { - m_Hook = hook; - m_Intercept = NULL; - } - - if (notify) - { - m_Notify = notify; - } else { - m_Notify = NULL; - } - - m_MsgId = msgid; - m_IsInterceptHook = intercept; -} - -inline void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) -{ - cell_t res; - size_t size = PreparePlArray(g_MsgPlayers, pFilter); - - m_Hook->PushCell(msg_id); - m_Hook->PushCell(0); //:TODO: push handle! - m_Hook->PushArray(g_MsgPlayers, size); - m_Hook->PushCell(size); - m_Hook->PushCell(pFilter->IsReliable()); - m_Hook->PushCell(pFilter->IsInitMessage()); - m_Hook->Execute(&res); -} - -inline ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) -{ - cell_t res = static_cast(Pl_Continue); - size_t size = PreparePlArray(g_MsgPlayers, pFilter); - - m_Intercept->PushCell(msg_id); - m_Intercept->PushCell(0); //:TODO: push handle! - m_Intercept->PushArray(g_MsgPlayers, size); - m_Intercept->PushCell(size); - m_Intercept->PushCell(pFilter->IsReliable()); - m_Intercept->PushCell(pFilter->IsInitMessage()); - m_Intercept->Execute(&res); - - return static_cast(res); -} - -inline void MsgListenerWrapper::OnUserMessageSent(int msg_id) -{ - cell_t res; - - if (!m_Notify) - { - return; - } - - m_Notify->PushCell(msg_id); - m_Notify->Execute(&res); -} - -#endif //_INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 76298884..46e68a91 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ - - @@ -365,6 +361,10 @@ RelativePath="..\sm_version.h" > + + diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index c9eff762..155d7c22 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -15,7 +15,7 @@ #include "HandleSys.h" #include "PluginSys.h" #include "CUserMessages.h" -#include "CMsgListenerWrapper.h" +#include "smn_usermsgs.h" HandleType_t g_WrBitBufType; Handle_t g_CurMsgHandle; @@ -149,11 +149,119 @@ bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper return true; } -/************************************** -* * -* USER MESSAGE NATIVE IMPLEMENTATIONS * -* * -***************************************/ +/*************************************** + * * + * USER MESSAGE WRAPPER IMPLEMENTATION * + * * + ***************************************/ + +size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter) +{ + size_t size = static_cast(pFilter->GetRecipientCount()); + + for (size_t i=0; iGetRecipientIndex(i); + } + + return size; +} + +bool MsgListenerWrapper::IsInterceptHook() const +{ + return m_IsInterceptHook; +} + +int MsgListenerWrapper::GetMessageId() const +{ + return m_MsgId; +} + +IPluginFunction *MsgListenerWrapper::GetHookedFunction() const +{ + if (m_Hook) + { + return m_Hook; + } else { + return m_Intercept; + } +} + +IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const +{ + return m_Notify; +} + +void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept) +{ + if (intercept) + { + m_Intercept = hook; + m_Hook = NULL; + } else { + m_Hook = hook; + m_Intercept = NULL; + } + + if (notify) + { + m_Notify = notify; + } else { + m_Notify = NULL; + } + + m_MsgId = msgid; + m_IsInterceptHook = intercept; +} + +void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +{ + cell_t res; + size_t size = PreparePlArray(g_MsgPlayers, pFilter); + + m_Hook->PushCell(msg_id); + m_Hook->PushCell(0); //:TODO: push handle! + m_Hook->PushArray(g_MsgPlayers, size); + m_Hook->PushCell(size); + m_Hook->PushCell(pFilter->IsReliable()); + m_Hook->PushCell(pFilter->IsInitMessage()); + m_Hook->Execute(&res); +} + +ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +{ + cell_t res = static_cast(Pl_Continue); + size_t size = PreparePlArray(g_MsgPlayers, pFilter); + + m_Intercept->PushCell(msg_id); + m_Intercept->PushCell(0); //:TODO: push handle! + m_Intercept->PushArray(g_MsgPlayers, size); + m_Intercept->PushCell(size); + m_Intercept->PushCell(pFilter->IsReliable()); + m_Intercept->PushCell(pFilter->IsInitMessage()); + m_Intercept->Execute(&res); + + return static_cast(res); +} + +void MsgListenerWrapper::OnUserMessageSent(int msg_id) +{ + cell_t res; + + if (!m_Notify) + { + return; + } + + m_Notify->PushCell(msg_id); + m_Notify->Execute(&res); +} + +/*************************************** + * * + * USER MESSAGE NATIVE IMPLEMENTATIONS * + * * + ***************************************/ static UsrMessageNatives s_UsrMessageNatives; diff --git a/core/smn_usermsgs.h b/core/smn_usermsgs.h new file mode 100644 index 00000000..54efc186 --- /dev/null +++ b/core/smn_usermsgs.h @@ -0,0 +1,42 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ +#define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ + +extern int g_MsgPlayers[256]; + +class MsgListenerWrapper : public IUserMessageListener +{ +public: + void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); + bool IsInterceptHook() const; + int GetMessageId() const; + IPluginFunction *GetHookedFunction() const; + IPluginFunction *GetNotifyFunction() const; +public: //IUserMessageListener + void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); + ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); + void OnUserMessageSent(int msg_id); +private: + size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter); +private: + IPluginFunction *m_Hook; + IPluginFunction *m_Intercept; + IPluginFunction *m_Notify; + bool m_IsInterceptHook; + int m_MsgId; +}; + +#endif //_INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ From 749ddc8c155fe0ec8ad2c44b7a627844310a8bed Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 10 Mar 2007 21:18:07 +0000 Subject: [PATCH 0566/1664] part 1 of singleton renaming --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40597 --- core/AdminCache.cpp | 2 +- core/CGameConfigs.cpp | 2 +- core/ConCmdManager.cpp | 4 +- .../{CPlayerManager.cpp => PlayerManager.cpp} | 2 +- core/{CPlayerManager.h => PlayerManager.h} | 0 core/{CTextParsers.cpp => TextParsers.cpp} | 2 +- core/{CTextParsers.h => TextParsers.h} | 0 core/{CTranslator.cpp => Translator.cpp} | 4 +- core/{CTranslator.h => Translator.h} | 0 core/msvc8/sourcemod_mm.vcproj | 48 +++++++++---------- core/sm_stringutil.cpp | 4 +- core/smn_console.cpp | 2 +- core/smn_entities.cpp | 2 +- core/smn_halflife.cpp | 2 +- core/smn_lang.cpp | 2 +- core/smn_player.cpp | 2 +- core/smn_textparse.cpp | 2 +- core/sourcemod.cpp | 4 +- core/systems/PluginSys.cpp | 2 +- 19 files changed, 43 insertions(+), 43 deletions(-) rename core/{CPlayerManager.cpp => PlayerManager.cpp} (96%) rename core/{CPlayerManager.h => PlayerManager.h} (100%) rename core/{CTextParsers.cpp => TextParsers.cpp} (95%) rename core/{CTextParsers.h => TextParsers.h} (100%) rename core/{CTranslator.cpp => Translator.cpp} (95%) rename core/{CTranslator.h => Translator.h} (100%) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 3db94043..f60accb0 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -16,7 +16,7 @@ #include "AdminCache.h" #include "ShareSys.h" #include "ForwardSys.h" -#include "CPlayerManager.h" +#include "PlayerManager.h" #include "ConCmdManager.h" AdminCache g_Admins; diff --git a/core/CGameConfigs.cpp b/core/CGameConfigs.cpp index 048704cc..2d4eee60 100644 --- a/core/CGameConfigs.cpp +++ b/core/CGameConfigs.cpp @@ -14,7 +14,7 @@ #include #include #include "CGameConfigs.h" -#include "CTextParsers.h" +#include "TextParsers.h" #include "sm_stringutil.h" #include "sourcemod.h" #include "sourcemm_api.h" diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 094e3619..19ae8501 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -15,8 +15,8 @@ #include "sm_srvcmds.h" #include "AdminCache.h" #include "sm_stringutil.h" -#include "CPlayerManager.h" -#include "CTranslator.h" +#include "PlayerManager.h" +#include "Translator.h" ConCmdManager g_ConCmds; diff --git a/core/CPlayerManager.cpp b/core/PlayerManager.cpp similarity index 96% rename from core/CPlayerManager.cpp rename to core/PlayerManager.cpp index 8e4776ba..0b9581c3 100644 --- a/core/CPlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -11,7 +11,7 @@ * Version: $Id$ */ -#include "CPlayerManager.h" +#include "PlayerManager.h" #include "ForwardSys.h" #include "ShareSys.h" #include "AdminCache.h" diff --git a/core/CPlayerManager.h b/core/PlayerManager.h similarity index 100% rename from core/CPlayerManager.h rename to core/PlayerManager.h diff --git a/core/CTextParsers.cpp b/core/TextParsers.cpp similarity index 95% rename from core/CTextParsers.cpp rename to core/TextParsers.cpp index b1e8a205..521d1c1c 100644 --- a/core/CTextParsers.cpp +++ b/core/TextParsers.cpp @@ -17,7 +17,7 @@ #include #include #include -#include "CTextParsers.h" +#include "TextParsers.h" #include "ShareSys.h" CTextParsers g_TextParser; diff --git a/core/CTextParsers.h b/core/TextParsers.h similarity index 100% rename from core/CTextParsers.h rename to core/TextParsers.h diff --git a/core/CTranslator.cpp b/core/Translator.cpp similarity index 95% rename from core/CTranslator.cpp rename to core/Translator.cpp index ce73c044..a29937de 100644 --- a/core/CTranslator.cpp +++ b/core/Translator.cpp @@ -14,9 +14,9 @@ #include #include #include -#include "CTranslator.h" +#include "Translator.h" #include "CLogger.h" -#include "CTextParsers.h" +#include "TextParsers.h" #include "LibrarySys.h" #include "sm_stringutil.h" #include "sourcemod.h" diff --git a/core/CTranslator.h b/core/Translator.h similarity index 100% rename from core/CTranslator.h rename to core/Translator.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 46e68a91..57ca29d2 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -211,22 +211,10 @@ RelativePath="..\ConVarManager.cpp" > - - - - - - @@ -235,6 +223,10 @@ RelativePath="..\EventManager.cpp" > + + @@ -263,6 +255,14 @@ RelativePath="..\sourcemod.cpp" > + + + + - - - - - - @@ -329,6 +317,10 @@ RelativePath="..\EventManager.h" > + + @@ -373,6 +365,14 @@ RelativePath="..\sourcemod.h" > + + + + Date: Sat, 10 Mar 2007 21:26:04 +0000 Subject: [PATCH 0567/1664] part 2 of singleton renaming --HG-- rename : core/CGameConfigs.cpp => core/GameConfigs.cpp extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40598 --- core/{CDbgReporter.cpp => DebugReporter.cpp} | 4 +- core/{CDbgReporter.h => DebugReporter.h} | 0 core/{CGameConfigs.cpp => GameConfigs.cpp} | 6 +- core/{CGameConfigs.h => GameConfigs.h} | 0 core/{CHalfLife2.cpp => HalfLife2.cpp} | 2 +- core/{CHalfLife2.h => HalfLife2.h} | 0 core/{CLogger.cpp => Logger.cpp} | 2 +- core/{CLogger.h => Logger.h} | 0 core/{CTimerSys.cpp => TimerSys.cpp} | 2 +- core/{CTimerSys.h => TimerSys.h} | 0 core/Translator.cpp | 2 +- core/{CUserMessages.cpp => UserMessages.cpp} | 2 +- core/{CUserMessages.h => UserMessages.h} | 0 core/msvc8/sourcemod_mm.vcproj | 84 ++++++++++---------- core/sm_stringutil.cpp | 2 +- core/smn_entities.cpp | 2 +- core/smn_filesystem.cpp | 2 +- core/smn_usermsgs.cpp | 2 +- core/sourcemod.cpp | 2 +- core/systems/ExtensionSys.cpp | 2 +- core/systems/PluginSys.cpp | 2 +- 21 files changed, 59 insertions(+), 59 deletions(-) rename core/{CDbgReporter.cpp => DebugReporter.cpp} (94%) rename core/{CDbgReporter.h => DebugReporter.h} (100%) rename core/{CGameConfigs.cpp => GameConfigs.cpp} (94%) rename core/{CGameConfigs.h => GameConfigs.h} (100%) rename core/{CHalfLife2.cpp => HalfLife2.cpp} (94%) rename core/{CHalfLife2.h => HalfLife2.h} (100%) rename core/{CLogger.cpp => Logger.cpp} (94%) rename core/{CLogger.h => Logger.h} (100%) rename core/{CTimerSys.cpp => TimerSys.cpp} (95%) rename core/{CTimerSys.h => TimerSys.h} (100%) rename core/{CUserMessages.cpp => UserMessages.cpp} (95%) rename core/{CUserMessages.h => UserMessages.h} (100%) diff --git a/core/CDbgReporter.cpp b/core/DebugReporter.cpp similarity index 94% rename from core/CDbgReporter.cpp rename to core/DebugReporter.cpp index 601de0e5..20657b9b 100644 --- a/core/CDbgReporter.cpp +++ b/core/DebugReporter.cpp @@ -11,8 +11,8 @@ * Version: $Id$ */ -#include "CDbgReporter.h" -#include "CLogger.h" +#include "DebugReporter.h" +#include "Logger.h" #include "PluginSys.h" CDbgReporter g_DbgReporter; diff --git a/core/CDbgReporter.h b/core/DebugReporter.h similarity index 100% rename from core/CDbgReporter.h rename to core/DebugReporter.h diff --git a/core/CGameConfigs.cpp b/core/GameConfigs.cpp similarity index 94% rename from core/CGameConfigs.cpp rename to core/GameConfigs.cpp index 2d4eee60..66036e41 100644 --- a/core/CGameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -13,13 +13,13 @@ #include #include -#include "CGameConfigs.h" +#include "GameConfigs.h" #include "TextParsers.h" #include "sm_stringutil.h" #include "sourcemod.h" #include "sourcemm_api.h" -#include "CHalfLife2.h" -#include "CLogger.h" +#include "HalfLife2.h" +#include "Logger.h" #include "ShareSys.h" CGameConfigManager g_GameConfigs; diff --git a/core/CGameConfigs.h b/core/GameConfigs.h similarity index 100% rename from core/CGameConfigs.h rename to core/GameConfigs.h diff --git a/core/CHalfLife2.cpp b/core/HalfLife2.cpp similarity index 94% rename from core/CHalfLife2.cpp rename to core/HalfLife2.cpp index ca07c45f..d16972b4 100644 --- a/core/CHalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -11,7 +11,7 @@ * Version: $Id$ */ -#include "CHalfLife2.h" +#include "HalfLife2.h" #include "sourcemm_api.h" CHalfLife2 g_HL2; diff --git a/core/CHalfLife2.h b/core/HalfLife2.h similarity index 100% rename from core/CHalfLife2.h rename to core/HalfLife2.h diff --git a/core/CLogger.cpp b/core/Logger.cpp similarity index 94% rename from core/CLogger.cpp rename to core/Logger.cpp index 545256dc..5b0c7e60 100644 --- a/core/CLogger.cpp +++ b/core/Logger.cpp @@ -14,7 +14,7 @@ #include #include "sourcemod.h" #include "sourcemm_api.h" -#include "CLogger.h" +#include "Logger.h" #include "systems/LibrarySys.h" #include "sm_version.h" diff --git a/core/CLogger.h b/core/Logger.h similarity index 100% rename from core/CLogger.h rename to core/Logger.h diff --git a/core/CTimerSys.cpp b/core/TimerSys.cpp similarity index 95% rename from core/CTimerSys.cpp rename to core/TimerSys.cpp index 166b54ed..9740ce9e 100644 --- a/core/CTimerSys.cpp +++ b/core/TimerSys.cpp @@ -12,7 +12,7 @@ * Version: $Id$ */ -#include "CTimerSys.h" +#include "TimerSys.h" CTimerSystem g_Timers; diff --git a/core/CTimerSys.h b/core/TimerSys.h similarity index 100% rename from core/CTimerSys.h rename to core/TimerSys.h diff --git a/core/Translator.cpp b/core/Translator.cpp index a29937de..cea55b40 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -15,7 +15,7 @@ #include #include #include "Translator.h" -#include "CLogger.h" +#include "Logger.h" #include "TextParsers.h" #include "LibrarySys.h" #include "sm_stringutil.h" diff --git a/core/CUserMessages.cpp b/core/UserMessages.cpp similarity index 95% rename from core/CUserMessages.cpp rename to core/UserMessages.cpp index d675b737..e9f294b4 100644 --- a/core/CUserMessages.cpp +++ b/core/UserMessages.cpp @@ -12,7 +12,7 @@ * Version: $Id$ */ -#include "CUserMessages.h" +#include "UserMessages.h" CUserMessages g_UserMsgs; diff --git a/core/CUserMessages.h b/core/UserMessages.h similarity index 100% rename from core/CUserMessages.h rename to core/UserMessages.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 57ca29d2..d8f75c8c 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -187,22 +187,6 @@ RelativePath="..\CDataPack.cpp" > - - - - - - - - @@ -212,17 +196,25 @@ > - - + + + + + + @@ -259,10 +251,18 @@ RelativePath="..\TextParsers.cpp" > + + + + - - - - - - - - @@ -306,17 +290,25 @@ > - - + + + + + + @@ -369,10 +361,18 @@ RelativePath="..\TextParsers.h" > + + + + #include #include "sm_stringutil.h" -#include "CLogger.h" +#include "Logger.h" #include "PluginSys.h" #include "Translator.h" #include "PlayerManager.h" diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 8694f7c1..5f0a9f4d 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -16,7 +16,7 @@ #include "sourcemm_api.h" #include "server_class.h" #include "PlayerManager.h" -#include "CHalfLife2.h" +#include "HalfLife2.h" inline edict_t *GetEdict(cell_t num) { diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index f875b0a1..eeb02565 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -16,7 +16,7 @@ #include "HandleSys.h" #include "LibrarySys.h" #include "sm_stringutil.h" -#include "CLogger.h" +#include "Logger.h" #include "PluginSys.h" #include "sourcemm_api.h" diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 155d7c22..02c03ae9 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -14,7 +14,7 @@ #include "HandleSys.h" #include "PluginSys.h" -#include "CUserMessages.h" +#include "UserMessages.h" #include "smn_usermsgs.h" HandleType_t g_WrBitBufType; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 15f0a7d1..ecceb494 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -19,7 +19,7 @@ #include #include "PluginSys.h" #include "ShareSys.h" -#include "CLogger.h" +#include "Logger.h" #include "ExtensionSys.h" #include "AdminCache.h" #include "sm_stringutil.h" diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 066f616b..7bc8abec 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -15,7 +15,7 @@ #include "ExtensionSys.h" #include "LibrarySys.h" #include "ShareSys.h" -#include "CLogger.h" +#include "Logger.h" #include "sourcemm_api.h" #include "PluginSys.h" #include "sm_srvcmds.h" diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 8b6bcaa7..0b38ff04 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -19,7 +19,7 @@ #include "sourcemm_api.h" #include "sourcemod.h" #include "TextParsers.h" -#include "CLogger.h" +#include "Logger.h" #include "ExtensionSys.h" #include "sm_srvcmds.h" #include "sm_stringutil.h" From f78b3fa08699b3b122887256aec86cb1ee50d210 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 11 Mar 2007 03:04:39 +0000 Subject: [PATCH 0568/1664] rewrite of user messages fixed possible iterator corruption --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40599 --- core/CellRecipientFilter.h | 40 +++---- core/UserMessages.cpp | 201 ++++++++++++++++++++++++--------- core/UserMessages.h | 17 ++- core/msvc8/sourcemod_mm.vcproj | 2 +- core/smn_usermsgs.cpp | 173 +++++++++++++++------------- core/smn_usermsgs.h | 4 +- core/sourcemod.cpp | 2 +- 7 files changed, 278 insertions(+), 161 deletions(-) diff --git a/core/CellRecipientFilter.h b/core/CellRecipientFilter.h index 243855c2..2afc0844 100644 --- a/core/CellRecipientFilter.h +++ b/core/CellRecipientFilter.h @@ -21,7 +21,7 @@ class CellRecipientFilter : public IRecipientFilter { public: - CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0) {} + CellRecipientFilter() : m_IsReliable(false), m_IsInitMessage(false), m_Size(0) {} ~CellRecipientFilter() {} public: //IRecipientFilter bool IsReliable() const; @@ -29,32 +29,32 @@ public: //IRecipientFilter int GetRecipientCount() const; int GetRecipientIndex(int slot) const; public: - void SetRecipientPtr(cell_t *ptr, size_t count); - void SetReliable(bool isreliable); - void SetInitMessage(bool isinitmsg); - void ResetFilter(); + void Initialize(cell_t *ptr, size_t count); + void SetToReliable(bool isreliable); + void SetToInit(bool isinitmsg); + void Reset(); private: - cell_t m_CellRecipients[255]; - bool m_Reliable; - bool m_InitMessage; + cell_t m_Players[255]; + bool m_IsReliable; + bool m_IsInitMessage; size_t m_Size; }; -inline void CellRecipientFilter::ResetFilter() +inline void CellRecipientFilter::Reset() { - m_Reliable = false; - m_InitMessage = false; + m_IsReliable = false; + m_IsInitMessage = false; m_Size = 0; } inline bool CellRecipientFilter::IsReliable() const { - return m_Reliable; + return m_IsReliable; } inline bool CellRecipientFilter::IsInitMessage() const { - return m_InitMessage; + return m_IsInitMessage; } inline int CellRecipientFilter::GetRecipientCount() const @@ -68,22 +68,22 @@ inline int CellRecipientFilter::GetRecipientIndex(int slot) const { return -1; } - return static_cast(m_CellRecipients[slot]); + return static_cast(m_Players[slot]); } -inline void CellRecipientFilter::SetInitMessage(bool isinitmsg) +inline void CellRecipientFilter::SetToInit(bool isinitmsg) { - m_InitMessage = isinitmsg; + m_IsInitMessage = isinitmsg; } -inline void CellRecipientFilter::SetReliable(bool isreliable) +inline void CellRecipientFilter::SetToReliable(bool isreliable) { - m_Reliable = isreliable; + m_IsReliable = isreliable; } -inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count) +inline void CellRecipientFilter::Initialize(cell_t *ptr, size_t count) { - memcpy(m_CellRecipients, ptr, count * sizeof(cell_t)); + memcpy(m_Players, ptr, count * sizeof(cell_t)); m_Size = count; } diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index e9f294b4..5b0fb7af 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -88,8 +88,8 @@ bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) { bf_write *buffer; - - if (m_InExec) + + if (m_InExec || m_InHook) { return NULL; } @@ -98,16 +98,16 @@ bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int return NULL; } - m_CellRecFilter.SetRecipientPtr(players, playersNum); + m_CellRecFilter.Initialize(players, playersNum); m_CurFlags = flags; if (m_CurFlags & USERMSG_INITMSG) { - m_CellRecFilter.SetInitMessage(true); + m_CellRecFilter.SetToInit(true); } if (m_CurFlags & USERMSG_RELIABLE) { - m_CellRecFilter.SetReliable(true); + m_CellRecFilter.SetToReliable(true); } m_InExec = true; @@ -138,7 +138,7 @@ bool CUserMessages::EndMessage() m_InExec = false; m_CurFlags = 0; - m_CellRecFilter.ResetFilter(); + m_CellRecFilter.Reset(); return true; } @@ -150,6 +150,19 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, return false; } + ListenerInfo *pInfo; + if (m_FreeListeners.empty()) + { + pInfo = new ListenerInfo; + } else { + pInfo = m_FreeListeners.front(); + m_FreeListeners.pop(); + } + + pInfo->Callback = pListener; + pInfo->IsHooked = false; + pInfo->KillMe = false; + if (!m_HookCount++) { SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); @@ -160,20 +173,19 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, if (intercept) { - m_msgIntercepts[msg_id].push_back(pListener); + m_msgIntercepts[msg_id].push_back(pInfo); } else { - m_msgHooks[msg_id].push_back(pListener); + m_msgHooks[msg_id].push_back(pInfo); } return true; } bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) -{ - //:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess - List *lst; - IUserMessageListener *listener; +{ + MsgList *pList; MsgIter iter; + ListenerInfo *pInfo; bool deleted = false; if (msg_id < 0 || msg_id >= 255) @@ -181,27 +193,40 @@ bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListene return false; } - lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id]; - for (iter=lst->begin(); iter!=lst->end(); iter++) + pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id]; + for (iter=pList->begin(); iter!=pList->end(); iter++) { - listener = (*iter); - if (listener == pListener) + pInfo = (*iter); + if (pInfo->Callback == pListener) { - lst->erase(iter); + if (pInfo->IsHooked) + { + pInfo->KillMe = true; + return true; + } + pList->erase(iter); deleted = true; break; } } - if (deleted && !(--m_HookCount)) + if (deleted) + { + _DecRefCounter(); + } + + return deleted; +} + +void CUserMessages::_DecRefCounter() +{ + if (--m_HookCount == 0) { SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); } - - return (deleted) ? true : false; } bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type) @@ -209,13 +234,8 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty bool is_intercept_empty = m_msgIntercepts[msg_type].empty(); bool is_hook_empty = m_msgHooks[msg_type].empty(); - if (is_intercept_empty && is_hook_empty) - { - m_InHook = false; - RETURN_META_VALUE(MRES_IGNORED, NULL); - } - - if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL)) + if ((is_intercept_empty && is_hook_empty) + || (m_InExec && !(m_CurFlags & USERMSG_PASSTHRU_ALL))) { m_InHook = false; RETURN_META_VALUE(MRES_IGNORED, NULL); @@ -223,11 +243,11 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty m_CurId = msg_type; m_CurRecFilter = filter; - m_InterceptBuffer.Reset(); m_InHook = true; if (!is_intercept_empty) { + m_InterceptBuffer.Reset(); RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer); } @@ -253,23 +273,48 @@ void CUserMessages::OnMessageEnd_Post() RETURN_META(MRES_IGNORED); } - List *lst; - IUserMessageListener *listener; + MsgList *pList; MsgIter iter; + ListenerInfo *pInfo; - lst = &m_msgIntercepts[m_CurId]; - for (iter=lst->begin(); iter!=lst->end(); iter++) + pList = &m_msgIntercepts[m_CurId]; + for (iter=pList->begin(); iter!=pList->end(); ) { - listener = (*iter); - listener->OnUserMessageSent(m_CurId); + pInfo = (*iter); + pInfo->IsHooked = true; + pInfo->Callback->OnUserMessageSent(m_CurId); + + if (pInfo->KillMe) + { + iter = pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + continue; + } + + pInfo->IsHooked = false; + iter++; } - lst = &m_msgHooks[m_CurId]; - for (iter=lst->begin(); iter!=lst->end(); iter++) + pList = &m_msgHooks[m_CurId]; + for (iter=pList->begin(); iter!=pList->end(); iter++) { - listener = (*iter); - listener->OnUserMessageSent(m_CurId); + pInfo = (*iter); + pInfo->Callback->OnUserMessageSent(m_CurId); + + if (pInfo->KillMe) + { + iter = pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + continue; + } + + pInfo->IsHooked = false; + iter++; } + + m_InHook = false; } void CUserMessages::OnMessageEnd_Pre() @@ -279,26 +324,61 @@ void CUserMessages::OnMessageEnd_Pre() RETURN_META(MRES_IGNORED); } - List *lst; - IUserMessageListener *listener; - bf_write *engine_bfw; + MsgList *pList; MsgIter iter; + ListenerInfo *pInfo; + ResultType res; bool intercepted = false; bool handled = false; - lst = &m_msgIntercepts[m_CurId]; - for (iter=lst->begin(); iter!=lst->end(); iter++) + pList = &m_msgIntercepts[m_CurId]; + for (iter=pList->begin(); iter!=pList->end(); ) { - listener = (*iter); - res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter); - if (res == Pl_Stop) + pInfo = (*iter); + pInfo->IsHooked = true; + res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter); + + switch (res) { - goto supercede; - } else if (res == Pl_Handled) { - handled = true; + case Pl_Stop: + { + if (pInfo->KillMe) + { + pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + goto supercede; + } + pInfo->IsHooked = false; + goto supercede; + } + case Pl_Handled: + { + handled = true; + if (pInfo->KillMe) + { + iter = pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + continue; + } + break; + } + default: + { + if (pInfo->KillMe) + { + iter = pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + continue; + } + } } + pInfo->IsHooked = false; intercepted = true; + iter++; } if (handled) @@ -308,21 +388,36 @@ void CUserMessages::OnMessageEnd_Pre() if (intercepted) { + bf_write *engine_bfw; + engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId); m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten()); engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten()); ENGINE_CALL(MessageEnd)(); + goto supercede; } - lst = &m_msgHooks[m_CurId]; - for (iter=lst->begin(); iter!=lst->end(); iter++) + pList = &m_msgHooks[m_CurId]; + for (iter=pList->begin(); iter!=pList->end(); ) { - listener = (*iter); - listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter); + pInfo = (*iter); + pInfo->IsHooked = true; + pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter); + + if (pInfo->KillMe) + { + iter = pList->erase(iter); + m_FreeListeners.push(pInfo); + _DecRefCounter(); + continue; + } + + iter++; } RETURN_META(MRES_IGNORED); supercede: + m_InHook = false; RETURN_META(MRES_SUPERCEDE); } diff --git a/core/UserMessages.h b/core/UserMessages.h index d18ce29a..b9d5abf0 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -26,7 +26,15 @@ using namespace SourceMod; #define INVALID_MESSAGE_ID -1 -typedef List::iterator MsgIter; +struct ListenerInfo +{ + IUserMessageListener *Callback; + bool IsHooked; + bool KillMe; +}; + +typedef List MsgList; +typedef List::iterator MsgIter; class CUserMessages : public IUserMessages, @@ -51,8 +59,11 @@ public: void OnMessageEnd_Pre(); void OnMessageEnd_Post(); private: - List m_msgHooks[255]; - List m_msgIntercepts[255]; + void _DecRefCounter(); +private: + List m_msgHooks[255]; + List m_msgIntercepts[255]; + CStack m_FreeListeners; unsigned char m_pBase[2500]; IRecipientFilter *m_CurRecFilter; bf_write m_InterceptBuffer; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d8f75c8c..99409e11 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ MsgWrapperList; +typedef List::iterator MsgWrapperIter; + class UsrMessageNatives : public SMGlobalClass, public IHandleTypeDispatch, @@ -33,9 +36,9 @@ public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener void OnHandleDestroy(HandleType_t type, void *object); void OnPluginUnloaded(IPlugin *plugin); public: - MsgListenerWrapper *GetNewListener(IPluginContext *pCtx); - MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept); - bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept); + MsgListenerWrapper *CreateListener(IPluginContext *pCtx); + MsgWrapperIter FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept); + bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter); private: CStack m_FreeListeners; }; @@ -59,92 +62,91 @@ void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin) { - List *wrapper_list; + MsgWrapperList *pList; - if (plugin->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list), true)) + if (plugin->GetProperty("MsgListeners", reinterpret_cast(&pList), true)) { - List::iterator iter; - MsgListenerWrapper *listener; + MsgWrapperIter iter; + MsgListenerWrapper *pListener; - for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) + for (iter=pList->begin(); iter!=pList->end(); iter++) { - listener = (*iter); - if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook())) + pListener = (*iter); + if (g_UserMsgs.UnhookUserMessage(pListener->GetMessageId(), pListener, pListener->IsInterceptHook())) { - m_FreeListeners.push(listener); + m_FreeListeners.push(pListener); } } - delete wrapper_list; + delete pList; } } -MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx) +MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx) { - MsgListenerWrapper *listener_wrapper; + MsgWrapperList *pList; + MsgListenerWrapper *pListener; + IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); if (m_FreeListeners.empty()) { - listener_wrapper = new MsgListenerWrapper; + pListener = new MsgListenerWrapper; } else { - listener_wrapper = m_FreeListeners.front(); + pListener = m_FreeListeners.front(); m_FreeListeners.pop(); } - List *wrapper_list; - IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); - - if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&pList))) { - wrapper_list = new List; - pl->SetProperty("MsgListeners", wrapper_list); + pList = new List; + pl->SetProperty("MsgListeners", pList); } - wrapper_list->push_back(listener_wrapper); + pList->push_back(pListener); - return listener_wrapper; + return pListener; } -MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept) +MsgWrapperIter UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept) { - MsgListenerWrapper *listener; - List *wrapper_list; - List::iterator iter; + MsgWrapperList *pList; + MsgWrapperIter iter; + MsgListenerWrapper *pListener; IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); - bool found = false; - if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&pList))) { return NULL; } - for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) + for (iter=pList->begin(); iter!=pList->end(); iter++) { - listener = (*iter); - if ((msgid == listener->GetMessageId()) - && (intercept == listener->IsInterceptHook()) - && (pHook == listener->GetHookedFunction())) + pListener = (*iter); + if ((msgid == pListener->GetMessageId()) + && (intercept == pListener->IsInterceptHook()) + && (pHook == pListener->GetHookedFunction())) { - found = true; - break; + return iter; } } - return (found) ? listener : NULL; + return NULL; } -bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept) +bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter) { - List *wrapper_list; + MsgWrapperList *pList; + MsgListenerWrapper *pListener; IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); - if (!pl->GetProperty("MsgListeners", reinterpret_cast(&wrapper_list))) + if (!pl->GetProperty("MsgListeners", reinterpret_cast(&pList))) { return false; } - wrapper_list->remove(listener); - m_FreeListeners.push(listener); + pListener = (*iter); + pList->erase(iter); + m_FreeListeners.push(pListener); return true; } @@ -155,7 +157,29 @@ bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper * * ***************************************/ -size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter) +void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept) +{ + if (intercept) + { + m_Intercept = hook; + m_Hook = NULL; + } else { + m_Hook = hook; + m_Intercept = NULL; + } + + if (notify) + { + m_Notify = notify; + } else { + m_Notify = NULL; + } + + m_MsgId = msgid; + m_IsInterceptHook = intercept; +} + +size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter) { size_t size = static_cast(pFilter->GetRecipientCount()); @@ -192,32 +216,10 @@ IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const return m_Notify; } -void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept) -{ - if (intercept) - { - m_Intercept = hook; - m_Hook = NULL; - } else { - m_Hook = hook; - m_Intercept = NULL; - } - - if (notify) - { - m_Notify = notify; - } else { - m_Notify = NULL; - } - - m_MsgId = msgid; - m_IsInterceptHook = intercept; -} - void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) { cell_t res; - size_t size = PreparePlArray(g_MsgPlayers, pFilter); + size_t size = _FillInPlayers(g_MsgPlayers, pFilter); m_Hook->PushCell(msg_id); m_Hook->PushCell(0); //:TODO: push handle! @@ -231,7 +233,7 @@ void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilte ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) { cell_t res = static_cast(Pl_Continue); - size_t size = PreparePlArray(g_MsgPlayers, pFilter); + size_t size = _FillInPlayers(g_MsgPlayers, pFilter); m_Intercept->PushCell(msg_id); m_Intercept->PushCell(0); //:TODO: push handle! @@ -246,13 +248,12 @@ ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IR void MsgListenerWrapper::OnUserMessageSent(int msg_id) { - cell_t res; - if (!m_Notify) { return; } + cell_t res; m_Notify->PushCell(msg_id); m_Notify->Execute(&res); } @@ -319,6 +320,10 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) pCtx->LocalToPhysAddr(params[2], &cl_array); pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); + if (!pBitBuf) + { + return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); + } g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); g_IsMsgInExec = true; @@ -345,6 +350,10 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params) pCtx->LocalToPhysAddr(params[2], &cl_array); pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); + if (!pBitBuf) + { + return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); + } g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); g_IsMsgInExec = true; @@ -375,7 +384,7 @@ static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params) static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) { IPluginFunction *pHook, *pNotify; - MsgListenerWrapper *listener; + MsgListenerWrapper *pListener; bool intercept; int msgid = params[1]; @@ -390,12 +399,12 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); } pNotify = pCtx->GetFunctionById(params[4]); - intercept = (params[3]) ? true : false; - listener = s_UsrMessageNatives.GetNewListener(pCtx); - listener->InitListener(msgid, pHook, pNotify, intercept); - g_UserMsgs.HookUserMessage(msgid, listener, intercept); + pListener = s_UsrMessageNatives.CreateListener(pCtx); + pListener->Initialize(msgid, pHook, pNotify, intercept); + + g_UserMsgs.HookUserMessage(msgid, pListener, intercept); return 1; } @@ -403,7 +412,8 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params) { IPluginFunction *pFunc; - MsgListenerWrapper *listener; + MsgListenerWrapper *pListener; + MsgWrapperIter iter; bool intercept; int msgid = params[1]; @@ -417,20 +427,21 @@ static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params) { return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); } - intercept = (params[3]) ? true : false; - listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept); - if (!listener) + + iter = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept); + if (iter == NULL) { return pCtx->ThrowNativeError("Unable to unhook the current user message"); } - if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept)) + pListener = (*iter); + if (!g_UserMsgs.UnhookUserMessage(msgid, pListener, intercept)) { return pCtx->ThrowNativeError("Unable to unhook the current user message"); } - s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept); + s_UsrMessageNatives.DeleteListener(pCtx, iter); return 1; } diff --git a/core/smn_usermsgs.h b/core/smn_usermsgs.h index 54efc186..f9e72a3d 100644 --- a/core/smn_usermsgs.h +++ b/core/smn_usermsgs.h @@ -20,7 +20,7 @@ extern int g_MsgPlayers[256]; class MsgListenerWrapper : public IUserMessageListener { public: - void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); + void Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); bool IsInterceptHook() const; int GetMessageId() const; IPluginFunction *GetHookedFunction() const; @@ -30,7 +30,7 @@ public: //IUserMessageListener ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); void OnUserMessageSent(int msg_id); private: - size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter); + size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter); private: IPluginFunction *m_Hook; IPluginFunction *m_Intercept; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index ecceb494..e537ad8b 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -26,7 +26,7 @@ #include "PlayerManager.h" #include "Translator.h" #include "ForwardSys.h" -#include "CTimerSys.h" +#include "TimerSys.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); From d51ea0695fb328f6b0b0589899ffef8a1f39ccc6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 11 Mar 2007 03:25:28 +0000 Subject: [PATCH 0569/1664] HAHA estoy usando el internet!!!11! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40600 --- core/UserMessages.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 5b0fb7af..0f8a8c38 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -297,9 +297,10 @@ void CUserMessages::OnMessageEnd_Post() } pList = &m_msgHooks[m_CurId]; - for (iter=pList->begin(); iter!=pList->end(); iter++) + for (iter=pList->begin(); iter!=pList->end(); ) { pInfo = (*iter); + pInfo->IsHooked = true; pInfo->Callback->OnUserMessageSent(m_CurId); if (pInfo->KillMe) @@ -413,6 +414,7 @@ void CUserMessages::OnMessageEnd_Pre() continue; } + pInfo->IsHooked = false; iter++; } From c2f106d4c63d0a66a58e1fff2c3826f5eaba8437 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 11 Mar 2007 18:30:29 +0000 Subject: [PATCH 0570/1664] added request amb80 (system time) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40601 --- core/smn_core.cpp | 13 +++++++++++++ plugins/include/sourcemod.inc | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/core/smn_core.cpp b/core/smn_core.cpp index bc7b342a..c37dbd95 100644 --- a/core/smn_core.cpp +++ b/core/smn_core.cpp @@ -11,6 +11,7 @@ * Version: $Id$ */ +#include #include "sm_globals.h" #include "sourcemod.h" @@ -28,8 +29,20 @@ static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) return 0; } +static cell_t GetTime(IPluginContext *pContext, const cell_t *params) +{ + time_t t = time(NULL); + cell_t *addr; + pContext->LocalToPhysAddr(params[1], &addr); + + *(time_t *)addr = t; + + return static_cast(t); +} + REGISTER_NATIVES(coreNatives) { + {"GetTime", GetTime}, {"ThrowError", ThrowError}, {NULL, NULL}, }; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 4143dfb6..67cd32b8 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -146,6 +146,14 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); */ native LogError(const String:format[], {Handle,Float,String,_}:...); +/** + * Gets the system time as a unix timestamp. + * + * @param bigStamp Optional array to store the 64bit timestamp in. + * @return 32bit timestamp (number of seconds since unix epoch). + */ +native GetTime(bigStamp[2]={0,0}); + /** * Sets the seed value for the global Half-Life 2 Random Stream * From d8c02c294f4da5baf2a1ac7684c9d477684f3487 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 11 Mar 2007 18:37:55 +0000 Subject: [PATCH 0571/1664] fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40602 --- core/Makefile | 5 ++--- core/vm/sp_vm_function.cpp | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/Makefile b/core/Makefile index 7d744920..d9669fb5 100644 --- a/core/Makefile +++ b/core/Makefile @@ -20,8 +20,7 @@ HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp ConVarManager.cpp CDataPack.cpp \ - CDbgReporter.cpp CLogger.cpp CPlayerManager.cpp CTextParsers.cpp CTranslator.cpp \ - ConCmdManager.cpp \ + DebugReporter.cpp Logger.cpp PlayerManager.cpp TextParsers.cpp Translator.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ smn_player.cpp smn_string.cpp smn_textparse.cpp smn_console.cpp smn_admin.cpp \ @@ -29,7 +28,7 @@ OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp ConVarManager.cpp CDataP systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ systems/PluginSys.cpp systems/ShareSys.cpp vm/sp_vm_basecontext.cpp \ - vm/sp_vm_engine.cpp vm/sp_vm_function.cpp + vm/sp_vm_engine.cpp vm/sp_vm_function.cpp ConCmdManager.cpp TimerSys.cpp OBJECTS_C = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \ zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \ zlib/uncompr.c zlib/zutil.c diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 9ee3d29a..3bd995f6 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -139,7 +139,6 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ } ParamInfo *info = &m_info[m_curparam]; - size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); info->marked = true; info->orig_addr = (cell_t *)string; From 95dcffc9721f6497fd95fcf6285bc95967c761d4 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 11 Mar 2007 19:26:47 +0000 Subject: [PATCH 0572/1664] user messages tested and working fixed some floating point casts --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40603 --- core/UserMessages.cpp | 12 +++++++----- core/UserMessages.h | 1 + core/smn_entities.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 0f8a8c38..6e0b6f23 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -244,6 +244,7 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty m_CurId = msg_type; m_CurRecFilter = filter; m_InHook = true; + m_BlockEndPost = false; if (!is_intercept_empty) { @@ -268,7 +269,7 @@ bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_t void CUserMessages::OnMessageEnd_Post() { - if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE)) + if (!m_InHook || m_BlockEndPost) { RETURN_META(MRES_IGNORED); } @@ -340,6 +341,8 @@ void CUserMessages::OnMessageEnd_Pre() pInfo->IsHooked = true; res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter); + intercepted = true; + switch (res) { case Pl_Stop: @@ -375,10 +378,10 @@ void CUserMessages::OnMessageEnd_Pre() _DecRefCounter(); continue; } + break; } } pInfo->IsHooked = false; - intercepted = true; iter++; } @@ -395,8 +398,6 @@ void CUserMessages::OnMessageEnd_Pre() m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten()); engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten()); ENGINE_CALL(MessageEnd)(); - - goto supercede; } pList = &m_msgHooks[m_CurId]; @@ -418,8 +419,9 @@ void CUserMessages::OnMessageEnd_Pre() iter++; } - RETURN_META(MRES_IGNORED); + RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED); supercede: m_InHook = false; + m_BlockEndPost = true; RETURN_META(MRES_SUPERCEDE); } diff --git a/core/UserMessages.h b/core/UserMessages.h index b9d5abf0..5f833f7b 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -71,6 +71,7 @@ private: bf_read m_ReadBuffer; size_t m_HookCount; bool m_InHook; + bool m_BlockEndPost; Trie *m_Names; CellRecipientFilter m_CellRecFilter; diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 5f0a9f4d..d38d1325 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -351,9 +351,9 @@ static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params) cell_t *vec; pContext->LocalToPhysAddr(params[3], &vec); - vec[0] = v->x; - vec[1] = v->y; - vec[2] = v->z; + vec[0] = sp_ftoc(v->x); + vec[1] = sp_ftoc(v->y); + vec[2] = sp_ftoc(v->z); return 1; } @@ -379,9 +379,9 @@ static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params) cell_t *vec; pContext->LocalToPhysAddr(params[3], &vec); - v->x = vec[0]; - v->y = vec[1]; - v->z = vec[2]; + v->x = sp_ctof(vec[0]); + v->y = sp_ctof(vec[1]); + v->z = sp_ctof(vec[2]); if (params[4]) { From f64945b2aa3994ca8db4a76b19327bf3fbe3bc9f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 11 Mar 2007 21:09:05 +0000 Subject: [PATCH 0573/1664] implemented the bf_read natives message hooks now receive the bf_read handle --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40604 --- core/smn_bitbuffer.cpp | 319 +++++++++++++++++++++++++++++++++- core/smn_usermsgs.cpp | 27 ++- core/sourcemod.h | 1 + plugins/include/bitbuffer.inc | 140 ++++++++++++++- public/IUserMessages.h | 2 +- 5 files changed, 482 insertions(+), 7 deletions(-) diff --git a/core/smn_bitbuffer.cpp b/core/smn_bitbuffer.cpp index b6692069..48483d04 100644 --- a/core/smn_bitbuffer.cpp +++ b/core/smn_bitbuffer.cpp @@ -328,7 +328,310 @@ static cell_t smn_BfWriteAngles(IPluginContext *pCtx, const cell_t *params) return 1; } -REGISTER_NATIVES(wrbitbufnatives) +static cell_t smn_BfReadBool(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadOneBit() ? 1 : 0; +} + +static cell_t smn_BfReadByte(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadByte(); +} + +static cell_t smn_BfReadChar(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadChar(); +} + +static cell_t smn_BfReadShort(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadShort(); +} + +static cell_t smn_BfReadWord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadWord(); +} + +static cell_t smn_BfReadNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return static_cast(pBitBuf->ReadLong()); +} + +static cell_t smn_BfReadFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return sp_ftoc(pBitBuf->ReadFloat()); +} + +static cell_t smn_BfReadString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + char *buf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToPhysAddr(params[2], (cell_t **)&buf); + if (!pBitBuf->ReadString(buf, params[3], params[4] ? true : false)) + { + return pCtx->ThrowNativeError("Destination string buffer is too short, try increasing its size"); + } + + return 1; +} + +static cell_t smn_BfReadEntity(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return pBitBuf->ReadShort(); +} + +static cell_t smn_BfReadAngle(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return sp_ftoc(pBitBuf->ReadBitAngle(params[2])); +} + +static cell_t smn_BfReadCoord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + return sp_ftoc(pBitBuf->ReadBitCoord()); +} + +static cell_t smn_BfReadVecCoord(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pVec; + pCtx->LocalToPhysAddr(params[2], &pVec); + + Vector vec; + pBitBuf->ReadBitVec3Coord(vec); + + pVec[0] = sp_ftoc(vec.x); + pVec[1] = sp_ftoc(vec.y); + pVec[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t smn_BfReadVecNormal(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pVec; + pCtx->LocalToPhysAddr(params[2], &pVec); + + Vector vec; + pBitBuf->ReadBitVec3Normal(vec); + + pVec[0] = sp_ftoc(vec.x); + pVec[1] = sp_ftoc(vec.y); + pVec[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t smn_BfReadAngles(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + bf_read *pBitBuf; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_RdBitBufType, &sec, (void **)&pBitBuf)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr); + } + + cell_t *pAng; + pCtx->LocalToPhysAddr(params[2], &pAng); + + QAngle ang; + pBitBuf->ReadBitAngles(ang); + + pAng[0] = sp_ftoc(ang.x); + pAng[1] = sp_ftoc(ang.y); + pAng[2] = sp_ftoc(ang.z); + + return 1; +} + +REGISTER_NATIVES(bitbufnatives) { {"BfWriteBool", smn_BfWriteBool}, {"BfWriteByte", smn_BfWriteByte}, @@ -344,5 +647,19 @@ REGISTER_NATIVES(wrbitbufnatives) {"BfWriteVecCoord", smn_BfWriteVecCoord}, {"BfWriteVecNormal", smn_BfWriteVecNormal}, {"BfWriteAngles", smn_BfWriteAngles}, + {"BfReadBool", smn_BfReadBool}, + {"BfReadByte", smn_BfReadByte}, + {"BfReadChar", smn_BfReadChar}, + {"BfReadShort", smn_BfReadShort}, + {"BfReadWord", smn_BfReadWord}, + {"BfReadNum", smn_BfReadNum}, + {"BfReadFloat", smn_BfReadFloat}, + {"BfReadString", smn_BfReadString}, + {"BfReadEntity", smn_BfReadEntity}, + {"BfReadAngle", smn_BfReadAngle}, + {"BfReadCoord", smn_BfReadCoord}, + {"BfReadVecCoord", smn_BfReadVecCoord}, + {"BfReadVecNormal", smn_BfReadVecNormal}, + {"BfReadAngles", smn_BfReadAngles}, {NULL, NULL} }; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index cc6567f2..d62fdc85 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -18,7 +18,11 @@ #include "smn_usermsgs.h" HandleType_t g_WrBitBufType; +HandleType_t g_RdBitBufType; Handle_t g_CurMsgHandle; +Handle_t g_ReadBufHandle; +bf_read g_ReadBitBuf; + int g_MsgPlayers[256]; bool g_IsMsgInExec = false; @@ -45,15 +49,30 @@ private: void UsrMessageNatives::OnSourceModAllInitialized() { + HandleAccess sec; + sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY; + g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_RdBitBufType = g_HandleSys.CreateType("BitBufReader", this, 0, NULL, &sec, g_pCoreIdent, NULL); + + g_ReadBufHandle = g_HandleSys.CreateHandle(g_RdBitBufType, &g_ReadBitBuf, NULL, g_pCoreIdent, NULL); + g_PluginSys.AddPluginsListener(this); } void UsrMessageNatives::OnSourceModShutdown() { + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + + g_HandleSys.FreeHandle(g_ReadBufHandle, &sec); + g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent); + g_HandleSys.RemoveType(g_RdBitBufType, g_pCoreIdent); + g_PluginSys.RemovePluginsListener(this); g_WrBitBufType = 0; + g_RdBitBufType = 0; } void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) @@ -221,8 +240,10 @@ void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilte cell_t res; size_t size = _FillInPlayers(g_MsgPlayers, pFilter); + g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten()); + m_Hook->PushCell(msg_id); - m_Hook->PushCell(0); //:TODO: push handle! + m_Hook->PushCell(g_ReadBufHandle); m_Hook->PushArray(g_MsgPlayers, size); m_Hook->PushCell(size); m_Hook->PushCell(pFilter->IsReliable()); @@ -235,8 +256,10 @@ ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IR cell_t res = static_cast(Pl_Continue); size_t size = _FillInPlayers(g_MsgPlayers, pFilter); + g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten()); + m_Intercept->PushCell(msg_id); - m_Intercept->PushCell(0); //:TODO: push handle! + m_Intercept->PushCell(g_ReadBufHandle); m_Intercept->PushArray(g_MsgPlayers, size); m_Intercept->PushCell(size); m_Intercept->PushCell(pFilter->IsReliable()); diff --git a/core/sourcemod.h b/core/sourcemod.h index 2913d71a..0a4009a4 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -102,5 +102,6 @@ private: extern SourceModBase g_SourceMod; extern HandleType_t g_WrBitBufType; +extern HandleType_t g_RdBitBufType; #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/plugins/include/bitbuffer.inc b/plugins/include/bitbuffer.inc index b6ec5bdf..db7cd4ec 100644 --- a/plugins/include/bitbuffer.inc +++ b/plugins/include/bitbuffer.inc @@ -133,7 +133,7 @@ native BfWriteCoord(Handle:bf, Float:coord); /** * Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). * - * @param bif bf_write handle to write to. + * @param bf bf_write handle to write to. * @param coord Coordinate array to write. * @noreturn * @error Invalid or incorrect Handle. @@ -143,7 +143,7 @@ native BfWriteVecCoord(Handle:bf, Float:coord[3]); /** * Writes a 3D normal vector to a writable bitbuffer (bf_write). * - * @param bif bf_write handle to write to. + * @param bf bf_write handle to write to. * @param vec Vector to write. * @noreturn * @error Invalid or incorrect Handle. @@ -153,9 +153,143 @@ native BfWriteVecNormal(Handle:bf, Float:vec[3]); /** * Writes a 3D angle vector to a writable bitbuffer (bf_write). * - * @param bif bf_write handle to write to. + * @param bf bf_write handle to write to. * @param angles Angle vector to write. * @noreturn * @error Invalid or incorrect Handle. */ native BfWriteAngles(Handle:bf, Float:angles[3]); + +/** + * Reads a single bit from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Bit value read. + * @error Invalid or incorrect Handle. + */ +native bool:BfReadBool(Handle:bf); + +/** + * Reads a byte from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Byte value read (read as 8bit). + * @error Invalid or incorrect Handle. + */ +native BfReadByte(Handle:bf); + +/** + * Reads a character from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Character value read. + * @error Invalid or incorrect Handle. + */ +native BfReadChar(Handle:bf); + +/** + * Reads a 16bit integer from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 16bit). + * @error Invalid or incorrect Handle. + */ +native BfReadShort(Handle:bf); + +/** + * Reads a 16bit unsigned integer from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 16bit). + * @error Invalid or incorrect Handle. + */ +native BfReadWord(Handle:bf); + +/** + * Reads a normal integer to a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 32bit). + * @error Invalid or incorrect Handle. + */ +native BfReadNum(Handle:bf); + +/** + * Reads a floating point number from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Floating point value read. + * @error Invalid or incorrect Handle. + */ +native Float:BfReadFloat(Handle:bf); + +/** + * Reads a string from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param Line If true the buffer will be copied until it reaches a '\n' or a null terminator. + * @noreturn + * @error Invalid or incorrect Handle, destination string buffer was too short. + */ +native BfReadString(Handle:bf, String:buffer[], maxlength, bool:Line=false); + +/** + * Reads an entity from a readable bitbuffer (bf_read). + * @note This is a wrapper around BfReadShort(). + * + * @param bf bf_read handle to read from. + * @return Entity index read. + * @error Invalid or incorrect Handle. + */ +native BfReadEntity(Handle:bf); + +/** + * Reads a bit angle from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param numBits Optional number of bits to use. + * @return Angle read. + * @error Invalid or incorrect Handle. + */ +native Float:BfReadAngle(Handle:bf, numBits=8); + +/** + * Reads a coordinate from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Coordinate read. + * @error Invalid or incorrect Handle. + */ +native Float:BfReadCoord(Handle:bf); + +/** + * Reads a 3D vector of coordinates from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param coord Destination coordinate array. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfReadVecCoord(Handle:bf, Float:coord[3]); + +/** + * Reads a 3D normal vector from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param vec Destination vector array. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfReadVecNormal(Handle:bf, Float:vec[3]); + +/** + * Reads a 3D angle vector from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param angles Destination angle vector. + * @noreturn + * @error Invalid or incorrect Handle. + */ +native BfReadAngles(Handle:bf, Float:angles[3]); diff --git a/public/IUserMessages.h b/public/IUserMessages.h index 6307c336..d3d8b775 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -59,7 +59,7 @@ namespace SourceMod * @param msg_id Message Id. * @param bf bf_write structure containing written bytes. * @param pFtiler Recipient filter. - * @return True to allow message, false to scrap it. + * @return Pl_Continue to allow message, Pl_Stop or Pl_Handled to scrap it. */ virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) { From 2aa8810021ba03a1150f6d157a1aaa6c7ef35ca3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 00:06:20 +0000 Subject: [PATCH 0574/1664] used a better error number --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40605 --- core/sm_stringutil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 6a6e86b8..b5686319 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -28,7 +28,7 @@ #define CHECK_ARGS(x) \ if ((arg+x) > args) { \ - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ return 0; \ } From 7ab8e2027b3c2b34ed2a91b0f55139dfeb9a9740 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 00:07:54 +0000 Subject: [PATCH 0575/1664] fixed spacing on headers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40606 --- core/smn_bitbuffer.cpp | 24 ++++++++++++------------ core/smn_datapacks.cpp | 24 ++++++++++++------------ core/smn_events.cpp | 22 +++++++++++----------- core/smn_usermsgs.cpp | 24 ++++++++++++------------ 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/core/smn_bitbuffer.cpp b/core/smn_bitbuffer.cpp index 48483d04..549dba26 100644 --- a/core/smn_bitbuffer.cpp +++ b/core/smn_bitbuffer.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "sourcemod.h" #include "HandleSys.h" diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp index 4128c992..a73dd251 100644 --- a/core/smn_datapacks.cpp +++ b/core/smn_datapacks.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "sm_globals.h" #include "HandleSys.h" diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 96e52598..1b72eafd 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -1,15 +1,15 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "sm_globals.h" #include "sourcemm_api.h" diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index d62fdc85..750a2235 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "HandleSys.h" #include "PluginSys.h" From 7c06d89b00a19e8a002a654ffa093a11016f106c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 07:08:05 +0000 Subject: [PATCH 0576/1664] initial import of dynamic native code for both the JIT and plugins note: dependency resolution is not done yet! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40607 --- core/msvc8/sourcemod_mm.vcproj | 6 +- core/smn_fakenatives.cpp | 430 ++++++++++++++++++++++++ core/systems/PluginSys.cpp | 55 ++- core/systems/PluginSys.h | 18 + plugins/include/functions.inc | 205 +++++++++++ plugins/include/sourcemod.inc | 1 + plugins/testsuite/fakenative1.sp | 85 +++++ plugins/testsuite/fakenative2.sp | 87 +++++ public/sourcepawn/sp_vm_api.h | 19 +- public/sourcepawn/sp_vm_types.h | 6 + sourcepawn/jit/x86/dll_exports.cpp | 4 +- sourcepawn/jit/x86/jit_x86.cpp | 46 +++ sourcepawn/jit/x86/jit_x86.h | 2 + sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 4 + 14 files changed, 963 insertions(+), 5 deletions(-) create mode 100644 core/smn_fakenatives.cpp create mode 100644 plugins/include/functions.inc create mode 100644 plugins/testsuite/fakenative1.sp create mode 100644 plugins/testsuite/fakenative2.sp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 99409e11..6a66d17d 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp new file mode 100644 index 00000000..5b90816b --- /dev/null +++ b/core/smn_fakenatives.cpp @@ -0,0 +1,430 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "sm_trie.h" +#include "sm_globals.h" +#include "PluginSys.h" +#include "sourcemod.h" +#include "sm_stringutil.h" + +using namespace SourceHook; + +static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1]; +static FakeNative *s_curnative = NULL; +static IPluginContext *s_curcaller = NULL; + +cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData) +{ + FakeNative *native = (FakeNative *)pData; + + /* Check if too many parameters were passed */ + if (params[0] > SP_MAX_EXEC_PARAMS) + { + return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS); + } + + /* Check if the native is paused */ + sp_context_t *pNativeCtx = native->ctx->GetContext(); + if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + { + return pContext->ThrowNativeError("Plugin owning this native is currently paused."); + } + + CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + /* Save any old data on the stack */ + FakeNative *pSaveNative = s_curnative; + IPluginContext *pSaveCaller = s_curcaller; + cell_t save_params[SP_MAX_EXEC_PARAMS+1]; + if (pSaveNative != NULL) + { + /* Copy all old parameters */ + for (cell_t i=0; i<=s_curparams[0]; i++) + { + save_params[i] = s_curparams[i]; + } + } + + /* Save the current parameters */ + s_curnative = native; + s_curcaller = pContext; + for (cell_t i=0; i<=params[0]; i++) + { + s_curparams[i] = params[i]; + } + + /* Push info and execute. */ + cell_t result = 0; + native->call->PushCell(pCaller->GetMyHandle()); + native->call->PushCell(params[0]); + if (native->call->Execute(&result) != SP_ERROR_NONE) + { + if (pContext->GetContext()->n_err == SP_ERROR_NONE) + { + pContext->ThrowNativeError("Error encountered while processing a dynamic native"); + } + } + + /* Restore everything from the stack if necessary */ + if (pSaveNative != NULL) + { + s_curnative = pSaveNative; + s_curcaller = pSaveCaller; + for (cell_t i=0; i<=save_params[0]; i++) + { + s_curparams[i] = save_params[i]; + } + } + + return result; +} + +static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) +{ + char *name; + pContext->LocalToString(params[1], &name); + + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); + if (!pFunction) + { + return pContext->ThrowNativeError("Function %x is not a valid function", params[2]); + } + + if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter)) + { + return pContext->ThrowNativeError("Fatal error creating dynamic native!"); + } + + return 1; +} + +static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + char buffer[512]; + + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); + + if (pContext->GetContext()->n_err != SP_ERROR_NONE) + { + s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native"); + } else { + s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer); + } + + return 0; +} + +static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + char *str; + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[2], &addr); + *addr = (cell_t)strlen(str); + + return SP_ERROR_NONE; +} + +static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + char *str; + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE) + { + return err; + } + + size_t bytes = 0; + pContext->StringToLocalUTF8(params[2], params[3], str, &bytes); + + cell_t *addr; + pContext->LocalToPhysAddr(params[4], &addr); + *addr = (cell_t)bytes; + + return SP_ERROR_NONE; +} + +static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + char *str; + pContext->LocalToString(params[2], &str); + + int err; + size_t bytes = 0; + if (params[4]) + { + err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes); + } else { + err = s_curcaller->StringToLocal(s_curparams[param], params[3], str); + /* Eww */ + bytes = strlen(str); + if (bytes >= (size_t)params[3]) + { + bytes = params[3] - 1; + } + } + + if (err != SP_ERROR_NONE) + { + return err; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[5], &addr); + *addr = (cell_t)bytes; + + return SP_ERROR_NONE; +} + +static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + return s_curparams[param]; +} + +static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + cell_t *addr; + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE) + { + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value"); + } + + return *addr; +} + +static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + cell_t *addr; + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE) + { + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value"); + } + + *addr = params[2]; + + return 1; +} + +static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + cell_t *addr; + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *src; + pContext->LocalToPhysAddr(params[2], &src); + + memcpy(src, addr, sizeof(cell_t) * params[3]); + + return SP_ERROR_NONE; +} + +static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + cell_t *addr; + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *src; + pContext->LocalToPhysAddr(params[2], &src); + + memcpy(addr, src, sizeof(cell_t) * params[3]); + + return SP_ERROR_NONE; +} + +static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + int out_param = params[1]; + int fmt_param = params[2]; + int var_param = params[3]; + + /* Validate input */ + if (out_param && (out_param < 1 || out_param > s_curparams[0])) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param); + } + if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0])) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param); + } + if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1)) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param); + } + + /* Get buffer information */ + int err; + char *output_buffer; + char *format_buffer; + + if (out_param) + { + if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE) + { + return err; + } + } else { + pContext->LocalToString(params[6], &output_buffer); + } + + if (fmt_param) + { + if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE) + { + return err; + } + } else { + pContext->LocalToString(params[7], &format_buffer); + } + + /* Get maximum length */ + size_t maxlen = (size_t)params[4]; + + /* Do the format */ + size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param); + + cell_t *addr; + pContext->LocalToPhysAddr(params[5], &addr); + *addr = (cell_t)written; + + return s_curcaller->GetContext()->n_err; +} + +//tee hee +REGISTER_NATIVES(nativeNatives) +{ + {"CreateNative", CreateNative}, + {"GetNativeArray", GetNativeArray}, + {"GetNativeCell", GetNativeCell}, + {"GetNativeCellRef", GetNativeCellRef}, + {"GetNativeString", GetNativeString}, + {"GetNativeStringLength", GetNativeStringLength}, + {"FormatNativeString", FormatNativeString}, + {"ThrowNativeError", ThrowNativeError}, + {"SetNativeArray", SetNativeArray}, + {"SetNativeCellRef", SetNativeCellRef}, + {"SetNativeString", SetNativeString}, + {NULL, NULL}, +}; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 0b38ff04..6864afba 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -588,6 +588,7 @@ CPluginManager::CPluginManager() m_LoadLookup = sm_trie_create(); m_AllPluginsLoaded = false; m_MyIdent = NULL; + m_pNativeLookup = sm_trie_create(); } CPluginManager::~CPluginManager() @@ -598,9 +599,9 @@ CPluginManager::~CPluginManager() * will crash anyway. YAY */ sm_trie_destroy(m_LoadLookup); + sm_trie_destroy(m_pNativeLookup); } - void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) { /* First read in the database of plugin settings */ @@ -958,6 +959,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng /* Bind all extra natives */ g_Extensions.BindAllNativesToPlugin(pPlugin); + AddFakeNativesToPlugin(pPlugin); /* Find any unbound natives * Right now, these are not allowed @@ -1013,6 +1015,32 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) } } +void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin) +{ + IPluginContext *pContext = pPlugin->GetBaseContext(); + sp_nativeinfo_t native; + + List::iterator iter; + FakeNative *pNative; + sp_context_t *ctx; + for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++) + { + pNative = (*iter); + ctx = pNative->ctx->GetContext(); + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + { + /* Ignore natives in paused plugins */ + continue; + } + native.name = pNative->name.c_str(); + native.func = pNative->func; + if (pContext->BindNative(&native) == SP_ERROR_NONE) + { + /* :TODO: add to dependency list */ + } + } +} + bool CPluginManager::UnloadPlugin(IPlugin *plugin) { CPlugin *pPlugin = (CPlugin *)plugin; @@ -1675,3 +1703,28 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused) } } +bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func) +{ + if (sm_trie_retrieve(m_pNativeLookup, name, NULL)) + { + return false; + } + + FakeNative *pNative = new FakeNative; + + pNative->func = g_pVM->CreateFakeNative(func, pNative); + if (!pNative->func) + { + delete pNative; + return false; + } + + pNative->call = pFunction; + pNative->name.assign(name); + pNative->ctx = pFunction->GetParentContext(); + + m_Natives.push_back(pNative); + sm_trie_insert(m_pNativeLookup, name,pNative); + + return true; +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 05838db0..1eb2cec9 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "sm_globals.h" #include "vm/sp_vm_basecontext.h" #include "PluginInfoDatabase.h" @@ -232,6 +233,14 @@ private: Trie *m_pProps; }; +struct FakeNative +{ + IPluginContext *ctx; + IPluginFunction *call; + String name; + SPVM_NATIVE_FUNC func; +}; + class CPluginManager : public IPluginManager, public SMGlobalClass, @@ -380,6 +389,10 @@ protected: { return m_MyIdent; } +public: + bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func); +private: + void AddFakeNativesToPlugin(CPlugin *pPlugin); private: List m_listeners; List m_plugins; @@ -389,6 +402,11 @@ private: Trie *m_LoadLookup; bool m_AllPluginsLoaded; IdentityToken_t *m_MyIdent; + + /* Dynamic native stuff */ + List m_Natives; + Trie *m_pNativeLookup; + }; extern CPluginManager g_PluginSys; diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc new file mode 100644 index 00000000..2cea70a0 --- /dev/null +++ b/plugins/include/functions.inc @@ -0,0 +1,205 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#define SP_ERROR_NONE 0 /**< No error occurred */ +#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */ +#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */ +#define SP_ERROR_INDEX 7 /**< Invalid index parameter */ +#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /**< Error originates from a native */ +#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ +#define SP_ERROR_ABORTED 25 /**< Function call was aborted */ + +/** + * Defines a native function. + * + * It is not necessary to validate the parameter count + * + * @param plugin Handle of the calling plugin. + * @param numParams Number of parameters passed to the native. + * @return Value for the native call to return. + */ +functag NativeCall public(Handle:plugin, numParams); + +/** + * Creates a dynamic native. This should only be called in AskPluginLoad(), or + * else you risk not having your native shared with other plugins. + * + * @param name Name of the dynamic native; must be unique amongst + * all other registered dynamic native.s + * @param func Function to use as the dynamic native. + * @noreturn + */ +native CreateNative(const String:name[], NativeCall:func); + +/** + * Throws an error in the calling plugin of a native, instead of your own plugin. + * + * @param error Error code to use. + * @param fmt Error message format. + * @param ... Format arguments. + */ +native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...); + +/** + * Retrieves the string length from a native parameter string. This is useful + * fetching the entire string using dynamic arrays. + * @note If this function succeeds, Get/SetNativeString will also succeed. + * + * @param param Parameter number, starting from 1. + * @param length Stores the length of the string. + * @return SP_ERROR_NONE on sucecss, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native GetNativeStringLength(param, &length); + +/** + * Retrieves a string from a native parameter. + * @note Output conditions are undefined on failure. + * + * @param param Parameter number, starting from 1. + * @param buffer Buffer to store the string in. + * @param maxlength Maximum length of the buffer. + * @param bytes Optionally store the number of bytes written. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native GetNativeString(param, String:buffer[], maxlength, &bytes=0); + +/** + * Sets a string in a native parameter. + * @note Output conditions are undefined on failure. + * + * @param param Parameter number, starting from 1. + * @param source Source string to use. + * @param maxlength Maximum number of bytes to write. + * @param utf8 If false, string will not be written + * with UTF8 safety. + * @param bytes Optionally store the number of bytes written. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native SetNativeString(param, const String:source[], maxlength, bool:utf8=true, &bytes=0); + +/** + * Gets a cell from a native parameter. + * + * @param param Parameter number, starting from 1. + * @return Cell value at the parameter number. + * @error Invalid parameter number or calling from a non-native function. + */ +native GetNativeCell(param); + +/** + * Gets a cell from a native parameter, by reference. + * + * @param param Parameter number, starting from 1. + * @return Cell value at the parameter number. + * @error Invalid parameter number or calling from a non-native function. + */ +native GetNativeCellRef(param); + +/** + * Sets a cell from a native parameter, by reference. + * + * @param param Parameter number, starting from 1. + * @param value Cell value at the parameter number to set by reference. + * @noreturn + * @error Invalid parameter number or calling from a non-native function. + */ +native SetNativeCellRef(param, {Float,Handle,_}:value); + +/** + * Gets an array from a native parameter (always by reference). + * + * @param param Parameter number, starting from 1. + * @param local Local array to copy into. + * @param size Maximum size of local array. + * @return SP_ERROR_NONE on success, anything else on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native GetNativeArray(param, {Float,Handle,_}:local[], size); + +/** + * Copies a local array into a native parameter array (always by reference). + * + * @param param Parameter number, starting from 1. + * @param local Local array to copy from. + * @param size Size of the local array to copy. + * @return SP_ERROR_NONE on success, anything else on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native SetNativeArray(param, const {Float,Handle,_}:local[], size); + +/** + * Formats a string using parameters from a native. + * + * @note All parameter indexes start at 1. + * @note If the input and output buffers overlap, the contents + * of the output buffer at the end is undefined. + * + * @param out_param Output parameter number to write to. If 0, out_string is used. + * @param fmt_param Format parameter number. If 0, fmt_string is used. + * @param vararg_param First variable parameter number. + * @param out_len Output string buffer maximum length (always required). + * @param written Optionally stores the number of bytes written. + * @param out_string Output string buffer to use if out_param is not used. + * @param fmt_string Format string to use if fmt_param is not used. + * @return SP_ERROR_NONE on success, anything else on failure. + */ +native FormatNativeString(out_param, + fmt_param, + vararg_param, + out_len, + &written=0, + String:out_string[]="", + const String:fmt_string[]=""); + +stock Float:GetNativeFloat(param, bool:byref) +{ + if (!byref) + { + return Float:GetNativeCell(param); + } else { + return Float:GetNativeCellRef(param); + } +} +stock Handle:GetNativeHandle(param, bool:byref) +{ + if (!byref) + { + return Handle:GetNativeCell(param); + } else { + return Handle:GetNativeCellRef(param); + } +} diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 67cd32b8..ba0d0a00 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -39,6 +39,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. diff --git a/plugins/testsuite/fakenative1.sp b/plugins/testsuite/fakenative1.sp new file mode 100644 index 00000000..3c747695 --- /dev/null +++ b/plugins/testsuite/fakenative1.sp @@ -0,0 +1,85 @@ +#include + +public Plugin:myinfo = +{ + name = "FakeNative Testing Lab #1", + author = "AlliedModders LLC", + description = "Test suite #1 for dynamic natives", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) +{ + CreateNative("TestNative1", __TestNative1); + CreateNative("TestNative2", __TestNative2); + CreateNative("TestNative3", __TestNative3); + CreateNative("TestNative4", __TestNative4); + CreateNative("TestNative5", __TestNative5); + return true; +} + +public __TestNative1(Handle:plugin, numParams) +{ + PrintToServer("TestNative1: Plugin: %x params: %d", plugin, numParams); + if (numParams == 4) + { + ThrowNativeError(SP_ERROR_NATIVE, "Four parameters ARE NOT ALLOWED lol"); + } + return 5; +} + +public __TestNative2(Handle:plugin, numParams) +{ + new String:buffer[512]; + new bytes; + + GetNativeString(1, buffer, sizeof(buffer), bytes); + + for (new i=0; i + +native TestNative1(gaben, ...); +native TestNative2(String:buffer[]); +native TestNative3(value1, &value2); +native TestNative4(const input[], output[], size); +native TestNative5(bool:local, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,_}:...); + +public Plugin:myinfo = +{ + name = "FakeNative Testing Lab #2", + author = "AlliedModders LLC", + description = "Test suite #2 for dynamic natives", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public OnPluginStart() +{ + RegServerCmd("test_native1", Test_Native1); + RegServerCmd("test_native2", Test_Native2); + RegServerCmd("test_native3", Test_Native3); + RegServerCmd("test_native4", Test_Native4); + RegServerCmd("test_native5", Test_Native5); +} + +public Action:Test_Native1(args) +{ + PrintToServer("Returned: %d", TestNative1(1)); + PrintToServer("Returned: %d", TestNative1(1,2)); + PrintToServer("Returned: %d", TestNative1(1,2,3,4)); + + return Plugin_Handled; +} + +public Action:Test_Native2(args) +{ + new String:buffer[] = "IBM"; + + PrintToServer("Before: %s", buffer); + + TestNative2(buffer); + + PrintToServer("AfteR: %s", buffer); + + return Plugin_Handled; +} + +public Action:Test_Native3(args) +{ + new value1 = 5, value2 = 6 + + PrintToServer("Before: %d, %d", value1, value2); + + TestNative3(value1, value2); + + PrintToServer("After: %d, %d", value1, value2); + + return Plugin_Handled; +} + +public Action:Test_Native4(args) +{ + new input[5] = {0, 1, 2, 3, 4}; + new output[5]; + + TestNative4(input, output, 5); + + PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", input[0], input[1], input[2], input[3], input[4]); + PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", output[0], output[1], output[2], output[3], output[4]); + + return Plugin_Handled; +} + +public Action:Test_Native5(args) +{ + new String:buffer1[512]; + new String:buffer2[512]; + + TestNative5(true, buffer1, sizeof(buffer1), "%d gabens in the %s", 50, "gabpark"); + TestNative5(true, buffer2, sizeof(buffer2), "%d gabens in the %s", 50, "gabpark"); + + PrintToServer("Test 1: %s", buffer1); + PrintToServer("Test 2: %s", buffer2); + + return Plugin_Handled; +} diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 3db0b0bc..832de0b1 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -28,7 +28,7 @@ #include "sp_vm_types.h" /** SourcePawn VM API Version */ -#define SOURCEPAWN_VM_API_VERSION 1 +#define SOURCEPAWN_VM_API_VERSION 2 #if defined SOURCEMOD_BUILD namespace SourceMod @@ -820,6 +820,23 @@ namespace SourcePawn * @return True if code index is valid, false otherwise. */ virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; + + /** + * @brief Creates a fake native and binds it to a general callback function. + * + * @param callback Callback function to bind the native to. + * @param pData Private data to pass to the callback when the native is invoked. + * @return A new fake native function as a wrapper around the callback. + */ + virtual SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) =0; + + /** + * @brief Destroys a fake native function wrapper. + * + * @param function Pointer to the fake native created by CreateFakeNative. + * @noreturn + */ + virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0; }; }; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 2ba21ffd..7d73bf33 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -136,6 +136,12 @@ struct sp_context_s; */ typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); +/** + * @brief Fake native callback prototype, passed a context, parameter stack, and private data. + * A cell must be returned. + */ +typedef cell_t (*SPVM_FAKENATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *, void *); + /********************************************** *** The following structures are bound to the VM/JIT. *** Changing them will result in necessary recompilation. diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index 6ac0a56c..bd54f789 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -17,7 +17,7 @@ #include "dll_exports.h" SourcePawn::ISourcePawnEngine *engine = NULL; -JITX86 jit; +JITX86 g_jit; EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) { @@ -45,7 +45,7 @@ EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum) return NULL; } - return &jit; + return &g_jit; } #if defined __linux__ diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 7c9e5e89..cc030b1e 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2188,6 +2188,52 @@ jit_rewind: return ctx; } +SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) +{ + JitWriter jw; + JitWriter *jit = &jw; + + jw.outbase = NULL; + jw.outptr = NULL; + jw.data = NULL; + + /* First pass, calculate size */ +rewind: + //push pData ;push pData + //push [esp+12] ;push params + //push [esp+12] ;push ctx + //call [callback] ;invoke the meta-callback + //add esp, 12 ;restore the stack + //ret ;return + IA32_Push_Imm32(jit, (jit_int32_t)pData); + IA32_Push_Rm_Disp8_ESP(jit, 12); + IA32_Push_Rm_Disp8_ESP(jit, 12); + uint32_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, (void *)callback); + IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG); + IA32_Return(jit); + + if (jw.outbase == NULL) + { + /* Second pass: Actually write */ + jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos()); + if (!jw.outbase) + { + return NULL; + } + jw.outptr = jw.outbase; + + goto rewind; + } + + return (SPVM_NATIVE_FUNC)jw.outbase; +} + +void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func) +{ + engine->ExecFree(func); +} + const char *JITX86::GetVMName() { return "JIT (x86)"; diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 4d65745a..02801438 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -98,6 +98,8 @@ public: unsigned int FunctionCount(const sp_context_t *ctx); const char *GetVersionString(); const char *GetCPUOptimizations(); + SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); + void DestroyFakenative(SPVM_NATIVE_FUNC func); }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index f2972a94..e5e623e2 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -234,6 +234,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + From 57d0a7a23af6d42cb98c4c0e9bd67823fa9c4aa0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 17:33:39 +0000 Subject: [PATCH 0577/1664] gcc fix --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40608 --- sourcepawn/jit/x86/jit_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index cc030b1e..b4b272c9 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2231,7 +2231,7 @@ rewind: void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func) { - engine->ExecFree(func); + engine->ExecFree((void *)func); } const char *JITX86::GetVMName() From b3d3b308555b9e8af8d8a34c0a3d94a90edaf598 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 17:42:44 +0000 Subject: [PATCH 0578/1664] updated Makefile to have all the .cpp files - we need to keep better track of this various gcc whinings fixed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40609 --- core/EventManager.cpp | 2 +- core/Makefile | 23 +++++++++++++---------- core/smn_entities.cpp | 1 + core/smn_sorting.cpp | 1 + 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 13561e5a..35a1b33b 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -369,7 +369,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) { EventHook *pHook; IChangeableForward *pForward; - Handle_t hndl; + Handle_t hndl = 0; if (!m_NotifyPlugins) { diff --git a/core/Makefile b/core/Makefile index d9669fb5..2cbb9229 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,16 +19,19 @@ BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk -OBJECTS = sourcemm_api.cpp sourcemod.cpp AdminCache.cpp ConVarManager.cpp CDataPack.cpp \ - DebugReporter.cpp Logger.cpp PlayerManager.cpp TextParsers.cpp Translator.cpp \ - sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_trie.cpp \ - sm_stringutil.cpp smn_filesystem.cpp smn_float.cpp smn_handles.cpp \ - smn_player.cpp smn_string.cpp smn_textparse.cpp smn_console.cpp smn_admin.cpp \ - smn_datapacks.cpp smn_lang.cpp \ - systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ - systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp \ - systems/PluginSys.cpp systems/ShareSys.cpp vm/sp_vm_basecontext.cpp \ - vm/sp_vm_engine.cpp vm/sp_vm_function.cpp ConCmdManager.cpp TimerSys.cpp +OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp \ + DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ + PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ + sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ + sourcemm_api.cpp sourcemod.cpp +OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ + smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ + smn_filesystem.cpp smn_float.cpp smn_halflife.cpp smn_handles.cpp smn_lang.cpp \ + smn_player.cpp smn_sorting.cpp smn_textparse.cpp smn_usermsgs.cpp +OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ + systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ + systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ + vm/sp_vm_function.cpp OBJECTS_C = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \ zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \ zlib/uncompr.c zlib/zutil.c diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index d38d1325..2e346f81 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -516,6 +516,7 @@ REGISTER_NATIVES(entityNatives) {"GetEntDataEnt", GetEntDataEnt}, {"GetEntDataFloat", GetEntDataFloat}, {"GetEntDataVector", GetEntDataVector}, + {"GetEntityCount", GetEntityCount}, {"GetEntityNetClass", GetEntityNetClass}, {"GetMaxEntities", GetMaxEntities}, {"IsEntNetworkable", IsEntNetworkable}, diff --git a/core/smn_sorting.cpp b/core/smn_sorting.cpp index 4807598b..b181cb52 100644 --- a/core/smn_sorting.cpp +++ b/core/smn_sorting.cpp @@ -14,6 +14,7 @@ #include "sm_globals.h" #include #include +#include /*********************************** * About the double array hack * From 8e4a59a4e0816c15a66a9165e8281553fb465476 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 20:11:54 +0000 Subject: [PATCH 0579/1664] This assertion is no longer correct because of sm_trie_delete() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40610 --- core/sm_trie.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index b87faed2..375e3e72 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -802,12 +802,6 @@ bool sm_trie_insert(Trie *trie, const char *key, void *value) */ assert(node->mode == Node_Arc); - /* Furthermore, if this is the last arc label in an arc, we should have a value set. */ - if (node->idx == 0) - { - assert(node->valset == true); - } - if (!node->valset) { /* Insert is only possible if we have no production */ From 21ed05048fc7157bd6dcbd9c6b30ddbb7747ea62 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Mar 2007 20:40:30 +0000 Subject: [PATCH 0580/1664] dynamic native providers can now be unloaded safely fixed an api naming typo :( --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40611 --- core/systems/PluginSys.cpp | 190 +++++++++++++++++++++++++++++---- core/systems/PluginSys.h | 22 ++-- public/sourcepawn/sp_vm_api.h | 2 +- sourcepawn/jit/x86/jit_x86.cpp | 2 +- sourcepawn/jit/x86/jit_x86.h | 2 +- 5 files changed, 188 insertions(+), 30 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6864afba..ddb5eb73 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -41,6 +41,7 @@ CPlugin::CPlugin(const char *file) m_handle = 0; m_ident = NULL; m_pProps = sm_trie_create(); + m_FakeNativesMissing = false; } CPlugin::~CPlugin() @@ -219,8 +220,15 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) { + PluginStatus old_status = m_status; m_status = status; + if (old_status == Plugin_Running) + { + /* Tell everyone we're now paused */ + g_PluginSys._SetPauseState(this, true); + } + va_list ap; va_start(ap, error_fmt); vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); @@ -540,6 +548,47 @@ unsigned int CPlugin::GetLangFileByIndex(unsigned int index) const return m_PhraseFiles.at(index); } +void CPlugin::DependencyDropped(CPlugin *pOwner) +{ + if (!m_ctx.ctx) + { + return; + } + + IPluginContext *pContext = pOwner->GetBaseContext(); + List::iterator iter; + FakeNative *pNative; + sp_native_t *native; + uint32_t idx; + unsigned int unbound = 0; + + for (iter = pOwner->m_fakeNatives.begin(); + iter != pOwner->m_fakeNatives.end(); + iter++) + { + pNative = (*iter); + /* Find this native! */ + if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE) + { + continue; + } + /* Unbind it */ + m_ctx.base->GetNativeByIndex(idx, &native); + native->pfn = NULL; + native->status = SP_NATIVE_UNBOUND; + unbound++; + } + + /* :IDEA: in the future, add native trapping? */ + if (unbound) + { + m_FakeNativesMissing = true; + SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename()); + } + + m_dependsOn.remove(pOwner); +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -995,6 +1044,24 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng /* Tell this plugin to finish initializing itself */ pPlugin->Call_OnPluginStart(); + /* Now, if we have fake natives, go through all plugins that might need rebinding */ + if (pPlugin->m_fakeNatives.size()) + { + List::iterator pl_iter; + CPlugin *pOther; + for (pl_iter = m_plugins.begin(); + pl_iter != m_plugins.end(); + pl_iter++) + { + pOther = (*pl_iter); + if (pOther->GetStatus() == Plugin_Error + && pOther->m_FakeNativesMissing) + { + TryRefreshNatives(pOther); + } + } + } + return true; } @@ -1015,6 +1082,40 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) } } +void CPluginManager::TryRefreshNatives(CPlugin *pPlugin) +{ + assert(pPlugin->GetBaseContext() != NULL); + + AddFakeNativesToPlugin(pPlugin); + + /* Find any unbound natives + * Right now, these are not allowed + */ + IPluginContext *pContext = pPlugin->GetBaseContext(); + uint32_t num = pContext->GetNativesNum(); + sp_native_t *native; + for (unsigned int i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + break; + } + if (native->status == SP_NATIVE_UNBOUND) + { + pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name); + return; + } + } + + /* If we got here, all natives are okay again! */ + pPlugin->m_status = Plugin_Running; + if ((pPlugin->m_ctx.ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + { + pPlugin->m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED; + _SetPauseState(pPlugin, false); + } +} + void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin) { IPluginContext *pContext = pPlugin->GetBaseContext(); @@ -1036,7 +1137,19 @@ void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin) native.func = pNative->func; if (pContext->BindNative(&native) == SP_ERROR_NONE) { - /* :TODO: add to dependency list */ + /* Add us as a dependency, but we're careful not to do this circularly! */ + if (pNative->ctx != pContext) + { + CPlugin *pOther = GetPluginByCtx(ctx); + if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end()) + { + pOther->m_dependents.push_back(pPlugin); + } + if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end()) + { + pPlugin->m_dependsOn.push_back(pOther); + } + } } } } @@ -1051,6 +1164,44 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) return false; } + /* Remove us from the lookup table and linked list */ + m_plugins.remove(pPlugin); + sm_trie_delete(m_LoadLookup, pPlugin->m_filename); + + /* Go through all dependent plugins and tell them this plugin is now gone */ + List::iterator pl_iter; + CPlugin *pOther; + for (pl_iter = pPlugin->m_dependents.begin(); + pl_iter != pPlugin->m_dependents.end(); + pl_iter++) + { + pOther = (*pl_iter); + pOther->DependencyDropped(pPlugin); + } + + /* Tell everyone we depend on that we no longer exist */ + for (pl_iter = pPlugin->m_dependsOn.begin(); + pl_iter != pPlugin->m_dependsOn.end(); + pl_iter++) + { + pOther = (*pl_iter); + pOther->m_dependents.remove(pPlugin); + } + + /* Remove all of our native functions */ + List::iterator fn_iter; + FakeNative *pNative; + for (fn_iter = pPlugin->m_fakeNatives.begin(); + fn_iter != pPlugin->m_fakeNatives.end(); + fn_iter++) + { + pNative = (*fn_iter); + m_Natives.remove(pNative); + sm_trie_delete(m_pNativeLookup, pNative->name.c_str()); + g_pVM->DestroyFakeNative(pNative->func); + delete pNative; + } + List::iterator iter; IPluginsListener *pListener; @@ -1072,10 +1223,6 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener = (*iter); pListener->OnPluginDestroyed(pPlugin); } - - /* Remove us from the lookup table and linked list */ - m_plugins.remove(pPlugin); - sm_trie_delete(m_LoadLookup, pPlugin->m_filename); /* Tell the plugin to delete itself */ delete pPlugin; @@ -1570,15 +1717,12 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc { if (IS_STR_FILLED(info->name)) { - g_RootMenu.ConsolePrint(" Title: %s", info->name); - } - if (IS_STR_FILLED(info->version)) - { - g_RootMenu.ConsolePrint(" Version: %s", info->version); - } - if (IS_STR_FILLED(info->url)) - { - g_RootMenu.ConsolePrint(" URL: %s", info->url); + if (IS_STR_FILLED(info->description)) + { + g_RootMenu.ConsolePrint(" Title: %s (%s)", info->name, info->description); + } else { + g_RootMenu.ConsolePrint(" Title: %s", info->name); + } } if (IS_STR_FILLED(info->author)) { @@ -1588,12 +1732,17 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc { g_RootMenu.ConsolePrint(" Version: %s", info->version); } - if (IS_STR_FILLED(info->description)) + if (IS_STR_FILLED(info->url)) { - g_RootMenu.ConsolePrint(" Description: %s", info->description); - } - g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no"); - g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "no" : "yes"); + g_RootMenu.ConsolePrint(" URL: %s", info->url); + } + if (pl->GetStatus() == Plugin_Error) + { + g_RootMenu.ConsolePrint(" Error: %s", pl->m_errormsg); + } else { + g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no"); + g_RootMenu.ConsolePrint(" Running: %s", pl->GetStatus() == Plugin_Running ? "yes" : "no"); + } } else { g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg); g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")", @@ -1726,5 +1875,8 @@ bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, m_Natives.push_back(pNative); sm_trie_insert(m_pNativeLookup, name,pNative); + CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext()); + pPlugin->m_fakeNatives.push_back(pNative); + return true; } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 1eb2cec9..f9bda46a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -92,6 +92,14 @@ struct ContextPair IVirtualMachine *vm; }; +struct FakeNative +{ + IPluginContext *ctx; + IPluginFunction *call; + String name; + SPVM_NATIVE_FUNC func; +}; + enum LoadRes { LoadRes_Successful, @@ -216,6 +224,7 @@ public: protected: void UpdateInfo(); void SetTimeStamp(time_t t); + void DependencyDropped(CPlugin *pOwner); private: ContextPair m_ctx; PluginType m_type; @@ -230,15 +239,11 @@ private: Handle_t m_handle; bool m_WasRunning; CVector m_PhraseFiles; + List m_dependents; + List m_dependsOn; + List m_fakeNatives; Trie *m_pProps; -}; - -struct FakeNative -{ - IPluginContext *ctx; - IPluginFunction *call; - String name; - SPVM_NATIVE_FUNC func; + bool m_FakeNativesMissing; }; class CPluginManager : @@ -393,6 +398,7 @@ public: bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func); private: void AddFakeNativesToPlugin(CPlugin *pPlugin); + void TryRefreshNatives(CPlugin *pOther); private: List m_listeners; List m_plugins; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 832de0b1..531eef4d 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -836,7 +836,7 @@ namespace SourcePawn * @param function Pointer to the fake native created by CreateFakeNative. * @noreturn */ - virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0; + virtual void DestroyFakeNative(SPVM_NATIVE_FUNC func) =0; }; }; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index b4b272c9..df505752 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2229,7 +2229,7 @@ rewind: return (SPVM_NATIVE_FUNC)jw.outbase; } -void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func) +void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) { engine->ExecFree((void *)func); } diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 02801438..33b4f1af 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -99,7 +99,7 @@ public: const char *GetVersionString(); const char *GetCPUOptimizations(); SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); - void DestroyFakenative(SPVM_NATIVE_FUNC func); + void DestroyFakeNative(SPVM_NATIVE_FUNC func); }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); From 8867fb1ce7793c79d6b43a2e81ae2f2cc8a90b69 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Mar 2007 05:55:58 +0000 Subject: [PATCH 0581/1664] fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40612 --- core/systems/PluginSys.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index ddb5eb73..e380377a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -555,7 +555,6 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) return; } - IPluginContext *pContext = pOwner->GetBaseContext(); List::iterator iter; FakeNative *pNative; sp_native_t *native; From c4a677df79b4b0b0047ac956eaedaedcf8710ea0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 14 Mar 2007 02:58:12 +0000 Subject: [PATCH 0584/1664] Made this define consistent with AMXX --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40615 --- core/sm_stringutil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index b5686319..235a790b 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -22,7 +22,7 @@ #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define UPPERDIGITS 0x00000100 /* make alpha digits uppercase */ +#define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) From 3f7180aa65889a38469097b3f02939097211dff0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 14 Mar 2007 04:08:59 +0000 Subject: [PATCH 0585/1664] whoops, i should have done this a long time ago --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40616 --- plugins/include/entity.inc | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 31b922d9..8c983636 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -18,6 +18,14 @@ #endif #define _entity_included +/** + * Property types for entities. + */ +enum PropType +{ + Prop_Send = 0, /**< This property is networked. */ + Prop_Data = 1, /**< This property is for saved game files. */ +}; /** * For more information on these, see the HL2SDK (public/edict.h) @@ -300,12 +308,13 @@ stock GetEntSendPropOffs(ent, const String:prop[]) * Gets a network property as an integer; wrapper around GetEntData(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param size Number of bytes to read (valid values are 1, 2, or 4). * @return Value at the given property offset. * @error Invalid entity or property not found. */ -stock GetEntProp(entity, const String:prop[], size=4) +stock GetEntProp(entity, PropType:type, const String:prop[], size=4) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -319,12 +328,13 @@ stock GetEntProp(entity, const String:prop[], size=4) * Sets a network property as an integer; wrapper around GetEntData(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param size Number of bytes to write (valid values are 1, 2, or 4). * @error Invalid entity or offset out of reasonable bounds. * @noreturn */ -stock SetEntProp(entity, const String:prop[], value, size=4) +stock SetEntProp(entity, PropType:type, const String:prop[], value, size=4) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -338,11 +348,12 @@ stock SetEntProp(entity, const String:prop[], value, size=4) * Gets a network property as a float; wrapper around GetEntDataFloat(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @return Value at the given property offset.. * @error Invalid entity or offset out of reasonable bounds. */ -stock Float:GetEntPropFloat(entity, const String:prop[]) +stock Float:GetEntPropFloat(entity, PropType:type, const String:prop[]) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -356,12 +367,13 @@ stock Float:GetEntPropFloat(entity, const String:prop[]) * Sets a network property as a float; wrapper around SetEntDataFloat(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param value Value to set. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -stock SetEntPropFloat(entity, const String:prop[], Float:value) +stock SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -375,11 +387,12 @@ stock SetEntPropFloat(entity, const String:prop[], Float:value) * Gets a network property as a handle entity; wrapper around GetEntDataEnt(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @return Entity index at the given property, or 0 if none. * @error Invalid entity or offset out of reasonable bounds. */ -stock GetEntPropEnt(entity, const String:prop[]) +stock GetEntPropEnt(entity, PropType:type, const String:prop[]) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -393,12 +406,13 @@ stock GetEntPropEnt(entity, const String:prop[]) * Sets a network property as a handle entity; wrapper around SetEntDataEnt(). * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param other Entity index to set, or 0 to unset. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -stock SetEntPropEnt(entity, const String:prop[], other) +stock SetEntPropEnt(entity, PropType:type, const String:prop[], other) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -414,12 +428,13 @@ stock SetEntPropEnt(entity, const String:prop[], other) * convenience function and will work with both types. * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param vec Vector buffer to store data in. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -stock GetEntPropVector(entity, const String:prop[], Float:vec[3]) +stock GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3]) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) @@ -435,12 +450,13 @@ stock GetEntPropVector(entity, const String:prop[], Float:vec[3]) * convenience function and will work with both types. * * @param entity Edict index. + * @param type Property type. * @param prop Property to use. * @param vec Vector to set. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -stock SetEntPropVector(entity, const String:prop[], const Float:vec[3]) +stock SetEntPropVector(entity, PropType:type, const String:prop[], const Float:vec[3]) { new offs = GetEntSendPropOffs(entity, prop); if (offs == -1) From 62aa55b23bf414afd5f4bbb648f145f80bb1a3fc Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 14 Mar 2007 07:54:54 +0000 Subject: [PATCH 0586/1664] Global forwards created after all plugins have been loaded now properly get filled with IPluginFunction pointers. Added CPluginManager::AddFunctionsToForward() to help do this... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40617 --- core/systems/ForwardSys.cpp | 2 ++ core/systems/PluginSys.cpp | 23 +++++++++++++++++++++++ core/systems/PluginSys.h | 7 +++++++ 3 files changed, 32 insertions(+) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index bbbee3f5..1cbcccd9 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -55,6 +55,8 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned if (fwd) { + g_PluginSys.AddFunctionsToForward(name, fwd); + m_managed.push_back(fwd); } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index e380377a..235d6499 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -16,6 +16,7 @@ #include "ShareSys.h" #include "LibrarySys.h" #include "HandleSys.h" +#include "ForwardSys.h" #include "sourcemm_api.h" #include "sourcemod.h" #include "TextParsers.h" @@ -1879,3 +1880,25 @@ bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, return true; } + +void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward) +{ + List::iterator iter; + CPlugin *pPlugin; + IPluginFunction *pFunction; + + for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++) + { + pPlugin = (*iter); + + if (pPlugin->GetStatus() <= Plugin_Paused) + { + pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name); + + if (pFunction) + { + pForward->AddFunction(pFunction); + } + } + } +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index f9bda46a..39634ac2 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -354,6 +355,12 @@ public: */ void ReloadOrUnloadPlugins(); + /** + * Add public functions from all running or paused + * plugins to the specified forward if the names match. + */ + void AddFunctionsToForward(const char *name, IChangeableForward *pForward); + private: LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); From 971cb8f7e7bf5b6e599123838cdaf49f745c02cd Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Mar 2007 11:34:03 +0000 Subject: [PATCH 0587/1664] implemented timer natives fixed some design issues in the timer manager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40618 --- core/TimerSys.cpp | 12 +- core/msvc8/sourcemod_mm.vcproj | 4 + core/smn_timers.cpp | 222 +++++++++++++++++++++++++++++++++ plugins/include/timers.inc | 107 ++++++++++++++++ 4 files changed, 339 insertions(+), 6 deletions(-) create mode 100644 core/smn_timers.cpp create mode 100644 plugins/include/timers.inc diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 9740ce9e..d110f41d 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -44,10 +44,7 @@ void CTimerSystem::RunFrame() { pTimer->m_InExec = true; pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); - if (pTimer->m_KillMe) - { - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - } + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); iter = m_SingleTimers.erase(iter); m_FreeTimers.push(pTimer); } else { @@ -144,9 +141,12 @@ void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) m_SingleTimers.remove(pTimer); m_FreeTimers.push(pTimer); } else { - if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe) + if ((res != Pl_Stop) && !pTimer->m_KillMe) { - pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + if (delayExec) + { + pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + } pTimer->m_InExec = false; return; } diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 6a66d17d..16c50aef 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -753,6 +753,10 @@ RelativePath="..\smn_textparse.cpp" > + + diff --git a/core/smn_timers.cpp b/core/smn_timers.cpp new file mode 100644 index 00000000..1328dba0 --- /dev/null +++ b/core/smn_timers.cpp @@ -0,0 +1,222 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "HandleSys.h" +#include "TimerSys.h" +#include "Logger.h" + +#define TIMER_HNDL_CLOSE (1<<9) + +HandleType_t g_TimerType; + +struct TimerInfo +{ + ITimer *Timer; + IPluginFunction *Hook; + IPluginContext *pContext; + Handle_t TimerHandle; + int UserData; + int Flags; +}; + +class TimerNatives : + public SMGlobalClass, + public IHandleTypeDispatch, + public ITimedEvent +{ +public: //ITimedEvent + ResultType OnTimer(ITimer *pTimer, void *pData); + void OnTimerEnd(ITimer *pTimer, void *pData); +public: //IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: + TimerInfo *CreateTimerInfo(); + void DeleteTimerInfo(TimerInfo *pInfo); +private: + CStack m_FreeTimers; +}; + +void TimerNatives::OnSourceModAllInitialized() +{ + HandleAccess sec; + sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY; + + g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL); +} + +void TimerNatives::OnSourceModShutdown() +{ + g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent); + g_TimerType = 0; +} + +void TimerNatives::OnHandleDestroy(HandleType_t type, void *object) +{ + TimerInfo *pTimer = reinterpret_cast(object); + + g_Timers.KillTimer(pTimer->Timer); +} + +TimerInfo *TimerNatives::CreateTimerInfo() +{ + TimerInfo *pInfo; + + if (m_FreeTimers.empty()) + { + pInfo = new TimerInfo; + } else { + pInfo = m_FreeTimers.front(); + m_FreeTimers.pop(); + } + + return pInfo; +} + +void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo) +{ + m_FreeTimers.push(pInfo); +} + +ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData) +{ + TimerInfo *pInfo = reinterpret_cast(pData); + IPluginFunction *pFunc = pInfo->Hook; + cell_t res = static_cast(Pl_Continue); + + pFunc->PushCell(pInfo->TimerHandle); + pFunc->PushCell(pInfo->UserData); + pFunc->Execute(&res); + + return static_cast(res); +} + +void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData) +{ + HandleSecurity sec; + HandleError herr; + TimerInfo *pInfo = reinterpret_cast(pData); + Handle_t usrhndl = static_cast(pInfo->UserData); + + sec.pOwner = pInfo->pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + if (pInfo->Flags & TIMER_HNDL_CLOSE) + { + if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None) + { + g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr); + } + } + + g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec); +} + +/******************************* +* * +* TIMER NATIVE IMPLEMENTATIONS * +* * +********************************/ + +static TimerNatives s_TimerNatives; + +static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params) +{ + IPluginFunction *pFunc; + TimerInfo *pInfo; + ITimer *pTimer; + Handle_t hndl; + int flags = params[4]; + + pFunc = pCtx->GetFunctionById(params[2]); + if (!pFunc) + { + return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + pInfo = s_TimerNatives.CreateTimerInfo(); + pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags); + hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL); + + pInfo->UserData = params[3]; + pInfo->Flags = flags; + pInfo->TimerHandle = hndl; + pInfo->Hook = pFunc; + pInfo->Timer = pTimer; + pInfo->pContext = pCtx; + + return hndl; +} + +static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + TimerInfo *pInfo; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); + } + + g_Timers.KillTimer(pInfo->Timer); + + if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE)) + { + sec.pOwner = pInfo->pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.FreeHandle(static_cast(pInfo->UserData), &sec)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr); + } + } + + return 1; +} + +static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + TimerInfo *pInfo; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); + } + + g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false); + + return 1; +} + +REGISTER_NATIVES(timernatives) +{ + {"CreateTimer", smn_CreateTimer}, + {"KillTimer", smn_KillTimer}, + {"TriggerTimer", smn_TriggerTimer}, + {NULL, NULL} +}; diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc new file mode 100644 index 00000000..12add657 --- /dev/null +++ b/plugins/include/timers.inc @@ -0,0 +1,107 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _timers_included + #endinput +#endif +#define _timers_included + +#include + +#define TIMER_REPEAT (1<<0) /**< Timer will repeat until it returns Plugin_Stop */ +#define TIMER_HNDL_CLOSE (1<<9) /**< Timer will automatically call CloseHandle() on its value when finished */ + +/** + * Any of the following prototypes will work for a timed function. + */ +funcenum Timer +{ + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @param hndl Handle passed when the timer was created. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + Action:public(Handle:timer, Handle:hndl), + + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @param value Value passed when the timer was created. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + Action:public(Handle:timer, value), + + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + Action:public(Handle:timer), +}; + +/** + * Creates a basic timer. Calling CloseHandle() on a timer will end the timer. + * + * @param interval Interval from the current game time to execute the given function. + * @param func Function to execute once the given interval has elapsed. + * @param value Handle or value to give to the timer function. + * @param flags Flags to set (such as repeatability or auto-Handle closing). + * @return Handle to the timer object. You do not need to call CloseHandle(). + */ +native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags); + +/** + * Kills a timer. Use this instead of CloseHandle() if you need more options. + * + * @param autoClose If autoClose is true, the timer's value will be + * closed as a handle if TIMER_HNDL_CLOSE was not specified. + * @noreturn + */ +native KillTimer(Handle:timer, bool:autoClose=false); + +/** + * Manually triggers a timer so its function will be called. + * + * @param timer Timer Handle to trigger. + * @param reset If reset is true, the elapsed time counter is reset + * so the full interval must pass again. + * @noreturn + */ +native TriggerTimer(Handle:timer, bool:reset=false); + +/** + * Creates a timer associated with a new data pack, and returns the datapack. + * @note The datapack is automatically freed when the timer ends. + * @note The position of the datapack is not reset or changed for the timer function. + * + * @param interval Interval from the current game time to execute the given function. + * @param func Function to execute once the given interval has elapsed. + * @param data The newly created datapack is passed though this by-reference parameter. + * @param flags Timer flags. + * @return Handle to the timer object. You do not need to call CloseHandle(). + */ +stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:data, flags) +{ + data = CreateDataPack(); + flags |= TIMER_HNDL_CLOSE; + return CreateTimer(interval, func, data, flags); +} From df2d234b062b68c322f0d382725f0c6b1e177479 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 14 Mar 2007 15:32:28 +0000 Subject: [PATCH 0588/1664] oh forgot to delete killed timers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40619 --- core/smn_timers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/smn_timers.cpp b/core/smn_timers.cpp index 1328dba0..140787b1 100644 --- a/core/smn_timers.cpp +++ b/core/smn_timers.cpp @@ -122,6 +122,7 @@ void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData) } g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec); + DeleteTimerInfo(pInfo); } /******************************* From 0bbb4670fc78efb13170fb85413d479eefc92f0e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 04:23:46 +0000 Subject: [PATCH 0589/1664] my easter egg. if you're wondering, this only took an hour. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40620 --- core/ConCmdManager.cpp | 131 +++++++++++++++++++++++++++++++++++++++++ core/sm_srvcmds.cpp | 7 +++ 2 files changed, 138 insertions(+) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 19ae8501..1fc98f81 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -790,3 +790,134 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco g_RootMenu.ConsolePrint("[SM] Usage: sm cmds "); } + +static int g_yam_state = 0; +void _YamState(int state) +{ + if (state == 0) + { + g_RootMenu.ConsolePrint("Welcome to the SourceMod Text Adventure."); + g_RootMenu.ConsolePrint("Type sm_text to see the last message."); + g_RootMenu.ConsolePrint("Type sm_text to follow a capital word."); + g_RootMenu.ConsolePrint("-------------------------------"); + g_RootMenu.ConsolePrint("You are at VALVE HEADQUARTERS."); + g_RootMenu.ConsolePrint("To your LEFT is BAILOPAN, rearranging the letters to spell"); + g_RootMenu.ConsolePrint("\"A HARD VEAL QUEST\". FORWARD is the entrance to the building."); + g_RootMenu.ConsolePrint("To your RIGHT is your last chance to flee in terror."); + } else if (state == 1) { + g_RootMenu.ConsolePrint("BAILOPAN tells you that his name his pronounced"); + g_RootMenu.ConsolePrint("\"bye low pahn,\" not \"bay low pan.\" Do you "); + g_RootMenu.ConsolePrint("MOCK him, or NOD quietly?"); + } else if (state == 2) { + g_RootMenu.ConsolePrint("You enter the Valve building. You hear screams coming from within."); + g_RootMenu.ConsolePrint("A grotesque figure lumbers up to greet you; it is Gabe Newell."); + g_RootMenu.ConsolePrint("\"Welcome,\" he belches, \"to my lair.\""); + g_RootMenu.ConsolePrint("Do you SHAKE Gaben's hand, WALK past him, or OFFER a donut?"); + } else if (state == 3) { + g_RootMenu.ConsolePrint("You walk into the break room. Alfred \"Adolf\" Reynolds and"); + g_RootMenu.ConsolePrint("Yahn \"Yeti\" Bernier are discussing something (you overhear "); + g_RootMenu.ConsolePrint("the phrase \"and next Steam update, here's what we should break\")."); + g_RootMenu.ConsolePrint("Should you DIE in a fire, REPORT a bug, REQUEST a feature, or "); + g_RootMenu.ConsolePrint("SPRAY them with butter?"); + } + g_yam_state = state; +} + +void _IntExt_CallYams() +{ + const char *arg = engine->Cmd_Argv(1); + + /* should be impossible */ + if (!arg || arg[0] == '\0') + { + _YamState(g_yam_state); + } + + if (g_yam_state == 1) + { + if (strcasecmp(arg, "mock") == 0) + { + g_RootMenu.ConsolePrint("You mock BAILOPAN's pronounciation. In a fit of range, "); + g_RootMenu.ConsolePrint("he sticks an INT 3 call into your chest, rendering you broken."); + g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); + g_yam_state = 0; + } else if (strcasecmp(arg, "nod") == 0) { + g_RootMenu.ConsolePrint("You nod quietly, and then slowly back away into the Valve headquarters."); + _YamState(2); + } else { + g_RootMenu.ConsolePrint("Commands are MOCK and NOD."); + } + } else if (g_yam_state == 3) { + if (strcasecmp(arg, "report") == 0) + { + g_RootMenu.ConsolePrint("You report a bug to Alfred and Yeti. Immediately, both fall asleep."); + g_RootMenu.ConsolePrint("You decay in the break room for two years while they sleep."); + g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); + g_yam_state = 0; + } else if (strcasecmp(arg, "request") == 0) { + g_RootMenu.ConsolePrint("You request a feature to Alfred and Yeti. They both mutter something"); + g_RootMenu.ConsolePrint("about it being implemented \"soon.\" Then, by accident, someone sends"); + g_RootMenu.ConsolePrint("a message over \"Friends.\" The entire building catches fire."); + g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); + g_yam_state = 0; + } else if (strcasecmp(arg, "die") == 0) { + g_RootMenu.ConsolePrint("For no reason, you suddenly catch fire. Alfred and Yeti find this"); + g_RootMenu.ConsolePrint("deeply disturbing, and cover your flaming corpse with Episode 2"); + g_RootMenu.ConsolePrint("advertisments. Coming soon, with Team Fortress 2, and Portal!"); + g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); + g_yam_state = 0; + } else if (strcasecmp(arg, "spray") == 0) { + g_RootMenu.ConsolePrint("You spray Alfred and Yeti with butter. Like Jack Thompson to an"); + g_RootMenu.ConsolePrint("ambulance, Gabe Newell instantly appears and devours them both."); + g_RootMenu.ConsolePrint("You run away, just in time, as Gabe Newell explodes, registering "); + g_RootMenu.ConsolePrint("a 5.6 earthquake. Outside, world peace is achieved."); + g_RootMenu.ConsolePrint("YOU HAVE WON."); + g_yam_state = 0; + } + } else if (g_yam_state == 2) { + if (strcasecmp(arg, "shake") == 0) + { + g_RootMenu.ConsolePrint("You shake Gaben's hand. It is a terrifying and disgusting experience."); + g_RootMenu.ConsolePrint("However, you survive, and continue on."); + _YamState(3); + } else if (strcasecmp(arg, "offer") == 0) { + g_RootMenu.ConsolePrint("You offer Gabe Newell one (1) donut. With a gleam in his eyes, "); + g_RootMenu.ConsolePrint("he picks you up and devours you whole."); + g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); + g_yam_state = 0; + } else if (strcasecmp(arg, "walk") == 0) { + g_RootMenu.ConsolePrint("You walk past Gabe Newell. He can't keep up with your pace!"); + _YamState(3); + } else { + g_RootMenu.ConsolePrint("Commands are SHAKE, OFFER, and WALK."); + } + } else if (g_yam_state == 0) { + if (strcasecmp(arg, "left") == 0) + { + _YamState(1); + } else if (strcasecmp(arg, "right") == 0) { + g_RootMenu.ConsolePrint("You run away from the Valve headquarters in sheer terror."); + g_RootMenu.ConsolePrint("While running, you smash into an unknown person, who turns out to be your soul mate."); + g_RootMenu.ConsolePrint("You marry and raise a family of 3 kids."); + g_RootMenu.ConsolePrint("Many years later, you look back, and realize this was your best choice."); + g_RootMenu.ConsolePrint("YOU HAVE WON."); + g_yam_state = 0; + } else if (strcasecmp(arg, "forward") == 0) { + _YamState(2); + } else if (arg[0] != '\0') { + g_RootMenu.ConsolePrint("Commands are FORWARD, LEFT, and RIGHT."); + } + } +} + +void _IntExt_EnableYams() +{ + static ConCommand *pCmd = NULL; + if (!pCmd) + { + pCmd = new ConCommand("sm_text", _IntExt_CallYams, "Fountain of Yams Adventure Game", FCVAR_GAMEDLL); + g_RootMenu.ConsolePrint("Something is now enabled..."); + } else { + g_RootMenu.ConsolePrint("Something is already enabled..."); + } +} diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 74bccdd7..d86a0a8c 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -166,6 +166,8 @@ void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text) } } +extern void _IntExt_EnableYams(); + void RootConsoleMenu::GotRootCmd() { unsigned int argnum = GetArgumentCount(); @@ -173,6 +175,11 @@ void RootConsoleMenu::GotRootCmd() if (argnum >= 2) { const char *cmd = GetArgument(1); + if (strcmp(cmd, "text") == 0) + { + _IntExt_EnableYams(); + return; + } IRootConsoleCommand *pHandler; if (sm_trie_retrieve(m_pCommands, cmd, (void **)&pHandler)) { From 043b8f255fbf69e06f8383cf55913cc277fe9edc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 04:34:42 +0000 Subject: [PATCH 0590/1664] removed const from most apis. it was pointless since there were no actual const pointers. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40621 --- core/PlayerManager.cpp | 18 +++++++++--------- core/PlayerManager.h | 18 +++++++++--------- core/systems/ForwardSys.cpp | 6 +++--- core/systems/ForwardSys.h | 6 +++--- core/systems/PluginSys.cpp | 28 ++++++++++++++-------------- core/systems/PluginSys.h | 28 ++++++++++++++-------------- public/IForwardSys.h | 6 +++--- public/IPlayerHelpers.h | 16 ++++++++-------- public/IPluginSys.h | 20 ++++++++++---------- 9 files changed, 73 insertions(+), 73 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 0b9581c3..53a528f2 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -467,42 +467,42 @@ void CPlayer::SetName(const char *name) m_Name.assign(name); } -const char *CPlayer::GetName() const +const char *CPlayer::GetName() { return m_Name.c_str(); } -const char *CPlayer::GetIPAddress() const +const char *CPlayer::GetIPAddress() { return m_Ip.c_str(); } -const char *CPlayer::GetAuthString() const +const char *CPlayer::GetAuthString() { return m_AuthID.c_str(); } -edict_t *CPlayer::GetEdict() const +edict_t *CPlayer::GetEdict() { return m_pEdict; } -bool CPlayer::IsInGame() const +bool CPlayer::IsInGame() { return m_IsInGame; } -bool CPlayer::IsConnected() const +bool CPlayer::IsConnected() { return m_IsConnected; } -bool CPlayer::IsAuthorized() const +bool CPlayer::IsAuthorized() { return m_IsAuthorized; } -bool CPlayer::IsFakeClient() const +bool CPlayer::IsFakeClient() { return (strcmp(m_AuthID.c_str(), "BOT") == 0); } @@ -520,7 +520,7 @@ void CPlayer::SetAdminId(AdminId id, bool temporary) m_TempAdmin = temporary; } -AdminId CPlayer::GetAdminId() const +AdminId CPlayer::GetAdminId() { return m_Admin; } diff --git a/core/PlayerManager.h b/core/PlayerManager.h index afdbd884..87632aa5 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -32,16 +32,16 @@ class CPlayer : public IGamePlayer public: CPlayer(); public: - const char *GetName() const; - const char *GetIPAddress() const; - const char *GetAuthString() const; - edict_t *GetEdict() const; - bool IsInGame() const; - bool IsConnected() const; - bool IsAuthorized() const; - bool IsFakeClient() const; + const char *GetName(); + const char *GetIPAddress(); + const char *GetAuthString(); + edict_t *GetEdict(); + bool IsInGame(); + bool IsConnected(); + bool IsAuthorized(); + bool IsFakeClient(); void SetAdminId(AdminId id, bool temporary); - AdminId GetAdminId() const; + AdminId GetAdminId(); private: void Initialize(const char *name, const char *ip, edict_t *pEntity); void Connect(); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 1cbcccd9..ae18abdf 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -671,17 +671,17 @@ bool CForward::AddFunction(IPluginFunction *func) return true; } -const char *CForward::GetForwardName() const +const char *CForward::GetForwardName() { return m_name; } -unsigned int CForward::GetFunctionCount() const +unsigned int CForward::GetFunctionCount() { return m_functions.size(); } -ExecType CForward::GetExecType() const +ExecType CForward::GetExecType() { return m_ExecType; } diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 2dbde5c8..b1d8703a 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -55,9 +55,9 @@ public: //ICallable virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual void Cancel(); public: //IForward - virtual const char *GetForwardName() const; - virtual unsigned int GetFunctionCount() const; - virtual ExecType GetExecType() const; + virtual const char *GetForwardName(); + virtual unsigned int GetFunctionCount(); + virtual ExecType GetExecType(); virtual int Execute(cell_t *result, IForwardFilter *filter); public: //IChangeableForward virtual bool RemoveFunction(IPluginFunction *func); diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 235d6499..95b4f4e7 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -349,47 +349,47 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) return true; } -const sp_plugin_t *CPlugin::GetPluginStructure() const +const sp_plugin_t *CPlugin::GetPluginStructure() { return m_plugin; } -IPluginContext *CPlugin::GetBaseContext() const +IPluginContext *CPlugin::GetBaseContext() { return m_ctx.base; } -sp_context_t *CPlugin::GetContext() const +sp_context_t *CPlugin::GetContext() { return m_ctx.ctx; } -const char *CPlugin::GetFilename() const +const char *CPlugin::GetFilename() { return m_filename; } -PluginType CPlugin::GetType() const +PluginType CPlugin::GetType() { return m_type; } -const sm_plugininfo_t *CPlugin::GetPublicInfo() const +const sm_plugininfo_t *CPlugin::GetPublicInfo() { return &m_info; } -unsigned int CPlugin::GetSerial() const +unsigned int CPlugin::GetSerial() { return m_serial; } -PluginStatus CPlugin::GetStatus() const +PluginStatus CPlugin::GetStatus() { return m_status; } -bool CPlugin::IsDebugging() const +bool CPlugin::IsDebugging() { if (!m_ctx.ctx) { @@ -430,7 +430,7 @@ bool CPlugin::SetPauseState(bool paused) return true; } -IdentityToken_t *CPlugin::GetIdentity() const +IdentityToken_t *CPlugin::GetIdentity() { return m_ident; } @@ -501,7 +501,7 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) return true; } -bool CPlugin::IsRunnable() const +bool CPlugin::IsRunnable() { return (m_status <= Plugin_Paused) ? true : false; } @@ -524,7 +524,7 @@ time_t CPlugin::GetFileTimeStamp() } } -time_t CPlugin::GetTimeStamp() const +time_t CPlugin::GetTimeStamp() { return m_LastAccess; } @@ -539,12 +539,12 @@ void CPlugin::AddLangFile(unsigned int index) m_PhraseFiles.push_back(index); } -size_t CPlugin::GetLangFileCount() const +size_t CPlugin::GetLangFileCount() { return m_PhraseFiles.size(); } -unsigned int CPlugin::GetLangFileByIndex(unsigned int index) const +unsigned int CPlugin::GetLangFileByIndex(unsigned int index) { return m_PhraseFiles.at(index); } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 39634ac2..d68340c2 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -116,17 +116,17 @@ public: CPlugin(const char *file); ~CPlugin(); public: - virtual PluginType GetType() const; - virtual SourcePawn::IPluginContext *GetBaseContext() const; - virtual sp_context_t *GetContext() const; - virtual const sm_plugininfo_t *GetPublicInfo() const; - virtual const char *GetFilename() const; - virtual bool IsDebugging() const; - virtual PluginStatus GetStatus() const; + virtual PluginType GetType(); + virtual SourcePawn::IPluginContext *GetBaseContext(); + virtual sp_context_t *GetContext(); + virtual const sm_plugininfo_t *GetPublicInfo(); + virtual const char *GetFilename(); + virtual bool IsDebugging(); + virtual PluginStatus GetStatus(); virtual bool SetPauseState(bool paused); - virtual unsigned int GetSerial() const; - virtual const sp_plugin_t *GetPluginStructure() const; - virtual IdentityToken_t *GetIdentity() const; + virtual unsigned int GetSerial(); + virtual const sp_plugin_t *GetPluginStructure(); + virtual IdentityToken_t *GetIdentity(); virtual bool SetProperty(const char *prop, void *ptr); virtual bool GetProperty(const char *prop, void **ptr, bool remove=false); public: @@ -189,7 +189,7 @@ public: /** * Returns true if a plugin is usable. */ - bool IsRunnable() const; + bool IsRunnable(); /** * Adds a language file index to the plugin's list. @@ -199,17 +199,17 @@ public: /** * Get language file count for this plugin. */ - size_t GetLangFileCount() const; + size_t GetLangFileCount(); /** * Get language file index based on the vector index. */ - unsigned int GetLangFileByIndex(unsigned int index) const; + unsigned int GetLangFileByIndex(unsigned int index); public: /** * Returns the modification time during last plugin load. */ - time_t GetTimeStamp() const; + time_t GetTimeStamp(); /** * Returns the current modification time of the plugin file. diff --git a/public/IForwardSys.h b/public/IForwardSys.h index a6e9b018..da188d27 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -146,21 +146,21 @@ namespace SourceMod * * @return Forward name. */ - virtual const char *GetForwardName() const =0; + virtual const char *GetForwardName() =0; /** * @brief Returns the number of functions in this forward. * * @return Number of functions in forward. */ - virtual unsigned int GetFunctionCount() const =0; + virtual unsigned int GetFunctionCount() =0; /** * @brief Returns the method of multi-calling this forward has. * * @return ExecType of the forward. */ - virtual ExecType GetExecType() const =0; + virtual ExecType GetExecType() =0; /** * @brief Executes the forward. diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 91142e90..92dae146 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -45,7 +45,7 @@ namespace SourceMod * @return String containing the player's name, * or NULL if unavailable. */ - virtual const char *GetName() const =0; + virtual const char *GetName() =0; /** * @brief Returns the player's IP address. @@ -53,7 +53,7 @@ namespace SourceMod * @return String containing the player's IP address, * or NULL if unavailable. */ - virtual const char *GetIPAddress() const =0; + virtual const char *GetIPAddress() =0; /** * @brief Returns the player's authentication string. @@ -61,21 +61,21 @@ namespace SourceMod * @return String containing the player's auth string. * May be NULL if unavailable. */ - virtual const char *GetAuthString() const =0; + virtual const char *GetAuthString() =0; /** * @brief Returns the player's edict_t structure. * * @return edict_t pointer, or NULL if unavailable. */ - virtual edict_t *GetEdict() const =0; + virtual edict_t *GetEdict() =0; /** * @brief Returns whether the player is in game (putinserver). * * @return True if in game, false otherwise. */ - virtual bool IsInGame() const =0; + virtual bool IsInGame() =0; /** * @brief Returns whether the player is connected. @@ -85,21 +85,21 @@ namespace SourceMod * * @return True if connected, false otherwise. */ - virtual bool IsConnected() const =0; + virtual bool IsConnected() =0; /** * @brief Returns whether the player is a fake client. * * @return True if a fake client, false otherwise. */ - virtual bool IsFakeClient() const =0; + virtual bool IsFakeClient() =0; /** * @brief Returns the client's AdminId, if any. * * @return AdminId, or INVALID_ADMIN_ID if none. */ - virtual AdminId GetAdminId() const =0; + virtual AdminId GetAdminId() =0; /** * @brief Sets the client's AdminId. diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 7cbcb5a9..f9154c3d 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -93,50 +93,50 @@ namespace SourceMod /** * @brief Returns the lifetime of a plugin. */ - virtual PluginType GetType() const =0; + virtual PluginType GetType() =0; /** * @brief Returns the current API context being used in the plugin. * * @return Pointer to an IPluginContext, or NULL if not loaded. */ - virtual SourcePawn::IPluginContext *GetBaseContext() const =0; + virtual SourcePawn::IPluginContext *GetBaseContext() =0; /** * @brief Returns the context structure being used in the plugin. * * @return Pointer to an sp_context_t, or NULL if not loaded. */ - virtual sp_context_t *GetContext() const =0; + virtual sp_context_t *GetContext() =0; /** * @brief Returns the plugin file structure. * * @return Pointer to an sp_plugin_t, or NULL if not loaded. */ - virtual const sp_plugin_t *GetPluginStructure() const =0; + virtual const sp_plugin_t *GetPluginStructure() =0; /** * @brief Returns information about the plugin by reference. * * @return Pointer to a sm_plugininfo_t object, NULL if plugin is not loaded. */ - virtual const sm_plugininfo_t *GetPublicInfo() const =0; + virtual const sm_plugininfo_t *GetPublicInfo() =0; /** * @brief Returns the plugin filename (relative to plugins dir). */ - virtual const char *GetFilename() const =0; + virtual const char *GetFilename() =0; /** * @brief Returns true if a plugin is in debug mode, false otherwise. */ - virtual bool IsDebugging() const =0; + virtual bool IsDebugging() =0; /** * @brief Returns the plugin status. */ - virtual PluginStatus GetStatus() const =0; + virtual PluginStatus GetStatus() =0; /** * @brief Sets whether the plugin is paused or not. @@ -148,12 +148,12 @@ namespace SourceMod /** * @brief Returns the unique serial number of a plugin. */ - virtual unsigned int GetSerial() const =0; + virtual unsigned int GetSerial() =0; /** * @brief Returns a plugin's identity token. */ - virtual IdentityToken_t *GetIdentity() const =0; + virtual IdentityToken_t *GetIdentity() =0; /** * @brief Sets a property on this plugin. This is used for per-plugin From 2c70ec1a8c3f7612d755963507fbd66e97cab22a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 04:45:17 +0000 Subject: [PATCH 0591/1664] refactored singleton class names --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40622 --- core/DebugReporter.cpp | 8 ++--- core/DebugReporter.h | 4 +-- core/GameConfigs.cpp | 16 ++++----- core/GameConfigs.h | 8 ++--- core/Logger.cpp | 30 ++++++++--------- core/Logger.h | 6 ++-- core/PlayerManager.cpp | 76 +++++++++++++++++++++--------------------- core/PlayerManager.h | 10 +++--- core/TextParsers.cpp | 18 +++++----- core/TextParsers.h | 6 ++-- core/TimerSys.cpp | 14 ++++---- core/TimerSys.h | 4 +-- core/Translator.cpp | 36 ++++++++++---------- core/Translator.h | 14 ++++---- core/UserMessages.cpp | 56 +++++++++++++++---------------- core/UserMessages.h | 8 ++--- 16 files changed, 157 insertions(+), 157 deletions(-) diff --git a/core/DebugReporter.cpp b/core/DebugReporter.cpp index 20657b9b..f9eb027f 100644 --- a/core/DebugReporter.cpp +++ b/core/DebugReporter.cpp @@ -15,14 +15,14 @@ #include "Logger.h" #include "PluginSys.h" -CDbgReporter g_DbgReporter; +DebugReport g_DbgReporter; -void CDbgReporter::OnSourceModAllInitialized() +void DebugReport::OnSourceModAllInitialized() { g_pSourcePawn->SetDebugListener(this); } -void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) +void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) { const char *lastname; const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename(); @@ -68,7 +68,7 @@ void CDbgReporter::OnContextExecuteError(IPluginContext *ctx, IContextTrace *err } } -int CDbgReporter::_GetPluginIndex(IPluginContext *ctx) +int DebugReport::_GetPluginIndex(IPluginContext *ctx) { int id = 1; IPluginIterator *iter = g_PluginSys.GetPluginIterator(); diff --git a/core/DebugReporter.h b/core/DebugReporter.h index 020438c4..1fda4bc0 100644 --- a/core/DebugReporter.h +++ b/core/DebugReporter.h @@ -17,7 +17,7 @@ #include "sp_vm_api.h" #include "sm_globals.h" -class CDbgReporter : +class DebugReport : public SMGlobalClass, public IDebugListener { @@ -29,7 +29,7 @@ private: int _GetPluginIndex(IPluginContext *ctx); }; -extern CDbgReporter g_DbgReporter; +extern DebugReport g_DbgReporter; #endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index 66036e41..249b32f3 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -22,7 +22,7 @@ #include "Logger.h" #include "ShareSys.h" -CGameConfigManager g_GameConfigs; +GameConfigManager g_GameConfigs; IGameConfig *g_pGameConf = NULL; char g_mod[255]; @@ -285,17 +285,17 @@ unsigned int CGameConfig::DecRefCount() return m_RefCount; } -CGameConfigManager::CGameConfigManager() +GameConfigManager::GameConfigManager() { m_pLookup = sm_trie_create(); } -CGameConfigManager::~CGameConfigManager() +GameConfigManager::~GameConfigManager() { sm_trie_destroy(m_pLookup); } -void CGameConfigManager::OnSourceModStartup(bool late) +void GameConfigManager::OnSourceModStartup(bool late) { LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); @@ -323,7 +323,7 @@ void CGameConfigManager::OnSourceModStartup(bool late) } } -void CGameConfigManager::OnSourceModAllInitialized() +void GameConfigManager::OnSourceModAllInitialized() { /* NOW initialize the game file */ CGameConfig *pGameConf = (CGameConfig *)g_pGameConf; @@ -337,12 +337,12 @@ void CGameConfigManager::OnSourceModAllInitialized() g_ShareSys.AddInterface(NULL, this); } -void CGameConfigManager::OnSourceModAllShutdown() +void GameConfigManager::OnSourceModAllShutdown() { CloseGameConfigFile(g_pGameConf); } -bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) +bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) { CGameConfig *pConfig; @@ -372,7 +372,7 @@ bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCo return retval; } -void CGameConfigManager::CloseGameConfigFile(IGameConfig *cfg) +void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg) { CGameConfig *pConfig = (CGameConfig *)cfg; diff --git a/core/GameConfigs.h b/core/GameConfigs.h index 5b55cfb6..c6b93d8f 100644 --- a/core/GameConfigs.h +++ b/core/GameConfigs.h @@ -63,13 +63,13 @@ private: char m_mod[255]; }; -class CGameConfigManager : +class GameConfigManager : public IGameConfigManager, public SMGlobalClass { public: - CGameConfigManager(); - ~CGameConfigManager(); + GameConfigManager(); + ~GameConfigManager(); public: //IGameConfigManager bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength); void CloseGameConfigFile(IGameConfig *cfg); @@ -82,7 +82,7 @@ private: Trie *m_pLookup; }; -extern CGameConfigManager g_GameConfigs; +extern GameConfigManager g_GameConfigs; extern IGameConfig *g_pGameConf; #endif //_INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ diff --git a/core/Logger.cpp b/core/Logger.cpp index 5b0c7e60..d6b15308 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -18,24 +18,24 @@ #include "systems/LibrarySys.h" #include "sm_version.h" -CLogger g_Logger; +Logger g_Logger; /** * :TODO: This should be creating the log folder if it doesn't exist */ -void CLogger::OnSourceModStartup(bool late) +void Logger::OnSourceModStartup(bool late) { //:TODO: read these options from a file, dont hardcode them InitLogger(LoggingMode_Daily, true); } -void CLogger::OnSourceModAllShutdown() +void Logger::OnSourceModAllShutdown() { CloseLogger(); } -void CLogger::_NewMapFile() +void Logger::_NewMapFile() { if (!m_Active) { @@ -76,7 +76,7 @@ void CLogger::_NewMapFile() } } -void CLogger::_CloseFile() +void Logger::_CloseFile() { if (!m_Active) { @@ -110,7 +110,7 @@ void CLogger::_CloseFile() m_ErrFileName.clear(); } -void CLogger::InitLogger(LoggingMode mode, bool startlogging) +void Logger::InitLogger(LoggingMode mode, bool startlogging) { m_mode = mode; m_Active = startlogging; @@ -149,12 +149,12 @@ void CLogger::InitLogger(LoggingMode mode, bool startlogging) } } -void CLogger::CloseLogger() +void Logger::CloseLogger() { _CloseFile(); } -void CLogger::LogMessage(const char *vafmt, ...) +void Logger::LogMessage(const char *vafmt, ...) { if (!m_Active) { @@ -233,7 +233,7 @@ print_error: m_Active = false; } -void CLogger::LogError(const char *vafmt, ...) +void Logger::LogError(const char *vafmt, ...) { if (!m_Active) { @@ -282,7 +282,7 @@ void CLogger::LogError(const char *vafmt, ...) g_SMAPI->ConPrintf("L %s: %s\n", date, msg); } -void CLogger::MapChange(const char *mapname) +void Logger::MapChange(const char *mapname) { m_CurMapName.assign(mapname); @@ -312,7 +312,7 @@ void CLogger::MapChange(const char *mapname) m_ErrMapStart = false; } -void CLogger::_PrintToHL2Log(const char *fmt, va_list ap) +void Logger::_PrintToHL2Log(const char *fmt, va_list ap) { char msg[3072]; size_t len; @@ -326,7 +326,7 @@ void CLogger::_PrintToHL2Log(const char *fmt, va_list ap) engine->LogPrint(msg); } -const char *CLogger::GetLogFileName(LogType type) const +const char *Logger::GetLogFileName(LogType type) const { switch (type) { @@ -345,12 +345,12 @@ const char *CLogger::GetLogFileName(LogType type) const } } -LoggingMode CLogger::GetLoggingMode() const +LoggingMode Logger::GetLoggingMode() const { return m_mode; } -void CLogger::EnableLogging() +void Logger::EnableLogging() { if (m_Active) { @@ -360,7 +360,7 @@ void CLogger::EnableLogging() LogMessage("Logging enabled manually by user."); } -void CLogger::DisableLogging() +void Logger::DisableLogging() { if (!m_Active) { diff --git a/core/Logger.h b/core/Logger.h index df4d77a0..5dd95e78 100644 --- a/core/Logger.h +++ b/core/Logger.h @@ -32,10 +32,10 @@ enum LoggingMode LoggingMode_HL2 }; -class CLogger : public SMGlobalClass +class Logger : public SMGlobalClass { public: - CLogger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} + Logger() : m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false) {} public: //SMGlobalClass void OnSourceModStartup(bool late); void OnSourceModAllShutdown(); @@ -65,6 +65,6 @@ private: bool m_DailyPrintHdr; }; -extern CLogger g_Logger; +extern Logger g_Logger; #endif // _INCLUDE_SOURCEMOD_CLOGGER_H_ diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 53a528f2..d1575139 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -17,7 +17,7 @@ #include "AdminCache.h" #include "ConCmdManager.h" -CPlayerManager g_Players; +PlayerManager g_Players; SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int); SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *); @@ -26,27 +26,27 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *) SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int); -CPlayerManager::CPlayerManager() +PlayerManager::PlayerManager() { m_AuthQueue = NULL; m_FirstPass = true; } -CPlayerManager::~CPlayerManager() +PlayerManager::~PlayerManager() { delete [] m_AuthQueue; } -void CPlayerManager::OnSourceModAllInitialized() +void PlayerManager::OnSourceModAllInitialized() { - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect_Post, true); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); - SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); - SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect_Post, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false); + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true); g_ShareSys.AddInterface(NULL, this); @@ -62,15 +62,15 @@ void CPlayerManager::OnSourceModAllInitialized() m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String); } -void CPlayerManager::OnSourceModShutdown() +void PlayerManager::OnSourceModShutdown() { - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true); - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true); - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true); - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true); /* Release forwards */ g_Forwards.ReleaseForward(m_clconnect); @@ -84,7 +84,7 @@ void CPlayerManager::OnSourceModShutdown() delete [] m_Players; } -void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { if (m_FirstPass) { @@ -99,7 +99,7 @@ void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int c } } -void CPlayerManager::RunAuthChecks() +void PlayerManager::RunAuthChecks() { CPlayer *pPlayer; const char *authstr; @@ -168,7 +168,7 @@ void CPlayerManager::RunAuthChecks() } } -bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) +bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { int client = engine->IndexOfEdict(pEntity); @@ -202,7 +202,7 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons return true; } -bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) +bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { int client = engine->IndexOfEdict(pEntity); bool orig_value = META_RESULT_ORIG_RET(bool); @@ -220,7 +220,7 @@ bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, return true; } -void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername) +void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername) { cell_t res; int client = engine->IndexOfEdict(pEntity); @@ -258,7 +258,7 @@ void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playernam m_clputinserver->Execute(&res, NULL); } -void CPlayerManager::OnClientDisconnect(edict_t *pEntity) +void PlayerManager::OnClientDisconnect(edict_t *pEntity) { cell_t res; int client = engine->IndexOfEdict(pEntity); @@ -306,7 +306,7 @@ void CPlayerManager::OnClientDisconnect(edict_t *pEntity) m_Players[client].Disconnect(); } -void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) +void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity) { cell_t res; int client = engine->IndexOfEdict(pEntity); @@ -323,7 +323,7 @@ void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity) } } -void CPlayerManager::OnClientCommand(edict_t *pEntity) +void PlayerManager::OnClientCommand(edict_t *pEntity) { cell_t res = Pl_Continue; int client = engine->IndexOfEdict(pEntity); @@ -347,7 +347,7 @@ void CPlayerManager::OnClientCommand(edict_t *pEntity) } } -void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) +void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) { cell_t res; int client = engine->IndexOfEdict(pEntity); @@ -357,12 +357,12 @@ void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity) m_Players[client].SetName(engine->GetClientConVarValue(client, "name")); } -int CPlayerManager::GetMaxClients() +int PlayerManager::GetMaxClients() { return m_maxClients; } -CPlayer *CPlayerManager::GetPlayerByIndex(int client) const +CPlayer *PlayerManager::GetPlayerByIndex(int client) const { if (client > m_maxClients || client < 1) { @@ -371,33 +371,33 @@ CPlayer *CPlayerManager::GetPlayerByIndex(int client) const return &m_Players[client]; } -int CPlayerManager::GetNumPlayers() +int PlayerManager::GetNumPlayers() { return m_PlayerCount; } -void CPlayerManager::AddClientListener(IClientListener *listener) +void PlayerManager::AddClientListener(IClientListener *listener) { m_hooks.push_back(listener); } -void CPlayerManager::RemoveClientListener(IClientListener *listener) +void PlayerManager::RemoveClientListener(IClientListener *listener) { m_hooks.remove(listener); } -IGamePlayer *CPlayerManager::GetGamePlayer(edict_t *pEdict) +IGamePlayer *PlayerManager::GetGamePlayer(edict_t *pEdict) { int index = engine->IndexOfEdict(pEdict); return GetGamePlayer(index); } -IGamePlayer *CPlayerManager::GetGamePlayer(int client) +IGamePlayer *PlayerManager::GetGamePlayer(int client) { return GetPlayerByIndex(client); } -void CPlayerManager::ClearAdminId(AdminId id) +void PlayerManager::ClearAdminId(AdminId id) { for (int i=1; i<=m_maxClients; i++) { @@ -408,7 +408,7 @@ void CPlayerManager::ClearAdminId(AdminId id) } } -void CPlayerManager::ClearAllAdmins() +void PlayerManager::ClearAllAdmins() { for (int i=1; i<=m_maxClients; i++) { diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 87632aa5..1b8f31cb 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -28,7 +28,7 @@ using namespace SourceHook; class CPlayer : public IGamePlayer { - friend class CPlayerManager; + friend class PlayerManager; public: CPlayer(); public: @@ -61,13 +61,13 @@ private: edict_t *m_pEdict; }; -class CPlayerManager : +class PlayerManager : public SMGlobalClass, public IPlayerManager { public: - CPlayerManager(); - ~CPlayerManager(); + PlayerManager(); + ~PlayerManager(); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); @@ -118,6 +118,6 @@ private: unsigned int *m_AuthQueue; }; -extern CPlayerManager g_Players; +extern PlayerManager g_Players; #endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_ diff --git a/core/TextParsers.cpp b/core/TextParsers.cpp index 521d1c1c..d16fee3e 100644 --- a/core/TextParsers.cpp +++ b/core/TextParsers.cpp @@ -20,12 +20,12 @@ #include "TextParsers.h" #include "ShareSys.h" -CTextParsers g_TextParser; +TextParsers g_TextParser; static int g_ini_chartable1[255] = {0}; static int g_ws_chartable[255] = {0}; -CTextParsers::CTextParsers() +TextParsers::TextParsers() { g_ini_chartable1[(unsigned)'_'] = 1; g_ini_chartable1[(unsigned)'-'] = 1; @@ -43,12 +43,12 @@ CTextParsers::CTextParsers() g_ws_chartable[(unsigned)' '] = 1; } -void CTextParsers::OnSourceModAllInitialized() +void TextParsers::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); } -unsigned int CTextParsers::GetUTF8CharBytes(const char *stream) +unsigned int TextParsers::GetUTF8CharBytes(const char *stream) { return _GetUTF8CharBytes(stream); } @@ -83,7 +83,7 @@ bool CharStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int return true; } -SMCParseError CTextParsers::ParseString_SMC(const char *stream, +SMCParseError TextParsers::ParseString_SMC(const char *stream, ITextListener_SMC *smc, unsigned int *line, unsigned int *col) @@ -111,7 +111,7 @@ bool FileStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int return (ferror((FILE *)stream) == 0); } -SMCParseError CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, unsigned int *line, unsigned int *col) +SMCParseError TextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, unsigned int *line, unsigned int *col) { FILE *fp = fopen(file, "rt"); @@ -220,7 +220,7 @@ char *lowstring(StringInfo info[3]) return NULL; } -SMCParseError CTextParsers::ParseStream_SMC(void *stream, +SMCParseError TextParsers::ParseStream_SMC(void *stream, STREAMREADER srdr, ITextListener_SMC *smc, unsigned int *line, @@ -620,7 +620,7 @@ failed: * INI parser */ -bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col) +bool TextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col) { FILE *fp = fopen(file, "rt"); unsigned int curline = 0; @@ -918,7 +918,7 @@ event_failed: return false; } -const char *CTextParsers::GetSMCErrorString(SMCParseError err) +const char *TextParsers::GetSMCErrorString(SMCParseError err) { static const char *s_errors[] = { diff --git a/core/TextParsers.h b/core/TextParsers.h index 6150fccc..a4078923 100644 --- a/core/TextParsers.h +++ b/core/TextParsers.h @@ -46,12 +46,12 @@ inline unsigned int _GetUTF8CharBytes(const char *stream) */ typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *); -class CTextParsers : +class TextParsers : public ITextParsers, public SMGlobalClass { public: - CTextParsers(); + TextParsers(); public: //SMGlobalClass void OnSourceModAllInitialized(); public: @@ -81,6 +81,6 @@ private: }; -extern CTextParsers g_TextParser; +extern TextParsers g_TextParser; #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index d110f41d..8c90a3ea 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -14,7 +14,7 @@ #include "TimerSys.h" -CTimerSystem g_Timers; +TimerSystem g_Timers; void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags) { @@ -27,12 +27,12 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, m_KillMe = false; } -void CTimerSystem::OnSourceModAllInitialized() +void TimerSystem::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); } -void CTimerSystem::RunFrame() +void TimerSystem::RunFrame() { ITimer *pTimer; TimerIter iter; @@ -76,7 +76,7 @@ void CTimerSystem::RunFrame() m_LastExecTime = gpGlobals->curtime; } -ITimer *CTimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) +ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) { ITimer *pTimer; TimerIter iter; @@ -123,7 +123,7 @@ return_timer: return pTimer; } -void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) +void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) { ResultType res; @@ -156,7 +156,7 @@ void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) } } -void CTimerSystem::KillTimer(ITimer *pTimer) +void TimerSystem::KillTimer(ITimer *pTimer) { TimerList *pList; @@ -180,7 +180,7 @@ void CTimerSystem::KillTimer(ITimer *pTimer) m_FreeTimers.push(pTimer); } -void CTimerSystem::MapChange() +void TimerSystem::MapChange() { ITimer *pTimer; TimerIter iter; diff --git a/core/TimerSys.h b/core/TimerSys.h index 520a33f1..96576004 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -40,7 +40,7 @@ public: bool m_KillMe; }; -class CTimerSystem : +class TimerSystem : public ITimerSystem, public SMGlobalClass { @@ -60,6 +60,6 @@ private: float m_LastExecTime; }; -extern CTimerSystem g_Timers; +extern TimerSystem g_Timers; #endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_ diff --git a/core/Translator.cpp b/core/Translator.cpp index cea55b40..c9827e5e 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -21,7 +21,7 @@ #include "sm_stringutil.h" #include "sourcemod.h" -CTranslator g_Translator; +Translator g_Translator; CPhraseFile *g_pCorePhrases = NULL; struct trans_t @@ -39,7 +39,7 @@ struct phrase_t unsigned int translations; }; -CPhraseFile::CPhraseFile(CTranslator *pTranslator, const char *file) +CPhraseFile::CPhraseFile(Translator *pTranslator, const char *file) { m_pStringTab = pTranslator->GetStringTable(); m_pMemory = m_pStringTab->GetMemTable(); @@ -579,13 +579,13 @@ const char *CPhraseFile::GetFilename() ** MAIN TRANSLATOR CODE ** **************************/ -CTranslator::CTranslator() +Translator::Translator() { m_pStringTab = new BaseStringTable(2048); m_pLCodeLookup = sm_trie_create(); } -CTranslator::~CTranslator() +Translator::~Translator() { for (size_t i=0; i= m_Files.size()) { @@ -773,7 +773,7 @@ CPhraseFile *CTranslator::GetFileByIndex(unsigned int index) return m_Files[index]; } -size_t CTranslator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans) +size_t Translator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans) { void *new_params[MAX_TRANSLATE_PARAMS]; @@ -786,7 +786,7 @@ size_t CTranslator::Translate(char *buffer, size_t maxlength, void **params, con return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params); } -TransError CTranslator::CoreTrans(int client, +TransError Translator::CoreTrans(int client, char *buffer, size_t maxlength, const char *phrase, diff --git a/core/Translator.h b/core/Translator.h index 3138e91c..04ca914c 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -26,7 +26,7 @@ /* :TODO: write a templatized version of tries? */ using namespace SourceHook; -class CTranslator; +class Translator; enum PhraseParseState { @@ -60,7 +60,7 @@ enum TransError class CPhraseFile : public ITextListener_SMC { public: - CPhraseFile(CTranslator *pTranslator, const char *file); + CPhraseFile(Translator *pTranslator, const char *file); ~CPhraseFile(); public: void ReparseFile(); @@ -79,7 +79,7 @@ private: private: Trie *m_pPhraseLookup; String m_File; - CTranslator *m_pTranslator; + Translator *m_pTranslator; PhraseParseState m_ParseState; int m_CurPhrase; BaseMemTable *m_pMemory; @@ -91,13 +91,13 @@ private: bool m_FileLogged; }; -class CTranslator : +class Translator : public ITextListener_SMC, public SMGlobalClass { public: - CTranslator(); - ~CTranslator(); + Translator(); + ~Translator(); public: //SMGlobalClass void OnSourceModAllInitialized(); public: //ITextListener_SMC @@ -131,6 +131,6 @@ private: }; extern CPhraseFile *g_pCorePhrases; -extern CTranslator g_Translator; +extern Translator g_Translator; #endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_ diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 6e0b6f23..5687d504 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -14,14 +14,14 @@ #include "UserMessages.h" -CUserMessages g_UserMsgs; +UserMessages g_UserMsgs; SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); //:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time -CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500) +UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500) { m_Names = sm_trie_create(); m_HookCount = 0; @@ -31,29 +31,29 @@ CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500) m_CurId = INVALID_MESSAGE_ID; } -CUserMessages::~CUserMessages() +UserMessages::~UserMessages() { sm_trie_destroy(m_Names); } -void CUserMessages::OnSourceModAllInitialized() +void UserMessages::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); } -void CUserMessages::OnSourceModAllShutdown() +void UserMessages::OnSourceModAllShutdown() { if (m_HookCount) { - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); } m_HookCount = 0; } -int CUserMessages::GetMessageIndex(const char *msg) +int UserMessages::GetMessageIndex(const char *msg) { int msgid; if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid))) @@ -78,14 +78,14 @@ int CUserMessages::GetMessageIndex(const char *msg) return msgid; } -bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const +bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const { int dummy; return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy); } -bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) +bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) { bf_write *buffer; @@ -122,7 +122,7 @@ bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int return buffer; } -bool CUserMessages::EndMessage() +bool UserMessages::EndMessage() { if (!m_InExec) { @@ -143,7 +143,7 @@ bool CUserMessages::EndMessage() return true; } -bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) +bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) { if (msg_id < 0 || msg_id >= 255) { @@ -165,10 +165,10 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, if (!m_HookCount++) { - SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); - SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); - SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); - SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); } if (intercept) @@ -181,7 +181,7 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, return true; } -bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) +bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) { MsgList *pList; MsgIter iter; @@ -218,18 +218,18 @@ bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListene return deleted; } -void CUserMessages::_DecRefCounter() +void UserMessages::_DecRefCounter() { if (--m_HookCount == 0) { - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false); - SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); } } -bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type) +bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type) { bool is_intercept_empty = m_msgIntercepts[msg_type].empty(); bool is_hook_empty = m_msgHooks[msg_type].empty(); @@ -255,7 +255,7 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty RETURN_META_VALUE(MRES_IGNORED, NULL); } -bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type) +bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type) { if (!m_InHook) { @@ -267,7 +267,7 @@ bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_t RETURN_META_VALUE(MRES_IGNORED, NULL); } -void CUserMessages::OnMessageEnd_Post() +void UserMessages::OnMessageEnd_Post() { if (!m_InHook || m_BlockEndPost) { @@ -319,7 +319,7 @@ void CUserMessages::OnMessageEnd_Post() m_InHook = false; } -void CUserMessages::OnMessageEnd_Pre() +void UserMessages::OnMessageEnd_Pre() { if (!m_InHook) { diff --git a/core/UserMessages.h b/core/UserMessages.h index 5f833f7b..f900f07f 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -36,13 +36,13 @@ struct ListenerInfo typedef List MsgList; typedef List::iterator MsgIter; -class CUserMessages : +class UserMessages : public IUserMessages, public SMGlobalClass { public: - CUserMessages(); - ~CUserMessages(); + UserMessages(); + ~UserMessages(); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModAllShutdown(); @@ -80,6 +80,6 @@ private: int m_CurId; }; -extern CUserMessages g_UserMsgs; +extern UserMessages g_UserMsgs; #endif //_INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ From dc9f6e405e3170210c1bd7b4130ba0f04e296c97 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 04:45:33 +0000 Subject: [PATCH 0592/1664] fixed two spelling mistakes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40623 --- core/ConCmdManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 1fc98f81..11970155 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -837,7 +837,7 @@ void _IntExt_CallYams() { if (strcasecmp(arg, "mock") == 0) { - g_RootMenu.ConsolePrint("You mock BAILOPAN's pronounciation. In a fit of range, "); + g_RootMenu.ConsolePrint("You mock BAILOPAN's pronounciation. In a fit of rage, "); g_RootMenu.ConsolePrint("he sticks an INT 3 call into your chest, rendering you broken."); g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); g_yam_state = 0; @@ -863,7 +863,7 @@ void _IntExt_CallYams() } else if (strcasecmp(arg, "die") == 0) { g_RootMenu.ConsolePrint("For no reason, you suddenly catch fire. Alfred and Yeti find this"); g_RootMenu.ConsolePrint("deeply disturbing, and cover your flaming corpse with Episode 2"); - g_RootMenu.ConsolePrint("advertisments. Coming soon, with Team Fortress 2, and Portal!"); + g_RootMenu.ConsolePrint("advertisements. Coming soon, with Team Fortress 2, and Portal!"); g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); g_yam_state = 0; } else if (strcasecmp(arg, "spray") == 0) { From 0aadfbdfabb06cd10a378087311a97e710873739 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 20:10:25 +0000 Subject: [PATCH 0593/1664] added natives for iterating plugins and retrieving plugin info --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40624 --- core/smn_core.cpp | 212 ++++++++++++++++++++++++++++++++++ plugins/include/core.inc | 29 +++++ plugins/include/sourcemod.inc | 68 +++++++++++ 3 files changed, 309 insertions(+) diff --git a/core/smn_core.cpp b/core/smn_core.cpp index c37dbd95..d1849343 100644 --- a/core/smn_core.cpp +++ b/core/smn_core.cpp @@ -14,6 +14,36 @@ #include #include "sm_globals.h" #include "sourcemod.h" +#include "PluginSys.h" +#include "HandleSys.h" + +HandleType_t g_PlIter; + + +class CoreNativeHelpers : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + HandleAccess hacc; + g_HandleSys.InitAccessDefaults(NULL, &hacc); + hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; + + g_PlIter = g_HandleSys.CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnHandleDestroy(HandleType_t type, void *object) + { + IPluginIterator *iter = (IPluginIterator *)object; + iter->Release(); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_PlIter, g_pCoreIdent); + } +} g_CoreNativeHelpers; + static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) { @@ -40,9 +70,191 @@ static cell_t GetTime(IPluginContext *pContext, const cell_t *params) return static_cast(t); } +static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params) +{ + IPluginIterator *iter = g_PluginSys.GetPluginIterator(); + + Handle_t hndl = g_HandleSys.CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL); + + if (hndl == BAD_HANDLE) + { + iter->Release(); + } + + return hndl; +} + +static cell_t MorePlugins(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IPluginIterator *pIter; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + return pIter->MorePlugins() ? 1 : 0; +} + +static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IPluginIterator *pIter; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + CPlugin *pPlugin = (CPlugin *)pIter->GetPlugin(); + if (!pPlugin) + { + return BAD_HANDLE; + } + + pIter->NextPlugin(); + + return pPlugin->GetMyHandle(); +} + +CPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl) +{ + if (hndl == BAD_HANDLE) + { + return g_PluginSys.GetPluginByCtx(pContext->GetContext()); + } else { + HandleError err; + CPlugin *pPlugin = (CPlugin *)g_PluginSys.PluginFromHandle(hndl, &err); + if (!pPlugin) + { + pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + return pPlugin; + } +} + +static cell_t GetPluginStatus(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); + if (!pPlugin) + { + return 0; + } + + return pPlugin->GetStatus(); +} + +static cell_t GetPluginFilename(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); + if (!pPlugin) + { + return 0; + } + + pContext->StringToLocalUTF8(params[2], params[3], pPlugin->GetFilename(), NULL); + + return 1; +} + +static cell_t IsPluginDebugging(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); + if (!pPlugin) + { + return 0; + } + + return pPlugin->IsDebugging() ? 1 : 0; +} + +/* Local to plugins only */ +enum PluginInfo +{ + PlInfo_Name, /**< Plugin name */ + PlInfo_Author, /**< Plugin author */ + PlInfo_Description, /**< Plugin description */ + PlInfo_Version, /**< Plugin verison */ + PlInfo_URL, /**< Plugin URL */ +}; + +static cell_t GetPluginInfo(IPluginContext *pContext, const cell_t *params) +{ + CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); + if (!pPlugin) + { + return 0; + } + + const sm_plugininfo_t *info = pPlugin->GetPublicInfo(); + + if (!info) + { + return 0; + } + + const char *str = NULL; + + switch ((PluginInfo)params[2]) + { + case PlInfo_Name: + { + str = info->name; + break; + } + case PlInfo_Author: + { + str = info->author; + break; + } + case PlInfo_Description: + { + str = info->description; + break; + } + case PlInfo_Version: + { + str = info->version; + break; + } + case PlInfo_URL: + { + str = info->url; + break; + } + } + + if (!str || str[0] == '\0') + { + return 0; + } + + pContext->StringToLocalUTF8(params[3], params[4], str, NULL); + + return 1; +} + REGISTER_NATIVES(coreNatives) { + {"GetPluginFilename", GetPluginFilename}, + {"GetPluginInfo", GetPluginInfo}, + {"GetPluginIterator", GetPluginIterator}, + {"GetPluginStatus", GetPluginStatus}, {"GetTime", GetTime}, + {"IsPluginDebugging", IsPluginDebugging}, + {"MorePlugins", MorePlugins}, + {"ReadPlugin", ReadPlugin}, {"ThrowError", ThrowError}, {NULL, NULL}, }; diff --git a/plugins/include/core.inc b/plugins/include/core.inc index f5aed571..19843503 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -43,6 +43,35 @@ public PlVers:__version = filevers = SOURCEMOD_VERSION }; +/** + * Plugin status values. + */ +enum PluginStatus +{ + Plugin_Running=0, /**< Plugin is running */ + /* All states below are "temporarily" unexecutable */ + Plugin_Paused, /**< Plugin is loaded but paused */ + Plugin_Error, /**< Plugin is loaded but errored/locked */ + /* All states below do not have all natives */ + Plugin_Loaded, /**< Plugin has passed loading and can be finalized */ + Plugin_Failed, /**< Plugin has a fatal failure */ + Plugin_Created, /**< Plugin is created but not initialized */ + Plugin_Uncompiled, /**< Plugin is not yet compiled by the JIT */ + Plugin_BadLoad, /**< Plugin failed to load */ +}; + +/** + * Plugin information properties. + */ +enum PluginInfo +{ + PlInfo_Name, /**< Plugin name */ + PlInfo_Author, /**< Plugin author */ + PlInfo_Description, /**< Plugin description */ + PlInfo_Version, /**< Plugin verison */ + PlInfo_URL, /**< Plugin URL */ +}; + struct Extension { const String:name[], /* Short name */ diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index ba0d0a00..b6fffb69 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -108,6 +108,74 @@ forward OnGameFrame(); */ native Handle:GetMyHandle(); +/** + * Returns an iterator that can be used to search through plugins. + * + * @return Handle to iterate with. Must be closed via + * CloseHandle(). + * @error Invalid Handle. + */ +native Handle:GetPluginIterator(); + +/** + * Returns whether there are more plugins available in the iterator. + * + * @param iter Handle to the plugin iterator. + * @return True on more plugins, false otherwise. + * @error Invalid Handle. + */ +native bool:MorePlugins(Handle:iter); + +/** + * Returns the current plugin in the iterator and advances the iterator. + * + * @param iter Handle to the plugin iterator. + * @return Current plugin the iterator is at, before + * the iterator is advanced. + * @error Invalid Handle. + */ +native Handle:ReadPlugin(Handle:iter); + +/** + * Returns a plugin's status. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @return Status code for the plugin. + * @error Invalid Handle. + */ +native PluginStatus:GetPluginStatus(Handle:plugin); + +/** + * Retrieves a plugin's file name relative to the plugins folder. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @param buffer Buffer to the store the file name. + * @param maxlength Maximum length of the name buffer. + * @noreturn + * @error Invalid Handle. + */ +native GetPluginFilename(Handle:plugin, String:buffer[], maxlength); + +/** + * Retrieves whether or not a plugin is being debugged. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @return True if being debugged, false otherwise. + * @error Invalid Handle. + */ +native bool:IsPluginDebugging(Handle:hndl); + +/** + * Retrieves a plugin's public info. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @param info Plugin info property to retrieve. + * @param buffer Buffer to store info in. + * @param maxlength Maximum length of buffer. + * @return True on success, false if property is not available. + * @error Invalid Handle. + */ +native bool:GetPluginInfo(Handle:plugin, PluginInfo:info, String:buffer[], maxlength); /** * Aborts the current callback and throws an error. This function From 279c102ddc25dfc6dbf5b24036e06623d697e229 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Mar 2007 20:44:23 +0000 Subject: [PATCH 0594/1664] random touchups that might not be so great --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40625 --- plugins/include/admin.inc | 30 ++++++++++++++++++++++++------ plugins/include/clients.inc | 1 - plugins/include/console.inc | 8 ++++++-- plugins/include/core.inc | 3 +++ plugins/include/entity.inc | 4 ++++ plugins/include/events.inc | 3 +++ plugins/include/files.inc | 20 +++++++++++++------- plugins/include/float.inc | 30 +++++++++++++++++++----------- plugins/include/geoip.inc | 7 +++++-- plugins/include/handles.inc | 3 +++ plugins/include/sorting.inc | 2 +- plugins/include/sourcemod.inc | 19 +++++++++++-------- plugins/include/string.inc | 17 ++++++++--------- plugins/include/textparse.inc | 6 ++++++ plugins/include/usermessages.inc | 3 +++ plugins/include/version.inc | 8 ++++---- 16 files changed, 113 insertions(+), 51 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 6c929eb0..0e8596e9 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -47,10 +47,10 @@ enum AdminFlag /* --- */ }; -#define AdminFlags_TOTAL 21 +#define AdminFlags_TOTAL 21 /**< Total number of admin flags */ /** - * These define bitwise values for bitstrings (numbers containing bitwise flags). + * @section These define bitwise values for bitstrings (numbers containing bitwise flags). */ #define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ #define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ @@ -74,22 +74,42 @@ enum AdminFlag #define ADMFLAG_CUSTOM5 (1<<19) /**< Convenience macro for Admin_Custom5 as a FlagBit */ #define ADMFLAG_CUSTOM6 (1<<20) /**< Convenience macro for Admin_Custom6 as a FlagBit */ +/** + * @endsection + */ + +/** + * @section Hardcoded authentication methods + */ #define AUTHMETHOD_STEAM "steam" #define AUTHMETHOD_IP "ip" #define AUTHMETHOD_NAME "name" +/** + * @endsection + */ + +/** + * Override types. + */ enum OverrideType { Override_Command = 1, /* Command */ Override_CommandGroup, /* Command group */ }; +/** + * Override rules. + */ enum OverrideRule { Command_Deny = 0, Command_Allow = 1, }; +/** + * Immunity types. + */ enum ImmunityType { Immunity_Default = 1, /* Immune from everyone with no immunity */ @@ -303,8 +323,7 @@ native AdminId:CreateAdmin(const String:name[]=""); /** * Retrieves an admin's user name as made with CreateAdmin(). - * - * NOTE: This function can return UTF-8 strings, and will safely chop UTF-8 strings. + * @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. * * @param id AdminId of the admin. * @param name String buffer to store name. @@ -416,8 +435,7 @@ native AdminId:FindAdminByIdentity(const String:auth[], const String:identity[]) /** * Removes an admin entry from the cache. - * - * Note: This will remove any bindings to a specific user. + * @note This will remove any bindings to a specific user. * * @param id AdminId index to remove/invalidate. * @return True on success, false otherwise. diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 8cd04cb2..25780f25 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -254,7 +254,6 @@ native GetUserFlagBits(client); */ native bool:CanUserTarget(client, target); - /** * Creates a fake client. * diff --git a/plugins/include/console.inc b/plugins/include/console.inc index e84d68f4..fd915290 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -19,8 +19,8 @@ #define _console_included /** - * Flags for console commands and console variables - * @note The descriptions for each constant come directly from the Source SDK. + * @section Flags for console commands and console variables. The descriptions + * for each constant come directly from the Source SDK. */ #define FCVAR_NONE 0 /**< The default, no flags at all */ #define FCVAR_UNREGISTERED (1<<0) /**< If this is set, don't add to linked list, etc. */ @@ -52,6 +52,10 @@ #define FCVAR_NETWORKSYSTEM (1<<26) /**< Defined by the network system. */ #define FCVAR_VPHYSICS (1<<27) /**< Defined by vphysics. */ +/** + * @endsection + */ + /** * Executes a server command as if it were on the server console (or RCON) * diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 19843503..49a53d49 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -72,6 +72,9 @@ enum PluginInfo PlInfo_URL, /**< Plugin URL */ }; +/** + * Defines how an extension must expose itself for autoloading. + */ struct Extension { const String:name[], /* Short name */ diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 8c983636..986503ac 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -275,6 +275,10 @@ native GetEntDataVector(entity, offset, Float:vec[3]); */ native SetEntDataVector(entity, offset, const Float:vec[3], bool:changeState=false); +/** + * @endsection + */ + /** * Given a ServerClass name, finds a networkable send property offset. * This information is cached for future calls. diff --git a/plugins/include/events.inc b/plugins/include/events.inc index 349517cb..ba1f297c 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -33,6 +33,9 @@ enum EventHookMode EventHookMode_PostNoCopy /**< Hook callback fired after event is fired, but event data won't be copied */ }; +/** + * Hook function types for events. + */ funcenum EventHook { /** diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 4df1f731..dc83b13e 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -18,8 +18,11 @@ #endif #define _files_included -/* @note All paths in SourceMod natives are relative to the mod folder unless otherwise noted. */ - +/* @global All paths in SourceMod natives are relative to the mod folder unless otherwise noted. */ + +/** + * File inode types. + */ enum FileType { FileType_Unknown = 0, /* Unknown file type (device/socket) */ @@ -27,15 +30,18 @@ enum FileType FileType_File = 2, /* File is a file */ }; -#define PLATFORM_MAX_PATH 256 +#define PLATFORM_MAX_PATH 256 /**< Maximum path length. */ -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 +#define SEEK_SET 0 /**< Seek from start. */ +#define SEEK_CUR 1 /**< Seek from current position. */ +#define SEEK_END 2 /**< Seek from end position. */ +/** + * Path types. + */ enum PathType { - Path_SM, /* SourceMod root folder */ + Path_SM, /**< SourceMod root folder */ }; /** diff --git a/plugins/include/float.inc b/plugins/include/float.inc index f71ac877..4b302a37 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -19,18 +19,14 @@ #define _float_included /** - * @GLOBAL@ - * All the trigonometric functions take in or return its values in RADIANS. - * Use DegToRad or RadToDeg stocks to convert the radix units. + * Different methods of rounding. */ - -/* Different methods of rounding */ enum floatround_method { - floatround_round = 0, - floatround_floor, - floatround_ceil, - floatround_tozero + floatround_round = 0, /**< Standard IEEE rounding */ + floatround_floor, /**< Next lowest integer value. */ + floatround_ceil, /**< Next highest integer value. */ + floatround_tozero /** Closest integer to zero. */ }; /** @@ -164,10 +160,10 @@ native Float:Cosine(Float:value); native Float:Tangent(Float:value); /** - * Returns the absolute value. + * Returns an absolute value. * * @param value Input value. - * @return abs(value). + * @return Absolute value of the input. */ native Float:FloatAbs(Float:value); @@ -304,11 +300,23 @@ forward operator%(oper1, Float:oper2); #define FLOAT_PI 3.1415926535897932384626433832795 +/** + * Converts degrees to radians. + * + * @param angle Degrees. + * @return Radians. + */ stock Float:DegToRad(Float:angle) { return (angle*FLOAT_PI)/180; } +/** + * Converts degrees to radians. + * + * @param angle Radians. + * @return Degrees. + */ stock Float:RadToDeg(Float:angle) { return (angle*180)/FLOAT_PI; diff --git a/plugins/include/geoip.inc b/plugins/include/geoip.inc index 161e9210..ad28ef0f 100644 --- a/plugins/include/geoip.inc +++ b/plugins/include/geoip.inc @@ -21,8 +21,7 @@ #include /** - * @GLOBAL@ - * IP address can contain ports, the ports will be stripped out. + * @section IP addresses can contain ports, the ports will be stripped out. */ /** @@ -53,6 +52,10 @@ native GeoipCode3(const String:ip[], String:ccode[4]); */ native GeoipCountry(const String:ip[], String:name[], len=45); +/** + * @endsection + */ + /** * Do not edit below this line! */ diff --git a/plugins/include/handles.inc b/plugins/include/handles.inc index 8655c5c4..724c883a 100644 --- a/plugins/include/handles.inc +++ b/plugins/include/handles.inc @@ -18,6 +18,9 @@ #endif #define _handles_included +/** + * Handle helper macros. + */ enum Handle { INVALID_HANDLE = 0, diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc index 14f689f2..eb03b5bb 100644 --- a/plugins/include/sorting.inc +++ b/plugins/include/sorting.inc @@ -20,7 +20,7 @@ #define _sorting_included /** - * @brief Contains sorting orders. + * Contains sorting orders. */ enum SortOrder { diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index b6fffb69..41baa13b 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -18,13 +18,16 @@ #endif #define _sourcemod_included +/** + * Plugin public information. + */ struct Plugin { - const String:name[], /* Plugin Name */ - const String:description[], /* Plugin Description */ - const String:author[], /* Plugin Author */ - const String:version[], /* Plugin Version */ - const String:url[], /* Plugin URL */ + const String:name[], /**< Plugin Name */ + const String:description[], /**< Plugin Description */ + const String:author[], /**< Plugin Author */ + const String:version[], /**< Plugin Version */ + const String:url[], /**< Plugin URL */ }; #include @@ -56,7 +59,7 @@ public Plugin:myinfo; /** * Called when the plugin is fully initialized and all known external references are resolved. * This is called even if the plugin type is "private." - * NOTE: Errors in this function will cause the plugin to stop running. + * @note Errors in this function will cause the plugin to stop running. * * @noreturn */ @@ -68,8 +71,8 @@ forward OnPluginStart(); * not available at this point. Thus, this forward should only be used for explicit * pre-emptive things, such as adding dynamic natives, or setting certain types of load filters. * - * NOTE: It is not safe to call externally resolved natives until OnPluginStart(). - * NOTE: Any sort of RTE in this function will cause the plugin to fail loading. + * @note It is not safe to call externally resolved natives until OnPluginStart(). + * @note Any sort of RTE in this function will cause the plugin to fail loading. * * @param myself Handle to the plugin. * @param late Whether or not the plugin was loaded "late" (after map load). diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 6d61f7de..b8ed4180 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -19,10 +19,9 @@ #define _string_included /** - * @GLOBAL@ - * Unless otherwise noted, all string functions which take in a writable buffer and maximum length - * should have the null terminator INCLUDED in the length. This means that this is valid: - * StrCopy(string, sizeof(string), ...) + * @global Unless otherwise noted, all string functions which take in a writable buffer + * and maximum length should have the null terminator INCLUDED in the length. This means + * that this is valid: StrCopy(string, sizeof(string), ...) */ /** @@ -75,8 +74,8 @@ stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive /** * Copies one string to another string. - * NOTE: If the destination buffer is too small to hold the source string, - * the destination will be truncated. + * @note If the destination buffer is too small to hold the source string, the + * destination will be truncated. * * @param dest Destination string buffer to copy to. * @param destlen Destination buffer length (includes null terminator). @@ -99,7 +98,7 @@ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,S /** * Formats a string according to the SourceMod format rules (see documentation). * @note This is the same as Format(), except none of the input buffers can overlap the same - * memory as the output buffer. Since this security check is removed, it is slightly faster. + * memory as the output buffer. Since this security check is removed, it is slightly faster. * * @param buffer Destination string buffer. * @param maxlength Maximum length of output string buffer. @@ -112,8 +111,8 @@ native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float /** * Formats a string according to the SourceMod format rules (see documentation). * @note This is the same as Format(), except it grabs parameters from a parent parameter - * stack, rather than a local. This is useful for implementing your own variable argument - * functions. + * stack, rather than a local. This is useful for implementing your own variable + * argument functions. * * @param buffer Destination string buffer. * @param maxlength Maximum length of output string buffer. diff --git a/plugins/include/textparse.inc b/plugins/include/textparse.inc index e03cd4d6..ba302608 100644 --- a/plugins/include/textparse.inc +++ b/plugins/include/textparse.inc @@ -25,6 +25,9 @@ * The file format itself is nearly identical to Valve's KeyValues format. ********************************/ +/** + * Parse result directive. + */ enum SMCResult { SMCParse_Continue, /**< Continue parsing */ @@ -32,6 +35,9 @@ enum SMCResult SMCParse_HaltFail /**< Stop parsing and return failure */ }; +/** + * Parse error codes. + */ enum SMCError { SMCError_Okay = 0, /**< No error */ diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 29d38ed1..fbb6c1ae 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -18,6 +18,9 @@ #endif #define _eventsmsgs_included +/** + * UserMsg helper values. + */ enum UserMsg { INVALID_MESSAGE_ID = -1, diff --git a/plugins/include/version.inc b/plugins/include/version.inc index cad96bad..558a178c 100644 --- a/plugins/include/version.inc +++ b/plugins/include/version.inc @@ -18,8 +18,8 @@ #endif #define _version_included -#define SOURCEMOD_V_MAJOR 1 -#define SOURCEMOD_V_MINOR 0 -#define SOURCEMOD_V_RELEASE 0 +#define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */ +#define SOURCEMOD_V_MINOR 0 /**< SourceMod Minor version */ +#define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */ -#define SOURCEMOD_VERSION "1.0.0.577" +#define SOURCEMOD_VERSION "1.0.0.577" /**< SourceMod version string (major.minor.release.build) */ From b45b71fdd2814554520aace9b226b523f9fe27ba Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 15 Mar 2007 22:32:45 +0000 Subject: [PATCH 0595/1664] some doxygen fixes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40626 --- public/IAdminSystem.h | 7 +++++-- public/IGameConfigs.h | 6 ++++-- public/IPlayerHelpers.h | 5 +++++ public/ITimerSystem.h | 6 ++++++ public/IUserMessages.h | 4 ++-- public/sourcepawn/sp_vm_api.h | 3 +-- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index be93cbe9..ea247439 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -196,6 +196,9 @@ namespace SourceMod virtual void OnRebuildOverrideCache() =0; }; + /** + * @brief Admin permission levels. + */ typedef unsigned int FlagBits; /** @@ -487,7 +490,7 @@ namespace SourceMod * @brief Sets a password on an admin. * * @param id AdminId index of the admin. - * @param passwd String containing the password. + * @param password String containing the password. */ virtual void SetAdminPassword(AdminId id, const char *password) =0; @@ -559,7 +562,7 @@ namespace SourceMod * Note: This is a wrapper around GetAdminFlags(). * * @param id AdminId index of admin. - * @param flags Bitstring containing the permissions to check. + * @param bits Bitstring containing the permissions to check. * @return True if user has permission, false otherwise. */ virtual bool CheckAdminFlags(AdminId id, FlagBits bits) =0; diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h index 988f2824..acd5ed8f 100644 --- a/public/IGameConfigs.h +++ b/public/IGameConfigs.h @@ -22,7 +22,7 @@ #include /** - * @file IGameConfig.h + * @file IGameConfigs.h * @brief Abstracts game private data configuration. */ @@ -43,6 +43,9 @@ namespace SourceMod PropType_Data = 2, /**< Property type is a data/save property */ }; + /** + * @brief Details the property states. + */ enum PropError { PropError_Okay = 0, /**< No error */ @@ -71,7 +74,6 @@ namespace SourceMod * @brief Returns information about a dynamic offset. * * @param key Key to retrieve from the property section. - * @param value Pointer to store the offset value. Will be -1 on failure. * @return A PropError error code. */ virtual SendProp *GetSendProp(const char *key) =0; diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 92dae146..1d120a9a 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -116,6 +116,11 @@ namespace SourceMod class IClientListener { public: + /** + * @brief Returns the current client listener version. + * + * @return Client listener version. + */ virtual unsigned int GetClientListenerVersion() { return SMINTERFACE_PLAYERMANAGER_VERSION; diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index 23d19353..9a8fb89c 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -19,6 +19,12 @@ #ifndef _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ #define _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ +/** + * @file ITimerSystem.h + * @brief Contains functions for creating and managing timers. + */ + + #include #include diff --git a/public/IUserMessages.h b/public/IUserMessages.h index d3d8b775..2fe872e4 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -58,7 +58,7 @@ namespace SourceMod * * @param msg_id Message Id. * @param bf bf_write structure containing written bytes. - * @param pFtiler Recipient filter. + * @param pFilter Recipient filter. * @return Pl_Continue to allow message, Pl_Stop or Pl_Handled to scrap it. */ virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) @@ -68,7 +68,7 @@ namespace SourceMod /** * @brief Called when a hooked user message is sent, regardless of the hook type. - * @param mgs_id Message Id. + * @param msg_id Message Id. */ virtual void OnUserMessageSent(int msg_id) { diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 531eef4d..634e346d 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -833,8 +833,7 @@ namespace SourcePawn /** * @brief Destroys a fake native function wrapper. * - * @param function Pointer to the fake native created by CreateFakeNative. - * @noreturn + * @param func Pointer to the fake native created by CreateFakeNative. */ virtual void DestroyFakeNative(SPVM_NATIVE_FUNC func) =0; }; From 5fa53bfc682035f472fd7f790b0d5c76033c8485 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 06:54:24 +0000 Subject: [PATCH 0596/1664] Dear me, I should have committed this long ago... 1) Added natives to create and manipulate global and private forward 2) Added natives to call forwards and functions 3) Added an IChanageableForward::RemoveFunction overload for convenience or something 4) Added test suite plugins for functions and forwards 5) Some random touch-ups to some include files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40627 --- core/msvc8/sourcemod_mm.vcproj | 4 + core/smn_functions.cpp | 590 ++++++++++++++++++++++++++++++ core/systems/ForwardSys.cpp | 12 + core/systems/ForwardSys.h | 1 + core/vm/sp_vm_function.cpp | 5 - plugins/include/clients.inc | 2 +- plugins/include/console.inc | 6 +- plugins/include/core.inc | 8 + plugins/include/files.inc | 4 +- plugins/include/functions.inc | 289 ++++++++++++++- plugins/include/helpers.inc | 27 ++ plugins/include/sourcemod.inc | 8 +- plugins/include/string.inc | 4 +- plugins/include/usermessages.inc | 6 +- plugins/testsuite/callfunctest.sp | 104 ++++++ plugins/testsuite/fwdtest1.sp | 169 +++++++++ plugins/testsuite/fwdtest2.sp | 43 +++ public/IForwardSys.h | 10 + 18 files changed, 1268 insertions(+), 24 deletions(-) create mode 100644 core/smn_functions.cpp create mode 100644 plugins/testsuite/callfunctest.sp create mode 100644 plugins/testsuite/fwdtest1.sp create mode 100644 plugins/testsuite/fwdtest2.sp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 16c50aef..0e4575de 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -725,6 +725,10 @@ RelativePath="..\smn_float.cpp" > + + diff --git a/core/smn_functions.cpp b/core/smn_functions.cpp new file mode 100644 index 00000000..b0f9154e --- /dev/null +++ b/core/smn_functions.cpp @@ -0,0 +1,590 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "sm_globals.h" +#include "PluginSys.h" +#include "ForwardSys.h" +#include "HandleSys.h" + +HandleType_t g_GlobalFwdType = 0; +HandleType_t g_PrivateFwdType = 0; + +static bool s_CallStarted = false; +static ICallable *s_pCallable = NULL; +static IPluginFunction *s_pFunction = NULL; +static IForward *s_pForward = NULL; + +class ForwardNativeHelpers : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + HandleAccess sec; + + /* Set GlobalFwd handle access security */ + g_HandleSys.InitAccessDefaults(NULL, &sec); + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + /* Create 'GlobalFwd' handle type */ + g_GlobalFwdType = g_HandleSys.CreateType("GlobalFwd", this, 0, NULL, &sec, g_pCoreIdent, NULL); + + /* Private forwards are cloneable */ + sec.access[HandleAccess_Clone] = 0; + + /* Create 'PrivateFwd' handle type */ + g_PrivateFwdType = g_HandleSys.CreateType("PrivateFwd", this, g_GlobalFwdType, NULL, &sec, g_pCoreIdent, NULL); + } + + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_PrivateFwdType, g_pCoreIdent); + g_HandleSys.RemoveType(g_GlobalFwdType, g_pCoreIdent); + } + + void OnHandleDestroy(HandleType_t type, void *object) + { + IForward *pForward = static_cast(object); + + g_Forwards.ReleaseForward(pForward); + } +} g_ForwardNativeHelpers; + + +/* Turn a public index into a function ID */ +inline funcid_t PublicIndexToFuncId(uint32_t idx) +{ + return (idx << 1) | (1 << 0); +} + +/* Reset global function/forward call variables */ +inline void ResetCall() +{ + s_CallStarted = false; + s_pFunction = NULL; + s_pCallable = NULL; +} + +static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + char *name; + uint32_t idx; + IPlugin *pPlugin; + + if (hndl == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + pPlugin = g_PluginSys.PluginFromHandle(hndl, &err); + + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err); + } + } + + pContext->LocalToString(params[2], &name); + + /* Get public function index */ + if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND) + { + /* Return INVALID_FUNCTION if not found */ + return -1; + } + + /* Return function ID */ + return PublicIndexToFuncId(idx); +} + +static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *params) +{ + cell_t count = params[0]; + char *name; + ParamType forwardParams[SP_MAX_EXEC_PARAMS]; + + if (count - 2 > SP_MAX_EXEC_PARAMS) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL); + } + + pContext->LocalToString(params[1], &name); + + cell_t *addr; + for (int i = 3; i <= count; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + forwardParams[i - 3] = static_cast(*addr); + } + + IForward *pForward = g_Forwards.CreateForward(name, static_cast(params[2]), count - 2, forwardParams); + + return g_HandleSys.CreateHandle(g_GlobalFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t sm_CreateForward(IPluginContext *pContext, const cell_t *params) +{ + cell_t count = params[0]; + ParamType forwardParams[SP_MAX_EXEC_PARAMS]; + + if (count - 1 > SP_MAX_EXEC_PARAMS) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL); + } + + cell_t *addr; + for (int i = 2; i <= count; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + forwardParams[i - 2] = static_cast(*addr); + } + + IChangeableForward *pForward = g_Forwards.CreateForwardEx(NULL, static_cast(params[1]), count - 1, forwardParams); + + return g_HandleSys.CreateHandle(g_PrivateFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t sm_GetForwardFunctionCount(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + IForward *pForward; + + if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err); + } + + return pForward->GetFunctionCount(); +} + +static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params) +{ + Handle_t fwdHandle = static_cast(params[1]); + Handle_t plHandle = static_cast(params[2]); + HandleError err; + IChangeableForward *pForward; + IPlugin *pPlugin; + + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err); + } + + if (plHandle == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err); + + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err); + } + } + + IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[3]); + } + + return pForward->AddFunction(pFunction); +} + +static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params) +{ + Handle_t fwdHandle = static_cast(params[1]); + Handle_t plHandle = static_cast(params[2]); + HandleError err; + IChangeableForward *pForward; + IPlugin *pPlugin; + + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err); + } + + if (plHandle == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err); + + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err); + } + } + + IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[3]); + } + + return pForward->RemoveFunction(pFunction); +} + +static cell_t sm_RemoveAllFromForward(IPluginContext *pContext, const cell_t *params) +{ + Handle_t fwdHandle = static_cast(params[1]); + Handle_t plHandle = static_cast(params[2]); + HandleError err; + IChangeableForward *pForward; + IPlugin *pPlugin; + + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err); + } + + if (plHandle == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err); + + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err); + } + } + + return pForward->RemoveFunctionsOfPlugin(pPlugin); +} + +static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl; + HandleError err; + IPlugin *pPlugin; + + if (s_CallStarted) + { + return pContext->ThrowNativeError("Cannot start a call while one is already in progress"); + } + + hndl = static_cast(params[1]); + + if (hndl == 0) + { + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + } else { + pPlugin = g_PluginSys.PluginFromHandle(hndl, &err); + + if (!pPlugin) + { + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err); + } + } + + s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]); + + if (!s_pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + s_pCallable = static_cast(s_pFunction); + + s_CallStarted = true; + + return 1; +} + +static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl; + HandleError err; + IForward *pForward; + + if (s_CallStarted) + { + return pContext->ThrowNativeError("Cannot start a call while one is already in progress"); + } + + hndl = static_cast(params[1]); + + if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err); + } + + s_pForward = pForward; + + s_pCallable = static_cast(pForward); + + s_CallStarted = true; + + return 1; +} + +static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params) +{ + int err; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + err = s_pCallable->PushCell(params[1]); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushCellRef(IPluginContext *pContext, const cell_t *params) +{ + int err; + cell_t *addr; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToPhysAddr(params[1], &addr); + + err = s_pCallable->PushCellByRef(addr); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushFloat(IPluginContext *pContext, const cell_t *params) +{ + int err; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + err = s_pCallable->PushFloat(sp_ctof(params[1])); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushFloatRef(IPluginContext *pContext, const cell_t *params) +{ + int err; + cell_t *addr; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToPhysAddr(params[1], &addr); + + err = s_pCallable->PushFloatByRef(reinterpret_cast(addr)); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushArray(IPluginContext *pContext, const cell_t *params) +{ + int err; + cell_t *addr; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToPhysAddr(params[1], &addr); + + err = s_pCallable->PushArray(addr, params[2], NULL); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushArrayEx(IPluginContext *pContext, const cell_t *params) +{ + int err; + cell_t *addr; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToPhysAddr(params[1], &addr); + + err = s_pCallable->PushArray(addr, params[2], params[3]); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushString(IPluginContext *pContext, const cell_t *params) +{ + int err; + char *value; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToString(params[1], &value); + + err = s_pCallable->PushString(value); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params) +{ + int err; + char *value; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress"); + } + + pContext->LocalToString(params[1], &value); + + err = s_pCallable->PushStringEx(value, params[2], params[3], params[4]); + + if (err) + { + s_pCallable->Cancel(); + ResetCall(); + return pContext->ThrowNativeErrorEx(err, NULL); + } + + return 1; +} + +static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params) +{ + int err; + cell_t *result; + + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot finish call when there is no call in progress"); + } + + pContext->LocalToPhysAddr(params[1], &result); + + if (s_pFunction) + { + IPluginFunction *pFunction = s_pFunction; + err = pFunction->Execute(result); + } else if (s_pForward) { + IForward *pForward = s_pForward; + err = pForward->Execute(result, NULL); + } + + ResetCall(); + + return err; +} + +static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params) +{ + if (!s_CallStarted) + { + return pContext->ThrowNativeError("Cannot cancel call when there is no call in progress"); + } + + s_pCallable->Cancel(); + ResetCall(); + + return 1; +} + +REGISTER_NATIVES(functionNatives) +{ + {"GetFunctionByName", sm_GetFunctionByName}, + {"CreateGlobalForward", sm_CreateGlobalForward}, + {"CreateForward", sm_CreateForward}, + {"GetForwardFunctionCount", sm_GetForwardFunctionCount}, + {"AddToForward", sm_AddToForward}, + {"RemoveFromForward", sm_RemoveFromForward}, + {"RemoveAllFromForward", sm_RemoveAllFromForward}, + {"Call_StartFunction", sm_CallStartFunction}, + {"Call_StartForward", sm_CallStartForward}, + {"Call_PushCell", sm_CallPushCell}, + {"Call_PushCellRef", sm_CallPushCellRef}, + {"Call_PushFloat", sm_CallPushFloat}, + {"Call_PushFloatRef", sm_CallPushFloatRef}, + {"Call_PushArray", sm_CallPushArray}, + {"Call_PushArrayEx", sm_CallPushArrayEx}, + {"Call_PushString", sm_CallPushString}, + {"Call_PushStringEx", sm_CallPushStringEx}, + {"Call_Finish", sm_CallFinish}, + {"Call_Cancel", sm_CallCancel}, + {NULL, NULL}, +}; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index ae18abdf..f0ef70c6 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -601,6 +601,18 @@ bool CForward::AddFunction(IPluginContext *pContext, funcid_t index) return AddFunction(pFunc); } +bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index) +{ + IPluginFunction *pFunc = pContext->GetFunctionById(index); + + if (!pFunc) + { + return false; + } + + return RemoveFunction(pFunc); +} + bool CForward::RemoveFunction(IPluginFunction *func) { bool found = false; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index b1d8703a..77d798c6 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -64,6 +64,7 @@ public: //IChangeableForward virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin); virtual bool AddFunction(IPluginFunction *func); virtual bool AddFunction(IPluginContext *ctx, funcid_t index); + virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index); public: static CForward *CreateForward(const char *name, ExecType et, diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 3bd995f6..58abee22 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -81,11 +81,6 @@ int CFunction::PushCell(cell_t cell) int CFunction::PushCellByRef(cell_t *cell, int flags) { - if (m_curparam >= SP_MAX_EXEC_PARAMS) - { - return SetError(SP_ERROR_PARAMS_MAX); - } - return PushArray(cell, 1, flags); } diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 25780f25..c01150dd 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -272,4 +272,4 @@ native CreateFakeClient(const String:name[]); * @error Invalid client index, client not connected, * or client not a fake client. */ -native SetFakeClientConVar(client, const String:cvar[], const String:value[]); \ No newline at end of file +native SetFakeClientConVar(client, const String:cvar[], const String:value[]); diff --git a/plugins/include/console.inc b/plugins/include/console.inc index fd915290..dcebe2e7 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -91,7 +91,7 @@ native ServerExecute(); * @noreturn * @error Invalid client index, or client not connected. */ -native ClientCommand(client, const String:fmt[], {String,Float,Handle,_}:...); +native ClientCommand(client, const String:fmt[], {String,Float,Handle,Function,_}:...); /** * Sends a message to the server console. @@ -100,7 +100,7 @@ native ClientCommand(client, const String:fmt[], {String,Float,Handle,_}:...); * @param ... Variable number of format parameters. * @noreturn */ -native PrintToServer(const String:format[], {Handle,Float,String,_}:...); +native PrintToServer(const String:format[], {Handle,Float,String,Function,_}:...); /** * Sends a message to a client's console. @@ -111,7 +111,7 @@ native PrintToServer(const String:format[], {Handle,Float,String,_}:...); * @noreturn * @error If the client is not connected an error will be thrown. */ -native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...); +native PrintToConsole(client, const String:format[], {Handle,Float,String,Function,_}:...); /** * Called when a server-only command is invoked. diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 49a53d49..9e2272d3 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -27,6 +27,14 @@ struct PlVers String:filevers[], }; +/** + * Function helper values + */ +enum Function +{ + INVALID_FUNCTION = -1, +}; + /** * Specifies what to do after a hook completes. */ diff --git a/plugins/include/files.inc b/plugins/include/files.inc index dc83b13e..9fdb5406 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -54,7 +54,7 @@ enum PathType * @param ... Format arguments. * @return Number of bytes written to buffer (not including null terminator). */ -native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], ...); +native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,Function,_}:...); /** * @brief Opens a directory/folder for contents enumeration. @@ -186,4 +186,4 @@ native bool:RemoveDir(const String:path[]); * @param ... Variable number of format parameters. * @return True on success, false otherwise. */ -native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,_}:...); +native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,Function,_}:...); diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index 2cea70a0..bc0bf255 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -13,6 +13,48 @@ * Version: $Id$ */ +#define SP_PARAMFLAG_BYREF (1<<0) /**< Internal use only. */ + +/** + * Describes the various ways to pass parameters to functions or forwards. + */ +enum ParamType +{ + Param_Any = 0, /**< Any data type can be pushed */ + Param_Cell = (1<<1), /**< Only basic cells can be pushed */ + Param_Float = (2<<1), /**< Only floats can be pushed */ + Param_String = (3<<1)|SP_PARAMFLAG_BYREF, /**< Only strings can be pushed */ + Param_Array = (4<<1)|SP_PARAMFLAG_BYREF, /**< Only arrays can be pushed */ + Param_VarArgs = (5<<1), /**< Same as "..." in plugins, anything can be pushed, but it will always be byref */ + Param_CellByRef = (1<<1)|SP_PARAMFLAG_BYREF, /**< Only a cell by reference can be pushed */ + Param_FloatByRef = (2<<1)|SP_PARAMFLAG_BYREF /**< Only a float by reference can be pushed */ +}; + +/** + * Defines how a forward iterates through plugin functions. + */ +enum ExecType +{ + ET_Ignore = 0, /**< Ignore all return values, return 0 */ + ET_Single = 1, /**< Only return the last exec, ignore all others */ + ET_Event = 2, /**< Acts as an event with the Actions defined in core.inc, no mid-Stops allowed, returns highest */ + ET_Hook = 3 /**< Acts as a hook with the Actions defined in core.inc, mid-Stops allowed, returns highest */ +}; + +/** + * @section Flags that are used with Call_PushArrayEx() and Call_PushStringEx() + */ +#define SM_PARAM_COPYBACK (1<<0) /**< Copy an array/reference back after call */ +#define SM_PARAM_STRING_UTF8 (1<<0) /**< String should be UTF-8 handled */ +#define SM_PARAM_STRING_COPY (1<<1) /**< String should be copied into the plugin */ + +/** + * @endsection + */ + +/** + * @section Error codes + */ #define SP_ERROR_NONE 0 /**< No error occurred */ #define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */ #define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */ @@ -40,6 +82,243 @@ #define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ #define SP_ERROR_ABORTED 25 /**< Function call was aborted */ +/** + * @endsection + */ + +/** + * Gets a function id from a function name. + * + * @param plugin Handle of the plugin that contains the function. + Pass INVALID_HANDLE to search in the calling plugin. + * @param name Name of the function. + * @return Function id or INVALID_FUNCTION if not found. + * @error Invalid or corrupt plugin handle. + */ +native Function:GetFunctionByName(Handle:plugin, const String:name[]); + +/** + * Creates a global forward. + * + * @note The name used to create the forward is used as its public function in all target plugins. + * @note This is ideal for global, static forwards that are never changed. + * + * @param name Name of public function to use in forward. + * @param type Execution type to be used. + * @param ... Variable number of parameter types (up to 32). + * @return Handle to new global forward. + * @error More than 32 paramater types passed. + */ +native Handle:CreateGlobalForward(const String:name[], ExecType:type, {ParamType}:...); + +/** + * Creates a private forward. + * + * @note No functions are automatically added. Use AddToForward() to do this. + * + * @param type Execution type to be used. + * @param ... Variable number of parameter types (up to 32). + * @return Handle to new private forward. + * @error More than 32 paramater types passed. + */ +native Handle:CreateForward(ExecType:type, {ParamType}:...); + +/** + * Returns the number of functions in a global or private forward's call list. + * + * @param fwd Handle to global or private forward. + * @return Number of functions in forward. + * @error Invalid or corrupt forward handle. + */ +native GetForwardFunctionCount(Handle:fwd); + +/** + * Adds a function to a private forward's call list. + * + * @note Cannot be used during an incompleted call. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to add to forward. + * @return True on success, false otherwise. + * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. + */ +native bool:AddToForward(Handle:fwd, Handle:plugin, Function:func); + +/** + * Removes a function from a private forward's call list. + * + * @note Only removes one instance. + * @note Functions will be removed automatically if their parent plugin is unloaded. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to remove from forward. + * @return True on success, false otherwise. + * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. + */ +native bool:RemoveFromForward(Handle:fwd, Handle:plugin, Function:func); + +/** + * Removes all instances of a plugin from a private forward's call list. + * + * @note Functions will be removed automatically if their parent plugin is unloaded. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin to remove instances of. + * Pass INVALID_HANDLE to specify the calling plugin. + * @return Number of functions removed from forward. + * @error Invalid or corrupt private forward handle or invalid or corrupt plugin handle. + */ +native RemoveAllFromForward(Handle:fwd, Handle:plugin); + +/** + * Starts a call to functions in a forward's call list. + * + * @note Cannot be used during an incompleted call. + * + * @param fwd Handle to global or private forward. + * @noreturn + * @error Invalid or corrupt forward handle or called before another call has completed. + */ +native Call_StartForward(Handle:fwd); + +/** + * Starts a call to a function. + * + * @note Cannot be used during an incompleted call. + * + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to call. + * @noreturn + * @error Invalid or corrupt plugin handle, invalid function, or called before another call has completed. + */ +native Call_StartFunction(Handle:plugin, Function:func); + +/** + * Pushes a cell onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Cell value to push. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushCell({Handle,Function,_}:value); + +/** + * Pushes a cell by reference onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Cell reference to push. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushCellRef(&{Handle,Function,_}:value); + + +/** + * Pushes a float onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Floating point value to push. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushFloat(Float:value); + +/** + * Pushes a float by reference onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Floating point reference to push. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushFloatRef(&Float:value); + +/** + * Pushes an array onto the current call. + * + * @note Changes to array are not copied back to caller. Use PushArrayEx() to do this. + * @note Cannot be used before a call has been started. + * + * @param value Array to push. + * @param size Size of array. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushArray(const {Handle,Float,Function,_}:value[], size); + +/** + * Pushes an array onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Array to push. + * @param size Size of array. + * @param cpflags Whether or not changes should be copied back to the input array. + * See SP_PARAM_* constants for details. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushArrayEx({Handle,Float,Function,_}:value[], size, cpflags); + +/** + * Pushes a string onto the current call. + * + * @note Changes to string are not copied back to caller. Use PushStringEx() to do this. + * @note Cannot be used before a call has been started. + * + * @param value String to push. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushString(const String:value[]); + +/** + * Pushes a string onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value String to push. + * @param length Length of string buffer. + * @param szflags Flags determining how string should be handled. + * See SP_PARAM_STRING_* constants for details. + * @param cpflags Whether or not changes should be copied back to the input array. + * See SP_PARAM_* constants for details. + * @noreturn + * @error Called before a call has been started. + */ +native Call_PushStringEx(String:value[], length, szflags, cpflags); + +/** + * Completes a call to a function or forward's call list. + * + * @note Cannot be used before a call has been started. + * + * @param result Return value of function or forward's call list. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Called before a call has been started. + */ +native Call_Finish(&result); + +/** + * Cancels a call to a function or forward's call list. + * + * @note Cannot be used before a call has been started. + * + * @noreturn + * @error Called before a call has been started. + */ +native Call_Cancel(); + /** * Defines a native function. * @@ -69,7 +348,7 @@ native CreateNative(const String:name[], NativeCall:func); * @param fmt Error message format. * @param ... Format arguments. */ -native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...); +native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,Function,_}:...); /** * Retrieves the string length from a native parameter string. This is useful @@ -78,7 +357,7 @@ native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...); * * @param param Parameter number, starting from 1. * @param length Stores the length of the string. - * @return SP_ERROR_NONE on sucecss, any other integer on failure. + * @return SP_ERROR_NONE on success, any other integer on failure. * @error Invalid parameter number or calling from a non-native function. */ native GetNativeStringLength(param, &length); @@ -137,7 +416,7 @@ native GetNativeCellRef(param); * @noreturn * @error Invalid parameter number or calling from a non-native function. */ -native SetNativeCellRef(param, {Float,Handle,_}:value); +native SetNativeCellRef(param, {Float,Function,Handle,_}:value); /** * Gets an array from a native parameter (always by reference). @@ -148,7 +427,7 @@ native SetNativeCellRef(param, {Float,Handle,_}:value); * @return SP_ERROR_NONE on success, anything else on failure. * @error Invalid parameter number or calling from a non-native function. */ -native GetNativeArray(param, {Float,Handle,_}:local[], size); +native GetNativeArray(param, {Float,Function,Handle,_}:local[], size); /** * Copies a local array into a native parameter array (always by reference). @@ -159,7 +438,7 @@ native GetNativeArray(param, {Float,Handle,_}:local[], size); * @return SP_ERROR_NONE on success, anything else on failure. * @error Invalid parameter number or calling from a non-native function. */ -native SetNativeArray(param, const {Float,Handle,_}:local[], size); +native SetNativeArray(param, const {Float,Function,Handle,_}:local[], size); /** * Formats a string using parameters from a native. diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc index 61fd8f82..e33e2f58 100644 --- a/plugins/include/helpers.inc +++ b/plugins/include/helpers.inc @@ -44,3 +44,30 @@ stock FormatUserLogText(client, String:buffer[], maxlength) Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth); } + +/** + * Returns plugin handle from plugin filename. + * + * @param filename Filename of the plugin to search for. + * @Returns Handle to plugin if found, INVALID_HANDLE otherwise. + */ +stock Handle:FindPluginByFile(const String:filename[]) +{ + decl String:buffer[256]; + + new Handle:iter = GetPluginIterator(); + new Handle:pl; + + while (MorePlugins(iter)) + { + pl = ReadPlugin(iter); + + GetPluginFilename(pl, buffer, sizeof(buffer)); + if (StrCompare(buffer, filename) == 0) + { + return pl; + } + } + + return INVALID_HANDLE; +} diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 41baa13b..782512a8 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -189,7 +189,7 @@ native bool:GetPluginInfo(Handle:plugin, PluginInfo:info, String:buffer[], maxle * @noreturn * @error Always! */ -native ThrowError(const String:fmt[], {Handle,Float,String,_}:...); +native ThrowError(const String:fmt[], {Handle,Float,String,Function,_}:...); /** * Logs a generic message to the HL2 logs. @@ -198,7 +198,7 @@ native ThrowError(const String:fmt[], {Handle,Float,String,_}:...); * @param ... Format arguments. * @noreturn */ -native LogToGame(const String:format[], {Handle,Float,String,_}:...); +native LogToGame(const String:format[], {Handle,Float,String,Function,_}:...); /** * Logs a plugin message to the SourceMod logs. @@ -207,7 +207,7 @@ native LogToGame(const String:format[], {Handle,Float,String,_}:...); * @param ... Format arguments. * @noreturn */ -native LogMessage(const String:format[], {Handle,Float,String,_}:...); +native LogMessage(const String:format[], {Handle,Float,String,Function,_}:...); /** * Logs a plugin error message to the SourceMod logs. @@ -216,7 +216,7 @@ native LogMessage(const String:format[], {Handle,Float,String,_}:...); * @param ... Format arguments. * @noreturn */ -native LogError(const String:format[], {Handle,Float,String,_}:...); +native LogError(const String:format[], {Handle,Float,String,Function,_}:...); /** * Gets the system time as a unix timestamp. diff --git a/plugins/include/string.inc b/plugins/include/string.inc index b8ed4180..9dee3579 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -93,7 +93,7 @@ native StrCopy(String:dest[], destLen, const String:source[]); * @param ... Variable number of format parameters. * @return Number of cells written. */ -native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); +native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...); /** * Formats a string according to the SourceMod format rules (see documentation). @@ -106,7 +106,7 @@ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,S * @param ... Variable number of format parameters. * @return Number of cells written. */ -native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...); +native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...); /** * Formats a string according to the SourceMod format rules (see documentation). diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index fbb6c1ae..41909fda 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -57,11 +57,12 @@ native bool:GetUserMessageName(UserMsg:msg_id, String:msg[], maxlength); * @param msgname Message name to start. * @param clients Array containing player indexes to broadcast to. * @param numClients Number of players in the array. + * @param flags Optional flags to set. * @return A handle to a bf_write bit packing structure, or * INVALID_HANDLE on failure. * @error Invalid message name or unable to start a message. */ -native Handle:StartMessage(String:msgname[], clients[], numClients, flags); +native Handle:StartMessage(String:msgname[], clients[], numClients, flags=0); /** * Starts a usermessage (network message). @@ -71,11 +72,12 @@ native Handle:StartMessage(String:msgname[], clients[], numClients, flags); * @param msg Message index to start. * @param clients Array containing player indexes to broadcast to. * @param numClients Number of players in the array. + * @param flags Optional flags to set. * @return A handle to a bf_write bit packing structure, or * INVALID_HANDLE on failure. * @error Invalid message name or unable to start a message. */ -native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags); +native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags=0); /** * Ends a previously started user message (network message). diff --git a/plugins/testsuite/callfunctest.sp b/plugins/testsuite/callfunctest.sp new file mode 100644 index 00000000..93bc379b --- /dev/null +++ b/plugins/testsuite/callfunctest.sp @@ -0,0 +1,104 @@ +#include + +public Plugin:myinfo = +{ + name = "Function Call Testing Lab", + author = "AlliedModders LLC", + description = "Tests basic function calls", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public OnPluginStart() +{ + RegServerCmd("test_callfunc", Command_CallFunc); +} + +public OnCallFuncReceived(num, Float:fnum, String:str[], String:str2[], &val, &Float:fval, array[], array2[], size, hello2[1]) +{ + PrintToServer("Inside OnCallFuncReceived..."); + + PrintToServer("num = %d (expected: %d)", num, 5); + PrintToServer("fnum = %f (expected: %f)", fnum, 7.17); + PrintToServer("str[] = \"%s\" (expected: \"%s\")", str, "Gaben"); + PrintToServer("str2[] = \"%s\" (expected: \"%s\")", str2, ".taf si nebaG"); + + PrintToServer("val = %d (expected %d, setting to %d)", val, 62, 15); + val = 15; + + PrintToServer("fval = %f (expected: %f, setting to %f)", fval, 6.25, 1.5); + fval = 1.5; + + PrintToServer("Printing %d elements of array[] (expected: %d)", size, 6); + for (new i = 0; i < size; i++) + { + PrintToServer("array[%d] = %d (expected: %d)", i, array[i], i); + } + for (new i = 0; i < size; i++) + { + PrintToServer("array2[%d] = %d (expected: %d)", i, array[i], i); + } + + /* This shouldn't get copied back */ + StrCopy(str, strlen(str) + 1, "Yeti"); + /* This should get copied back */ + StrCopy(str2, strlen(str2) + 1, "Gaben is fat."); + + /* This should get copied back */ + array[0] = 5; + array[1] = 6; + /* This shouldn't get copied back */ + hello2[0] = 25; + + return 42; +} + +public Action:Command_CallFunc(args) +{ + new a = 62; + new Float:b = 6.25; + new const String:what[] = "Gaben"; + new String:truth[] = ".taf si nebaG"; + new hello[] = {0, 1, 2, 3, 4, 5}; + new hello2[] = {9}; + new pm = 6; + new err; + new ret; + + new Function:func = GetFunctionByName(INVALID_HANDLE, "OnCallFuncReceived"); + + if (func == INVALID_FUNCTION) + { + PrintToServer("Failed to get the function id of OnCallFuncReceived"); + return Plugin_Handled; + } + + PrintToServer("Calling OnCallFuncReceived..."); + + Call_StartFunction(INVALID_HANDLE, func); + Call_PushCell(5); + Call_PushFloat(7.17); + Call_PushString(what); + Call_PushStringEx(truth, sizeof(truth), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); + Call_PushCellRef(a); + Call_PushFloatRef(b); + Call_PushArrayEx(hello, pm, SM_PARAM_COPYBACK); + Call_PushArray(hello, pm); + Call_PushCell(pm); + Call_PushArray(hello2, 1); + err = Call_Finish(ret); + + PrintToServer("Call to OnCallFuncReceived has finished!"); + PrintToServer("Error code = %d (expected: %d)", err, 0); + PrintToServer("Return value = %d (expected: %d)", ret, 42); + + PrintToServer("a = %d (expected: %d)", a, 15); + PrintToServer("b = %f (expected: %f)", b, 1.5); + PrintToServer("what = \"%s\" (expected: \"%s\")", what, "Gaben"); + PrintToServer("truth = \"%s\" (expected: \"%s\")", truth, "Gaben is fat."); + PrintToServer("hello[0] = %d (expected: %d)", hello[0], 5); + PrintToServer("hello[1] = %d (expected: %d)", hello[1], 6); + PrintToServer("hello2[0] = %d (expected: %d)", hello2[0], 9); + + return Plugin_Handled; +} diff --git a/plugins/testsuite/fwdtest1.sp b/plugins/testsuite/fwdtest1.sp new file mode 100644 index 00000000..29dc4ce0 --- /dev/null +++ b/plugins/testsuite/fwdtest1.sp @@ -0,0 +1,169 @@ +#include + +public Plugin:myinfo = +{ + name = "Forward Testing Lab #1", + author = "AlliedModders LLC", + description = "Tests suite #1 for forwards created by plugins", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +new Handle:g_GlobalFwd = INVALID_HANDLE; +new Handle:g_PrivateFwd = INVALID_HANDLE; + +public OnPluginStart() +{ + PrintToServer("OnPluginStart: %d", OnPluginStart); + + RegServerCmd("test_create_gforward", Command_CreateGlobalForward); + RegServerCmd("test_create_pforward", Command_CreatePrivateForward); + RegServerCmd("test_exec_gforward", Command_ExecGlobalForward); + RegServerCmd("test_exec_pforward", Command_ExecPrivateForward); +} + +public OnPluginEnd() +{ + CloseHandle(g_GlobalFwd); + CloseHandle(g_PrivateFwd); +} + +public Action:Command_CreateGlobalForward(args) +{ + if (g_GlobalFwd != INVALID_HANDLE) + { + CloseHandle(g_GlobalFwd); + } + + g_GlobalFwd = CreateGlobalForward("OnGlobalForward", ET_Ignore, Param_Any, Param_Cell, Param_Float, Param_String, Param_Array, Param_CellByRef, Param_FloatByRef); + + if (g_GlobalFwd == INVALID_HANDLE) + { + PrintToServer("Failed to create global forward!"); + } + + return Plugin_Handled; +} + +public Action:Command_CreatePrivateForward(args) +{ + new Handle:pl; + new Function:func; + + if (g_PrivateFwd != INVALID_HANDLE) + { + CloseHandle(g_PrivateFwd); + } + + g_PrivateFwd = CreateForward(ET_Hook, Param_Cell, Param_String, Param_VarArgs); + + if (g_PrivateFwd == INVALID_HANDLE) + { + PrintToServer("Failed to create private forward!") + } + + pl = FindPluginByFile("fwdtest2.smx"); + + if (!pl) + { + PrintToServer("Could not find fwdtest2.smx!"); + return Plugin_Handled; + } + + func = GetFunctionByName(pl, "OnPrivateForward"); + + /* This shouldn't happen, but oh well */ + if (func == INVALID_FUNCTION) + { + PrintToServer("Could not find \"OnPrivateForward\" in fwdtest2.smx!"); + return Plugin_Handled; + } + + if (!AddToForward(g_PrivateFwd, pl, func) || !AddToForward(g_PrivateFwd, GetMyHandle(), ZohMyGod)) + { + PrintToServer("Failed to add functions to private forward!"); + return Plugin_Handled; + } + + return Plugin_Handled; +} + +public Action:Command_ExecGlobalForward(args) +{ + new a = 99; + new Float:b = 4.215; + new err, ret; + + if (g_GlobalFwd == INVALID_HANDLE) + { + PrintToServer("Failed to execute global forward. Create it first."); + return Plugin_Handled; + } + + PrintToServer("Beginning call to %d functions in global forward \"OnGlobalForward\"", GetForwardFunctionCount(g_GlobalFwd)); + + Call_StartForward(g_GlobalFwd); + Call_PushCell(OnPluginStart); + Call_PushCell(7); + Call_PushFloat(-8.5); + Call_PushString("Anata wa doko desu ka?"); + Call_PushArray({0.0, 1.1, 2.2}, 3); + Call_PushCellRef(a); + Call_PushFloatRef(b); + err = Call_Finish(ret); + + PrintToServer("Call to global forward \"OnGlobalForward\" completed"); + PrintToServer("Error code = %d (expected: %d)", err, 0); + PrintToServer("Return value = %d (expected: %d)", ret, Plugin_Continue); + + PrintToServer("a = %d (expected: %d)", a, 777); + PrintToServer("b = %f (expected: %f)", b, -0.782); + + return Plugin_Handled; +} + +public Action:Command_ExecPrivateForward(args) +{ + new err, ret; + + if (g_PrivateFwd == INVALID_HANDLE) + { + PrintToServer("Failed to execute private forward. Create it first."); + return Plugin_Handled; + } + + PrintToServer("Beginning call to %d functions in private forward", GetForwardFunctionCount(g_PrivateFwd)); + + Call_StartForward(g_PrivateFwd); + Call_PushCell(24); + Call_PushString("I am a format string: %d %d %d %d %d %d"); + Call_PushCell(0); + Call_PushCell(1); + Call_PushCell(2); + Call_PushCell(3); + Call_PushCell(4); + Call_PushCell(5); + err = Call_Finish(ret); + + PrintToServer("Call to private forward completed"); + PrintToServer("Error code = %d (expected: %d)", err, 0); + PrintToServer("Return value = %d (expected: %d)", ret, Plugin_Handled); + + return Plugin_Handled; +} + +public Action:ZohMyGod(num, const String:format[], ...) +{ + decl String:buffer[128]; + + PrintToServer("Inside private forward #1"); + + PrintToServer("num = %d (expected: %d)", num, 24); + + VFormat(buffer, sizeof(buffer), format, 3); + PrintToServer("buffer = \"%s\" (expected: \"%s\")", buffer, "I am a format string: 0 1 2 3 4 5"); + + PrintToServer("End private forward #1"); + + return Plugin_Continue; +} diff --git a/plugins/testsuite/fwdtest2.sp b/plugins/testsuite/fwdtest2.sp new file mode 100644 index 00000000..a979eb68 --- /dev/null +++ b/plugins/testsuite/fwdtest2.sp @@ -0,0 +1,43 @@ +#include + +public Plugin:myinfo = +{ + name = "Forward Testing Lab #2", + author = "AlliedModders LLC", + description = "Tests suite #2 for forwards created by plugins", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public Action:OnPrivateForward(num, const String:format[], ...) +{ + decl String:buffer[128]; + + PrintToServer("Inside private forward #2"); + + PrintToServer("num = %d (expected: %d)", num, 24); + + VFormat(buffer, sizeof(buffer), format, 3); + PrintToServer("buffer = \"%s\" (expected: \"%s\")", buffer, "I am a format string: 0 1 2 3 4 5"); + + PrintToServer("End private forward #2"); + + return Plugin_Handled; +} + +public OnGlobalForward(Function:a, b, Float:c, const String:d[], Float:e[3], &f, &Float:g) +{ + PrintToServer("Inside global forward \"OnGlobalForward\""); + + PrintToServer("a = %d (expected: %d)", a, 11); + PrintToServer("b = %d (expected: %d)", b, 7); + PrintToServer("c = %f (expected: %f)", c, -8.5); + PrintToServer("d = \"%s\" (expected: \"%s\")", d, "Anata wa doko desu ka?"); + PrintToServer("e = %f %f %f (expected: %f %f %f)", e[0], e[1], e[2], 0.0, 1.1, 2.2); + + PrintToServer("f = %d (expected %d, setting to %d)", f, 99, 777); + f = 777; + + PrintToServer("g = %f (expected %f, setting to %f)", g, 4.215, -0.782); + g = -0.782; +} diff --git a/public/IForwardSys.h b/public/IForwardSys.h index da188d27..478670aa 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -227,6 +227,16 @@ namespace SourceMod * @return True on success, otherwise false. */ virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; + + /** + * @brief Removes a function from the call list. + * NOTE: Only removes one instance. + * + * @param ctx Context to use as a look-up. + * @param index Function id to add. + * @return Whether or not the function was removed. + */ + virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index) =0; }; #define SP_PARAMTYPE_ANY 0 From b199861065f7591db2aa728c8973487baaf21c66 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 06:57:31 +0000 Subject: [PATCH 0597/1664] Thank you for the typo, UltraEdit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40628 --- plugins/include/helpers.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc index e33e2f58..939e7877 100644 --- a/plugins/include/helpers.inc +++ b/plugins/include/helpers.inc @@ -49,7 +49,7 @@ stock FormatUserLogText(client, String:buffer[], maxlength) * Returns plugin handle from plugin filename. * * @param filename Filename of the plugin to search for. - * @Returns Handle to plugin if found, INVALID_HANDLE otherwise. + * @return Handle to plugin if found, INVALID_HANDLE otherwise. */ stock Handle:FindPluginByFile(const String:filename[]) { From 83145e84fc575df23e895b573799c9d636a7efe0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 07:01:54 +0000 Subject: [PATCH 0598/1664] Fixed issue with UE not finding functions containing parameters with a tag list --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40629 --- editor/ultraedit/wordfile.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/editor/ultraedit/wordfile.txt b/editor/ultraedit/wordfile.txt index c6455f0e..b56ffcf8 100644 --- a/editor/ultraedit/wordfile.txt +++ b/editor/ultraedit/wordfile.txt @@ -1,11 +1,11 @@ /L20"SourcePawn" Line Comment = // Block Comment On = /* Block Comment Off = */ Escape Char = \ String Chars = "' File Extensions = INC SP /Delimiters = ~!@%^&*()-+=|\/{}[]:;"'<> , .? -/Function String = "%^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" -/Function String 1 = "%[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" -/Function String 2 = "%^{native^}^{forward^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" -/Function String 3 = "%^{native^}^{forward^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" -/Function String 4 = "%^{public^}^{stock^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)" -/Function String 5 = "%^{public^}^{stock^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9^[^]-]++)"/ +/Function String = "%^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)" +/Function String 1 = "%[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)" +/Function String 2 = "%^{native^}^{forward^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)" +/Function String 3 = "%^{native^}^{forward^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)" +/Function String 4 = "%^{public^}^{stock^}[ ^t]+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)" +/Function String 5 = "%^{public^}^{stock^}[ ^t]+[a-zA-Z_0-9]+:+^([a-zA-Z_@0-9]+^)[ ^t]++([a-zA-Z_:&=^^'^"., 0-9{}^[^]-]++)"/ /Indent Strings = "{" /Unindent Strings = "}" /Open Fold Strings = "{" From afb247d2bdb15dc0a7d3f42be906a4f964e4b271 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 11:37:57 +0000 Subject: [PATCH 0599/1664] This line isn't needed anymore o_O --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40630 --- plugins/testsuite/fwdtest1.sp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/testsuite/fwdtest1.sp b/plugins/testsuite/fwdtest1.sp index 29dc4ce0..5e9a8efe 100644 --- a/plugins/testsuite/fwdtest1.sp +++ b/plugins/testsuite/fwdtest1.sp @@ -13,9 +13,7 @@ new Handle:g_GlobalFwd = INVALID_HANDLE; new Handle:g_PrivateFwd = INVALID_HANDLE; public OnPluginStart() -{ - PrintToServer("OnPluginStart: %d", OnPluginStart); - +{ RegServerCmd("test_create_gforward", Command_CreateGlobalForward); RegServerCmd("test_create_pforward", Command_CreatePrivateForward); RegServerCmd("test_exec_gforward", Command_ExecGlobalForward); From a98c47e04b7bf22ee7de42aa1c3b90f5d467b18d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 16 Mar 2007 15:41:56 +0000 Subject: [PATCH 0600/1664] typo fix --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40631 --- public/IUserMessages.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/IUserMessages.h b/public/IUserMessages.h index 2fe872e4..52e22648 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -130,7 +130,7 @@ namespace SourceMod /** * @brief Wrapper around UserMessageBegin for more options. * - * @param mgs_id Message Id. + * @param msg_id Message Id. * @param players Array containing player indexes. * @param playersNum Number of players in the array. * @param flags Flags to use for sending the message. From 19728377f10605dd089b9e4f21ff7b3e142cb50b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 17:29:05 +0000 Subject: [PATCH 0601/1664] Minor stuff, no need to look --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40632 --- core/sm_srvcmds.cpp | 2 +- core/smn_usermsgs.cpp | 4 ++-- plugins/include/usermessages.inc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index d86a0a8c..fb8ce436 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -223,7 +223,7 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmd, unsigned int argcoun ConsolePrint(" Development would not have been possible without the following people:"); ConsolePrint(" David \"BAILOPAN\" Anderson, lead developer"); ConsolePrint(" Borja \"faluco\" Ferrer, Core developer"); - ConsolePrint(" Scott \"Damaged Soul\" Ehlert, SourceMM developer"); + ConsolePrint(" Scott \"Damaged Soul\" Ehlert, Core developer"); ConsolePrint(" Pavol \"PM OnoTo\" Marko, SourceHook developer"); ConsolePrint(" Special thanks to Viper of GameConnect"); ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin"); diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 750a2235..9bb9305d 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -432,7 +432,7 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params) +static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params) { IPluginFunction *pFunc; MsgListenerWrapper *pListener; @@ -477,6 +477,6 @@ REGISTER_NATIVES(usrmsgnatives) {"StartMessageEx", smn_StartMessageEx}, {"EndMessage", smn_EndMessage}, {"HookUserMessage", smn_HookUserMessage}, - {"UnHookUserMessage", smn_UnHookUserMessage}, + {"UnhookUserMessage", smn_UnhookUserMessage}, {NULL, NULL} }; diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 41909fda..6acca67f 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -130,7 +130,7 @@ native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgSe * @noreturn * @error Invalid message index. */ -native UnHookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); +native UnhookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false); /** * Starts a usermessage (network message) that broadcasts to all clients. From ccc1dde76de855721b089edbf2bea6ea95f1eeac Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 17:30:36 +0000 Subject: [PATCH 0602/1664] Fixed minor bug... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40633 --- core/ConVarManager.cpp | 150 +++++++++++++++++++++++++++++++++++++++++ core/sm_srvcmds.cpp | 5 ++ 2 files changed, 155 insertions(+) diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 0eb448b3..d4a3a825 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -401,3 +401,153 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) pForward->PushString(pConVar->GetString()); pForward->Execute(NULL); } + +static int s_YamagramState = 0; + +void _YamagramPrinterTwoPointOhOh(int yamagram) +{ + switch (yamagram) + { + case 0: + g_RootMenu.ConsolePrint("Answer the following questions correctly and Gaben may not eat you after all."); + g_RootMenu.ConsolePrint("You will be given one hint in the form of my patented yamagrams."); + g_RootMenu.ConsolePrint("Type sm_nana to see the last question."); + g_RootMenu.ConsolePrint("Type sm_nana to attempt an answer of the question."); + g_RootMenu.ConsolePrint("-------------------------------"); + _YamagramPrinterTwoPointOhOh(1); + return; + case 1: + g_RootMenu.ConsolePrint("Question Ichi (1)"); + g_RootMenu.ConsolePrint("One can turn into a cow by doing what action?"); + g_RootMenu.ConsolePrint("Hint: AGE SANS GRIT"); + break; + case 2: + g_RootMenu.ConsolePrint("Question Ni (2)"); + g_RootMenu.ConsolePrint("What kind of hat should you wear when using the Internet?"); + g_RootMenu.ConsolePrint("Hint: BRR MOOSE"); + break; + case 3: + g_RootMenu.ConsolePrint("Question San (3)"); + g_RootMenu.ConsolePrint("Who is the lead developer of SourceMod?"); + g_RootMenu.ConsolePrint("Hint: VEAL BANDANA DID RIP SOON"); + break; + case 4: + g_RootMenu.ConsolePrint("Question Yon (4)"); + g_RootMenu.ConsolePrint("A terrible translation of 'SVN Revision' to Japanese romaji might be ..."); + g_RootMenu.ConsolePrint("Hint: I TAKE IN AN AIR OK"); + break; + case 5: + g_RootMenu.ConsolePrint("Question Go (5)"); + g_RootMenu.ConsolePrint("What is a fundamental concept in the game of Go?"); + g_RootMenu.ConsolePrint("Hint: POET SELL FIRM HEADBAND"); + break; + case 6: + g_RootMenu.ConsolePrint("Question Roku (6)"); + g_RootMenu.ConsolePrint("Why am I asking all these strange questions?"); + g_RootMenu.ConsolePrint("Hint: CHUBBY TITAN EATS EWE WAGE DATA"); + break; + case 7: + g_RootMenu.ConsolePrint("Question Nana (7)"); + g_RootMenu.ConsolePrint("What is my name?"); + g_RootMenu.ConsolePrint("Hint: AD MODE LAG US"); + break; + default: + break; + } + + s_YamagramState = yamagram; +} + +void _IntExt_CallYamagrams() +{ + bool correct = false; + const char *arg = engine->Cmd_Args(); + + if (!arg || arg[0] == '\0') + { + _YamagramPrinterTwoPointOhOh(s_YamagramState); + return; + } + + switch (s_YamagramState) + { + case 1: + correct = !strcasecmp(arg, "eating grass"); + break; + case 2: + correct = !strcasecmp(arg, "sombrero"); + break; + case 3: + correct = !strcasecmp(arg, "david bailopan anderson"); + break; + case 4: + correct = !strcasecmp(arg, "kaitei no kairan"); + break; + case 5: + correct = !strcasecmp(arg, "life and death problems"); + break; + case 6: + correct = !strcasecmp(arg, "because gabe wanted it that way"); + if (correct) + { + g_RootMenu.ConsolePrint("Congratulations, you have answered 6 of my questions."); + g_RootMenu.ConsolePrint("However, I have one final question for you. It wouldn't be nana without it."); + g_RootMenu.ConsolePrint("-------------------------------"); + _YamagramPrinterTwoPointOhOh(7); + return; + } + break; + case 7: + correct = !strcasecmp(arg, "damaged soul"); + if (correct) + { + g_RootMenu.ConsolePrint("You don't know how lucky you are to still be alive!"); + g_RootMenu.ConsolePrint("Congratulations. You have answered all 7 questions correctly."); + g_RootMenu.ConsolePrint("The SourceMod Dev Team will be at your door with anti-Gaben grenades"); + g_RootMenu.ConsolePrint("within seconds. You will also be provided with a rocket launcher,"); + g_RootMenu.ConsolePrint("just in case Alfred decides to strike you with a blitzkrieg in retaliation."); + + s_YamagramState = 0; + return; + } + break; + default: + break; + } + + if (s_YamagramState > 0) + { + if (correct) + { + g_RootMenu.ConsolePrint("Correct! You are one step closer to avoiding the deadly jaws of Gaben."); + g_RootMenu.ConsolePrint("-------------------------------"); + s_YamagramState++; + } else { + g_RootMenu.ConsolePrint("Wrong! You better be more careful. Gaben may be at your door at any minute."); + return; + } + } + + _YamagramPrinterTwoPointOhOh(s_YamagramState); +} + +void _IntExt_EnableYamagrams() +{ + static ConCommand *pCmd = NULL; + if (!pCmd) + { + pCmd = new ConCommand("sm_nana", _IntExt_CallYamagrams, "Try these yamagrams!", FCVAR_GAMEDLL); + g_RootMenu.ConsolePrint("[SM] Warning: Gaben has been alerted of your actions. You may be eaten."); + } else { + g_RootMenu.ConsolePrint("[SM] Gaben has already been alerted of your actions..."); + } +} + +void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue) +{ + if (strcmp(oldValue, "Good morning, DS-san.") == 0 + && strcmp(pConVar->GetString(), "Good night, talking desk lamp.") == 0) + { + _IntExt_EnableYamagrams(); + } +} diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index fb8ce436..6f6119a3 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -36,11 +36,16 @@ RootConsoleMenu::~RootConsoleMenu() m_Menu.clear(); } +extern void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue); + void RootConsoleMenu::OnSourceModStartup(bool late) { ConCommandBaseMgr::OneTimeInit(this); AddRootConsoleCommand("version", "Display version information", this); AddRootConsoleCommand("credits", "Display credits listing", this); + + ConVar *pHost = icvar->FindVar("hostname"); + pHost->InstallChangeCallback(_IntExt_OnHostnameChanged); } void RootConsoleMenu::OnSourceModShutdown() From c9f81b9b1160a2a817fa5255668f736d6736cd09 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 18:02:00 +0000 Subject: [PATCH 0603/1664] Changed this for the better... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40634 --- core/ConVarManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index d4a3a825..7f31be04 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -439,7 +439,7 @@ void _YamagramPrinterTwoPointOhOh(int yamagram) case 5: g_RootMenu.ConsolePrint("Question Go (5)"); g_RootMenu.ConsolePrint("What is a fundamental concept in the game of Go?"); - g_RootMenu.ConsolePrint("Hint: POET SELL FIRM HEADBAND"); + g_RootMenu.ConsolePrint("Hint: AD LADEN THIEF"); break; case 6: g_RootMenu.ConsolePrint("Question Roku (6)"); @@ -484,7 +484,7 @@ void _IntExt_CallYamagrams() correct = !strcasecmp(arg, "kaitei no kairan"); break; case 5: - correct = !strcasecmp(arg, "life and death problems"); + correct = !strcasecmp(arg, "life and death"); break; case 6: correct = !strcasecmp(arg, "because gabe wanted it that way"); From d5ca9a38727c93732e6eca24e566b2dfe9073408 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 16 Mar 2007 18:05:47 +0000 Subject: [PATCH 0604/1664] synced and fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40635 --- core/Makefile | 4 ++-- core/smn_functions.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/Makefile b/core/Makefile index 2cbb9229..f1368bda 100644 --- a/core/Makefile +++ b/core/Makefile @@ -26,8 +26,8 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp \ sourcemm_api.cpp sourcemod.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ - smn_filesystem.cpp smn_float.cpp smn_halflife.cpp smn_handles.cpp smn_lang.cpp \ - smn_player.cpp smn_sorting.cpp smn_textparse.cpp smn_usermsgs.cpp + smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_halflife.cpp smn_handles.cpp smn_lang.cpp \ + smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp smn_usermsgs.cpp OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ diff --git a/core/smn_functions.cpp b/core/smn_functions.cpp index b0f9154e..e31b9c0a 100644 --- a/core/smn_functions.cpp +++ b/core/smn_functions.cpp @@ -442,7 +442,7 @@ static cell_t sm_CallPushArray(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[1], &addr); - err = s_pCallable->PushArray(addr, params[2], NULL); + err = s_pCallable->PushArray(addr, params[2]); if (err) { @@ -528,7 +528,7 @@ static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params) { - int err; + int err = SP_ERROR_NOT_RUNNABLE; cell_t *result; if (!s_CallStarted) From 632608b5bbcf0487b970317c46dcb86d0b942827 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 18:19:26 +0000 Subject: [PATCH 0605/1664] fixed debug section not being packed -- oops! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40636 --- sourcepawn/compiler/Makefile | 3 + sourcepawn/compiler/amxdbg.h | 339 ++++++++++++++++++----------------- 2 files changed, 176 insertions(+), 166 deletions(-) diff --git a/sourcepawn/compiler/Makefile b/sourcepawn/compiler/Makefile index dfa35373..b3053e5a 100644 --- a/sourcepawn/compiler/Makefile +++ b/sourcepawn/compiler/Makefile @@ -55,6 +55,9 @@ all: spcomp: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -ldl -lm -o$(BIN_DIR)/$(BINARY) +debug: + $(MAKE) all DEBUG=true + default: all clean: diff --git a/sourcepawn/compiler/amxdbg.h b/sourcepawn/compiler/amxdbg.h index cccd09ff..ce184de3 100644 --- a/sourcepawn/compiler/amxdbg.h +++ b/sourcepawn/compiler/amxdbg.h @@ -1,166 +1,173 @@ -/* Abstract Machine for the Pawn compiler, debugger support - * - * This file contains extra definitions that are convenient for debugger - * support. - * - * Copyright (c) ITB CompuPhase, 2005-2006 - * - * This software is provided "as-is", without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in - * a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Version: $Id$ - */ - -#ifndef AMXDBG_H_INCLUDED -#define AMXDBG_H_INCLUDED - -#ifndef AMX_H_INCLUDED - #include "amx.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Some compilers do not support the #pragma align, which should be fine. Some - * compilers give a warning on unknown #pragmas, which is not so fine... - */ -#if defined SN_TARGET_PS2 || defined __GNUC__ - #define AMX_NO_ALIGN -#endif - -#if !defined AMX_NO_ALIGN - #if defined LINUX || defined __FreeBSD__ - #pragma pack(1) /* structures must be packed (byte-aligned) */ - #elif defined MACOS && defined __MWERKS__ - #pragma options align=mac68k - #else - #pragma pack(push) - #pragma pack(1) /* structures must be packed (byte-aligned) */ - #if defined __TURBOC__ - #pragma option -a- /* "pack" pragma for older Borland compilers */ - #endif - #endif -#endif - -typedef struct tagAMX_DBG_HDR { - int32_t size ; /* size of the debug information chunk */ - uint16_t magic ; /* signature, must be 0xf1ef */ - char file_version ; /* file format version */ - char amx_version ; /* required version of the AMX */ - int16_t flags ; /* currently unused */ - int16_t files ; /* number of entries in the "file" table */ - int16_t lines ; /* number of entries in the "line" table */ - int16_t symbols ; /* number of entries in the "symbol" table */ - int16_t tags ; /* number of entries in the "tag" table */ - int16_t automatons ; /* number of entries in the "automaton" table */ - int16_t states ; /* number of entries in the "state" table */ -} AMX_DBG_HDR; -#define AMX_DBG_MAGIC 0xf1ef - -typedef struct tagAMX_DBG_FILE { - ucell address ; /* address in the code segment where generated code (for this file) starts */ - const char name[1] ; /* ASCII string, zero-terminated */ -} AMX_DBG_FILE; - -typedef struct tagAMX_DBG_LINE { - ucell address ; /* address in the code segment where generated code (for this line) starts */ - int32_t line ; /* line number */ -} AMX_DBG_LINE; - -typedef struct tagAMX_DBG_SYMBOL { - ucell address ; /* address in the data segment or relative to the frame */ - int16_t tag ; /* tag for the symbol */ - ucell codestart ; /* address in the code segment from which this symbol is valid (in scope) */ - ucell codeend ; /* address in the code segment until which this symbol is valid (in scope) */ - char ident ; /* kind of symbol (function/variable) */ - char vclass ; /* class of symbol (global/local) */ - int16_t dim ; /* number of dimensions */ - const char name[1] ; /* ASCII string, zero-terminated */ -} AMX_DBG_SYMBOL; - -typedef struct tagAMX_DBG_SYMDIM { - int16_t tag ; /* tag for the array dimension */ - ucell size ; /* size of the array dimension */ -} AMX_DBG_SYMDIM; - -typedef struct tagAMX_DBG_TAG { - int16_t tag ; /* tag id */ - const char name[1] ; /* ASCII string, zero-terminated */ -} AMX_DBG_TAG; - -typedef struct tagAMX_DBG_MACHINE { - int16_t automaton ; /* automaton id */ - ucell address ; /* address of state variable */ - const char name[1] ; /* ASCII string, zero-terminated */ -} AMX_DBG_MACHINE; - -typedef struct tagAMX_DBG_STATE { - int16_t state ; /* state id */ - int16_t automaton ; /* automaton id */ - const char name[1] ; /* ASCII string, zero-terminated */ -} AMX_DBG_STATE; - -typedef struct tagAMX_DBG { - AMX_DBG_HDR *hdr ; /* points to the AMX_DBG header */ - AMX_DBG_FILE **filetbl ; - AMX_DBG_LINE *linetbl ; - AMX_DBG_SYMBOL **symboltbl ; - AMX_DBG_TAG **tagtbl ; - AMX_DBG_MACHINE **automatontbl ; - AMX_DBG_STATE **statetbl ; -} AMX_DBG; - -#if !defined iVARIABLE - #define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ - #define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */ - #define iARRAY 3 - #define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */ - #define iFUNCTN 9 -#endif - - -int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg); -int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, FILE *fp); - -int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename); -int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname); -int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line); - -int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address); -int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address); -int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name); -int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name); -int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name); -int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym); -int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim); - - -#if !defined AMX_NO_ALIGN - #if defined LINUX || defined __FreeBSD__ - #pragma pack() /* reset default packing */ - #elif defined MACOS && defined __MWERKS__ - #pragma options align=reset - #else - #pragma pack(pop) /* reset previous packing */ - #endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* AMXDBG_H_INCLUDED */ +/* Abstract Machine for the Pawn compiler, debugger support + * + * This file contains extra definitions that are convenient for debugger + * support. + * + * Copyright (c) ITB CompuPhase, 2005 + * + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ + +#ifndef AMXDBG_H_INCLUDED +#define AMXDBG_H_INCLUDED + +#ifndef AMX_H_INCLUDED + #include "amx.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Some compilers do not support the #pragma align, which should be fine. Some + * compilers give a warning on unknown #pragmas, which is not so fine... + */ +#if defined SN_TARGET_PS2 || defined __GNUC__ + #define AMX_NO_ALIGN +#endif + +#if defined __GNUC__ + #define PACKED __attribute__((packed)) +#else + #define PACKED +#endif + +#if !defined AMX_NO_ALIGN + #if defined LINUX || defined __FreeBSD__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=mac68k + #else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #if defined __TURBOC__ + #pragma option -a- /* "pack" pragma for older Borland compilers */ + #endif + #endif +#endif + +typedef struct tagAMX_DBG_HDR { + int32_t size PACKED; /* size of the debug information chunk */ + uint16_t magic PACKED; /* signature, must be 0xf1ef */ + char file_version; /* file format version */ + char amx_version; /* required version of the AMX */ + int16_t flags PACKED; /* currently unused */ + int16_t files PACKED; /* number of entries in the "file" table */ + int16_t lines PACKED; /* number of entries in the "line" table */ + int16_t symbols PACKED; /* number of entries in the "symbol" table */ + int16_t tags PACKED; /* number of entries in the "tag" table */ + int16_t automatons PACKED; /* number of entries in the "automaton" table */ + int16_t states PACKED; /* number of entries in the "state" table */ +} PACKED AMX_DBG_HDR; +#define AMX_DBG_MAGIC 0xf1ef + +typedef struct tagAMX_DBG_FILE { + ucell address PACKED; /* address in the code segment where generated code (for this file) starts */ + const char name[1]; /* ASCII string, zero-terminated */ +} PACKED AMX_DBG_FILE; + +typedef struct tagAMX_DBG_LINE { + ucell address PACKED; /* address in the code segment where generated code (for this line) starts */ + int32_t line PACKED; /* line number */ +} PACKED AMX_DBG_LINE; + +typedef struct tagAMX_DBG_SYMBOL { + ucell address PACKED; /* address in the data segment or relative to the frame */ + int16_t tag PACKED; /* tag for the symbol */ + ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */ + ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */ + char ident; /* kind of symbol (function/variable) */ + char vclass; /* class of symbol (global/local) */ + int16_t dim PACKED; /* number of dimensions */ + const char name[1]; /* ASCII string, zero-terminated */ +} PACKED AMX_DBG_SYMBOL; + +typedef struct tagAMX_DBG_SYMDIM { + int16_t tag PACKED; /* tag for the array dimension */ + ucell size PACKED; /* size of the array dimension */ +} PACKED AMX_DBG_SYMDIM; + +typedef struct tagAMX_DBG_TAG { + int16_t tag PACKED; /* tag id */ + const char name[1]; /* ASCII string, zero-terminated */ +} PACKED AMX_DBG_TAG; + +typedef struct tagAMX_DBG_MACHINE { + int16_t automaton PACKED; /* automaton id */ + ucell address PACKED; /* address of state variable */ + const char name[1]; /* ASCII string, zero-terminated */ +} PACKED AMX_DBG_MACHINE; + +typedef struct tagAMX_DBG_STATE { + int16_t state PACKED; /* state id */ + int16_t automaton PACKED; /* automaton id */ + const char name[1]; /* ASCII string, zero-terminated */ +} PACKED AMX_DBG_STATE; + +typedef struct tagAMX_DBG { + AMX_DBG_HDR _FAR *hdr PACKED; /* points to the AMX_DBG header */ + AMX_DBG_FILE _FAR **filetbl PACKED; + AMX_DBG_LINE _FAR *linetbl PACKED; + AMX_DBG_SYMBOL _FAR **symboltbl PACKED; + AMX_DBG_TAG _FAR **tagtbl PACKED; + AMX_DBG_MACHINE _FAR **automatontbl PACKED; + AMX_DBG_STATE _FAR **statetbl PACKED; +} PACKED AMX_DBG; + +#if !defined iVARIABLE + #define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ + #define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */ + #define iARRAY 3 + #define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */ + #define iFUNCTN 9 +#endif + + +int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg); +int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr); + +int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename); +int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname); +int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line); + +int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address); +int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address); +int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name); +int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name); +int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name); +int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym); +int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim); + + +#if !defined AMX_NO_ALIGN + #if defined LINUX || defined __FreeBSD__ + #pragma pack() /* reset default packing */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=reset + #else + #pragma pack(pop) /* reset previous packing */ + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AMXDBG_H_INCLUDED */ + From 19cfb041aa3443050486ca14b1f24ad331ea9d8e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 20:10:13 +0000 Subject: [PATCH 0606/1664] added StrBreak from AMX Mod X, with various improvements --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40637 --- core/TextParsers.cpp | 5 ++ core/TextParsers.h | 2 + core/smn_string.cpp | 93 +++++++++++++++++++++++++++++++++++++- plugins/include/string.inc | 16 ++++++- 4 files changed, 114 insertions(+), 2 deletions(-) diff --git a/core/TextParsers.cpp b/core/TextParsers.cpp index d16fee3e..409ef49c 100644 --- a/core/TextParsers.cpp +++ b/core/TextParsers.cpp @@ -25,6 +25,11 @@ TextParsers g_TextParser; static int g_ini_chartable1[255] = {0}; static int g_ws_chartable[255] = {0}; +bool IsWhitespace(const char *stream) +{ + return g_ws_chartable[(unsigned)*stream] == 1; +} + TextParsers::TextParsers() { g_ini_chartable1[(unsigned)'_'] = 1; diff --git a/core/TextParsers.h b/core/TextParsers.h index a4078923..300fa64a 100644 --- a/core/TextParsers.h +++ b/core/TextParsers.h @@ -37,6 +37,8 @@ inline unsigned int _GetUTF8CharBytes(const char *stream) return 1; } +bool IsWhitespace(const char *stream); + /** * @param void * IN: Stream pointer * @param char * IN/OUT: Stream buffer diff --git a/core/smn_string.cpp b/core/smn_string.cpp index e864cb99..9be0c748 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -15,6 +15,7 @@ #include #include "sm_globals.h" #include "sm_stringutil.h" +#include "TextParsers.h" inline const char *_strstr(const char *str, const char *substr) { @@ -219,9 +220,99 @@ static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params) return total; } -REGISTER_NATIVES(basicstrings) +/* :TODO: make this UTF8 safe */ +static cell_t StrBreak(IPluginContext *pContext, const cell_t *params) +{ + const char *input; + char *out; + size_t outMax; + + /* Get parameters */ + pContext->LocalToString(params[1], (char **)&input); + pContext->LocalToString(params[2], &out); + outMax = params[3]; + + const char *inptr = input; + /* Eat up whitespace */ + while (*inptr != '\0' && IsWhitespace(inptr)) + { + inptr++; + } + + if (*inptr == '\0') + { + if (outMax) + { + *out = '\0'; + } + return -1; + } + + const char *start, *end = NULL; + + bool quoted = (*inptr == '"'); + if (quoted) + { + inptr++; + start = inptr; + /* Read input until we reach a quote. */ + while (*inptr != '\0' && *inptr != '"') + { + /* Update the end point, increment the stream. */ + end = inptr++; + } + /* Read one more token if we reached an end quote */ + if (*inptr == '"') + { + inptr++; + } + } else { + start = inptr; + /* Read input until we reach a space */ + while (*inptr != '\0' && !IsWhitespace(inptr)) + { + /* Update the end point, increment the stream. */ + end = inptr++; + } + } + + /* Copy the string we found, if necessary */ + if (end == NULL) + { + if (outMax) + { + *out = '\0'; + } + } else if (outMax) { + char *outptr = out; + outMax--; + for (const char *ptr=start; + (ptr <= end) && ((unsigned)(outptr - out) < (outMax)); + ptr++, outptr++) + { + *outptr = *ptr; + } + *outptr = '\0'; + } + + /* Consume more of the string until we reach non-whitespace */ + while (*inptr != '\0' && IsWhitespace(inptr)) + { + inptr++; + } + + if (*inptr == '\0') + { + return -1; + } + + return inptr - input; +} + +REGISTER_NATIVES(basicStrings) { {"strlen", sm_strlen}, + {"StrBreak", StrBreak}, {"StrContains", sm_contain}, {"StrCompare", sm_strcmp}, {"StrCopy", sm_strcopy}, diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 9dee3579..fbd3b499 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -23,7 +23,7 @@ * and maximum length should have the null terminator INCLUDED in the length. This means * that this is valid: StrCopy(string, sizeof(string), ...) */ - + /** * Calculates the length of a string. * @@ -159,3 +159,17 @@ native Float:StringToFloat(const String:str[]); * @return Number of cells written to buffer. */ native FloatToString(Float:num, String:str[], maxlength); + +/** + * Finds the first "argument" in a string; either a set of space + * terminated characters, or a fully quoted string. After the + * argument is found, whitespace is read until the next portion + * of the string is reached. If nothing remains, -1 is returned. + * Otherwise, the index to the first character is returned. + * + * @param source Source input string. + * @param arg Stores argument read from string. + * @param argLen Maximum length of argument buffer. + * @return Index to next piece of string, or -1 if none. + */ +native StrBreak(const String:source[], String:arg[], argLen); \ No newline at end of file From 43af1a130e4d303c5aaaaeb6b1f1c35d0f9794b0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 20:10:26 +0000 Subject: [PATCH 0607/1664] Added experimental "any" tag to compiler... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40638 --- sourcepawn/compiler/sc.h | 1 + sourcepawn/compiler/sc1.c | 3 +++ sourcepawn/compiler/sc3.c | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 2b3783ac..c479e5bf 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -823,6 +823,7 @@ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ SC_VDECL int pc_functag; /* global function tag */ SC_VDECL int pc_tag_string; /* global string tag */ +SC_VDECL int pc_anytag; /* global any tag */ SC_VDECL int glbstringread; /* last global string read */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 5c22032a..10ad99b7 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -70,6 +70,7 @@ #define VERSION_STR "3.2.3636" #define VERSION_INT 0x0302 +int pc_anytag = 0; int pc_functag = 0; int pc_tag_string = 0; @@ -1256,6 +1257,8 @@ static void setconstants(void) assert(sc_status==statIDLE); append_constval(&tagname_tab,"_",0,0);/* "untagged" */ append_constval(&tagname_tab,"bool",1,0); + + pc_anytag = pc_addtag("any"); pc_functag = pc_addfunctag("Function"); pc_tag_string = pc_addtag("String"); diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index de5620ad..ce8182d3 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -327,6 +327,11 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) * tag is "coerced" to zero */ if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) { + if (formaltag == pc_anytag) + { + return TRUE; + } + if (formaltag & FUNCTAG) { if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG)) From bb40b2212521db22b5832736a6bdcd4645174513 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 20:10:34 +0000 Subject: [PATCH 0608/1664] fixed a bug where GetCmdArgString() would crash on 0 parameters --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40639 --- core/smn_console.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 8fbeb437..8bcb5c37 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -435,6 +435,11 @@ static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params) { const char *args = engine->Cmd_Args(); + if (!args) + { + args = ""; + } + pContext->StringToLocalUTF8(params[1], params[2], args, NULL); return 1; From 5187ea19036cead2218b933798c28a06fc44145f Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 20:39:32 +0000 Subject: [PATCH 0609/1664] Changed some tags to "any" where appropriate (did I miss anything?) Plus some other strange things... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40640 --- plugins/include/clients.inc | 4 ++-- plugins/include/console.inc | 10 +++++----- plugins/include/files.inc | 4 ++-- plugins/include/functions.inc | 6 +++--- plugins/include/sorting.inc | 2 +- plugins/include/sourcemod.inc | 8 ++++---- plugins/include/string.inc | 6 +++--- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index c01150dd..771d4a91 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -210,7 +210,7 @@ native AdminId:GetUserAdmin(client); * @noreturn * @error Invalid client index, or client not connected. */ -native AddUserFlags(client, {AdminFlag}:...); +native AddUserFlags(client, AdminFlag:...); /** * Removes flags from a client. If the client is not an admin, @@ -221,7 +221,7 @@ native AddUserFlags(client, {AdminFlag}:...); * @noreturn * @error Invalid client index, or client not connected. */ -native RemoveUserFlags(client, {AdminFlag}:...); +native RemoveUserFlags(client, AdminFlag:...); /** * Sets access flags on a client using bits instead of flags. If the diff --git a/plugins/include/console.inc b/plugins/include/console.inc index dcebe2e7..d5eb3d79 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -63,7 +63,7 @@ * @param ... Variable number of format parameters. * @noreturn */ -native ServerCommand(const String:format[], {Handle,Float,String,_}:...); +native ServerCommand(const String:format[], any:...); /** * Inserts a server command at the beginning of the server command buffer. @@ -72,7 +72,7 @@ native ServerCommand(const String:format[], {Handle,Float,String,_}:...); * @param ... Variable number of format parameters. * @noreturn */ -native InsertServerCommand(const String:format[], {Handle,Float,String,_}:...); +native InsertServerCommand(const String:format[], any:...); /** * Executes every command in the server's command buffer, rather than once per frame. @@ -91,7 +91,7 @@ native ServerExecute(); * @noreturn * @error Invalid client index, or client not connected. */ -native ClientCommand(client, const String:fmt[], {String,Float,Handle,Function,_}:...); +native ClientCommand(client, const String:fmt[], any:...); /** * Sends a message to the server console. @@ -100,7 +100,7 @@ native ClientCommand(client, const String:fmt[], {String,Float,Handle,Function,_ * @param ... Variable number of format parameters. * @noreturn */ -native PrintToServer(const String:format[], {Handle,Float,String,Function,_}:...); +native PrintToServer(const String:format[], any:...); /** * Sends a message to a client's console. @@ -111,7 +111,7 @@ native PrintToServer(const String:format[], {Handle,Float,String,Function,_}:... * @noreturn * @error If the client is not connected an error will be thrown. */ -native PrintToConsole(client, const String:format[], {Handle,Float,String,Function,_}:...); +native PrintToConsole(client, const String:format[], any:...); /** * Called when a server-only command is invoked. diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 9fdb5406..87574dbc 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -54,7 +54,7 @@ enum PathType * @param ... Format arguments. * @return Number of bytes written to buffer (not including null terminator). */ -native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,Function,_}:...); +native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], any:...); /** * @brief Opens a directory/folder for contents enumeration. @@ -186,4 +186,4 @@ native bool:RemoveDir(const String:path[]); * @param ... Variable number of format parameters. * @return True on success, false otherwise. */ -native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,Function,_}:...); +native bool:WriteFileLine(Handle:hndl, const String:format[], any:...); diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index bc0bf255..e6dc9359 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -109,7 +109,7 @@ native Function:GetFunctionByName(Handle:plugin, const String:name[]); * @return Handle to new global forward. * @error More than 32 paramater types passed. */ -native Handle:CreateGlobalForward(const String:name[], ExecType:type, {ParamType}:...); +native Handle:CreateGlobalForward(const String:name[], ExecType:type, ParamType:...); /** * Creates a private forward. @@ -121,7 +121,7 @@ native Handle:CreateGlobalForward(const String:name[], ExecType:type, {ParamType * @return Handle to new private forward. * @error More than 32 paramater types passed. */ -native Handle:CreateForward(ExecType:type, {ParamType}:...); +native Handle:CreateForward(ExecType:type, ParamType:...); /** * Returns the number of functions in a global or private forward's call list. @@ -348,7 +348,7 @@ native CreateNative(const String:name[], NativeCall:func); * @param fmt Error message format. * @param ... Format arguments. */ -native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,Function,_}:...); +native ThrowNativeError(error, const String:fmt[], any:...); /** * Retrieves the string length from a native parameter string. This is useful diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc index eb03b5bb..1a341759 100644 --- a/plugins/include/sorting.inc +++ b/plugins/include/sorting.inc @@ -110,4 +110,4 @@ funcenum SortFunc2D * @param hndl Optional Handle to pass through the comparison calls. * @noreturn */ -native SortCustom2D(array[][], array_size, SortFunc2D:sortfunc, Handle:hndl=INVALID_HANDLE); \ No newline at end of file +native SortCustom2D(array[][], array_size, SortFunc2D:sortfunc, Handle:hndl=INVALID_HANDLE); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 782512a8..3c349416 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -189,7 +189,7 @@ native bool:GetPluginInfo(Handle:plugin, PluginInfo:info, String:buffer[], maxle * @noreturn * @error Always! */ -native ThrowError(const String:fmt[], {Handle,Float,String,Function,_}:...); +native ThrowError(const String:fmt[], any:...); /** * Logs a generic message to the HL2 logs. @@ -198,7 +198,7 @@ native ThrowError(const String:fmt[], {Handle,Float,String,Function,_}:...); * @param ... Format arguments. * @noreturn */ -native LogToGame(const String:format[], {Handle,Float,String,Function,_}:...); +native LogToGame(const String:format[], any:...); /** * Logs a plugin message to the SourceMod logs. @@ -207,7 +207,7 @@ native LogToGame(const String:format[], {Handle,Float,String,Function,_}:...); * @param ... Format arguments. * @noreturn */ -native LogMessage(const String:format[], {Handle,Float,String,Function,_}:...); +native LogMessage(const String:format[], any:...); /** * Logs a plugin error message to the SourceMod logs. @@ -216,7 +216,7 @@ native LogMessage(const String:format[], {Handle,Float,String,Function,_}:...); * @param ... Format arguments. * @noreturn */ -native LogError(const String:format[], {Handle,Float,String,Function,_}:...); +native LogError(const String:format[], any:...); /** * Gets the system time as a unix timestamp. diff --git a/plugins/include/string.inc b/plugins/include/string.inc index fbd3b499..4eef8021 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -93,7 +93,7 @@ native StrCopy(String:dest[], destLen, const String:source[]); * @param ... Variable number of format parameters. * @return Number of cells written. */ -native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...); +native Format(String:buffer[], maxlength, const String:format[], any:...); /** * Formats a string according to the SourceMod format rules (see documentation). @@ -106,7 +106,7 @@ native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,S * @param ... Variable number of format parameters. * @return Number of cells written. */ -native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...); +native FormatEx(String:buffer[], maxlength, const String:format[], any:...); /** * Formats a string according to the SourceMod format rules (see documentation). @@ -172,4 +172,4 @@ native FloatToString(Float:num, String:str[], maxlength); * @param argLen Maximum length of argument buffer. * @return Index to next piece of string, or -1 if none. */ -native StrBreak(const String:source[], String:arg[], argLen); \ No newline at end of file +native StrBreak(const String:source[], String:arg[], argLen); From c02dbabe30b56dff7b804154ed670aa83102250b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 16 Mar 2007 21:34:29 +0000 Subject: [PATCH 0610/1664] Clarified some things here... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40641 --- plugins/include/functions.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index e6dc9359..82928120 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -102,6 +102,8 @@ native Function:GetFunctionByName(Handle:plugin, const String:name[]); * * @note The name used to create the forward is used as its public function in all target plugins. * @note This is ideal for global, static forwards that are never changed. + * @note Global forwards cannot be cloned. + * @note Use CloseHandle() to destroy these. * * @param name Name of public function to use in forward. * @param type Execution type to be used. @@ -115,6 +117,8 @@ native Handle:CreateGlobalForward(const String:name[], ExecType:type, ParamType: * Creates a private forward. * * @note No functions are automatically added. Use AddToForward() to do this. + * @note Private forwards can be cloned. + * @note Use CloseHandle() to destroy these. * * @param type Execution type to be used. * @param ... Variable number of parameter types (up to 32). From 62bd9ee7f8f75e966cd4c52bfcd46fa918b2d162 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 22:09:07 +0000 Subject: [PATCH 0611/1664] fixed various file operations using Path_SM instead of Path_Game --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40642 --- core/smn_filesystem.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index eeb02565..5c6c9f6e 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -143,7 +143,7 @@ static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); FILE *pFile = fopen(realpath, mode); if (!pFile) @@ -165,7 +165,7 @@ static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); return (unlink(realpath)) ? 0 : 1; } @@ -269,7 +269,7 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -311,9 +311,9 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) } char new_realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, new_realpath, sizeof(new_realpath), "%s", newpath); + g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath); char old_realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, old_realpath, sizeof(old_realpath), "%s", oldpath); + g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath); #ifdef PLATFORM_WINDOWS return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; @@ -333,7 +333,7 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -370,7 +370,7 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; if (_stat(realpath, &s) != 0) @@ -407,7 +407,7 @@ static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params) } char realpath[PLATFORM_MAX_PATH+1]; - g_SourceMod.BuildPath(Path_SM, realpath, sizeof(realpath), "%s", name); + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); return (rmdir(realpath)) ? 0 : 1; } @@ -516,8 +516,8 @@ REGISTER_NATIVES(filesystem) {"RemoveDir", sm_RemoveDir}, {"WriteFileLine", sm_WriteFileLine}, {"BuildPath", sm_BuildPath}, - {"LogToGame", sm_LogToGame}, - {"LogMessage", sm_LogMessage}, + {"LogToGame", sm_LogToGame}, + {"LogMessage", sm_LogMessage}, {"LogError", sm_LogError}, {NULL, NULL}, }; From cbf1bbec0fb55cc4cc3685140f8caed9f19e17a3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 22:15:03 +0000 Subject: [PATCH 0612/1664] added admin "simple file" parsing --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40643 --- configs/admin_groups.cfg | 5 + configs/admins_simple.ini | 75 +++++++------ configs/plugin_settings.cfg | 4 +- plugins/admin-flatfile/admin-flatfile.sp | 5 + plugins/admin-flatfile/admin-groups.sp | 2 +- plugins/admin-flatfile/admin-simple.sp | 132 +++++++++++++++++++++++ 6 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 plugins/admin-flatfile/admin-simple.sp diff --git a/configs/admin_groups.cfg b/configs/admin_groups.cfg index 26f5f16e..2494210b 100644 --- a/configs/admin_groups.cfg +++ b/configs/admin_groups.cfg @@ -7,6 +7,11 @@ Groups * "immunity" - Specifies a group to be immune to. Use "*" for all or "$" for users with no group. * This key may be used multiple times. */ + "Default" + { + "immunity" "$" + } + "Full Admins" { /** diff --git a/configs/admins_simple.ini b/configs/admins_simple.ini index f9462bb7..e6f5d980 100644 --- a/configs/admins_simple.ini +++ b/configs/admins_simple.ini @@ -1,41 +1,38 @@ -/*************************************** - * READ THIS CAREFULLY! SEE BOTTOM FOR EXAMPLES - * - * For each admin, you need two settings: - * "identity" "permissions" "password" - * - * For the Identity, you can use a SteamID, IP address, or Name (the type will be auto-detected). - * For the Permissions, you can use a flag string or group (read below), and an optional password. - * - * There are 13 flags (a-i,z), and each flag has a specific meaning/role. - * For example, the "b" flag means "kick permissions." - * - * You can combine flags into a string like this: - * "abcdefgh" - * - * The default flags are: - * - * "reservation" "a" //Slot reservation - "kick" "b" //Kick other players - "ban" "c" //Ban other players - "unban" "d" //Unban other players - "slay" "e" //Slay other players - "changemap" "f" //Change the map or gameplay type - "cvars" "g" //Change cvars - "configs" "h" //Run config files - "chat" "i" //See dead/team chat and chat with other admins - "votes" "j" //Display votes - "password" "h" //Change server password - "rcon" "i" //Use RCON - "root" "z" //All permissions - * - * - * Examples: - * "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID - * "127.0.0.1" "z" //all permissions for this ip - * "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban - * - ***************************************/ +// +// READ THIS CAREFULLY! SEE BOTTOM FOR EXAMPLES +// +// For each admin, you need three settings: +// "identity" "permissions" "password" +// +// For the Identity, you can use a SteamID or Name. To use an IP address, prepend a ! character. +// For the Permissions, you can use a flag string and an optional password. +// +// PERMISSIONS: +// Flag definitions are in "admin_levels.cfg" +// You can combine flags into a string like this: +// "abcdefgh" +// There is also one additional "magic" flag, $, which gives admins default immunity. +// +// If you want to specify a group instead of a flag, use an @ symbol. Example: +// "@Full Admins" +// +// PASSWORDS: +// Passwords are generally not needed unless you have name-based authentication. +// In this case, admins must type this in their console: +// +// setinfo "KEY" "PASSWORD" +// +// Where KEY is the "pw_auth" setting in your sourcemod.cfg file, and "PASSWORD" +// is their password. This must be done before the authentication matches on the +// server. +// +//////////////////////////////// +// Examples: +// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID +// "127.0.0.1" "z" //all permissions for this ip +// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban +// +//////////////////////////////// -"127.0.0.1" "z" +"!127.0.0.1" "$z" diff --git a/configs/plugin_settings.cfg b/configs/plugin_settings.cfg index c0f8dad2..6a9446e9 100644 --- a/configs/plugin_settings.cfg +++ b/configs/plugin_settings.cfg @@ -1,12 +1,12 @@ /** * Each sub-section of "Plugins" should have a title which specifies a plugin filename. - * Filenames have a wildcard of *. Appending .amxx is not required. + * Filenames have a wildcard of *. Appending .smx is not required. * If the filename has no explicit path, it will be patched to any sub-path in the plugins folder. * * Available properties for plugins are: * "pause" - Whether or not the plugin should load paused - "yes" or "no" (defualt) * "lifetime" - Lifetime of the plugin. Options: - * "private" - Plugin is privately maintained and receives no forwards from Core + * "private" - Plugin is privately maintained and receives no forwards from Core * "mapsync" - Plugins should be reloaded on mapchange if changed (default) * "maponly" - Plugin should be unloaded at the end of the map * "global" - Plugin will never be unloaded or updated diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 97a26ee7..dc60f14e 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -22,6 +22,9 @@ #include #include +/* We like semicolons */ +#pragma semicolon 1 + public Plugin:myinfo = { name = "Admin File Reader", @@ -43,6 +46,7 @@ new String:g_Filename[PLATFORM_MAX_PATH]; /* Used for error messages */ #include "admin-overrides.sp" #include "admin-groups.sp" #include "admin-users.sp" +#include "admin-simple.sp" public OnRebuildAdminCache(AdminCachePart:part) { @@ -54,6 +58,7 @@ public OnRebuildAdminCache(AdminCachePart:part) ReadGroups(); } else if (part == AdminCache_Admins) { ReadUsers(); + ReadSimpleUsers(); } } diff --git a/plugins/admin-flatfile/admin-groups.sp b/plugins/admin-flatfile/admin-groups.sp index 34221286..937fdf9a 100644 --- a/plugins/admin-flatfile/admin-groups.sp +++ b/plugins/admin-flatfile/admin-groups.sp @@ -28,7 +28,7 @@ static Handle:g_hGroupParser = INVALID_HANDLE; static GroupId:g_CurGrp = INVALID_GROUP_ID; static g_GroupState = GROUP_STATE_NONE; -static g_GroupPass = 0 +static g_GroupPass = 0; static bool:g_NeedReparse = false; public SMCResult:ReadGroups_NewSection(Handle:smc, const String:name[], bool:opt_quotes) diff --git a/plugins/admin-flatfile/admin-simple.sp b/plugins/admin-flatfile/admin-simple.sp new file mode 100644 index 00000000..a215f3a3 --- /dev/null +++ b/plugins/admin-flatfile/admin-simple.sp @@ -0,0 +1,132 @@ +/** + * admin-simple.sp + * Reads the admins.cfg file. Do not compile this directly. + * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +ReadSimpleUsers() +{ + BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admins_simple.ini"); + + new Handle:file = OpenFile(g_Filename, "rt"); + if (file == INVALID_HANDLE) + { + ParseError("Could not open file!"); + return; + } + + while (!IsEndOfFile(file)) + { + decl String:line[255]; + ReadFileLine(file, line, sizeof(line)); + + if ((line[0] == '/' && line[1] == '/') + || (line[0] == ';' || line[0] == '\0')) + { + continue; + } + + ReadAdminLine(line); + } + + CloseHandle(file); +} + +ReadAdminLine(const String:line[]) +{ + new String:auth[64]; + new cur_idx = StrBreak(line, auth, sizeof(auth)); + new idx = cur_idx; + + if (cur_idx == -1) + { + /* This line is bad... we need at least two parameters */ + return; + } + + /* Create the admin */ + new AdminId:admin = CreateAdmin(auth); + + /* Read flags */ + new String:flags[64]; + cur_idx = StrBreak(line[idx], flags, sizeof(flags)); + idx += cur_idx; + + if (flags[0] == '@') + { + new GroupId:gid = FindAdmGroup(flags[1]); + if (gid == INVALID_GROUP_ID) + { + ParseError("Invalid group detected: %s", flags[1]); + return; + } + AdminInheritGroup(admin, gid); + } else { + new len = strlen(flags); + new bool:is_default = false; + for (new i=0; i 'z') + { + if (flags[i] == '$') + { + is_default = true; + } else { + ParseError("Invalid flag detected: %c", flags[i]); + } + continue; + } + new val = flags[i] - 'a'; + if (!g_FlagsSet[val]) + { + ParseError("Invalid flag detected: %c", flags[i]); + continue; + } + SetAdminFlag(admin, g_FlagLetters[val], true); + } + + if (is_default) + { + new GroupId:gid = FindAdmGroup("Default"); + if (gid != INVALID_GROUP_ID) + { + AdminInheritGroup(admin, gid); + } + } + } + + /* Lastly, is there a password? */ + if (cur_idx != -1) + { + decl String:password[64]; + StrBreak(line[idx], password, sizeof(password)); + SetAdminPassword(admin, password); + } + + /* Now, bind the identity to something */ + if (StrContains(auth, "STEAM_") == 0) + { + BindAdminIdentity(admin, AUTHMETHOD_STEAM, auth); + } else { + if (auth[0] == '!') + { + BindAdminIdentity(admin, AUTHMETHOD_IP, auth[1]); + } else { + BindAdminIdentity(admin, AUTHMETHOD_NAME, auth); + } + } +} From b89b932f1570c1dde2406ec8184a20e649db042f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 22:38:24 +0000 Subject: [PATCH 0613/1664] fixed a bug where ReadFileLine could return true when no data was read --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40644 --- core/smn_filesystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 5c6c9f6e..9cad4d6c 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -194,7 +194,10 @@ static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) return 0; } - fgets(buf, params[3], pFile); + if (fgets(buf, params[3], pFile) == NULL) + { + return 0; + } return 1; } From c6183b14b0117e844a9b9fd729cf473f6b9a2840 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 22:49:52 +0000 Subject: [PATCH 0614/1664] moved to inner loop --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40645 --- plugins/admin-flatfile/admin-simple.sp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/admin-flatfile/admin-simple.sp b/plugins/admin-flatfile/admin-simple.sp index a215f3a3..a21fd2aa 100644 --- a/plugins/admin-flatfile/admin-simple.sp +++ b/plugins/admin-flatfile/admin-simple.sp @@ -17,8 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -ReadSimpleUsers() + +public ReadSimpleUsers() { BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admins_simple.ini"); @@ -32,7 +32,10 @@ ReadSimpleUsers() while (!IsEndOfFile(file)) { decl String:line[255]; - ReadFileLine(file, line, sizeof(line)); + if (!ReadFileLine(file, line, sizeof(line))) + { + break; + } if ((line[0] == '/' && line[1] == '/') || (line[0] == ';' || line[0] == '\0')) From c6166f4b44990178673c5314c6e6b6b943e18a3d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Mar 2007 22:50:27 +0000 Subject: [PATCH 0615/1664] fixed a very serious codegen bug where stack usage was not corrected when breaking or continuing in while loops. glad I caught this last minute! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40646 --- sourcepawn/compiler/sc1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 10ad99b7..2bd8e569 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -6417,8 +6417,8 @@ static void addwhile(int *ptr) { int k; - ptr[wqBRK]=(int)declared; /* stack pointer (for "break") */ - ptr[wqCONT]=(int)declared; /* for "continue", possibly adjusted later */ + ptr[wqBRK]=stackusage->list_id; /* stack pointer (for "break") */ + ptr[wqCONT]=stackusage->list_id; /* for "continue", possibly adjusted later */ ptr[wqLOOP]=getlabel(); ptr[wqEXIT]=getlabel(); if (wqptr>=(wq+wqTABSZ-wqSIZE)) From 6e78ac630298f82d2ffcf28041839b7450da9a79 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 17 Mar 2007 00:55:46 +0000 Subject: [PATCH 0616/1664] fixed several memory leaks fixed plugin listeners being removed before a OnPluginUnloaded Call_AskPluginLoad removed some virtuality all cached ptrs using the Stack system are freed now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40647 --- core/ConCmdManager.cpp | 1 - core/GameConfigs.cpp | 1 + core/TimerSys.cpp | 10 ++++++ core/TimerSys.h | 2 ++ core/UserMessages.cpp | 7 ++++ core/smn_timers.cpp | 12 +++++++ core/smn_usermsgs.cpp | 13 ++++++- core/systems/ExtensionSys.cpp | 1 - core/systems/ForwardSys.cpp | 15 +++++--- core/systems/ForwardSys.h | 3 +- core/systems/LibrarySys.h | 32 ++++++++--------- core/systems/PluginSys.cpp | 9 ++++- core/systems/PluginSys.h | 26 +++++++------- core/vm/sp_vm_basecontext.h | 66 +++++++++++++++++----------------- core/vm/sp_vm_engine.h | 15 ++++---- sourcepawn/jit/x86/jit_x86.cpp | 3 +- 16 files changed, 135 insertions(+), 81 deletions(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 11970155..140bc54b 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -56,7 +56,6 @@ void ConCmdManager::OnSourceModShutdown() /* All commands should already be removed by the time we're done */ SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); g_RootMenu.RemoveRootConsoleCommand("cmds", this); - g_PluginSys.RemovePluginsListener(this); } void ConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index 249b32f3..e23e051f 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -46,6 +46,7 @@ CGameConfig::CGameConfig(const char *file) m_pProps = sm_trie_create(); m_pKeys = sm_trie_create(); m_pStrings = new BaseStringTable(512); + m_RefCount = 0; } CGameConfig::~CGameConfig() diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 8c90a3ea..79acf385 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -27,6 +27,16 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, m_KillMe = false; } +TimerSystem::~TimerSystem() +{ + CStack::iterator iter; + for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++) + { + delete (*iter); + } + m_FreeTimers.popall(); +} + void TimerSystem::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); diff --git a/core/TimerSys.h b/core/TimerSys.h index 96576004..0da497ce 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -44,6 +44,8 @@ class TimerSystem : public ITimerSystem, public SMGlobalClass { +public: + ~TimerSystem(); public: //SMGlobalClass void OnSourceModAllInitialized(); public: //ITimerSystem diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 5687d504..08852c40 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -34,6 +34,13 @@ UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500) UserMessages::~UserMessages() { sm_trie_destroy(m_Names); + + CStack::iterator iter; + for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++) + { + delete (*iter); + } + m_FreeListeners.popall(); } void UserMessages::OnSourceModAllInitialized() diff --git a/core/smn_timers.cpp b/core/smn_timers.cpp index 140787b1..67e4b0b7 100644 --- a/core/smn_timers.cpp +++ b/core/smn_timers.cpp @@ -34,6 +34,8 @@ class TimerNatives : public IHandleTypeDispatch, public ITimedEvent { +public: + ~TimerNatives(); public: //ITimedEvent ResultType OnTimer(ITimer *pTimer, void *pData); void OnTimerEnd(ITimer *pTimer, void *pData); @@ -49,6 +51,16 @@ private: CStack m_FreeTimers; }; +TimerNatives::~TimerNatives() +{ + CStack::iterator iter; + for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++) + { + delete (*iter); + } + m_FreeTimers.popall(); +} + void TimerNatives::OnSourceModAllInitialized() { HandleAccess sec; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 9bb9305d..1d40e90a 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -34,6 +34,8 @@ class UsrMessageNatives : public IHandleTypeDispatch, public IPluginsListener { +public: + ~UsrMessageNatives(); public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener void OnSourceModAllInitialized(); void OnSourceModShutdown(); @@ -47,6 +49,16 @@ private: CStack m_FreeListeners; }; +UsrMessageNatives::~UsrMessageNatives() +{ + CStack::iterator iter; + for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++) + { + delete (*iter); + } + m_FreeListeners.popall(); +} + void UsrMessageNatives::OnSourceModAllInitialized() { HandleAccess sec; @@ -70,7 +82,6 @@ void UsrMessageNatives::OnSourceModShutdown() g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent); g_HandleSys.RemoveType(g_RdBitBufType, g_pCoreIdent); - g_PluginSys.RemovePluginsListener(this); g_WrBitBufType = 0; g_RdBitBufType = 0; } diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 7bc8abec..5d77c5b7 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -264,7 +264,6 @@ void CExtensionManager::OnSourceModAllInitialized() void CExtensionManager::OnSourceModShutdown() { g_RootMenu.RemoveRootConsoleCommand("exts", this); - g_PluginSys.RemovePluginsListener(this); g_ShareSys.DestroyIdentType(g_ExtType); } diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index f0ef70c6..c72d33b1 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -32,17 +32,22 @@ CForwardManager g_Forwards; // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS! +CForwardManager::~CForwardManager() +{ + CStack::iterator iter; + for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++) + { + delete (*iter); + } + m_FreeForwards.popall(); +} + void CForwardManager::OnSourceModAllInitialized() { g_PluginSys.AddPluginsListener(this); g_ShareSys.AddInterface(NULL, this); } -void CForwardManager::OnSourceModShutdown() -{ - g_PluginSys.RemovePluginsListener(this); -} - IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...) { CForward *fwd; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 77d798c6..2f0aeb00 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -105,6 +105,8 @@ class CForwardManager : public SMGlobalClass { friend class CForward; +public: + ~CForwardManager(); public: //IForwardManager IForward *CreateForward(const char *name, ExecType et, @@ -124,7 +126,6 @@ public: //IPluginsListener void OnPluginPauseChange(IPlugin *plugin, bool paused); public: //SMGlobalClass void OnSourceModAllInitialized(); - void OnSourceModShutdown(); protected: CForward *ForwardMake(); void ForwardFree(CForward *fwd); diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index 83009bdf..a7b5610f 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -31,12 +31,12 @@ public: CDirectory(const char *path); ~CDirectory(); public: - virtual bool MoreFiles(); - virtual void NextEntry(); - virtual const char *GetEntryName(); - virtual bool IsEntryDirectory(); - virtual bool IsEntryFile(); - virtual bool IsEntryValid(); + bool MoreFiles(); + void NextEntry(); + const char *GetEntryName(); + bool IsEntryDirectory(); + bool IsEntryFile(); + bool IsEntryValid(); public: bool IsValid(); private: @@ -56,8 +56,8 @@ public: CLibrary(LibraryHandle me); ~CLibrary(); public: - virtual void CloseLibrary(); - virtual void *GetSymbolAddress(const char *symname); + void CloseLibrary(); + void *GetSymbolAddress(const char *symname); private: LibraryHandle m_lib; }; @@ -65,14 +65,14 @@ private: class LibrarySystem : public ILibrarySys { public: - virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max); - virtual IDirectory *OpenDirectory(const char *path); - virtual void CloseDirectory(IDirectory *dir); - virtual bool PathExists(const char *path); - virtual bool IsPathFile(const char *path); - virtual bool IsPathDirectory(const char *path); - virtual void GetPlatformError(char *error, size_t err_max); - virtual size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); + ILibrary *OpenLibrary(const char *path, char *error, size_t err_max); + IDirectory *OpenDirectory(const char *path); + void CloseDirectory(IDirectory *dir); + bool PathExists(const char *path); + bool IsPathFile(const char *path); + bool IsPathDirectory(const char *path); + void GetPlatformError(char *error, size_t err_max); + size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); }; extern LibrarySystem g_LibSys; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 95b4f4e7..84214b76 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -78,7 +78,7 @@ CPlugin::~CPlugin() g_pSourcePawn->FreeFromMemory(m_plugin); m_plugin = NULL; } - if (!m_pProps) + if (m_pProps) { sm_trie_destroy(m_pProps); } @@ -649,6 +649,13 @@ CPluginManager::~CPluginManager() */ sm_trie_destroy(m_LoadLookup); sm_trie_destroy(m_pNativeLookup); + + CStack::iterator iter; + for (iter=m_iters.begin(); iter!=m_iters.end(); iter++) + { + delete (*iter); + } + m_iters.popall(); } void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index d68340c2..3f010148 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -116,19 +116,19 @@ public: CPlugin(const char *file); ~CPlugin(); public: - virtual PluginType GetType(); - virtual SourcePawn::IPluginContext *GetBaseContext(); - virtual sp_context_t *GetContext(); - virtual const sm_plugininfo_t *GetPublicInfo(); - virtual const char *GetFilename(); - virtual bool IsDebugging(); - virtual PluginStatus GetStatus(); - virtual bool SetPauseState(bool paused); - virtual unsigned int GetSerial(); - virtual const sp_plugin_t *GetPluginStructure(); - virtual IdentityToken_t *GetIdentity(); - virtual bool SetProperty(const char *prop, void *ptr); - virtual bool GetProperty(const char *prop, void **ptr, bool remove=false); + PluginType GetType(); + SourcePawn::IPluginContext *GetBaseContext(); + sp_context_t *GetContext(); + const sm_plugininfo_t *GetPublicInfo(); + const char *GetFilename(); + bool IsDebugging(); + PluginStatus GetStatus(); + bool SetPauseState(bool paused); + unsigned int GetSerial(); + const sp_plugin_t *GetPluginStructure(); + IdentityToken_t *GetIdentity(); + bool SetProperty(const char *prop, void *ptr); + bool GetProperty(const char *prop, void **ptr, bool remove=false); public: /** * Creates a plugin object with default values. diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 43d6d511..5f71bcea 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -36,43 +36,43 @@ namespace SourcePawn bool IsDebugging(); int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn); IPluginDebugInfo *GetDebugInfo(); - virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); - virtual int HeapPop(cell_t local_addr); - virtual int HeapRelease(cell_t local_addr); - virtual int FindNativeByName(const char *name, uint32_t *index); - virtual int GetNativeByIndex(uint32_t index, sp_native_t **native); - virtual uint32_t GetNativesNum(); - virtual int FindPublicByName(const char *name, uint32_t *index); - virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); - virtual uint32_t GetPublicsNum(); - virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); - virtual int FindPubvarByName(const char *name, uint32_t *index); - virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); - virtual uint32_t GetPubVarsNum(); - virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); - virtual int LocalToString(cell_t local_addr, char **addr); - virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); - virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes); - virtual int PushCell(cell_t value); - virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); - virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string); - virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); - virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite); - virtual int BindNative(const sp_nativeinfo_t *native); - virtual int BindNativeToAny(SPVM_NATIVE_FUNC native); - virtual int Execute(uint32_t code_addr, cell_t *result); - virtual cell_t ThrowNativeErrorEx(int error, const char *msg, ...); - virtual cell_t ThrowNativeError(const char *msg, ...); - virtual IPluginFunction *GetFunctionByName(const char *public_name); - virtual IPluginFunction *GetFunctionById(funcid_t func_id); + int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); + int HeapPop(cell_t local_addr); + int HeapRelease(cell_t local_addr); + int FindNativeByName(const char *name, uint32_t *index); + int GetNativeByIndex(uint32_t index, sp_native_t **native); + uint32_t GetNativesNum(); + int FindPublicByName(const char *name, uint32_t *index); + int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); + uint32_t GetPublicsNum(); + int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); + int FindPubvarByName(const char *name, uint32_t *index); + int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); + uint32_t GetPubVarsNum(); + int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); + int LocalToString(cell_t local_addr, char **addr); + int StringToLocal(cell_t local_addr, size_t chars, const char *source); + int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes); + int PushCell(cell_t value); + int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); + int PushString(cell_t *local_addr, char **phys_addr, const char *string); + int PushCellsFromArray(cell_t array[], unsigned int numcells); + int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite); + int BindNative(const sp_nativeinfo_t *native); + int BindNativeToAny(SPVM_NATIVE_FUNC native); + int Execute(uint32_t code_addr, cell_t *result); + cell_t ThrowNativeErrorEx(int error, const char *msg, ...); + cell_t ThrowNativeError(const char *msg, ...); + IPluginFunction *GetFunctionByName(const char *public_name); + IPluginFunction *GetFunctionById(funcid_t func_id); #if defined SOURCEMOD_BUILD - virtual SourceMod::IdentityToken_t *GetIdentity(); + SourceMod::IdentityToken_t *GetIdentity(); void SetIdentity(SourceMod::IdentityToken_t *token); #endif public: //IPluginDebugInfo - virtual int LookupFile(ucell_t addr, const char **filename); - virtual int LookupFunction(ucell_t addr, const char **name); - virtual int LookupLine(ucell_t addr, uint32_t *line); + int LookupFile(ucell_t addr, const char **filename); + int LookupFunction(ucell_t addr, const char **name); + int LookupLine(ucell_t addr, uint32_t *line); public: void SetContext(sp_context_t *_ctx); private: diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index f43c6b91..c4cf835c 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -32,13 +32,13 @@ class CContextTrace : public IContextTrace public: CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); public: - virtual int GetErrorCode(); - virtual const char *GetErrorString(); - virtual bool DebugInfoAvailable(); - virtual const char *GetCustomErrorString(); - virtual bool GetTraceInfo(CallStackInfo *trace); - virtual void ResetTrace(); - virtual const char *GetLastNative(uint32_t *index); + int GetErrorCode(); + const char *GetErrorString(); + bool DebugInfoAvailable(); + const char *GetCustomErrorString(); + bool GetTraceInfo(CallStackInfo *trace); + void ResetTrace(); + const char *GetLastNative(uint32_t *index); private: int m_Error; const char *m_pMsg; @@ -47,7 +47,6 @@ private: uint32_t m_Native; }; - class SourcePawnEngine : public ISourcePawnEngine { public: diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index df505752..36f305d3 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2258,7 +2258,8 @@ void JITX86::FreeContext(sp_context_t *ctx) delete [] ctx->symbols; engine->BaseFree(ctx->vm[JITVARS_REBASE]); free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); - delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; + delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; + delete (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; delete ctx; } From 3250b1d2b7830071a708b5ebe98560839a4f989e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Mar 2007 16:32:40 +0000 Subject: [PATCH 0617/1664] added the textpad files contributed by cybermind --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40648 --- editor/textpad/reg_class.reg | Bin 0 -> 2958 bytes editor/textpad/sourcepawn.syn | 533 ++++++++++++++++++++++++++++++++++ 2 files changed, 533 insertions(+) create mode 100644 editor/textpad/reg_class.reg create mode 100644 editor/textpad/sourcepawn.syn diff --git a/editor/textpad/reg_class.reg b/editor/textpad/reg_class.reg new file mode 100644 index 0000000000000000000000000000000000000000..ac558d86b8038e42844a8225a215b402a69cc870 GIT binary patch literal 2958 zcmcgt?`s-C5PhEu{U78$wQvNDzs^8E*_J?QDaJIErj+QNtzcBN!Q`KB`)1a2=R7yY zV#{&o?Ci{&H#58A?_XCKV~P|rtgu7{J!JS!-4Z{szymdJxI5-*#&rdsxWC};nCmIm zO`M?0=Q*C~`vvECN1xC5hAu9N*W>B~`dnY)f^rYn{GDM$%oT2kmQi!g??h3TT=luS z=l)0Tr;O5|?lpaexWg^?rrfI#f5QDGpNy|Vy(8X`Yw=vs?yItji1>gx^$}hXai!U$ zI8*Mz-#w>m>-V(0#eiSQReXL>zQ+r+@seJrM32=crkri$HtI&MZe&6C_Pc#s=xl6S z2D4=_ua#egxm!dpOBW*MzF>Zm?Sge0^VjBZ#%i`Uk-V?)^X!ZITEKpn-f`%&LId_$ z&dq!)ei7SOCaiCm_*Q<3ueZsxsL4g>9Xou?&cO&w#8RyD}ZK2c^JRxIW@mI_Lb8|v>YLXi@~-qtU~psvhX%AjWY zovs--w-}FGuTbXsVW=%zZJd<)&oPCH{#(OS3ky~SH@A-v14~-P6aR?{G z%;n?xm1`F2&LD8k64kpN*&3uepK98>rs;AyqG;TWz2JnDxq8Dnmrs!5+}NFO+50VL z&V(mg=4QmZKjYMPQ+ZBwnaU^BO0;Ml`)WOpyPUJ~kKp1){LjcOy0n<6)l)dheYW?_ z&wziS4|VkaF(~$RJ8qfZwngqA(o6jky~FPNxP8%Pf9*ZLLp^gIo?osBW%4(A&o4*c spVQ&z%;!+7!hXgfe)~O(`5epMR!8JAzhgx@4vyt_9K^%AFB4SWKiSwop8x;= literal 0 HcmV?d00001 diff --git a/editor/textpad/sourcepawn.syn b/editor/textpad/sourcepawn.syn new file mode 100644 index 00000000..844a5bdc --- /dev/null +++ b/editor/textpad/sourcepawn.syn @@ -0,0 +1,533 @@ + +C=1 + + +[Syntax] +Namespace1 = 6 +IgnoreCase = No +KeyWordLength = +BracketChars = {[()]} +OperatorChars = ~`!@$%^&*-+=|\:;"',.<>/? +PreprocStart = # +SyntaxStart = +SyntaxEnd = +HexPrefix = 0x +CommentStart = /* +CommentEnd = */ +CommentStartAlt = +CommentEndAlt = +SingleComment = // +SingleCommentCol = +SingleCommentAlt = +SingleCommentColAlt = +SingleCommentEsc = +StringsSpanLines = Yes +StringStart = " +StringEnd = " +StringAlt = +StringEsc = \ +CharStart = ' +CharEnd = ' +CharEsc = \ + + +; Preprocessor keywords +; ====== +[Preprocessor keywords] +#assert +#define +#else +#elseif +#emit +#endif +#endinput +#endscript +#if +#include +#pragma +#error +#tryinclude +#undef +align +ctrlchar +defined +dynamic +library +pack +rational +semicolon +tabsize + + +; Language keywords +; ====== +[Keywords 1] +assert +begin +break +case +cellsof +chars +const +continue +decl +default +do +else +enum +exit +for +forward +funcenum +functag +if +native +new +operator +public +return +sizeof +static +stock +struct +switch +tagof +while +;Compiler-defined types +bool +String +Float +Fixed +;Compiler-defined constants +false +true + + +; Constants +; ====== +[Keywords 2] +cellbits +cellmax +cellmin +charbits +charmax +charmin +ucharmax +__Pawn +debug +; +; admin.inc +; ------ +Admin_Reservation +Admin_Generic +Admin_Kick +Admin_Ban +Admin_Unban +Admin_Slay +Admin_Changemap +Admin_Convars +Admin_Config +Admin_Chat +Admin_Vote +Admin_Password +Admin_RCON +Admin_Cheats +Admin_Root +Admin_Custom1 +Admin_Custom2 +Admin_Custom3 +Admin_Custom4 +Admin_Custom5 +Admin_Custom6 +ADMFLAG_RESERVATION +ADMFLAG_GENERIC +ADMFLAG_KICK +ADMFLAG_BAN +ADMFLAG_UNBAN +ADMFLAG_SLAY +ADMFLAG_CHANGEMAP +ADMFLAG_CONVARS +ADMFLAG_CONFIG +ADMFLAG_CHAT +ADMFLAG_VOTE +ADMFLAG_PASSWORD +ADMFLAG_RCON +ADMFLAG_CHEATS +ADMFLAG_ROOT +ADMFLAG_CUSTOM1 +ADMFLAG_CUSTOM2 +ADMFLAG_CUSTOM3 +ADMFLAG_CUSTOM4 +ADMFLAG_CUSTOM5 +ADMFLAG_CUSTOM6 +AUTHMETHOD_STEAM +AUTHMETHOD_IP +AUTHMETHOD_NAME +AdminFlags_TOTAL +Override_Command +Override_CommandGroup +Command_Deny +Command_Allow +Immunity_Default +Immunity_Global +INVALID_GROUP_ID +INVALID_ADMIN_ID +Access_Real +Access_Effective +AdminCache_Overrides +AdminCache_Groups +AdminCache_Admins +; +; console.inc +; ------ +FCVAR_NONE +FCVAR_UNREGISTERED +FCVAR_LAUNCHER +FCVAR_GAMEDLL +FCVAR_CLIENTDLL +FCVAR_MATERIAL_SYSTEM +FCVAR_PROTECTED +FCVAR_SPONLY +FCVAR_ARCHIVE +FCVAR_NOTIFY +FCVAR_USERINFO +FCVAR_PRINTABLEONLY +FCVAR_UNLOGGED +FCVAR_NEVER_AS_STRING +FCVAR_REPLICATED +FCVAR_CHEAT +FCVAR_STUDIORENDER +FCVAR_DEMO +FCVAR_DONTRECORD +FCVAR_PLUGIN +FCVAR_DATACACHE +FCVAR_TOOLSYSTEM +FCVAR_FILESYSTEM +FCVAR_NOT_CONNECTED +FCVAR_SOUNDSYSTEM +FCVAR_ARCHIVE_XBOX +FCVAR_INPUTSYSTEM +FCVAR_NETWORKSYSTEM +FCVAR_VPHYSICS +; +; core.inc +; ------ +__version +Plugin_Continue +Plugin_Handled +Plugin_Stop +; +; files.inc +; ------ +FileType_Unknown +FileType_Directory +FileType_File +PLATFORM_MAX_PATH +SEEK_SET +SEEK_CUR +SEEK_END +Path_SM +; +; float.inc +; ------ +floatround_round +floatround_floor +floatround_ceil +floatround_tozero +FLOAT_PI +; +; handles.inc +; ------ +INVALID_HANDLE +; +; sourcemod.inc +; ------ +myinfo +; +; textparse.inc +; ------ +SMCParse_Continue +SMCParse_Halt +SMCParse_HaltFail +SMCError_Okay +SMCError_StreamOpen +SMCError_StreamError +SMCError_Custom +SMCError_InvalidSection1 +SMCError_InvalidSection2 +SMCError_InvalidSection3 +SMCError_InvalidSection4 +SMCError_InvalidSection5 +SMCError_InvalidTokens +SMCError_TokenOverflow +SMCError_InvalidProperty1 + + +; Natives and Stocks +; ====== +[Keywords 3] +; +; admin.inc +; ------ +DumpAdminCache +AddCommandOverride +GetCommandOverride +UnsetCommandOverride +CreateAdmGroup +FindAdmGroup +SetAdmGroupAddFlag +GetAdmGroupAddFlag +GetAdmGroupAddFlags +SetAdmGroupImmunity +GetAdmGroupImmunity +SetAdmGroupImmuneFrom +GetAdmGroupImmuneFrom +GetAdmGroupImmuneCount +AddAdmGroupCmdOverride +GetAdmGroupCmdOverride +RegisterAuthIdentType +CreateAdmin +GetAdminUsername +BindAdminIdentity +SetAdminFlag +GetAdminFlag +GetAdminFlags +AdminInheritGroup +GetAdminGroupCount +GetAdminGroup +SetAdminPassword +GetAdminPassword +FindAdminByIdentity +RemoveAdmin +FlagBitsToBitArray +FlagBitArrayToBits +FlagArrayToBits +FlagBitsToArray +FlagToBit +BitToFlag +; +; console.inc +; ------ +PrintToServer +PrintToConsole +CreateConVar +FindConVar +HookConVarChange +UnhookConVarChange +GetConVarBool +SetConVarBool +GetConVarInt +SetConVarInt +GetConVarFloat +SetConVarFloat +GetConVarString +SetConVarString +GetConVarFlags +SetConVarFlags +GetConVarName +GetConVarMin +GetConVarMax +ResetConVar +; +; datapack.inc +; ------ +CreateDataPack +WritePackCell +WritePackFloat +WritePackString +ReadPackCell +ReadPackFloat +ReadPackString +ResetPack +GetPackPosition +SetPackPosition +IsPackReadable +; +; files.inc +; ------ +BuildPath +OpenDirectory +ReadDirEntry +OpenFile +DeleteFile +ReadFileLine +IsEndOfFile +FileSeek +FilePosition +FileExists +RenameFile +DirExists +FileSize +RemoveDir +WriteFileLine +; +; float.inc +; ------ +float +FloatStr +;FloatMul +;FloatDiv +;FloatAdd +;FloatSub +FloatFraction +FloatRound +;FloatCompare +SquareRoot +Pow +Exponential +Logarithm +Sine +Cosine +Tangent +FloatAbs +ArcTangent +ArcCosine +ArcSine +ArcTangent2 +DegToRad +RadToDeg +; +; handles.inc +; ------ +IsValidHandle +CloseHandle +CloneHandle +; +; helpers.inc +; ------ +FormatUserLogText +; +; geoip.inc +; ------ +GeoipCode2 +GeoipCode3 +GeoipCountry +; +; lang.inc +; ------ +LoadTranslations +; +; sourcemod.inc +; ------ +GetMaxClients +GetClientCount +GetClientName +GetClientIP +GetClientAuthString +GetClientUserId +IsPlayerConnected +IsPlayerInGame +IsPlayerAuthorized +IsPlayerFakeClient +GetClientInfo +SetUserAdmin +GetUserAdmin +AddUserFlags +RemoveUserFlags +SetUserFlagBits +GetUserFlagBits +LogToGame +LogMessage +LogError +; +; string.inc +; ------ +strlen +StrContains +StrCompare +StrEqual +StrCopy +Format +FormatEx +VFormat +StringToInt +IntToString +StringToFloat +FloatToString +; +; textparse.inc +; ------ +SMC_CreateParser +SMC_ParseFile +SMC_GetErrorString +SMC_SetParseStart +SMC_SetParseEnd +SMC_SetReaders +SMC_SetRawLine + + +; Forwards +; ====== +[Keywords 4] +; +; admin.inc +; ------ +OnRebuildAdminCache +; +; sourcemod.inc +; ------ +OnPluginStart +AskPluginLoad +OnPluginEnd +OnPluginPauseChange +OnClientConnect +OnClientPutInServer +OnClientDisconnect +OnClientDisconnect_Post +OnClientCommand +OnClientSettingsChanged +OnClientAuthorized + + +; Tags/types +; ====== +[Keywords 5] +; +; admin.inc +; ------ +AdminFlag +OverrideType +OverrideRule +ImmunityType +GroupId +AdminId +AdmAccessMode +AdminCachePart +; +; console.inc +; ------ +OnConVarChanged +; +; core.inc +; ------ +Extension +Result +PlVers +; +; files.inc +; ------ +FileType +PathType +; +; float.inc +; ------ +floatround_method +; +; handles.inc +; ------ +Handle +; +; sourcemod.inc +; ------ +Plugin +; +; textparse.inc +; ------ +SMCResult +SMCError +SMC_ParseStart +SMC_ParseEnd +SMC_NewSection +SMC_KeyValue +SMC_EndSection +SMC_RawLine From 88eae4ad1e4308ab9f016f9a38ef2226d8305690 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Mar 2007 20:25:08 +0000 Subject: [PATCH 0618/1664] added a new forward for OnServerActivate included timers from sourcemod.inc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40649 --- core/PlayerManager.cpp | 3 +++ core/PlayerManager.h | 1 + plugins/include/sourcemod.inc | 8 ++++++++ plugins/include/timers.inc | 2 +- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index d1575139..3f1edac3 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -60,6 +60,7 @@ void PlayerManager::OnSourceModAllInitialized() m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell); m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String); + m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL); } void PlayerManager::OnSourceModShutdown() @@ -80,6 +81,7 @@ void PlayerManager::OnSourceModShutdown() g_Forwards.ReleaseForward(m_clcommand); g_Forwards.ReleaseForward(m_clinfochanged); g_Forwards.ReleaseForward(m_clauth); + g_Forwards.ReleaseForward(m_onActivate); delete [] m_Players; } @@ -97,6 +99,7 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1)); } + m_onActivate->Execute(NULL); } void PlayerManager::RunAuthChecks() diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 1b8f31cb..fd8e3e45 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -111,6 +111,7 @@ private: IForward *m_clcommand; IForward *m_clinfochanged; IForward *m_clauth; + IForward *m_onActivate; CPlayer *m_Players; int m_maxClients; int m_PlayerCount; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 3c349416..e222406f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -43,6 +43,7 @@ struct Plugin #include #include #include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -104,6 +105,13 @@ forward OnPluginPauseChange(bool:pause); */ forward OnGameFrame(); +/** + * Called when the map is loaded and configs have been parsed. + * Note that commands are processed per-frame, and thus config + * files may not be fully loaded until a few seconds later. + */ +forward OnServerLoad(); + /** * Returns the calling plugin's Handle. * diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index 12add657..a3356243 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -67,7 +67,7 @@ funcenum Timer * @param flags Flags to set (such as repeatability or auto-Handle closing). * @return Handle to the timer object. You do not need to call CloseHandle(). */ -native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags); +native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags=0); /** * Kills a timer. Use this instead of CloseHandle() if you need more options. From 49c9ab6e25637658b336db816ec3e341130e15c0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Mar 2007 23:03:44 +0000 Subject: [PATCH 0619/1664] added a playerinfo function to kick this off --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40650 --- core/PlayerManager.cpp | 50 ++++++++++++++++++++++++++++++++-- core/PlayerManager.h | 3 +++ core/smn_player.cpp | 54 ++++++++++++++++++++++++++----------- core/sourcemm_api.cpp | 4 +++ core/sourcemm_api.h | 2 ++ plugins/include/clients.inc | 9 +++++++ 6 files changed, 104 insertions(+), 18 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 3f1edac3..fdbf2a1c 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -196,8 +196,11 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const if (res) { - m_AuthQueue[++m_AuthQueue[0]] = client; - g_SourceMod.SetAuthChecking(true); + if (!m_Players[client].IsAuthorized()) + { + m_AuthQueue[++m_AuthQueue[0]] = client; + g_SourceMod.SetAuthChecking(true); + } } else { RETURN_META_VALUE(MRES_SUPERCEDE, false); } @@ -229,10 +232,13 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername int client = engine->IndexOfEdict(pEntity); CPlayer *pPlayer = GetPlayerByIndex(client); + /* If they're not connected, they're a bot */ if (!pPlayer->IsConnected()) { /* Run manual connection routines */ char error[255]; + const char *authid = engine->GetPlayerNetworkIDString(pEntity); + pPlayer->Authorize(authid); if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error))) { /* :TODO: kick the bot if it's rejected */ @@ -244,7 +250,35 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername { pListener = (*iter); pListener->OnClientConnected(client); + /* See if bot was kicked */ + if (!pPlayer->IsConnected()) + { + return; + } } + /* Now do authorization */ + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) + { + pListener = (*iter); + pListener->OnClientAuthorized(client, authid); + /* See if bot was kicked */ + if (!pPlayer->IsConnected()) + { + return; + } + } + /* Finally, tell plugins */ + if (m_clauth->GetFunctionCount()) + { + m_clauth->PushCell(client); + m_clauth->PushString(authid); + m_clauth->Execute(NULL); + } + } + + if (playerinfo) + { + pPlayer->m_Info = playerinfo->GetPlayerInfo(pEntity); } List::iterator iter; @@ -253,6 +287,11 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername { pListener = (*iter); pListener->OnClientPutInServer(client); + /* See if player was kicked */ + if (!pPlayer->IsConnected()) + { + return; + } } m_Players[client].Connect(); @@ -432,6 +471,7 @@ CPlayer::CPlayer() m_pEdict = NULL; m_Admin = INVALID_ADMIN_ID; m_TempAdmin = false; + m_Info = NULL; } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -463,6 +503,7 @@ void CPlayer::Disconnect() m_Ip.clear(); m_AuthID.clear(); m_pEdict = NULL; + m_Info = NULL; } void CPlayer::SetName(const char *name) @@ -505,6 +546,11 @@ bool CPlayer::IsAuthorized() return m_IsAuthorized; } +IPlayerInfo *CPlayer::GetPlayerInfo() +{ + return m_Info; +} + bool CPlayer::IsFakeClient() { return (strcmp(m_AuthID.c_str(), "BOT") == 0); diff --git a/core/PlayerManager.h b/core/PlayerManager.h index fd8e3e45..a61fb970 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -42,6 +42,8 @@ public: bool IsFakeClient(); void SetAdminId(AdminId id, bool temporary); AdminId GetAdminId(); +public: + IPlayerInfo *GetPlayerInfo(); private: void Initialize(const char *name, const char *ip, edict_t *pEntity); void Connect(); @@ -59,6 +61,7 @@ private: AdminId m_Admin; bool m_TempAdmin; edict_t *m_pEdict; + IPlayerInfo *m_Info; }; class PlayerManager : diff --git a/core/smn_player.cpp b/core/smn_player.cpp index f7c7190b..de742b3f 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -369,26 +369,48 @@ static cell_t CanUserTarget(IPluginContext *pContext, const cell_t *params) return g_Admins.CanAdminTarget(pPlayer->GetAdminId(), pTarget->GetAdminId()) ? 1 : 0; } +static cell_t GetClientTeam(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + return pInfo->GetTeamIndex(); +} + REGISTER_NATIVES(playernatives) { - {"GetMaxClients", sm_GetMaxClients}, - {"GetClientCount", sm_GetClientCount}, - {"GetClientName", sm_GetClientName}, - {"GetClientIP", sm_GetClientIP}, - {"GetClientAuthString", sm_GetClientAuthStr}, - {"IsClientConnected", sm_IsPlayerConnected}, - {"IsPlayerInGame", sm_IsPlayerIngame}, - {"IsClientAuthorized", sm_IsPlayerAuthorized}, - {"IsFakeClient", sm_IsPlayerFakeClient}, - {"GetClientInfo", sm_GetClientInfo}, - {"SetUserAdmin", SetUserAdmin}, - {"GetUserAdmin", GetUserAdmin}, {"AddUserFlags", AddUserFlags}, - {"RemoveUserFlags", RemoveUserFlags}, - {"SetUserFlagBits", SetUserFlagBits}, - {"GetUserFlagBits", GetUserFlagBits}, - {"GetClientUserId", GetClientUserId}, {"CanUserTarget", CanUserTarget}, + {"GetClientAuthString", sm_GetClientAuthStr}, + {"GetClientCount", sm_GetClientCount}, + {"GetClientInfo", sm_GetClientInfo}, + {"GetClientIP", sm_GetClientIP}, + {"GetClientName", sm_GetClientName}, + {"GetClientTeam", GetClientTeam}, + {"GetClientUserId", GetClientUserId}, + {"GetMaxClients", sm_GetMaxClients}, + {"GetUserAdmin", GetUserAdmin}, + {"GetUserFlagBits", GetUserFlagBits}, + {"IsClientAuthorized", sm_IsPlayerAuthorized}, + {"IsClientConnected", sm_IsPlayerConnected}, + {"IsFakeClient", sm_IsPlayerFakeClient}, + {"IsPlayerInGame", sm_IsPlayerIngame}, + {"RemoveUserFlags", RemoveUserFlags}, + {"SetUserAdmin", SetUserAdmin}, + {"SetUserFlagBits", SetUserFlagBits}, {NULL, NULL} }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 1374bba5..c483d489 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -27,6 +27,7 @@ IGameEventManager2 *gameevents = NULL; IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; CallClass *gamedllPatch = NULL; +IPlayerInfoManager *playerinfo = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -41,6 +42,9 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); + /* :TODO: Make this optional and... make it find earlier versions [?] */ + GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); + if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL) { if (error) diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 138b02e1..bc385c92 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -18,6 +18,7 @@ #include #include #include +#include #include /** @@ -54,6 +55,7 @@ extern IGameEventManager2 *gameevents; extern SourceHook::CallClass *enginePatch; extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; +extern IPlayerInfoManager *playerinfo; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 771d4a91..7668b0f6 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -181,6 +181,15 @@ native bool:IsFakeClient(client); */ native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); +/** + * Retrieves a client's team index. + * + * @param client Player's index. + * @return Team index the client is on (mod specific). + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientTeam(client); + /** * Sets a client's AdminId. * From ee8780966dfae303c523c17ddb773024814e9309 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 17 Mar 2007 23:03:56 +0000 Subject: [PATCH 0620/1664] made another timer parameter default --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40651 --- plugins/include/timers.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index a3356243..58dd6944 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -67,7 +67,7 @@ funcenum Timer * @param flags Flags to set (such as repeatability or auto-Handle closing). * @return Handle to the timer object. You do not need to call CloseHandle(). */ -native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags=0); +native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value=INVALID_HANDLE, flags=0); /** * Kills a timer. Use this instead of CloseHandle() if you need more options. From c6375166a1443aef30a24000370f8cb7d2f19e9c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 19 Mar 2007 01:29:29 +0000 Subject: [PATCH 0621/1664] added auth ident type creation fixed some spacing issues --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40652 --- core/smn_admin.cpp | 10 ++++++++++ core/smn_functions.cpp | 22 +++++++++++----------- plugins/include/admin.inc | 9 +++++++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index 4f6e3ed6..fa8c0c21 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -423,6 +423,15 @@ static cell_t CanAdminTarget(IPluginContext *pContext, const cell_t *params) return g_Admins.CanAdminTarget(params[1], params[2]) ? 1 : 0; } +static cell_t CreateAuthMethod(IPluginContext *pContext, const cell_t *params) +{ + char *name; + pContext->LocalToString(params[1], &name); + g_Admins.RegisterAuthIdentType(name); + + return 1; +} + REGISTER_NATIVES(adminNatives) { {"DumpAdminCache", DumpAdminCache}, @@ -460,6 +469,7 @@ REGISTER_NATIVES(adminNatives) {"FlagArrayToBits", FlagArrayToBits}, {"FlagBitsToArray", FlagBitsToArray}, {"CanAdminTarget", CanAdminTarget}, + {"CreateAuthMethod", CreateAuthMethod}, /* -------------------------------------------------- */ {NULL, NULL}, }; diff --git a/core/smn_functions.cpp b/core/smn_functions.cpp index e31b9c0a..679a8678 100644 --- a/core/smn_functions.cpp +++ b/core/smn_functions.cpp @@ -1,15 +1,15 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "sm_globals.h" #include "PluginSys.h" diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 0e8596e9..0fbea006 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -489,6 +489,15 @@ native FlagBitsToArray(bits, AdminFlag:array[], maxSize) =0; */ native CanAdminTarget(AdminId:admin, AdminId:target); +/** + * Creates an admin auth method. This does not need to be called more than once + * per method, ever. + * + * @param method Name of the authentication method. + * @return True on success, false on failure. + */ +native bool:CreateAuthMethod(const String:method[]); + /** * Converts a flag to its single bit. * From c6c4de1f75c5c1f98f62726c7b2eafea352eb281 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 19 Mar 2007 01:44:09 +0000 Subject: [PATCH 0622/1664] fixed a potential bug with kicking players during authorization --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40653 --- core/PlayerManager.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index fdbf2a1c..afc575e4 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -118,6 +118,10 @@ void PlayerManager::RunAuthChecks() pPlayer->m_AuthID.assign(authstr); pPlayer->m_IsAuthorized = true; + /* Mark as removed from queue */ + m_AuthQueue[i] = 0; + removed++; + /* Send to extensions */ List::iterator iter; IClientListener *pListener; @@ -125,19 +129,20 @@ void PlayerManager::RunAuthChecks() { pListener = (*iter); pListener->OnClientAuthorized(m_AuthQueue[i], authstr); + if (!pPlayer->IsConnected()) + { + break; + } } - /* Send to plugins */ - if (m_clauth->GetFunctionCount()) + /* Send to plugins if player is still connected */ + if (pPlayer->IsConnected() && m_clauth->GetFunctionCount()) { + /* :TODO: handle the case of a player disconnecting in the middle */ m_clauth->PushCell(m_AuthQueue[i]); m_clauth->PushString(authstr); m_clauth->Execute(NULL); } - - /* Mark as removed from queue */ - m_AuthQueue[i] = 0; - removed++; } } From ec0e0dca6390423c1df0a254071fdca3a198495f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 19 Mar 2007 01:50:03 +0000 Subject: [PATCH 0623/1664] whoops, tee hee, broke OnClientAuthorized --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40654 --- core/PlayerManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index afc575e4..baa7e4b5 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -119,6 +119,7 @@ void PlayerManager::RunAuthChecks() pPlayer->m_IsAuthorized = true; /* Mark as removed from queue */ + unsigned int client = i; m_AuthQueue[i] = 0; removed++; @@ -128,7 +129,7 @@ void PlayerManager::RunAuthChecks() for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) { pListener = (*iter); - pListener->OnClientAuthorized(m_AuthQueue[i], authstr); + pListener->OnClientAuthorized(client, authstr); if (!pPlayer->IsConnected()) { break; @@ -139,7 +140,7 @@ void PlayerManager::RunAuthChecks() if (pPlayer->IsConnected() && m_clauth->GetFunctionCount()) { /* :TODO: handle the case of a player disconnecting in the middle */ - m_clauth->PushCell(m_AuthQueue[i]); + m_clauth->PushCell(client); m_clauth->PushString(authstr); m_clauth->Execute(NULL); } From 1bb6f90d2e834d28f05f1801fb268a86d1206c3f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 19 Mar 2007 05:39:11 +0000 Subject: [PATCH 0624/1664] apparently I can't change a single line of code these days --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40655 --- core/PlayerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index baa7e4b5..931962ef 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -119,7 +119,7 @@ void PlayerManager::RunAuthChecks() pPlayer->m_IsAuthorized = true; /* Mark as removed from queue */ - unsigned int client = i; + unsigned int client = m_AuthQueue[i]; m_AuthQueue[i] = 0; removed++; From 1ced2210ede07820d7894af5c307ee3c3c8cda42 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 19 Mar 2007 18:07:15 +0000 Subject: [PATCH 0625/1664] Guess I forgot to close this. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40656 --- plugins/include/helpers.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc index 939e7877..5b7381f7 100644 --- a/plugins/include/helpers.inc +++ b/plugins/include/helpers.inc @@ -69,5 +69,7 @@ stock Handle:FindPluginByFile(const String:filename[]) } } + CloseHandle(iter); + return INVALID_HANDLE; } From 862f25b2234f4da4875fec5246a3bf2c07330a0d Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Mon, 19 Mar 2007 19:19:41 +0000 Subject: [PATCH 0626/1664] fixed possible overflow cases --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40657 --- core/sm_srvcmds.cpp | 2 +- core/sm_stringutil.cpp | 8 +++++++- core/systems/LibrarySys.cpp | 2 +- plugins/include/sourcemod.inc | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 6f6119a3..568f3b28 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -158,7 +158,7 @@ void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text) char buffer[255]; size_t len, cmdlen = strlen(cmd); - len = snprintf(buffer, sizeof(buffer), " %s", cmd); + len = UTIL_Format(buffer, sizeof(buffer), " %s", cmd); if (cmdlen < 16) { size_t num = 16 - cmdlen; diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 235a790b..57806aa1 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -890,7 +890,13 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) size_t len = vsnprintf(buffer, maxlength, fmt, ap); va_end(ap); - return (len >= maxlength) ? (maxlength - 1) : len; + if (len >= maxlength) + { + buffer[maxlength - 1] = '\0'; + return (maxlength - 1); + } else { + return len; + } } char *sm_strdup(const char *str) diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index aa3b1d25..cc52530d 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -305,7 +305,7 @@ size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) size_t mylen = vsnprintf(buffer, len, fmt, ap); va_end(ap); - mylen = (mylen >= len) ? (len - 1) : mylen; + mylen = (mylen >= len) ? len : mylen; for (size_t i=0; i Date: Thu, 22 Mar 2007 21:12:17 +0000 Subject: [PATCH 0627/1664] Made this more consistent or something... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40658 --- core/Translator.cpp | 2 +- core/smn_filesystem.cpp | 18 +++++++++--------- core/sourcemod.cpp | 2 +- core/sourcemod.h | 4 ++-- core/systems/ExtensionSys.cpp | 10 +++++----- core/systems/LibrarySys.cpp | 8 ++++++-- core/systems/PluginSys.cpp | 14 +++++++------- core/systems/PluginSys.h | 2 +- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/core/Translator.cpp b/core/Translator.cpp index c9827e5e..0d307ce4 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -101,7 +101,7 @@ void CPhraseFile::ReparseFile() } SMCParseError err; - char path[PLATFORM_MAX_PATH+1]; + char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str()); unsigned int line=0, col=0; diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 9cad4d6c..601a74c9 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -64,7 +64,7 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); IDirectory *pDir = g_LibSys.OpenDirectory(realpath); @@ -142,7 +142,7 @@ static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); FILE *pFile = fopen(realpath, mode); @@ -164,7 +164,7 @@ static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); return (unlink(realpath)) ? 0 : 1; @@ -271,7 +271,7 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; @@ -313,9 +313,9 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) return 0; } - char new_realpath[PLATFORM_MAX_PATH+1]; + char new_realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath); - char old_realpath[PLATFORM_MAX_PATH+1]; + char old_realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath); #ifdef PLATFORM_WINDOWS @@ -335,7 +335,7 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; @@ -372,7 +372,7 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) return -1; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #ifdef PLATFORM_WINDOWS struct _stat s; @@ -409,7 +409,7 @@ static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH+1]; + char realpath[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); return (rmdir(realpath)) ? 0 : 1; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index e537ad8b..eee4d010 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -286,7 +286,7 @@ void SourceModBase::DoGlobalPluginLoads() size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...) { - char _buffer[PLATFORM_MAX_PATH+1]; + char _buffer[PLATFORM_MAX_PATH]; va_list ap; va_start(ap, format); diff --git a/core/sourcemod.h b/core/sourcemod.h index 0a4009a4..dcd48c29 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -92,8 +92,8 @@ private: void GameFrame(bool simulating); private: CStack m_freepacks; - char m_SMBaseDir[PLATFORM_MAX_PATH+1]; - char m_SMRelDir[PLATFORM_MAX_PATH+1]; + char m_SMBaseDir[PLATFORM_MAX_PATH]; + char m_SMRelDir[PLATFORM_MAX_PATH]; bool m_IsMapLoading; bool m_ExecPluginReload; unsigned int m_target; diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 5d77c5b7..f6200124 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -33,7 +33,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) unload_code = 0; m_FullyLoaded = false; - char path[PLATFORM_MAX_PATH+1]; + char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename); m_pLib = g_LibSys.OpenLibrary(path, error, err_max); @@ -317,7 +317,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path) { if (!strstr(path, "." PLATFORM_LIB_EXT)) { - char newpath[PLATFORM_MAX_PATH+1]; + char newpath[PLATFORM_MAX_PATH]; snprintf(newpath, PLATFORM_MAX_PATH, "%s.%s", path, PLATFORM_LIB_EXT); return LoadAutoExtension(newpath); } @@ -355,7 +355,7 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file) } /* Make sure the file direction is right */ - char path[PLATFORM_MAX_PATH+1]; + char path[PLATFORM_MAX_PATH]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) @@ -768,7 +768,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco const char *unload = g_RootMenu.GetArgument(4); if (pExt->unload_code == (unsigned)atoi(unload)) { - char filename[PLATFORM_MAX_PATH+1]; + char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); UnloadExtension(pExt); g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); @@ -781,7 +781,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco if (!pExt->IsLoaded() || (!pExt->m_Deps.size() && !pExt->m_Plugins.size())) { - char filename[PLATFORM_MAX_PATH+1]; + char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); UnloadExtension(pExt); g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index cc52530d..7304c4d6 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -301,11 +301,15 @@ ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_m size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) { va_list ap; - va_start(ap,fmt); + va_start(ap, fmt); size_t mylen = vsnprintf(buffer, len, fmt, ap); va_end(ap); - mylen = (mylen >= len) ? len : mylen; + if (mylen >= len) + { + mylen = len - 1; + buffer[mylen] = '\0'; + } for (size_t i=0; iGetEntryName(), "disabled") != 0) && (strcmp(dir->GetEntryName(), "optional") != 0)) { - char new_local[PLATFORM_MAX_PATH+1]; + char new_local[PLATFORM_MAX_PATH]; if (localpath == NULL) { /* If no path yet, don't add a former slash */ @@ -724,7 +724,7 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa && strcmp(&name[len-4], ".smx") == 0) { /* If the filename matches, load the plugin */ - char plugin[PLATFORM_MAX_PATH+1]; + char plugin[PLATFORM_MAX_PATH]; if (localpath == NULL) { snprintf(plugin, sizeof(plugin), "%s", name); @@ -944,7 +944,7 @@ bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass uint32_t num = pBase->GetPubVarsNum(); sp_pubvar_t *pubvar; IExtension *pExt; - char path[PLATFORM_MAX_PATH+1]; + char path[PLATFORM_MAX_PATH]; char *file, *name; for (uint32_t i=0; iGetPlugin(); - char name[PLATFORM_MAX_PATH+1]; + char name[PLATFORM_MAX_PATH]; const sm_plugininfo_t *info = pl->GetPublicInfo(); strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 3f010148..f421c5ab 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -229,7 +229,7 @@ protected: private: ContextPair m_ctx; PluginType m_type; - char m_filename[PLATFORM_MAX_PATH+1]; + char m_filename[PLATFORM_MAX_PATH]; PluginStatus m_status; unsigned int m_serial; sm_plugininfo_t m_info; From bb92fc06a6071e515b3a5f8dcc2f6dc46dd754a0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 22 Mar 2007 21:50:20 +0000 Subject: [PATCH 0628/1664] More consistency of some sort... Oh god, what has possessed me to do this? --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40659 --- core/AdminCache.cpp | 1 + core/CDataPack.cpp | 24 ++++++++++---------- core/CDataPack.h | 24 ++++++++++---------- core/CellRecipientFilter.h | 24 ++++++++++---------- core/ConCmdManager.cpp | 1 + core/ConVarManager.cpp | 23 ++++++++++--------- core/ConVarManager.h | 23 ++++++++++--------- core/DebugReporter.cpp | 1 + core/DebugReporter.h | 1 + core/EventManager.cpp | 23 ++++++++++--------- core/EventManager.h | 23 ++++++++++--------- core/GameConfigs.cpp | 1 + core/HalfLife2.cpp | 1 + core/Logger.cpp | 1 + core/Logger.h | 1 + core/PlayerManager.cpp | 1 + core/PlayerManager.h | 1 + core/TextParsers.cpp | 1 + core/TextParsers.h | 1 + core/TimerSys.cpp | 24 ++++++++++---------- core/Translator.cpp | 1 + core/Translator.h | 1 + core/UserMessages.cpp | 24 ++++++++++---------- core/UserMessages.h | 24 ++++++++++---------- core/sm_autonatives.cpp | 1 + core/sm_autonatives.h | 1 + core/sm_globals.h | 1 + core/sm_memtable.cpp | 1 + core/sm_memtable.h | 1 + core/sm_srvcmds.cpp | 1 + core/sm_srvcmds.h | 1 + core/sm_stringutil.cpp | 1 + core/sm_stringutil.h | 1 + core/sm_trie.cpp | 1 + core/sm_trie.h | 1 + core/sm_version.h | 1 + core/sm_version.tpl | 1 + core/smn_admin.cpp | 1 + core/smn_console.cpp | 1 + core/smn_core.cpp | 1 + core/smn_entities.cpp | 1 + core/smn_events.cpp | 1 + core/smn_fakenatives.cpp | 1 + core/smn_filesystem.cpp | 1 + core/smn_float.cpp | 1 + core/smn_functions.cpp | 1 + core/smn_halflife.cpp | 1 + core/smn_handles.cpp | 1 + core/smn_lang.cpp | 1 + core/smn_player.cpp | 1 + core/smn_sorting.cpp | 1 + core/smn_string.cpp | 1 + core/smn_textparse.cpp | 1 + core/smn_timers.cpp | 23 ++++++++++--------- core/smn_usermsgs.h | 24 ++++++++++---------- core/sourcemm_api.cpp | 1 + core/sourcemm_api.h | 1 + core/sourcemod.cpp | 1 + core/sourcemod.h | 1 + core/systems/ExtensionSys.cpp | 1 + core/systems/ExtensionSys.h | 1 + core/systems/ForwardSys.cpp | 1 + core/systems/ForwardSys.h | 1 + core/systems/HandleSys.cpp | 1 + core/systems/HandleSys.h | 1 + core/systems/LibrarySys.cpp | 1 + core/systems/LibrarySys.h | 1 + core/systems/PluginInfoDatabase.cpp | 1 + core/systems/PluginInfoDatabase.h | 1 + core/systems/PluginSys.cpp | 1 + core/systems/PluginSys.h | 1 + core/systems/ShareSys.cpp | 1 + core/systems/ShareSys.h | 1 + core/vm/sp_vm_basecontext.cpp | 1 + core/vm/sp_vm_basecontext.h | 1 + core/vm/sp_vm_engine.cpp | 1 + core/vm/sp_vm_engine.h | 1 + core/vm/sp_vm_function.cpp | 1 + core/vm/sp_vm_function.h | 1 + public/IGameConfigs.h | 32 +++++++++++++-------------- public/ISourceMod.h | 1 + public/sourcepawn/sp_vm_base.h | 1 + sourcepawn/jit/jit_helpers.h | 1 + sourcepawn/jit/x86/dll_exports.cpp | 1 + sourcepawn/jit/x86/dll_exports.h | 1 + sourcepawn/jit/x86/jit_version.h | 1 + sourcepawn/jit/x86/jit_version.tpl | 1 + sourcepawn/jit/x86/jit_x86.cpp | 1 + sourcepawn/jit/x86/jit_x86.h | 1 + sourcepawn/jit/x86/opcode_helpers.cpp | 1 + sourcepawn/jit/x86/opcode_helpers.h | 1 + sourcepawn/jit/x86/ungen_opcodes.h | 1 + sourcepawn/jit/x86/x86_macros.h | 1 + 93 files changed, 240 insertions(+), 155 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index f60accb0..666164db 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp index d4c19fdf..d059e9f0 100644 --- a/core/CDataPack.cpp +++ b/core/CDataPack.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include #include diff --git a/core/CDataPack.h b/core/CDataPack.h index 5e86c86b..1200db89 100644 --- a/core/CDataPack.h +++ b/core/CDataPack.h @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_ #define _INCLUDE_SOURCEMOD_CDATAPACK_H_ diff --git a/core/CellRecipientFilter.h b/core/CellRecipientFilter.h index 2afc0844..c9a9fc9a 100644 --- a/core/CellRecipientFilter.h +++ b/core/CellRecipientFilter.h @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_ #define _INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_ diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 140bc54b..958c8b49 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 7f31be04..46c76b81 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -1,15 +1,16 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "ConVarManager.h" #include "PluginSys.h" diff --git a/core/ConVarManager.h b/core/ConVarManager.h index 59ecfffe..b22938e1 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -1,15 +1,16 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_CONVARMANAGER_H_ #define _INCLUDE_SOURCEMOD_CONVARMANAGER_H_ diff --git a/core/DebugReporter.cpp b/core/DebugReporter.cpp index f9eb027f..50e4eda4 100644 --- a/core/DebugReporter.cpp +++ b/core/DebugReporter.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/DebugReporter.h b/core/DebugReporter.h index 1fda4bc0..d3318593 100644 --- a/core/DebugReporter.h +++ b/core/DebugReporter.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 35a1b33b..082fe522 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -1,15 +1,16 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "EventManager.h" #include "ForwardSys.h" diff --git a/core/EventManager.h b/core/EventManager.h index 5d9df54b..588b87ed 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -1,15 +1,16 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_EVENTMANAGER_H_ #define _INCLUDE_SOURCEMOD_EVENTMANAGER_H_ diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index e23e051f..53cf6150 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index d16972b4..907ef2fa 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/Logger.cpp b/core/Logger.cpp index d6b15308..da3d5ff0 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/Logger.h b/core/Logger.h index 5dd95e78..074778a9 100644 --- a/core/Logger.h +++ b/core/Logger.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 931962ef..74bba3af 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/PlayerManager.h b/core/PlayerManager.h index a61fb970..ac4ebb90 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/TextParsers.cpp b/core/TextParsers.cpp index 409ef49c..2bee2732 100644 --- a/core/TextParsers.cpp +++ b/core/TextParsers.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/TextParsers.h b/core/TextParsers.h index 300fa64a..f91a355b 100644 --- a/core/TextParsers.h +++ b/core/TextParsers.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 79acf385..1b35b410 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "TimerSys.h" diff --git a/core/Translator.cpp b/core/Translator.cpp index 0d307ce4..0399f131 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/Translator.h b/core/Translator.h index 04ca914c..74f90d05 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 08852c40..7c21c88f 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "UserMessages.h" diff --git a/core/UserMessages.h b/core/UserMessages.h index f900f07f..2d3b1d9b 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ #define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_ diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp index a0740b2e..12de8abb 100644 --- a/core/sm_autonatives.cpp +++ b/core/sm_autonatives.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_autonatives.h b/core/sm_autonatives.h index 170998c0..faf4544f 100644 --- a/core/sm_autonatives.h +++ b/core/sm_autonatives.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_globals.h b/core/sm_globals.h index 73a5018a..af237e51 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_memtable.cpp b/core/sm_memtable.cpp index fc8b1393..e3cace97 100644 --- a/core/sm_memtable.cpp +++ b/core/sm_memtable.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_memtable.h b/core/sm_memtable.h index e77eeb88..f04d6083 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 568f3b28..8771eb78 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 1b190f3c..78002c5e 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 57806aa1..d8518ed9 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 2991aae2..df72ecc6 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 375e3e72..24c003b1 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_trie.h b/core/sm_trie.h index 38acd42d..2e7ddf37 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_version.h b/core/sm_version.h index f43e3372..07718215 100644 --- a/core/sm_version.h +++ b/core/sm_version.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sm_version.tpl b/core/sm_version.tpl index a0f33049..ffe8001d 100644 --- a/core/sm_version.tpl +++ b/core/sm_version.tpl @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_admin.cpp b/core/smn_admin.cpp index fa8c0c21..2d87ab51 100644 --- a/core/smn_admin.cpp +++ b/core/smn_admin.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 8bcb5c37..7975098a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_core.cpp b/core/smn_core.cpp index d1849343..08891f3e 100644 --- a/core/smn_core.cpp +++ b/core/smn_core.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 2e346f81..dc7ed320 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 1b72eafd..2eb1fb2a 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 5b90816b..0ab4ee23 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 601a74c9..4e59c426 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_float.cpp b/core/smn_float.cpp index 9f72c38a..e5585640 100644 --- a/core/smn_float.cpp +++ b/core/smn_float.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_functions.cpp b/core/smn_functions.cpp index 679a8678..cc20016f 100644 --- a/core/smn_functions.cpp +++ b/core/smn_functions.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 356ed2ff..79f48535 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 9d7b6dde..a159fec5 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_lang.cpp b/core/smn_lang.cpp index 5b9ddcbe..c6da6f2a 100644 --- a/core/smn_lang.cpp +++ b/core/smn_lang.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_player.cpp b/core/smn_player.cpp index de742b3f..2dd5053f 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_sorting.cpp b/core/smn_sorting.cpp index b181cb52..75b8fba3 100644 --- a/core/smn_sorting.cpp +++ b/core/smn_sorting.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_string.cpp b/core/smn_string.cpp index 9be0c748..ca1bf21b 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index d0ccf358..91c8b450 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/smn_timers.cpp b/core/smn_timers.cpp index 67e4b0b7..3fb77e74 100644 --- a/core/smn_timers.cpp +++ b/core/smn_timers.cpp @@ -1,15 +1,16 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "HandleSys.h" #include "TimerSys.h" diff --git a/core/smn_usermsgs.h b/core/smn_usermsgs.h index f9e72a3d..de6af77d 100644 --- a/core/smn_usermsgs.h +++ b/core/smn_usermsgs.h @@ -1,16 +1,16 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ #define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index c483d489..2be581b4 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index bc385c92..ade38342 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index eee4d010..8ca71c80 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/sourcemod.h b/core/sourcemod.h index dcd48c29..b4a1451b 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index f6200124..6be78c36 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index a0202c74..ae294182 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index c72d33b1..dc2a650e 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 2f0aeb00..1f1f8790 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 835bf3c9..dea38e9b 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 0288abda..819cd1c0 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 7304c4d6..63784c88 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index a7b5610f..df35b2f7 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index eb0705be..edbf9bfc 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/PluginInfoDatabase.h b/core/systems/PluginInfoDatabase.h index f40724d9..0617bcb7 100644 --- a/core/systems/PluginInfoDatabase.h +++ b/core/systems/PluginInfoDatabase.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 24234307..fd67bb5d 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index f421c5ab..075c738a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index b8649cea..3dea7ecd 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index 8c9fe6f3..829f5ad3 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 0c35b182..d855a624 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 5f71bcea..e84ca66c 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index 9f884da1..fb56e4df 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index c4cf835c..daa2ea70 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index 58abee22..c571ec7f 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index 56d91b67..0428f5e2 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h index acd5ed8f..a98b7930 100644 --- a/public/IGameConfigs.h +++ b/public/IGameConfigs.h @@ -1,20 +1,20 @@ /** -* vim: set ts=4 : -* =============================================================== -* SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. -* All rights reserved. -* =============================================================== -* -* This file is part of the SourceMod/SourcePawn SDK. This file may only be -* used or modified under the Terms and Conditions of its License Agreement, -* which is found in public/licenses/LICENSE.txt. As of this notice, derivative -* works must be licensed under the GNU General Public License (version 2 or -* greater). A copy of the GPL is included under public/licenses/GPL.txt. -* -* To view the latest information, see: http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #ifndef _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ #define _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ diff --git a/public/ISourceMod.h b/public/ISourceMod.h index db24b346..d9e3b270 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index ad9e0095..ab37f9fb 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn, Copyright (C) 2004-2007 AlliedModders LLC. * All rights reserved. diff --git a/sourcepawn/jit/jit_helpers.h b/sourcepawn/jit/jit_helpers.h index cdf257ce..c882a307 100644 --- a/sourcepawn/jit/jit_helpers.h +++ b/sourcepawn/jit/jit_helpers.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/x86/dll_exports.cpp index bd54f789..05fea4be 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/x86/dll_exports.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/dll_exports.h b/sourcepawn/jit/x86/dll_exports.h index fa3859f9..8599728b 100644 --- a/sourcepawn/jit/x86/dll_exports.h +++ b/sourcepawn/jit/x86/dll_exports.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/jit_version.h b/sourcepawn/jit/x86/jit_version.h index f0db73f2..ca2d8683 100644 --- a/sourcepawn/jit/x86/jit_version.h +++ b/sourcepawn/jit/x86/jit_version.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/jit_version.tpl b/sourcepawn/jit/x86/jit_version.tpl index 6b7c221b..4d19df06 100644 --- a/sourcepawn/jit/x86/jit_version.tpl +++ b/sourcepawn/jit/x86/jit_version.tpl @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 36f305d3..95b08304 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 33b4f1af..c5278209 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index dd63abef..00fc3dd7 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h index 08f041f2..2e1a4ff6 100644 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ b/sourcepawn/jit/x86/opcode_helpers.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/ungen_opcodes.h b/sourcepawn/jit/x86/ungen_opcodes.h index 60bd6a45..4ccb9b40 100644 --- a/sourcepawn/jit/x86/ungen_opcodes.h +++ b/sourcepawn/jit/x86/ungen_opcodes.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ diff --git a/sourcepawn/jit/x86/x86_macros.h b/sourcepawn/jit/x86/x86_macros.h index 256f6ce6..0f020b32 100644 --- a/sourcepawn/jit/x86/x86_macros.h +++ b/sourcepawn/jit/x86/x86_macros.h @@ -1,4 +1,5 @@ /** + * vim: set ts=4 : * ================================================================ * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ From 08ec195e27c2044d5fead6bdf9f7bc253f4247a9 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 25 Mar 2007 20:20:43 +0000 Subject: [PATCH 0629/1664] initial implementation of KV natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40660 --- core/msvc8/sourcemod_mm.vcproj | 6 +- core/smn_keyvalues.cpp | 639 +++++++++++++++++++++++++++++++++ core/sourcemm_api.cpp | 2 + core/sourcemm_api.h | 2 + plugins/include/keyvalues.inc | 280 +++++++++++++++ 5 files changed, 928 insertions(+), 1 deletion(-) create mode 100644 core/smn_keyvalues.cpp create mode 100644 plugins/include/keyvalues.inc diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0e4575de..7649f658 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp new file mode 100644 index 00000000..745756f1 --- /dev/null +++ b/core/smn_keyvalues.cpp @@ -0,0 +1,639 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "sm_stringutil.h" +#include "HandleSys.h" +#include + +HandleType_t g_KeyValueType; + +struct KeyValueStack +{ + KeyValues *pBase; + CStack pCurRoot; +}; + +class KeyValuekNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent); + g_KeyValueType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + KeyValueStack *pStk = reinterpret_cast(object); + pStk->pBase->deleteThis(); + delete pStk; + } +}; + +static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key, *value; + pCtx->LocalToString(params[2], &key); + pCtx->LocalToString(params[3], &value); + + pStk->pCurRoot.front()->SetString(key, value); + + return 1; +} + +static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToString(params[2], &key); + + pStk->pCurRoot.front()->SetInt(key, params[3]); + + return 1; +} + +static cell_t smn_KvSetUint64(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + cell_t *addr; + uint64 value; + pCtx->LocalToString(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &addr); + + value = static_cast(*addr); + pStk->pCurRoot.front()->SetUint64(key, value); + + return 1; +} + +static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToString(params[2], &key); + + pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3])); + + return 1; +} + +static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToString(params[2], &key); + + Color color(params[3], params[4], params[5], params[6]); + pStk->pCurRoot.front()->SetColor(key, color); + + return 1; +} + +static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + const char *value; + char *key, *defvalue; + pCtx->LocalToString(params[2], &key); + pCtx->LocalToString(params[5], &defvalue); + + value = pStk->pCurRoot.front()->GetString(key, defvalue); + pCtx->StringToLocalUTF8(params[3], params[4], value, NULL); + + return 1; +} + +static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + int value; + char *key; + pCtx->LocalToString(params[2], &key); + + value = pStk->pCurRoot.front()->GetInt(key, params[3]); + + return value; +} + +static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + float value; + char *key; + pCtx->LocalToString(params[2], &key); + + value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3])); + + return sp_ftoc(value); +} + +static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + Color color; + char *key; + cell_t *r, *g, *b, *a; + pCtx->LocalToString(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &r); + pCtx->LocalToPhysAddr(params[4], &g); + pCtx->LocalToPhysAddr(params[5], &b); + pCtx->LocalToPhysAddr(params[6], &a); + + color = pStk->pCurRoot.front()->GetColor(key); + *r = color.r(); + *g = color.g(); + *b = color.b(); + *a = color.a(); + + return 1; +} + +static cell_t smn_KvGetUint64(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + cell_t *addr, *defvalue; + uint64 value; + pCtx->LocalToString(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &addr); + pCtx->LocalToPhysAddr(params[4], &defvalue); + + value = pStk->pCurRoot.front()->GetUint64(key, static_cast(*defvalue)); + *reinterpret_cast(addr) = value; + + return 1; +} + +static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params) +{ + KeyValueStack *pStk; + char *name, *firstkey, *firstvalue; + bool is_empty; + + pCtx->LocalToString(params[1], &name); + pCtx->LocalToString(params[2], &firstkey); + pCtx->LocalToString(params[3], &firstvalue); + + is_empty = (firstkey[0] == '\0'); + pStk = new KeyValueStack; + pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue); + pStk->pCurRoot.push(pStk->pBase); + + return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + KeyValues *pSubKey = pStk->pBase->FindKey(name, (params[3]) ? true : false); + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.push(pSubKey); + + return 1; +} + +static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + KeyValues *pFirstSubKey = pSubKey->GetFirstSubKey(); + if (!pFirstSubKey) + { + return 0; + } + pStk->pCurRoot.push(pFirstSubKey); + + return 1; +} + +static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + KeyValues *pNextKey = pSubKey->GetNextKey(); + if (!pNextKey) + { + return 0; + } + pStk->pCurRoot.push(pNextKey); + + return 1; +} + +static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() == 1) + { + return 0; + } + pStk->pCurRoot.pop(); + + return 1; +} + +static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + while (pStk->pCurRoot.size() > 1) + { + pStk->pCurRoot.pop(); + } + + return 1; +} + +static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSection = pStk->pCurRoot.front(); + const char *name = pSection->GetName(); + if (!name) + { + return 0; + } + pCtx->StringToLocalUTF8(params[2], params[3], name, NULL); + + return 1; +} + +static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + KeyValues *pSection = pStk->pCurRoot.front(); + pSection->SetName(name); + + return 1; +} + +static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + return pStk->pCurRoot.front()->GetDataType(name); +} + +static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *path; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &path); + + char realpath[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); + + return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath); +} + +static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *path; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &path); + + char realpath[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); + + return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath); +} + +static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false); + + return 1; +} + +static KeyValuekNatives s_KeyValuekNatives; + +REGISTER_NATIVES(keyvaluenatives) +{ + {"KvSetString", smn_KvSetString}, + {"KvSetNum", smn_KvSetNum}, + {"KvSetUint64", smn_KvSetUint64}, + {"KvSetFloat", smn_KvSetFloat}, + {"KvSetColor", smn_KvSetColor}, + {"KvGetString", smn_KvGetString}, + {"KvGetNum", smn_KvGetNum}, + {"KvGetFloat", smn_KvGetFloat}, + {"KvGetColor", smn_KvGetColor}, + {"KvGetUint64", smn_KvGetUint64}, + {"CreateKeyValues", smn_CreateKeyValues}, + {"KvJumpToKey", smn_KvJumpToKey}, + {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey}, + {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, + {"KvGoBack", smn_KvGoBack}, + {"KvRewind", smn_KvRewind}, + {"KvGetSectionName", smn_KvGetSectionName}, + {"KvSetSectionName", smn_KvSetSectionName}, + {"KvGetDataType", smn_KvGetDataType}, + {"KeyValuesToFile", smn_KeyValuesToFile}, + {"FileToKeyValues", smn_FileToKeyValues}, + {"KvSetEscapeSequences", smn_KvSetEscapeSequences}, + {NULL, NULL} +}; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 2be581b4..cf687e62 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -29,6 +29,7 @@ IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; CallClass *gamedllPatch = NULL; IPlayerInfoManager *playerinfo = NULL; +IBaseFileSystem *basefilesystem; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -42,6 +43,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, icvar, ICvar, VENGINE_CVAR_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(fileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION); /* :TODO: Make this optional and... make it find earlier versions [?] */ GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index ade38342..be28c1f1 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -21,6 +21,7 @@ #include #include #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -57,6 +58,7 @@ extern SourceHook::CallClass *enginePatch; extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; extern IPlayerInfoManager *playerinfo; +extern IBaseFileSystem *basefilesystem; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc new file mode 100644 index 00000000..56ac067f --- /dev/null +++ b/plugins/include/keyvalues.inc @@ -0,0 +1,280 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _keyvalues_included + #endinput +#endif +#define _keyvalues_included + +/** + * KeyValue data value types + */ +enum KvDataTypes +{ + KvData_None = 0, /**< Type could not be identified, or no type */ + KvData_String, /**< String value */ + KvData_Int, /**< Integer value */ + KvData_Float, /**< Floating point value */ + KvData_Ptr, /**< Pointer value (sometimes called "long") */ + KvData_WString, /**< Wide string value */ + KvData_Color, /**< Color value */ + KvData_UInt64, /**< Large integer value */ + /* --- */ + KvData_NUMTYPES, +}; + +/** + * Creates a new KeyValues structure. The Handle must always be closed. + * + * @param name Name of the root section. + * @param firstKey If non-empty, specifies the first key value. + * @param firstValue If firstKey is non-empty, specifies the first key's value. + * @return A Handle to a new KeyValues structure. + */ +native Handle:CreateKeyValues(const String:name[], const String:firstkey[], const String:firstValue[]); + +/** + * Sets a string value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value String value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetString(Handle:kv, const String:key[], const String:value[]); + +/** + * Sets an integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Value number. + * @noreturn + * @error Invalid Handle. + */ +native KvSetNum(Handle:kv, const String:key[], value); + +/** + * Sets a large integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Large integer value (0=High bits, 1=Low bits) + * @noreturn + * @error Invalid Handle. + */ +native KvSetUint64(Handle:kv, const String:key[], const value[2]); + +/** + * Sets a floating point value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Floating point value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetFloat(Handle:kv, const String:key[], Float:value); + +/** + * Sets a set of color values of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param r Red value. + * @param g Green value. + * @param b Blue value. + * @param a Alpha value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetColor(Handle:kv, const String:key[], r, g, b, a=0); + +/** + * Retrieves a string value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Buffer to store key value in. + * @param maxlength Maximum length of the value buffer. + * @param defvalue Optional default value to use if the key is not found. + * @noreturn + * @error Invalid Handle. + */ +native KvGetString(Handle:kv, const String:key[], String:value[], maxlength, const String:defvalue[]=""); + +/** + * Retrieves an integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param defvalue Optional default value to use if the key is not found. + * @return Integer value of the key. + * @error Invalid Handle. + */ +native KvGetNum(Handle:kv, const String:key[], defvalue=0); + +/** + * Retrieves a floating point value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param defvalue Optional default value to use if the key is not found. + * @return Floating point value of the key. + * @error Invalid Handle. + */ +native Float:KvGetFloat(Handle:kv, const String:key[], Float:defvalue=0.0); + +/** + * Retrieves a set of color values from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param r Red value, set by reference. + * @param g Green value, set by reference. + * @param b Blue value, set by reference. + * @param a Alpha value, set by reference. + * @noreturn + * @error Invalid Handle. + */ +native KvGetColor(Handle:kv, const String:key[], &r, &g, &b, &a); + +/** + * Retrieves a large integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Array to represent the large integer. + * @param defvalue Optional default value to use if the key is not found. + * @noreturn + * @error Invalid Handle. + */ +native KvGetUint64(Handle:kv, const String:key[], value[2], defvalue[2]={0,0}); + +/** + * Sets the current position in the KeyValues tree to the given key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param create If true, and the key does not exist, it will be created. + * @return True if the key exists, false if it does not and was not created. + */ +native bool:KvJumpToKey(Handle:kv, const String:key[], bool:create=false); + +/** + * Sets the current position in the KeyValues tree to the first sub key. + * + * @param kv KeyValues Handle. + * @return True on success, false if there was no first sub key. + * @error Invalid Handle. + */ +native bool:KvJumpFirstSubKey(Handle:kv); + +/** + * Sets the current position in the KeyValues tree to the next sub key. + * + * @param kv KeyValues Handle. + * @return True on success, false if there was no next sub key. + * @error Invalid Handle. + */ +native bool:KvJumpNextSubKey(Handle:kv); + +/** + * Jumps back to the previous position. Returns false if there are no + * previous positions (i.e., at the root node). This should be called + * once for each successful Jump call, in order to return to the top node. + * + * @param kv KeyValues Handle. + * @return True on success, false if there is no higher node. + * @error Invalid Handle. + */ +native bool:KvGoBack(Handle:kv); + +/** + * Sets the position back to the top node, emptying the entire node + * traversal history. This can be used instead of looping KvGoBack() + * if recursive iteration is not important. + * + * @param kv KeyValues Handle. + * @noreturn + * @error Invalid Handle. + */ +native KvRewind(Handle:kv); + +/** + * Retrieves the current section name. + * + * @param kv KeyValues Handle. + * @param section Buffer to store the section name. + * @param maxlength Maximum length of the name buffer. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool:KvGetSectionName(Handle:kv, String:section[], maxlength); + +/** + * Sets the current section name. + * + * @param kv KeyValues Handle. + * @param section Section name. + * @noreturn + * @error Invalid Handle. + */ +native KvSetSectionName(Handle:kv, const String:section[]); + +/** + * Returns the data type at a key. + * + * @param kv KeyValues Handle. + * @param key Key name. + * @return KvDataType value of the key. + * @error Invalid Handle. + */ +native KvDataTypes:KvGetDataType(Handle:kv, const String:key[]); + +/** + * Converts a KeyValues tree to a file. The tree is dumped + * from the current position. + * + * @param kv KeyValues Handle. + * @param file File to dump write to. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool:KeyValuesToFile(Handle:kv, const String:file[]); + +/** + * Converts a file to a KeyValues tree. The file is read into + * the current position of the tree. + * + * @param kv KeyValues Handle. + * @param file File to read from. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool:FileToKeyValues(Handle:kv, const String:file[]); + +/** + * Sets whether or not the KeyValues parser will read escape sequences. + * For example, \n would be read as a literal newline. This defaults + * to false for new KeyValues structures. + * + * @param kv KeyValues Handle. + * @param useEscapes Whether or not to read escape sequences. + * @noreturn + * @error Invalid Handle. + */ +native KvSetEscapeSequences(Handle:kv, bool:useEscapes); From 5c7381f11acb891a7355c06ce382ae87f1ecfc22 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 25 Mar 2007 21:18:50 +0000 Subject: [PATCH 0630/1664] synced linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40661 --- core/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/Makefile b/core/Makefile index f1368bda..9c3f34a2 100644 --- a/core/Makefile +++ b/core/Makefile @@ -26,8 +26,9 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp \ sourcemm_api.cpp sourcemod.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ - smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_halflife.cpp smn_handles.cpp smn_lang.cpp \ - smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp smn_usermsgs.cpp + smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ + smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \ + smn_usermsgs.cpp OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ From fd1e3c4e9782048e62244973329e795861aa7115 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 25 Mar 2007 22:25:45 +0000 Subject: [PATCH 0631/1664] added precache natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40662 --- core/smn_halflife.cpp | 81 +++++++++++++++++++++++++++++++++++ core/sourcemm_api.cpp | 4 +- core/sourcemm_api.h | 2 + plugins/include/sourcemod.inc | 77 +++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 79f48535..3c79d501 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -135,6 +135,78 @@ static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) return bytes; } +static cell_t PrecacheModel(IPluginContext *pContext, const cell_t *params) +{ + char *model; + pContext->LocalToString(params[1], &model); + + return engine->PrecacheModel(model, params[2] ? true : false); +} + +static cell_t PrecacheSentenceFile(IPluginContext *pContext, const cell_t *params) +{ + char *sentencefile; + pContext->LocalToString(params[1], &sentencefile); + + return engine->PrecacheSentenceFile(sentencefile, params[2] ? true : false); +} + +static cell_t PrecacheDecal(IPluginContext *pContext, const cell_t *params) +{ + char *decal; + pContext->LocalToString(params[1], &decal); + + return engine->PrecacheDecal(decal, params[2] ? true : false); +} + +static cell_t PrecacheGeneric(IPluginContext *pContext, const cell_t *params) +{ + char *generic; + pContext->LocalToString(params[1], &generic); + + return engine->PrecacheGeneric(generic, params[2] ? true : false); +} + +static cell_t IsModelPrecached(IPluginContext *pContext, const cell_t *params) +{ + char *model; + pContext->LocalToString(params[1], &model); + + return engine->IsModelPrecached(model) ? 1 : 0; +} + +static cell_t IsDecalPrecached(IPluginContext *pContext, const cell_t *params) +{ + char *decal; + pContext->LocalToString(params[1], &decal); + + return engine->IsDecalPrecached(decal) ? 1 : 0; +} + +static cell_t IsGenericPrecached(IPluginContext *pContext, const cell_t *params) +{ + char *generic; + pContext->LocalToString(params[1], &generic); + + return engine->IsGenericPrecached(generic) ? 1 : 0; +} + +static cell_t PrecacheSound(IPluginContext *pContext, const cell_t *params) +{ + char *sample; + pContext->LocalToString(params[1], &sample); + + return enginesound->PrecacheSound(sample, params[2] ? true : false) ? 1 : 0; +} + +static cell_t IsSoundPrecached(IPluginContext *pContext, const cell_t *params) +{ + char *sample; + pContext->LocalToString(params[1], &sample); + + return enginesound->IsSoundPrecached(sample) ? 1 : 0; +} + REGISTER_NATIVES(halflifeNatives) { {"CreateFakeClient", CreateFakeClient}, @@ -148,5 +220,14 @@ REGISTER_NATIVES(halflifeNatives) {"IsMapValid", IsMapValid}, {"SetFakeClientConVar", SetFakeClientConVar}, {"SetRandomSeed", SetRandomSeed}, + {"PrecacheModel", PrecacheModel}, + {"PrecacheSentenceFile", PrecacheSentenceFile}, + {"PrecacheDecal", PrecacheDecal}, + {"PrecacheGeneric", PrecacheGeneric}, + {"IsModelPrecached", IsModelPrecached}, + {"IsDecalPrecached", IsDecalPrecached}, + {"IsGenericPrecached", IsGenericPrecached}, + {"PrecacheSound", PrecacheSound}, + {"IsSoundPrecached", IsSoundPrecached}, {NULL, NULL}, }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index cf687e62..ea4cdcd7 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -29,7 +29,8 @@ IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; CallClass *gamedllPatch = NULL; IPlayerInfoManager *playerinfo = NULL; -IBaseFileSystem *basefilesystem; +IBaseFileSystem *basefilesystem = NULL; +IEngineSound *enginesound = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -44,6 +45,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); GET_V_IFACE_CURRENT(fileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(engineFactory, enginesound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION); /* :TODO: Make this optional and... make it find earlier versions [?] */ GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index be28c1f1..a35c327e 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -22,6 +22,7 @@ #include #include #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -59,6 +60,7 @@ extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; extern IPlayerInfoManager *playerinfo; extern IBaseFileSystem *basefilesystem; +extern IEngineSound *enginesound; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 6f3a01c4..2ff3bdbc 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -310,5 +310,82 @@ native GetGameDescription(String:buffer[], maxlength, bool:original=false); */ native GetCurrentMap(String:buffer[], maxlength); +/** + * Precaches a given model. + * + * @param model Name of the model to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns the model index, 0 for error. + */ +native PrecacheModel(const String:model[], bool:preload=false); + +/** + * Precaches a given sentence file. + * + * @param file Name of the sentence file to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a sentence file index. + */ +native PrecacheSentenceFile(const String:file[], bool:preload=false); + +/** + * Precaches a given decal. + * + * @param decal Name of the decal to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a decal index. + */ +native PrecacheDecal(const String:decal[], bool:preload=false); + +/** + * Precaches a given generic file. + * + * @param generic Name of the generic file to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a generic file index. + */ +native PrecacheGeneric(const String:generic[], bool:preload=false); + +/** + * Returns if a given model is precached. + * + * @param model Name of the model to check. + * @return True if precached, false otherwise. + */ +native bool:IsModelPrecached(const String:model[]); + +/** + * Returns if a given decal is precached. + * + * @param decal Name of the decal to check. + * @return True if precached, false otherwise. + */ +native bool:IsDecalPrecached(const String:decal[]); + +/** + * Returns if a given generic file is precached. + * + * @param decal Name of the generic file to check. + * @return True if precached, false otherwise. + */ +native bool:IsGenericPrecached(const String:generic[]); + +/** + * Precaches a given sound. + * + * @param sound Name of the sound to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return True if successfully precached, false otherwise. + */ +native bool:PrecacheSound(const String:sound[], bool:preload=false); + +/** + * Returns if a given sound is precached. + * + * @param sound Name of the sound to check. + * @return True if precached, false otherwise. + */ +native bool:IsSoundPrecached(const String:sound[]); + #include #include From 22dd1ba5926c2b6fb620e916f5395e58055abb89 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 28 Mar 2007 20:28:42 +0000 Subject: [PATCH 0632/1664] Couple of quick things... - Changed SourceMod logtag from SRCMOD to SM - ConVars dynamically created by convar manager now can properly be set on srcds command line --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40663 --- core/sm_srvcmds.cpp | 7 +++++++ core/sourcemm_api.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 8771eb78..77cf815d 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -59,6 +59,13 @@ bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand) { META_REGCVAR(pCommand); + /* Override values of convars created by SourceMod convar manager if specified on command line */ + const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName()); + if (cmdLineValue && !pCommand->IsCommand()) + { + static_cast(pCommand)->SetValue(cmdLineValue); + } + return true; } diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index ea4cdcd7..c2461049 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -121,5 +121,5 @@ const char *SourceMod_Core::GetDate() const char *SourceMod_Core::GetLogTag() { - return "SRCMOD"; + return "SM"; } From daeb5a7dba4b377b368b9c365382fa14f8fba05e Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Wed, 28 Mar 2007 23:35:12 +0000 Subject: [PATCH 0633/1664] added iplayerinfo natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40664 --- core/PlayerManager.cpp | 2 +- core/smn_player.cpp | 257 +++++++++++++++++++++++++++++++++++- plugins/include/clients.inc | 98 ++++++++++++++ 3 files changed, 355 insertions(+), 2 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 74bba3af..12569f78 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -520,7 +520,7 @@ void CPlayer::SetName(const char *name) const char *CPlayer::GetName() { - return m_Name.c_str(); + return (m_Info) ? m_Info->GetName(): m_Name.c_str(); } const char *CPlayer::GetIPAddress() diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 2dd5053f..6f0a055b 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -391,6 +391,252 @@ static cell_t GetClientTeam(IPluginContext *pContext, const cell_t *params) return pInfo->GetTeamIndex(); } +static cell_t GetFragCount(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + return pInfo->GetFragCount(); +} + +static cell_t GetDeathCount(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + return pInfo->GetDeathCount(); +} + +static cell_t GetArmorValue(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + return pInfo->GetArmorValue(); +} + +static cell_t GetAbsOrigin(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + cell_t *pVec; + pContext->LocalToPhysAddr(params[2], &pVec); + + Vector vec = pInfo->GetAbsOrigin(); + pVec[0] = sp_ftoc(vec.x); + pVec[1] = sp_ftoc(vec.y); + pVec[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t GetAbsAngles(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + cell_t *pAng; + pContext->LocalToPhysAddr(params[2], &pAng); + + QAngle ang = pInfo->GetAbsAngles(); + pAng[0] = sp_ftoc(ang.x); + pAng[1] = sp_ftoc(ang.y); + pAng[2] = sp_ftoc(ang.z); + + return 1; +} + +static cell_t GetPlayerMins(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + cell_t *pVec; + pContext->LocalToPhysAddr(params[2], &pVec); + + Vector vec = pInfo->GetPlayerMins(); + pVec[0] = sp_ftoc(vec.x); + pVec[1] = sp_ftoc(vec.y); + pVec[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t GetPlayerMaxs(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + cell_t *pVec; + pContext->LocalToPhysAddr(params[2], &pVec); + + Vector vec = pInfo->GetPlayerMaxs(); + pVec[0] = sp_ftoc(vec.x); + pVec[1] = sp_ftoc(vec.y); + pVec[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t GetWeaponName(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pInfo->GetWeaponName(), NULL); + + return 1; +} + +static cell_t GetModelName(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pInfo->GetModelName(), NULL); + + return 1; +} + +static cell_t GetHealth(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } + + IPlayerInfo *pInfo = pPlayer->GetPlayerInfo(); + if (!pInfo) + { + return pContext->ThrowNativeError("IPlayerInfo not supported by game"); + } + + return pInfo->GetHealth(); +} + REGISTER_NATIVES(playernatives) { {"AddUserFlags", AddUserFlags}, @@ -412,6 +658,15 @@ REGISTER_NATIVES(playernatives) {"RemoveUserFlags", RemoveUserFlags}, {"SetUserAdmin", SetUserAdmin}, {"SetUserFlagBits", SetUserFlagBits}, + {"GetClientDeaths", GetDeathCount}, + {"GetClientFrags", GetFragCount}, + {"GetClientArmor", GetArmorValue}, + {"GetClientAbsOrigin", GetAbsOrigin}, + {"GetClientAbsAngles", GetAbsAngles}, + {"GetClientMins", GetPlayerMins}, + {"GetClientMaxs", GetPlayerMaxs}, + {"GetClientWeapon", GetWeaponName}, + {"GetClientModel", GetModelName}, + {"GetClientHealth", GetHealth}, {NULL, NULL} }; - diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 7668b0f6..bfcfa590 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -282,3 +282,101 @@ native CreateFakeClient(const String:name[]); * or client not a fake client. */ native SetFakeClientConVar(client, const String:cvar[], const String:value[]); + +/** + * Returns the client's health. + * + * @param client Player's index. + * @return Health value. + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientHealth(client); + +/** + * Returns the client's model name. + * + * @param client Player's index. + * @param model Buffer to store the client's model name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientModel(client, String:model[], maxlen); + +/** + * Returns the client's weapon name. + * + * @param client Player's index. + * @param weapon Buffer to store the client's weapon name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientWeapon(client, String:weapon[], maxlen); + +/** + * Returns the client's max size vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's max size. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientMaxs(client, Float:vec[3]); + +/** + * Returns the client's min size vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's min size. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientMins(client, Float:vec[3]); + +/** + * Returns the client's position angle. + * + * @param client Player's index. + * @param ang Destination vector to store the client's position angle. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientAbsAngles(client, Float:ang[3]); + +/** + * Returns the client's origin vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's origin vector. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientAbsOrigin(client, Float:vec[3]); + +/** + * Returns the client's armor. + * + * @param client Player's index. + * @return Armor value. + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientArmor(client); + +/** + * Returns the client's death count. + * + * @param client Player's index. + * @return Death count. + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientDeaths(client); + +/** + * Returns the client's frag count. + * + * @param client Player's index. + * @return Frag count. + * @error Invalid client index, client not in game, or no mod support. + */ +native GetClientFrags(client); From 708a3a9a5c941e48a6ad229b351ca702f53e821a Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 29 Mar 2007 19:48:54 +0000 Subject: [PATCH 0634/1664] oh one native for the hat man teame --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40665 --- core/smn_halflife.cpp | 23 +++++++++++++++++++++++ core/sourcemm_api.cpp | 2 ++ core/sourcemm_api.h | 1 + plugins/include/sourcemod.inc | 11 +++++++++++ 4 files changed, 37 insertions(+) diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 3c79d501..e9a2bf5e 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -207,6 +207,28 @@ static cell_t IsSoundPrecached(IPluginContext *pContext, const cell_t *params) return enginesound->IsSoundPrecached(sample) ? 1 : 0; } +static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + char buffer[256]; + g_SourceMod.FormatString(buffer, sizeof(buffer)-1, pContext, params, 2); + + serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer); + + return 1; +} + REGISTER_NATIVES(halflifeNatives) { {"CreateFakeClient", CreateFakeClient}, @@ -229,5 +251,6 @@ REGISTER_NATIVES(halflifeNatives) {"IsGenericPrecached", IsGenericPrecached}, {"PrecacheSound", PrecacheSound}, {"IsSoundPrecached", IsSoundPrecached}, + {"FakeClientCommand", FakeClientCommand}, {NULL, NULL}, }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index c2461049..387c7a1f 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -31,6 +31,7 @@ CallClass *gamedllPatch = NULL; IPlayerInfoManager *playerinfo = NULL; IBaseFileSystem *basefilesystem = NULL; IEngineSound *enginesound = NULL; +IServerPluginHelpers *serverpluginhelpers = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -46,6 +47,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); GET_V_IFACE_CURRENT(fileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, enginesound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(engineFactory, serverpluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS); /* :TODO: Make this optional and... make it find earlier versions [?] */ GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index a35c327e..8e3b7612 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -61,6 +61,7 @@ extern IUniformRandomStream *engrandom; extern IPlayerInfoManager *playerinfo; extern IBaseFileSystem *basefilesystem; extern IEngineSound *enginesound; +extern IServerPluginHelpers *serverpluginhelpers; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 2ff3bdbc..4fca185f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -387,5 +387,16 @@ native bool:PrecacheSound(const String:sound[], bool:preload=false); */ native bool:IsSoundPrecached(const String:sound[]); +/** + * Executes a client command on the server without being networked. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @noreturn + * @error Invalid client index, or client not connected. + */ +native FakeClientCommand(client, const String:fmt[], any:...); + #include #include From af77decdab3811ed224c5c3258947ba266187ba9 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 3 Apr 2007 07:02:27 +0000 Subject: [PATCH 0635/1664] configs/gamedata wasn't being copied... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40666 --- tools/builder/PkgCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 1190cd24..adacf38a 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -33,7 +33,7 @@ namespace builder folders[0] = "bin"; folders[1] = "plugins/disabled"; - folders[2] = "configs"; + folders[2] = "configs/gamedata"; folders[3] = "translations"; folders[4] = "logs"; folders[5] = "extensions"; @@ -55,6 +55,7 @@ namespace builder public override void OnCopyFolders(ABuilder builder) { builder.CopyFolder(this, "configs", "configs", null); + builder.CopyFolder(this, "configs/gamedata", "configs/gamedata", null); string [] plugin_omits = new string[1]; plugin_omits[0] = "spcomp.exe"; From ddfe6d84d63e32ee9a39c89d58a7772f5d9713f8 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 03:02:00 +0000 Subject: [PATCH 0636/1664] Ugh, initial import of core config file stuff Warning: This is positively terrible code. It works, but needs A LOT of work still :\ --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40667 --- configs/core.cfg | 12 +++ core/CoreConfig.cpp | 133 +++++++++++++++++++++++++++++++++ core/CoreConfig.h | 50 +++++++++++++ core/Logger.cpp | 64 +++++++++++++--- core/Logger.h | 11 ++- core/Translator.cpp | 26 ++++++- core/Translator.h | 7 +- core/msvc8/sourcemod_mm.vcproj | 10 ++- core/sm_globals.h | 28 ++++++- core/sm_stringutil.cpp | 6 +- core/sourcemod.cpp | 35 ++++++++- core/sourcemod.h | 13 +++- 12 files changed, 368 insertions(+), 27 deletions(-) create mode 100644 configs/core.cfg create mode 100644 core/CoreConfig.cpp create mode 100644 core/CoreConfig.h diff --git a/configs/core.cfg b/configs/core.cfg new file mode 100644 index 00000000..d1a7c25c --- /dev/null +++ b/configs/core.cfg @@ -0,0 +1,12 @@ +"Core" +{ + "BasePath" "addons/sourcemod" + + "Logging" "on" + + "LogMode" "daily" + + "ServerLang" "en" + + "InvalidOpt" "hello" +} diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp new file mode 100644 index 00000000..0a5850dc --- /dev/null +++ b/core/CoreConfig.cpp @@ -0,0 +1,133 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "CoreConfig.h" +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "sm_srvcmds.h" +#include "LibrarySys.h" +#include "TextParsers.h" +#include "Logger.h" + +#ifdef PLATFORM_WINDOWS +ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file"); +#else +ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file"); +#endif + +CoreConfig g_CoreConfig; + +void CoreConfig::OnSourceModAllInitialized() +{ + g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this); +} + +void CoreConfig::OnSourceModShutdown() +{ + g_RootMenu.RemoveRootConsoleCommand("config", this); +} + +void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount) +{ + if (argcount >= 4) + { + const char *option = engine->Cmd_Argv(2); + const char *value = engine->Cmd_Argv(3); + + CoreConfigErr err = SetConfigOption(option, value); + + switch (err) + { + case CoreConfig_NoRuntime: + g_RootMenu.ConsolePrint("[SM] Cannot set \"%s\" while SourceMod is running.", option); + break; + case CoreConfig_InvalidValue: + g_RootMenu.ConsolePrint("[SM] Invalid value \"%s\" specified for configuration option \"%s\"", value, option); + break; + case CoreConfig_InvalidOption: + g_RootMenu.ConsolePrint("[SM] Invalid configuration option specified: %s", option); + break; + default: + break; + } + + return; + } + + g_RootMenu.ConsolePrint("[SM] Usage: sm config + + @@ -289,6 +293,10 @@ RelativePath="..\ConVarManager.h" > + + diff --git a/core/sm_globals.h b/core/sm_globals.h index af237e51..213c76d6 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -27,12 +27,26 @@ using namespace SourcePawn; using namespace SourceMod; +/** +* @brief Lists error codes possible from attempting to set a core configuration option. +*/ +enum CoreConfigErr +{ + CoreConfig_Okay = 0, /**< No error */ + CoreConfig_NoRuntime = 1, /**< Cannot set config option while SourceMod is running */ + CoreConfig_InvalidValue = 2, /**< Invalid value specified for config option */ + CoreConfig_InvalidOption = 3, /**< Invalid config option specified */ + /* -------------------- */ + CoreConfig_TOTAL /**< Total number of core config error codes */ +}; + /** * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod */ class SMGlobalClass { friend class SourceModBase; + friend class CoreConfig; public: SMGlobalClass(); public: @@ -58,11 +72,21 @@ public: } /** - * @brief Called after SourceMod is completely shut down - */ + * @brief Called after SourceMod is completely shut down + */ virtual void OnSourceModAllShutdown() { } + + /** + * @brief Called when a core config option is changed. + * @note This is called once BEFORE OnSourceModStartup() when SourceMod is loading + * @note It can then be called again when the 'sm config' command is used + */ + virtual CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value) + { + return CoreConfig_InvalidOption; + } private: SMGlobalClass *m_pGlobalClassNext; static SMGlobalClass *head; diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index d8518ed9..b8d9f914 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -62,7 +62,7 @@ inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, un size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error) { unsigned int langid; - char *langname = NULL; + const char *langname = NULL; *error = false; Translation pTrans; CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); @@ -73,14 +73,14 @@ size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char * try_serverlang: if (target == LANG_SERVER) { - langname = "en"; //:TODO: read serverlang + langname = g_Translator.GetServerLanguageCode(); if (!TryServerLanguage(langname ? langname : "en", &langid)) { pCtx->ThrowNativeError("Translation failure: English language not found"); goto error_out; } } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { - langname = "en"; //:TODO: read player's lang + langname = g_Translator.GetServerLanguageCode(); /* :TODO: read player's lang */ if (!langname || !g_Translator.GetLanguageByCode(langname, &langid)) { if (langname && !strcmp(langname, "en")) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 8ca71c80..516fe270 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -20,6 +20,7 @@ #include #include "PluginSys.h" #include "ShareSys.h" +#include "CoreConfig.h" #include "Logger.h" #include "ExtensionSys.h" #include "AdminCache.h" @@ -65,13 +66,43 @@ SourceModBase::SourceModBase() { m_IsMapLoading = false; m_ExecPluginReload = false; + m_GotBasePath = false; +} + +CoreConfigErr SourceModBase::OnSourceModConfigChanged(const char *option, const char *value) +{ + if (strcasecmp(option, "BasePath") == 0) + { + if (!m_GotBasePath) + { + g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), value); + g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), value); + + m_GotBasePath = true; + + return CoreConfig_Okay; + } else { + return CoreConfig_NoRuntime; + } + } + + return CoreConfig_InvalidOption; } bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) { g_BaseDir.assign(g_SMAPI->GetBaseDir()); - g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); - g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod"); + + /* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */ + g_CoreConfig.Initialize(); + + /* This shouldn't happen, but can't hurt to be safe */ + if (!m_GotBasePath || !g_LibSys.PathExists(m_SMBaseDir)) + { + g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); + g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod"); + m_GotBasePath = true; + } /* Attempt to load the JIT! */ char file[PLATFORM_MAX_PATH]; diff --git a/core/sourcemod.h b/core/sourcemod.h index b4a1451b..878670d8 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -26,7 +26,9 @@ using namespace SourceHook; * @brief Implements SourceMod's global overall management, API, and logic */ -class SourceModBase : public ISourceMod +class SourceModBase : + public ISourceMod, + public SMGlobalClass { public: SourceModBase(); @@ -75,7 +77,9 @@ public: * @brief Sets whether if SoureMod needs to check player auths. */ void SetAuthChecking(bool set); -public: //ISourceMod +public: // SMGlobalClass + CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value); +public: // ISourceMod const char *GetModPath() const; const char *GetSourceModPath() const; size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); @@ -90,6 +94,10 @@ private: * @brief Loading plugins */ void DoGlobalPluginLoads(); + + /** + * @brief GameFrame hook + */ void GameFrame(bool simulating); private: CStack m_freepacks; @@ -99,6 +107,7 @@ private: bool m_ExecPluginReload; unsigned int m_target; bool m_CheckingAuth; + bool m_GotBasePath; }; extern SourceModBase g_SourceMod; From 3b9c8e1410b9ad283f6d50f27c770710b6713c6a Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 03:16:03 +0000 Subject: [PATCH 0637/1664] Oh, wow, I forgot to remove this. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40668 --- configs/core.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/configs/core.cfg b/configs/core.cfg index d1a7c25c..06a97600 100644 --- a/configs/core.cfg +++ b/configs/core.cfg @@ -7,6 +7,4 @@ "LogMode" "daily" "ServerLang" "en" - - "InvalidOpt" "hello" } From f93711bd82452e770ade4d8bf41a67e6028da531 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Apr 2007 05:25:11 +0000 Subject: [PATCH 0638/1664] changed the API around a bit to be more flexible removed some ghastly unneeded stuff from the Translator added Logger::LogFatal, experimental --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40669 --- core/CoreConfig.cpp | 49 ++++++++++++------------------- core/CoreConfig.h | 2 +- core/Logger.cpp | 65 +++++++++++++++++++++++++++++++----------- core/Logger.h | 16 ++++++++--- core/Translator.cpp | 40 ++++++++++++++++++++++---- core/Translator.h | 10 +++++-- core/sm_globals.h | 29 ++++++++++++------- core/sm_stringutil.cpp | 39 ++++++++++++------------- core/sm_stringutil.h | 1 + core/sourcemod.cpp | 24 ++++++++++------ core/sourcemod.h | 6 +++- 11 files changed, 179 insertions(+), 102 deletions(-) diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index 0a5850dc..362b23e9 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -22,7 +22,7 @@ #ifdef PLATFORM_WINDOWS ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file"); -#else +#elif defined PLATFORM_LINUX ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file"); #endif @@ -45,21 +45,13 @@ void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount const char *option = engine->Cmd_Argv(2); const char *value = engine->Cmd_Argv(3); - CoreConfigErr err = SetConfigOption(option, value); + char error[255]; - switch (err) + ConfigResult err = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error)); + + if (err == ConfigResult_Reject) { - case CoreConfig_NoRuntime: - g_RootMenu.ConsolePrint("[SM] Cannot set \"%s\" while SourceMod is running.", option); - break; - case CoreConfig_InvalidValue: - g_RootMenu.ConsolePrint("[SM] Invalid value \"%s\" specified for configuration option \"%s\"", value, option); - break; - case CoreConfig_InvalidOption: - g_RootMenu.ConsolePrint("[SM] Invalid configuration option specified: %s", option); - break; - default: - break; + g_Logger.LogError("Could not set config option \"%s\" to \"%s\" (error: %s)", option, value, error); } return; @@ -90,44 +82,39 @@ void CoreConfig::Initialize() != SMCParse_Okay) { /* :TODO: This won't actually log or print anything :( - So fix that somehow */ - g_Logger.LogError("[SM] Error encountered parsing core config file: %s", g_TextParser.GetSMCErrorString(err)); + const char *error = g_TextParser.GetSMCErrorString(err); + g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : ""); } } SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) { - CoreConfigErr err = SetConfigOption(key, value); + char error[255]; + ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error)); - if (err == CoreConfig_InvalidOption) + if (err == ConfigResult_Reject) { - g_Logger.LogError("[SM] Warning: Ignoring invalid option \"%s\" in configuration file.", key); - } else if (err == CoreConfig_InvalidValue) { - g_Logger.LogError("[SM] Warning encountered parsing core configuration file."); - g_Logger.LogError("[SM] Invalid value \"%s\" specified for option \"%s\"", value, key); + /* This is a fatal error */ + g_Logger.LogFatal("%s", error); } return SMCParse_Continue; } -CoreConfigErr CoreConfig::SetConfigOption(const char *option, const char *value) +ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength) { - CoreConfigErr err = CoreConfig_TOTAL; - CoreConfigErr currentErr; + ConfigResult result; /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) { - currentErr = pBase->OnSourceModConfigChanged(option, value); - - /* Lowest error code has priority */ - if (currentErr < err) + if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore) { - err = currentErr; + return result; } - pBase = pBase->m_pGlobalClassNext; } - return err; + return ConfigResult_Ignore; } diff --git a/core/CoreConfig.h b/core/CoreConfig.h index b08888a2..da83d46d 100644 --- a/core/CoreConfig.h +++ b/core/CoreConfig.h @@ -42,7 +42,7 @@ private: /** * Sets configuration option by notifying SourceMod components that rely on core.cfg */ - CoreConfigErr SetConfigOption(const char *option, const char *value); + ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength); }; extern CoreConfig g_CoreConfig; diff --git a/core/Logger.cpp b/core/Logger.cpp index 9ce90b61..15a5fb94 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -15,6 +15,7 @@ #include #include "sourcemod.h" #include "sourcemm_api.h" +#include "sm_stringutil.h" #include "Logger.h" #include "systems/LibrarySys.h" #include "sm_version.h" @@ -25,31 +26,39 @@ Logger g_Logger; * :TODO: This should be creating the log folder if it doesn't exist */ -CoreConfigErr Logger::OnSourceModConfigChanged(const char *option, const char *value) +ConfigResult Logger::OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength) { - if (strcasecmp(option, "Logging") == 0) + if (strcasecmp(key, "Logging") == 0) { bool state = true; if (strcasecmp(value, "on") == 0) { - state = true; } else if (strcasecmp(value, "off") == 0) { state = false; } else { - return CoreConfig_InvalidValue; + UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\""); + return ConfigResult_Reject; } - if (m_FirstPass) + if (source == ConfigSource_Console) { - m_InitialState = state; - m_FirstPass = false; + if (state && !m_Active) + { + EnableLogging(); + } else if (!state && m_Active) { + DisableLogging(); + } } else { - state ? g_Logger.EnableLogging() : g_Logger.DisableLogging(); + m_InitialState = state; } - return CoreConfig_Okay; - } else if (strcasecmp(option, "LogMode") == 0) { + return ConfigResult_Accept; + } else if (strcasecmp(key, "LogMode") == 0) { if (strcasecmp(value, "daily") == 0) { m_Mode = LoggingMode_Daily; @@ -58,18 +67,19 @@ CoreConfigErr Logger::OnSourceModConfigChanged(const char *option, const char *v } else if (strcasecmp(value, "game") == 0) { m_Mode = LoggingMode_Game; } else { - return CoreConfig_InvalidValue; + UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]"); + return ConfigResult_Reject; } - return CoreConfig_Okay; + return ConfigResult_Accept; } - return CoreConfig_InvalidOption; + return ConfigResult_Ignore; } void Logger::OnSourceModStartup(bool late) { - InitLogger(m_Mode, m_InitialState); + InitLogger(m_Mode); } void Logger::OnSourceModAllShutdown() @@ -155,10 +165,10 @@ void Logger::_CloseFile() m_ErrFileName.clear(); } -void Logger::InitLogger(LoggingMode mode, bool startlogging) +void Logger::InitLogger(LoggingMode mode) { m_Mode = mode; - m_Active = startlogging; + m_Active = m_InitialState; time_t t; time(&t); @@ -173,7 +183,7 @@ void Logger::InitLogger(LoggingMode mode, bool startlogging) { case LoggingMode_PerMap: { - if (!startlogging) + if (!m_Active) { m_DelayedStart = true; } @@ -414,3 +424,24 @@ void Logger::DisableLogging() LogMessage("Logging disabled manually by user."); m_Active = false; } + +void Logger::LogFatal(const char *msg, ...) +{ + char path[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log"); + FILE *fp = fopen(path, "at"); + if (!fp) + { + /* We're just doomed, aren't we... */ + return; + } + + va_list ap; + va_start(ap, msg); + vfprintf(fp, msg, ap); + va_end(ap); + + fputs("\n", fp); + + fclose(fp); +} diff --git a/core/Logger.h b/core/Logger.h index bc81bdf1..b469c71b 100644 --- a/core/Logger.h +++ b/core/Logger.h @@ -36,18 +36,27 @@ enum LoggingMode class Logger : public SMGlobalClass { public: - Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false), m_InitialState(true), m_FirstPass(true) {} + Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false), + m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false), + m_InitialState(true) + { + } public: //SMGlobalClass - CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value); + ConfigResult OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength); void OnSourceModStartup(bool late); void OnSourceModAllShutdown(); public: - void InitLogger(LoggingMode mode, bool startlogging); + void InitLogger(LoggingMode mode); void CloseLogger(); void EnableLogging(); void DisableLogging(); void LogMessage(const char *msg, ...); void LogError(const char *msg, ...); + void LogFatal(const char *msg, ...); void MapChange(const char *mapname); const char *GetLogFileName(LogType type) const; LoggingMode GetLoggingMode() const; @@ -66,7 +75,6 @@ private: bool m_DelayedStart; bool m_DailyPrintHdr; bool m_InitialState; - bool m_FirstPass; }; extern Logger g_Logger; diff --git a/core/Translator.cpp b/core/Translator.cpp index 6f90bfba..fd909a6f 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -604,15 +604,30 @@ Translator::~Translator() delete m_pStringTab; } -CoreConfigErr Translator::OnSourceModConfigChanged(const char *option, const char *value) +ConfigResult Translator::OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength) { - if (strcasecmp(option, "ServerLang") == 0) + if (strcasecmp(value, "ServerLang") == 0) { + if (source == ConfigSource_Console) + { + unsigned int index; + if (!GetLanguageByCode(value, &index)) + { + UTIL_Format(error, maxlength, "Language code \"%s\" is not registered", value); + return ConfigResult_Reject; + } + } + strncopy(m_ServerLangCode, value, sizeof(m_ServerLangCode)); - return CoreConfig_Okay; + + return ConfigResult_Accept; } - return CoreConfig_InvalidOption; + return ConfigResult_Ignore; } void Translator::OnSourceModAllInitialized() @@ -837,7 +852,20 @@ TransError Translator::CoreTrans(int client, return Trans_Okay; } -const char *Translator::GetServerLanguageCode() const +unsigned int Translator::GetServerLanguageCode() { - return m_ServerLangCode; + void *serverLang; + + /* :TODO: there is absolutely no reason this shouldn't be cached + * I don't even know why it was returning a string originally + */ + + if (!sm_trie_retrieve(m_pLCodeLookup, m_ServerLangCode, &serverLang)) + { + g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English"); + strncopy(m_ServerLangCode, "en", sizeof(m_ServerLangCode)); + return 0; + } + + return (unsigned int)serverLang; } diff --git a/core/Translator.h b/core/Translator.h index 73a5eab1..65836dc6 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -49,6 +49,8 @@ struct Translation int *fmt_order; /**< Format phrase order. */ }; +#define LANGUAGE_ENGLISH 0 + enum TransError { Trans_Okay = 0, @@ -100,7 +102,11 @@ public: Translator(); ~Translator(); public: // SMGlobalClass - CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value); + ConfigResult OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength); void OnSourceModAllInitialized(); public: // ITextListener_SMC void ReadSMC_ParseStart(); @@ -121,7 +127,7 @@ public: const char *phrase, void **params, size_t *outlen=NULL); - const char *GetServerLanguageCode() const; + unsigned int GetServerLanguageCode(); private: bool AddLanguage(const char *langcode, const char *description); private: diff --git a/core/sm_globals.h b/core/sm_globals.h index 213c76d6..bedf9d9e 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -28,16 +28,19 @@ using namespace SourcePawn; using namespace SourceMod; /** -* @brief Lists error codes possible from attempting to set a core configuration option. -*/ -enum CoreConfigErr + * @brief Lists error codes possible from attempting to set a core configuration option. + */ +enum ConfigResult { - CoreConfig_Okay = 0, /**< No error */ - CoreConfig_NoRuntime = 1, /**< Cannot set config option while SourceMod is running */ - CoreConfig_InvalidValue = 2, /**< Invalid value specified for config option */ - CoreConfig_InvalidOption = 3, /**< Invalid config option specified */ - /* -------------------- */ - CoreConfig_TOTAL /**< Total number of core config error codes */ + ConfigResult_Accept = 0, + ConfigResult_Reject = 1, + ConfigResult_Ignore = 2 +}; + +enum ConfigSource +{ + ConfigSource_File = 0, + ConfigSource_Console = 1, }; /** @@ -83,9 +86,13 @@ public: * @note This is called once BEFORE OnSourceModStartup() when SourceMod is loading * @note It can then be called again when the 'sm config' command is used */ - virtual CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value) + virtual ConfigResult OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength) { - return CoreConfig_InvalidOption; + return ConfigResult_Ignore; } private: SMGlobalClass *m_pGlobalClassNext; diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index b8d9f914..5682645b 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -73,24 +73,9 @@ size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char * try_serverlang: if (target == LANG_SERVER) { - langname = g_Translator.GetServerLanguageCode(); - if (!TryServerLanguage(langname ? langname : "en", &langid)) - { - pCtx->ThrowNativeError("Translation failure: English language not found"); - goto error_out; - } - } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { - langname = g_Translator.GetServerLanguageCode(); /* :TODO: read player's lang */ - if (!langname || !g_Translator.GetLanguageByCode(langname, &langid)) - { - if (langname && !strcmp(langname, "en")) - { - pCtx->ThrowNativeError("Translation failure: English language not found"); - goto error_out; - } - target = LANG_SERVER; - goto try_serverlang; - } + langid = g_Translator.GetServerLanguageCode(); + } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { + langid = g_Translator.GetServerLanguageCode(); } else { pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target); goto error_out; @@ -102,9 +87,8 @@ try_serverlang: { target = LANG_SERVER; goto try_serverlang; - } else { - if (!g_Translator.GetLanguageByCode("en", &langid) - || !TryTranslation(pl, key, langid, langcount, &pTrans)) + } else if (langid != LANGUAGE_ENGLISH) { + if (!TryTranslation(pl, key, LANGUAGE_ENGLISH, langcount, &pTrans)) { pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); goto error_out; @@ -900,6 +884,19 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) } } +size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap) +{ + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + + if (len >= maxlength) + { + buffer[maxlength - 1] = '\0'; + return (maxlength - 1); + } else { + return len; + } +} + char *sm_strdup(const char *str) { char *ptr = new char[strlen(str)+1]; diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index df72ecc6..2515dd1c 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -30,6 +30,7 @@ const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); +size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); char *sm_strdup(const char *str); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 516fe270..73d234c3 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -69,24 +69,32 @@ SourceModBase::SourceModBase() m_GotBasePath = false; } -CoreConfigErr SourceModBase::OnSourceModConfigChanged(const char *option, const char *value) +ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength) { - if (strcasecmp(option, "BasePath") == 0) + if (strcasecmp(value, "BasePath") == 0) { + if (source == ConfigSource_Console) + { + UTIL_Format(error, maxlength, "Cannot be set at runtime"); + return ConfigResult_Reject; + } + if (!m_GotBasePath) { g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), value); g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), value); m_GotBasePath = true; - - return CoreConfig_Okay; - } else { - return CoreConfig_NoRuntime; } + + return ConfigResult_Accept; } - return CoreConfig_InvalidOption; + return ConfigResult_Ignore; } bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) @@ -97,7 +105,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) g_CoreConfig.Initialize(); /* This shouldn't happen, but can't hurt to be safe */ - if (!m_GotBasePath || !g_LibSys.PathExists(m_SMBaseDir)) + if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath) { g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod"); diff --git a/core/sourcemod.h b/core/sourcemod.h index 878670d8..57ef3ef7 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -78,7 +78,11 @@ public: */ void SetAuthChecking(bool set); public: // SMGlobalClass - CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value); + ConfigResult OnSourceModConfigChanged(const char *key, + const char *value, + ConfigSource source, + char *error, + size_t maxlength); public: // ISourceMod const char *GetModPath() const; const char *GetSourceModPath() const; From 2cb7b5a06ae7a2a22d6005f7b9ff4307e19c1390 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Apr 2007 05:28:44 +0000 Subject: [PATCH 0639/1664] whoops --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40670 --- core/Translator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Translator.cpp b/core/Translator.cpp index fd909a6f..e6b7455f 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -862,9 +862,9 @@ unsigned int Translator::GetServerLanguageCode() if (!sm_trie_retrieve(m_pLCodeLookup, m_ServerLangCode, &serverLang)) { - g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English"); + g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_ServerLangCode); strncopy(m_ServerLangCode, "en", sizeof(m_ServerLangCode)); - return 0; + return LANGUAGE_ENGLISH; } return (unsigned int)serverLang; From eb006bb665363227e7008f7e766f83c899600570 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Apr 2007 05:45:35 +0000 Subject: [PATCH 0640/1664] fixed various retarded errors --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40671 --- core/CoreConfig.cpp | 10 +++++++--- core/Logger.cpp | 5 +++++ core/Translator.cpp | 2 +- core/sourcemod.cpp | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index 362b23e9..9adbf70c 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -51,7 +51,11 @@ void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount if (err == ConfigResult_Reject) { - g_Logger.LogError("Could not set config option \"%s\" to \"%s\" (error: %s)", option, value, error); + g_RootMenu.ConsolePrint("Could not set config option \"%s\" to \"%s\" (%s)", option, value, error); + } else if (err == ConfigResult_Ignore) { + g_RootMenu.ConsolePrint("No such config option \"%s\" exists.", option); + } else { + g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value); } return; @@ -81,7 +85,7 @@ void CoreConfig::Initialize() if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay) { - /* :TODO: This won't actually log or print anything :( - So fix that somehow */ + /* :TODO: This won't actually log or print anything :( - So fix that somehow */ const char *error = g_TextParser.GetSMCErrorString(err); g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : ""); } @@ -95,7 +99,7 @@ SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, if (err == ConfigResult_Reject) { /* This is a fatal error */ - g_Logger.LogFatal("%s", error); + g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error); } return SMCParse_Continue; diff --git a/core/Logger.cpp b/core/Logger.cpp index 15a5fb94..36b5246b 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -427,6 +427,11 @@ void Logger::DisableLogging() void Logger::LogFatal(const char *msg, ...) { + /* :TODO: make this print all pretty-like + * In fact, the pretty log printing function should be abstracted. + * It's already implemented twice which is bad. + */ + char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log"); FILE *fp = fopen(path, "at"); diff --git a/core/Translator.cpp b/core/Translator.cpp index e6b7455f..e47093d5 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -610,7 +610,7 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key, char *error, size_t maxlength) { - if (strcasecmp(value, "ServerLang") == 0) + if (strcasecmp(key, "ServerLang") == 0) { if (source == ConfigSource_Console) { diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 73d234c3..10f8ef5c 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -75,7 +75,7 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, char *error, size_t maxlength) { - if (strcasecmp(value, "BasePath") == 0) + if (strcasecmp(key, "BasePath") == 0) { if (source == ConfigSource_Console) { From 7263533fe595948965a39f71cf52f02544d45dc9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Apr 2007 07:08:39 +0000 Subject: [PATCH 0641/1664] initial import of skeletal DBI code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40672 --- core/Database.cpp | 153 +++++++++++++ core/Database.h | 49 ++++ core/msvc8/sourcemod_mm.vcproj | 188 ++++++++------- public/IDBDriver.h | 404 +++++++++++++++++++++++++++++++++ 4 files changed, 706 insertions(+), 88 deletions(-) create mode 100644 core/Database.cpp create mode 100644 core/Database.h create mode 100644 public/IDBDriver.h diff --git a/core/Database.cpp b/core/Database.cpp new file mode 100644 index 00000000..05257143 --- /dev/null +++ b/core/Database.cpp @@ -0,0 +1,153 @@ +#include "Database.h" +#include "HandleSys.h" +#include "sourcemod.h" + +DBManager g_DBMan; + +void DBManager::OnSourceModAllInitialized() +{ + HandleAccess sec; + + g_HandleSys.InitAccessDefaults(NULL, &sec); + sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY; + sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY; + + m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL); + m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL); + m_QueryType = g_HandleSys.CreateType("IQuery", this, 0, NULL, NULL, g_pCoreIdent, NULL); +} + +void DBManager::OnHandleDestroy(HandleType_t type, void *object) +{ + if (type == m_DriverType) + { + /* Ignore */ + return; + } + + if (g_HandleSys.TypeCheck(type, m_QueryType)) + { + IQuery *pQuery = (IQuery *)object; + pQuery->Release(); + } else if (g_HandleSys.TypeCheck(type, m_DatabaseType)) { + IDatabase *pdb = (IDatabase *)object; + pdb->Close(); + } +} + +void DBManager::AddDriver(IDBDriver *pDriver, IdentityToken_t *ident) +{ + if (!pDriver) + { + return; + } + + if (m_drivers.size() >= HANDLESYS_MAX_SUBTYPES) + { + return; + } + + db_driver *driver = new db_driver; + + driver->driver = pDriver; + driver->ident = ident; + + HandleSecurity sec; + + sec.pIdentity = ident; + sec.pOwner = g_pCoreIdent; + driver->hDriver = g_HandleSys.CreateHandleEx(m_DriverType, driver, &sec, NULL, NULL); + + driver->htDatabase = g_HandleSys.CreateType(NULL, this, m_DatabaseType, NULL, NULL, g_pCoreIdent, NULL); + driver->htQuery = g_HandleSys.CreateType(NULL, this, m_QueryType, NULL, NULL, g_pCoreIdent, NULL); + + m_drivers.push_back(driver); +} + +void DBManager::RemoveDriver(IDBDriver *pDriver) +{ + CVector::iterator iter; + for (iter = m_drivers.begin(); + iter != m_drivers.end(); + iter++) + { + if ((*iter)->driver == pDriver) + { + db_driver *driver = (*iter); + HandleSecurity sec; + + sec.pIdentity = driver->ident; + sec.pOwner = g_pCoreIdent; + g_HandleSys.RemoveType(driver->htQuery, driver->ident); + g_HandleSys.RemoveType(driver->htDatabase, driver->ident); + g_HandleSys.FreeHandle(driver->hDriver, &sec); + + delete driver; + m_drivers.erase(iter); + + return; + } + } +} + +const char *DBManager::GetInterfaceName() +{ + return SMINTERFACE_DBI_NAME; +} + +unsigned int DBManager::GetInterfaceVersion() +{ + return SMINTERFACE_DBI_VERSION; +} + +unsigned int DBManager::GetDriverCount() +{ + return (unsigned int)m_drivers.size(); +} + +IDBDriver *DBManager::GetDriver(unsigned int index, IdentityToken_t **pToken) +{ + if (index >= GetDriverCount()) + { + return NULL; + } + + if (pToken) + { + *pToken = m_drivers[index]->ident; + } + + return m_drivers[index]->driver; +} + +const DatabaseInfo *DBManager::FindDatabaseConf(const char *name) +{ + /* :TODO: implement */ + return NULL; +} + +bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent) +{ + const DatabaseInfo *pInfo = FindDatabaseConf(name); + + unsigned int count = GetDriverCount(); + for (unsigned int i=0; iGetIdentifier(), pInfo->driver) == 0) + { + *pdr = driver; + if (persistent) + { + *pdb = driver->PConnect(pInfo); + } else { + *pdb = driver->Connect(pInfo); + } + } + } + + *pdr = NULL; + *pdb = NULL; + + return false; +} diff --git a/core/Database.h b/core/Database.h new file mode 100644 index 00000000..ea56b588 --- /dev/null +++ b/core/Database.h @@ -0,0 +1,49 @@ +#ifndef _INCLUDE_DATABASE_MANAGER_H_ +#define _INCLUDE_DATABASE_MANAGER_H_ + +#include +#include +#include "sm_globals.h" +#include + +using namespace SourceHook; + +struct db_driver +{ + IDBDriver *driver; + IdentityToken_t *ident; + HandleType_t htDatabase; + HandleType_t htQuery; + Handle_t hDriver; +}; + +class DBManager : + public IDBManager, + public SMGlobalClass, + public IHandleTypeDispatch +{ + const char *GetInterfaceName(); + unsigned int GetInterfaceVersion(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); +public: //IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: //IDBManager + void AddDriver(IDBDriver *pDriver, IdentityToken_t *ident); + void RemoveDriver(IDBDriver *pDriver); + const DatabaseInfo *FindDatabaseConf(const char *name); + bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent); + unsigned int GetDriverCount(); + IDBDriver *GetDriver(unsigned int index, IdentityToken_t **pToken=NULL); +public: + db_driver *GetDriverInfo(unsigned int index); +private: + CVector m_drivers; + HandleType_t m_DriverType; + HandleType_t m_DatabaseType; + HandleType_t m_QueryType; +}; + +extern DBManager g_DBMan; + +#endif //_INCLUDE_DATABASE_MANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 571ca460..1867cdbc 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -199,6 +199,10 @@ RelativePath="..\CoreConfig.cpp" > + + @@ -297,6 +301,10 @@ RelativePath="..\CoreConfig.h" > + + @@ -393,6 +401,10 @@ RelativePath="..\..\public\IDataPack.h" > + + @@ -445,6 +457,94 @@ RelativePath="..\..\public\IUserMessages.h" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/IDBDriver.h b/public/IDBDriver.h new file mode 100644 index 00000000..f79e4843 --- /dev/null +++ b/public/IDBDriver.h @@ -0,0 +1,404 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_DBDRIVER_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_DBDRIVER_H_ + +#include +#include + +#define SMINTERFACE_DBI_NAME "IDBI" +#define SMINTERFACE_DBI_VERSION 1 + +namespace SourceMod +{ + /** + * @brief Describes a database field value. + */ + enum DBResult + { + DBVal_Error = 0, /**< Column number/field is invalid */ + DBVal_TypeMismatch = 1, /**< You cannot retrieve this data with this type */ + DBVal_Null = 2, /**< Field has no data (NULL) */ + DBVal_Data = 3, /**< Field has data */ + }; + + /** + * @brief Represents a one database result row. + */ + class IResultRow + { + public: + /** + * @brief Retrieves a database field result as a string. + * + * For NULL values, the resulting string pointer will be non-NULL, + * but empty. + * + * @param columnId Column to use, starting from 0. + * @param pString Pointer to store a pointer to the string. + * @return A DBResult return code. + */ + virtual DBResult GetString(unsigned int columnId, const char **pString) =0; + + /** + * @brief Retrieves a database field result as a float. + * + * For NULL entries, the returned float value will be 0.0. + * + * @param columnId Column to use, starting from 0. + * @param pFloat Pointer to a floating point number to set. + * @return A DBResult return code. + */ + virtual DBResult GetFloat(unsigned int columnId, float *pFloat) =0; + + /** + * @brief Retrieves a database field result as an integer. + * + * For NULL entries, the returned integer value will be 0. + * + * @param columnId Column to use, starting from 0. + * @param pInt Pointer to an integer number to set. + * @return A DBResult return code. + */ + virtual DBResult GetInt(unsigned int columnId, int *pInt) =0; + + /** + * @brief Returns whether or not a field is NULL. + * + * @param columnId Column to use, starting from 0. + * @return A DBResult return code. + */ + virtual DBResult CheckField(unsigned int columnId) =0; + + /** + * @brief Retrieves field data as a raw bitstream. + * + * @param columnId Column to use, starting from 0. + * @param pData Pointer to store the raw bit stream. + * @param length Pointer to store the data length. + * @return A DBResult return code. + */ + virtual DBResult GetRaw(unsigned int columnId, void **pData, size_t *length) =0; + }; + + /** + * @brief Describes a set of database results. + */ + class IResultSet + { + public: + /** + * @brief Returns the number of rows in the set. + * + * @return Number of rows in the set. + */ + virtual unsigned int GetRowCount() =0; + + /** + * @brief Returns the number of fields in the set. + * + * @return Number of fields in the set. + */ + virtual unsigned int GetFieldCount() =0; + + /** + * @brief Converts a column number to a column name. + * + * @param columnId Column to use, starting from 0. + * @return Pointer to column name, or NULL if not found. + */ + virtual const char *ColNumToName(unsigned int columnId) =0; + + /** + * @brief Converts a column name to a column id. + * + * @param name Column name (case sensitive). + * @param columnId Pointer to store the column id. If the + * name is not found, the value will be + * undefined. + * @return True on success, false if not found. + */ + virtual bool ColNumToName(const char *name, unsigned int *columnId) =0; + + /** + * @brief Returns if there is still data in the result set. + * + * @return False if there is more data to be read, + * true, otherwise. + */ + virtual bool IsFinished() =0; + + /** + * @brief Returns a pointer to the current row and advances + * the internal row pointer/counter to the next row available. + * + * @return IResultRow pointer to the current row, + * or NULL if there is no more data. + */ + virtual IResultRow *FetchRow() =0; + + /** + * @brief Rewinds back to the beginning of the row iteration. + * + * @return True on success, false otherwise. + */ + virtual bool Rewind() =0; + }; + + class IDatabase; + + /** + * @brief Encapsulates one database query. + */ + class IQuery + { + public: + /** + * @brief Number of rows affected by the last execute. + * + * @return Number of rows affected by the last execute. + */ + virtual unsigned int GetAffectedRows() =0; + + /** + * @brief Retrieves the last insert ID of this query, if any. + * + * @return Row insertion ID of the last execute, if any. + */ + virtual unsigned int GetInsertID() =0; + + /** + * @brief Returns the full query string. + * + * @return String containing the original query. + */ + virtual const char *GetQueryString() =0; + + /** + * @brief Returns the result set from the last Execute call. + * + * @return IResultSet from the last Execute call. + * Pointer will be NULL if there was no previous + * call, the last call failed, or the last call + * had no result set and Execute() was called with + * retEmptySet=false. + */ + virtual IResultSet *GetResultSet() =0; + + /** + * @brief Returns the IDatabase object which created this pointer. + * + * @return IDatabase object which created this pointer. + */ + virtual IDatabase *GetDatabase() =0; + + /** + * @brief Releases the resources associated with this query. + */ + virtual void Release() =0; + }; + + class IDBDriver; + + /** + * @brief Encapsulates a database connection. + */ + class IDatabase + { + public: + /** + * @brief Disconnects the database and frees its associated memory. + * If this pointer was received via IDBDriver::PConnect(), Close() + * must be called once for each successful PConnect() call which + * resulted in this pointer. + */ + virtual void Close() =0; + + /** + * @brief Error code and string returned by the last operation on this + * connection. + * + * @param errorCode Optional pointer to retrieve an error code. + * @return Error string pointer (empty if none). + */ + virtual const char *GetLastError(int *errorCode=NULL) =0; + + /** + * @brief Prepares and executes a query in one step, and returns + * the resulting IQuery pointer. + * + * @param fmt String format to parse. + * @param ... Format parameters. + * @return An IQuery pointer which must be freed, or + * NULL if the query failed. + */ + virtual IQuery *DoQuery(const char *fmt, ...) =0; + + /** + * Quotes a string for insertion into a query. + * + * @param str Source string. + * @param buffer Buffer to store new string (should not overlap source string). + * @param maxlen Maximum length of the output buffer. + * @param newSize Pointer to store the output size. + * @return True on success, false if the output buffer is not big enough. + * If not big enough, the required buffer size is passed through + * newSize. + */ + virtual bool QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize) =0; + + /** + * @brief Returns the parent driver. + * + * @return IDBDriver pointer that created this object. + */ + virtual IDBDriver *GetDriver() =0; + }; + + /** + * @brief Describes database connection info. + */ + struct DatabaseInfo + { + DatabaseInfo() + { + dbiVersion = SMINTERFACE_DBI_VERSION; + port = 0; + maxTimeout = 0; + } + unsigned int dbiVersion; /**< DBI Version for backwards compatibility */ + const char *host; /**< Host string */ + const char *database; /**< Database name string */ + const char *user; /**< User to authenticate as */ + const char *pass; /**< Password to authenticate with */ + const char *driver; /**< Driver to use */ + unsigned int port; /**< Port to use, 0=default */ + unsigned int maxTimeout; /**< Maximum timeout, 0=default */ + }; + + /** + * @brief Describes an SQL driver. + */ + class IDBDriver + { + public: + virtual unsigned int GetDBIVersion() + { + return SMINTERFACE_DBI_VERSION; + } + public: + /** + * @brief Initiates a database connection. + * + * @param info Database connection info pointer. + * @return A new IDatabase pointer, or NULL on failure. + */ + virtual IDatabase *Connect(const DatabaseInfo *info) =0; + + /** + * @brief Initiates a database connection. If a connection to the given database + * already exists, this will re-use the old connection handle. + * + * @param info Database connection info pointer. + * @return A new IDatabase pointer, or NULL on failure. + */ + virtual IDatabase *PConnect(const DatabaseInfo *info) =0; + + /** + * @brief Returns a case insensitive database identifier string. + */ + virtual const char *GetIdentifier() =0; + + /** + * @brief Returns a case sensitive implementation name. + */ + virtual const char *GetProductName() =0; + + /** + * @brief Returns the last connection error. + * + * @param errCode Optional pointer to store a platform-specific error code. + */ + virtual const char *GetLastError(int *errCode=NULL) =0; + }; + + /** + * @brief Describes the DBI manager. + */ + class IDBManager : public SMInterface + { + public: + virtual const char *GetInterfaceName() =0; + virtual unsigned int GetInterfaceVersion() =0; + public: + /** + * @brief Adds a driver to the DBI system. + * + * @param pDriver Database driver. + */ + virtual void AddDriver(IDBDriver *pDriver, IdentityToken_t *pToken) =0; + + /** + * @brief Removes a driver from the DBI system. + * + * @param pDriver Database driver. + */ + virtual void RemoveDriver(IDBDriver *pDriver) =0; + + /** + * @brief Searches for database info by name. + * + * @param name Named database info. + * @return DatabaseInfo pointer. + */ + virtual const DatabaseInfo *FindDatabaseConf(const char *name) =0; + + /** + * @brief Tries to connect to a named database. + * + * @param name Named database info. + * @param pdr Pointer to store the IDBDriver pointer in. + * If driver is not found, NULL will be stored. + * @param pdb Pointer to store the IDatabase pointer in. + * If connection fails, NULL will be stored. + * @param persistent If true, the dbmanager will attempt to PConnect + * instead of connect. + * @return True on success, false otherwise. + */ + virtual bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent) =0; + + /** + * @brief Returns the number of drivers loaded. + * + * @return Number of drivers loaded. + */ + virtual unsigned int GetDriverCount() =0; + + /** + * @brief Returns a driver by index. + * + * @param index Driver index, starting from 0. + * @param pToken Optional pointer to store the driver's identity token. + * @return IDBDriver pointer for the given index. + */ + virtual IDBDriver *GetDriver(unsigned int index, IdentityToken_t **pToken=NULL) =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_INTERFACE_DBDRIVER_H_ From 58ad1932c2e3819e6d7c3e153fed82a41f3d8c8f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Apr 2007 07:09:17 +0000 Subject: [PATCH 0642/1664] added file headers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40673 --- core/Database.cpp | 14 ++++++++++++++ core/Database.h | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/core/Database.cpp b/core/Database.cpp index 05257143..711eac03 100644 --- a/core/Database.cpp +++ b/core/Database.cpp @@ -1,3 +1,17 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #include "Database.h" #include "HandleSys.h" #include "sourcemod.h" diff --git a/core/Database.h b/core/Database.h index ea56b588..9e462f5c 100644 --- a/core/Database.h +++ b/core/Database.h @@ -1,3 +1,17 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + #ifndef _INCLUDE_DATABASE_MANAGER_H_ #define _INCLUDE_DATABASE_MANAGER_H_ From 5ee48f60a20959b515b0809c5493f301ab838d72 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 07:59:27 +0000 Subject: [PATCH 0643/1664] Added comments to core.cfg --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40674 --- configs/core.cfg | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/configs/core.cfg b/configs/core.cfg index 06a97600..43e0fb45 100644 --- a/configs/core.cfg +++ b/configs/core.cfg @@ -1,10 +1,39 @@ +/** + * This file is used to set various options that are important to SourceMod's core. + * If this file is missing or an option in this file is missing, then the default values will be used. + */ "Core" { + /** + * Relative path to SourceMod's base directory. This is relative to the game/mod directory. + * Only change this if you have installed SourceMod in a non-default location. + * + * The default value is "addons/sourcemod" + */ "BasePath" "addons/sourcemod" + /** + * This option determines if SourceMod logging is enabled. + * + * "on" - Logging is enabled (default) + * "off" - Logging is disabled + */ "Logging" "on" + /** + * This option determines how SourceMod logging should be handled. + * + * "daily" - New log file is created for each day (default) + * "map" - New log file is created for each map change + * "game" - Use game's log files + */ "LogMode" "daily" + /** + * Language that multilingual enabled plugins and extensions will use to print messages. + * Only languages listed in languages.cfg are valid. + * + * The default value is "en" + */ "ServerLang" "en" } From e677d5d5de6cd20f3890e9e3de2734686626da2d Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 10:55:40 +0000 Subject: [PATCH 0644/1664] Various things: - Fixed inline translations when using %T - "Improved" caching of server language - Renamed Translator::GetServerLanguageCode() to GetServerLanguage() - Added some more comments to sm_globals.h - Natives folder in project file mysteriously was moved inside Interfaces, so moved it back o_O - DS hates empty if statements :o --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40675 --- core/CoreConfig.cpp | 13 ++- core/Logger.cpp | 14 +-- core/Translator.cpp | 47 +++++---- core/Translator.h | 5 +- core/msvc8/sourcemod_mm.vcproj | 176 ++++++++++++++++----------------- core/sm_globals.h | 15 +-- core/sm_stringutil.cpp | 10 +- 7 files changed, 139 insertions(+), 141 deletions(-) diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index 9adbf70c..f969b271 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -47,13 +47,13 @@ void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount char error[255]; - ConfigResult err = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error)); + ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error)); - if (err == ConfigResult_Reject) + if (res == ConfigResult_Reject) { - g_RootMenu.ConsolePrint("Could not set config option \"%s\" to \"%s\" (%s)", option, value, error); - } else if (err == ConfigResult_Ignore) { - g_RootMenu.ConsolePrint("No such config option \"%s\" exists.", option); + g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error); + } else if (res == ConfigResult_Ignore) { + g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option); } else { g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value); } @@ -82,8 +82,7 @@ void CoreConfig::Initialize() g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetModPath(), corecfg); /* Parse config file */ - if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) - != SMCParse_Okay) + if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay) { /* :TODO: This won't actually log or print anything :( - So fix that somehow */ const char *error = g_TextParser.GetSMCErrorString(err); diff --git a/core/Logger.cpp b/core/Logger.cpp index 36b5246b..1af6a9a7 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -34,10 +34,11 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key, { if (strcasecmp(key, "Logging") == 0) { - bool state = true; + bool state; if (strcasecmp(value, "on") == 0) { + state = true; } else if (strcasecmp(value, "off") == 0) { state = false; } else { @@ -47,12 +48,7 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key, if (source == ConfigSource_Console) { - if (state && !m_Active) - { - EnableLogging(); - } else if (!state && m_Active) { - DisableLogging(); - } + state ? EnableLogging() : DisableLogging(); } else { m_InitialState = state; } @@ -412,7 +408,7 @@ void Logger::EnableLogging() return; } m_Active = true; - LogMessage("Logging enabled manually by user."); + LogMessage("[SM] Logging enabled manually by user."); } void Logger::DisableLogging() @@ -421,7 +417,7 @@ void Logger::DisableLogging() { return; } - LogMessage("Logging disabled manually by user."); + LogMessage("[SM] Logging disabled manually by user."); m_Active = false; } diff --git a/core/Translator.cpp b/core/Translator.cpp index e47093d5..e883d9b7 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -580,11 +580,11 @@ const char *CPhraseFile::GetFilename() ** MAIN TRANSLATOR CODE ** **************************/ -Translator::Translator() +Translator::Translator() : m_ServerLang(LANGUAGE_ENGLISH) { m_pStringTab = new BaseStringTable(2048); m_pLCodeLookup = sm_trie_create(); - strncopy(m_ServerLangCode, "en", sizeof(m_ServerLangCode)); + strncopy(m_InitialLang, "en", sizeof(m_InitialLang)); } Translator::~Translator() @@ -620,9 +620,11 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key, UTIL_Format(error, maxlength, "Language code \"%s\" is not registered", value); return ConfigResult_Reject; } - } - strncopy(m_ServerLangCode, value, sizeof(m_ServerLangCode)); + m_ServerLang = index; + } else { + strncopy(m_InitialLang, value, sizeof(m_InitialLang)); + } return ConfigResult_Accept; } @@ -712,6 +714,18 @@ void Translator::RebuildLanguageDatabase(const char *lang_header_file) g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", line, col, str_err); } + void *serverLang; + + if (!sm_trie_retrieve(m_pLCodeLookup, m_InitialLang, &serverLang)) + { + g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang); + + strncopy(m_InitialLang, "en", sizeof(m_InitialLang)); + m_ServerLang = LANGUAGE_ENGLISH; + } + + m_ServerLang = reinterpret_cast(serverLang); + if (!m_Languages.size()) { g_Logger.LogError("[SM] Fatal error, no languages found! Translation will not work."); @@ -829,15 +843,11 @@ TransError Translator::CoreTrans(int client, } /* Using server lang temporarily until client lang stuff is implemented */ - unsigned int serverLang; - if (!sm_trie_retrieve(m_pLCodeLookup, m_ServerLangCode, (void **)&serverLang)) - { - return Trans_BadLanguage; - } + unsigned int serverLang = GetServerLanguage(); Translation trans; TransError err; - if ((err=g_pCorePhrases->GetTranslation(phrase, serverLang, &trans)) != Trans_Okay) + if ((err=g_pCorePhrases->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay) { return err; } @@ -852,20 +862,7 @@ TransError Translator::CoreTrans(int client, return Trans_Okay; } -unsigned int Translator::GetServerLanguageCode() +unsigned int Translator::GetServerLanguage() { - void *serverLang; - - /* :TODO: there is absolutely no reason this shouldn't be cached - * I don't even know why it was returning a string originally - */ - - if (!sm_trie_retrieve(m_pLCodeLookup, m_ServerLangCode, &serverLang)) - { - g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_ServerLangCode); - strncopy(m_ServerLangCode, "en", sizeof(m_ServerLangCode)); - return LANGUAGE_ENGLISH; - } - - return (unsigned int)serverLang; + return m_ServerLang; } diff --git a/core/Translator.h b/core/Translator.h index 65836dc6..92cf610f 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -127,7 +127,7 @@ public: const char *phrase, void **params, size_t *outlen=NULL); - unsigned int GetServerLanguageCode(); + unsigned int GetServerLanguage(); private: bool AddLanguage(const char *langcode, const char *description); private: @@ -137,7 +137,8 @@ private: Trie *m_pLCodeLookup; bool m_InLanguageSection; String m_CustomError; - char m_ServerLangCode[3]; + unsigned int m_ServerLang; + char m_InitialLang[3]; }; extern CPhraseFile *g_pCorePhrases; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 1867cdbc..3126cad1 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -457,94 +457,6 @@ RelativePath="..\..\public\IUserMessages.h" > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/sm_globals.h b/core/sm_globals.h index bedf9d9e..2a2b312b 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -28,19 +28,22 @@ using namespace SourcePawn; using namespace SourceMod; /** - * @brief Lists error codes possible from attempting to set a core configuration option. + * @brief Lists result codes possible from attempting to set a core configuration option. */ enum ConfigResult { - ConfigResult_Accept = 0, - ConfigResult_Reject = 1, - ConfigResult_Ignore = 2 + ConfigResult_Accept = 0, /**< Config option was successfully set */ + ConfigResult_Reject = 1, /**< Config option was given an invalid value and was rejected */ + ConfigResult_Ignore = 2 /**< Config option was invalid, but ignored */ }; +/** + * @brief Lists possible sources of a config option change + */ enum ConfigSource { - ConfigSource_File = 0, - ConfigSource_Console = 1, + ConfigSource_File = 0, /**< Config option was set from config file (core.cfg) */ + ConfigSource_Console = 1, /**< Config option was set from console command (sm config) */ }; /** diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 5682645b..a27aed01 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -73,9 +73,9 @@ size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char * try_serverlang: if (target == LANG_SERVER) { - langid = g_Translator.GetServerLanguageCode(); + langid = g_Translator.GetServerLanguage(); } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) { - langid = g_Translator.GetServerLanguageCode(); + langid = g_Translator.GetServerLanguage(); } else { pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target); goto error_out; @@ -736,9 +736,11 @@ reswitch: char *key; bool error; size_t res; - cell_t target = params[arg++]; + cell_t *target; + pCtx->LocalToPhysAddr(params[arg++], &target); pCtx->LocalToString(params[arg++], &key); - res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error); + printf("target = %d\n", target); + res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error); if (error) { return 0; From 385a4408daae35740495edfca4052b58cd896004 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 10:59:26 +0000 Subject: [PATCH 0645/1664] Oh. This variable was no longer used. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40676 --- core/Translator.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/Translator.cpp b/core/Translator.cpp index e883d9b7..022b0b04 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -842,11 +842,10 @@ TransError Translator::CoreTrans(int client, return Trans_BadPhraseFile; } - /* Using server lang temporarily until client lang stuff is implemented */ - unsigned int serverLang = GetServerLanguage(); - Translation trans; TransError err; + + /* Using server lang temporarily until client lang stuff is implemented */ if ((err=g_pCorePhrases->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay) { return err; From a99089b518e332ce084898f050ffa87f03a95eff Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 11:01:12 +0000 Subject: [PATCH 0646/1664] Can't do anything right... removed debug message --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40677 --- core/sm_stringutil.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index a27aed01..010c57b0 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -739,7 +739,6 @@ reswitch: cell_t *target; pCtx->LocalToPhysAddr(params[arg++], &target); pCtx->LocalToString(params[arg++], &key); - printf("target = %d\n", target); res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error); if (error) { From c7f1f04246f77743a6b0cb8c93cc8e1385879a27 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 5 Apr 2007 11:02:22 +0000 Subject: [PATCH 0647/1664] Added LANG_SERVER constant to lang.inc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40678 --- plugins/include/lang.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/include/lang.inc b/plugins/include/lang.inc index ea6ef4a5..42c9b01b 100644 --- a/plugins/include/lang.inc +++ b/plugins/include/lang.inc @@ -18,6 +18,8 @@ #endif #define _lang_included +#define LANG_SERVER 0 /**< Translate using the server's language */ + /** * @brief Loads a translation file for the plugin calling this native. * From dee3a2b3cf758e008c339d9f6e45e1f091be0790 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 7 Apr 2007 03:58:20 +0000 Subject: [PATCH 0648/1664] added some levelchange functions to SMGlobalClass to get rid of some messy crap --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40679 --- core/AdminCache.cpp | 6 ++++++ core/AdminCache.h | 1 + core/Logger.cpp | 5 +++++ core/Logger.h | 1 + core/TimerSys.cpp | 5 +++++ core/TimerSys.h | 1 + core/Translator.cpp | 8 ++++++++ core/Translator.h | 1 + core/sm_globals.h | 14 ++++++++++++++ core/sourcemod.cpp | 23 ++++++++++++++--------- 10 files changed, 56 insertions(+), 9 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 666164db..e5ddaa75 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -84,6 +84,12 @@ void AdminCache::OnSourceModShutdown() m_pCacheFwd = NULL; } +void AdminCache::OnSourceModPluginsLoaded() +{ + DumpAdminCache(AdminCache_Overrides, true); + DumpAdminCache(AdminCache_Groups, true); +} + void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags) { Trie *pTrie = NULL; diff --git a/core/AdminCache.h b/core/AdminCache.h index eb40a5cf..e75e653d 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -88,6 +88,7 @@ public: //SMGlobalClass void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModShutdown(); + void OnSourceModPluginsLoaded(); public: //IAdminSystem /** Command cache stuff */ void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags); diff --git a/core/Logger.cpp b/core/Logger.cpp index 1af6a9a7..5ffea1c4 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -83,6 +83,11 @@ void Logger::OnSourceModAllShutdown() CloseLogger(); } +void Logger::OnSourceModLevelChange(const char *mapName) +{ + MapChange(mapName); +} + void Logger::_NewMapFile() { if (!m_Active) diff --git a/core/Logger.h b/core/Logger.h index b469c71b..30246296 100644 --- a/core/Logger.h +++ b/core/Logger.h @@ -49,6 +49,7 @@ public: //SMGlobalClass size_t maxlength); void OnSourceModStartup(bool late); void OnSourceModAllShutdown(); + void OnSourceModLevelChange(const char *mapName); public: void InitLogger(LoggingMode mode); void CloseLogger(); diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 1b35b410..3ce7839d 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -42,6 +42,11 @@ void TimerSystem::OnSourceModAllInitialized() g_ShareSys.AddInterface(NULL, this); } +void TimerSystem::OnSourceModLevelChange(const char *mapName) +{ + MapChange(); +} + void TimerSystem::RunFrame() { ITimer *pTimer; diff --git a/core/TimerSys.h b/core/TimerSys.h index 0da497ce..4078b6a3 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -48,6 +48,7 @@ public: ~TimerSystem(); public: //SMGlobalClass void OnSourceModAllInitialized(); + void OnSourceModLevelChange(const char *mapName); public: //ITimerSystem ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags); void KillTimer(ITimer *pTimer); diff --git a/core/Translator.cpp b/core/Translator.cpp index 022b0b04..52070e8a 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -632,6 +632,14 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key, return ConfigResult_Ignore; } +void Translator::OnSourceModLevelChange(const char *mapName) +{ + /* Refresh language stuff */ + char path[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg"); + RebuildLanguageDatabase(path); +} + void Translator::OnSourceModAllInitialized() { AddLanguage("en", "English"); diff --git a/core/Translator.h b/core/Translator.h index 92cf610f..63498f62 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -108,6 +108,7 @@ public: // SMGlobalClass char *error, size_t maxlength); void OnSourceModAllInitialized(); + void OnSourceModLevelChange(const char *mapName); public: // ITextListener_SMC void ReadSMC_ParseStart(); SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); diff --git a/core/sm_globals.h b/core/sm_globals.h index 2a2b312b..6636fbe1 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -97,6 +97,20 @@ public: { return ConfigResult_Ignore; } + + /** + * @brief Called when the level changes. + */ + virtual void OnSourceModLevelChange(const char *mapName) + { + } + + /** + * @brief Called after plugins are loaded on mapchange. + */ + virtual void OnSourceModPluginsLoaded() + { + } private: SMGlobalClass *m_pGlobalClassNext; static SMGlobalClass *head; diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 10f8ef5c..b1dda3d9 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -233,20 +233,25 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_LastTime = 0.0f; g_LastAuthCheck = 0.0f; - g_Logger.MapChange(pMapName); - g_Timers.MapChange(); - - /* Refresh language stuff */ - char path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg"); - g_Translator.RebuildLanguageDatabase(path); + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModLevelChange(pMapName); + pBase = pBase->m_pGlobalClassNext; + } DoGlobalPluginLoads(); m_IsMapLoading = false; - g_Admins.DumpAdminCache(AdminCache_Overrides, true); - g_Admins.DumpAdminCache(AdminCache_Groups, true); + /* Notify! */ + pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModPluginsLoaded(); + pBase = pBase->m_pGlobalClassNext; + } if (!g_pOnGameFrame) { From b6e992239437b257db6caf86b0a37dd07a02d9dd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 7 Apr 2007 04:01:24 +0000 Subject: [PATCH 0649/1664] fixed a linux build problem --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40680 --- core/sm_stringutil.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 010c57b0..6af95646 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -62,7 +62,6 @@ inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, un size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error) { unsigned int langid; - const char *langname = NULL; *error = false; Translation pTrans; CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext()); From 4c3d5673e60bb28fc500ef9e0b05d87bac8eb0fc Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 8 Apr 2007 18:19:06 +0000 Subject: [PATCH 0650/1664] Added VSP listening and a function to SMGlobalClass --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40681 --- core/sm_globals.h | 10 ++++++++++ core/sourcemm_api.cpp | 22 ++++++++++++++++++++++ core/sourcemm_api.h | 6 +++++- core/sourcemod.h | 4 ++-- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/core/sm_globals.h b/core/sm_globals.h index 6636fbe1..8f86e75d 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -27,6 +27,8 @@ using namespace SourcePawn; using namespace SourceMod; +class IServerPluginCallbacks; + /** * @brief Lists result codes possible from attempting to set a core configuration option. */ @@ -51,6 +53,7 @@ enum ConfigSource */ class SMGlobalClass { + friend class SourceMod_Core; friend class SourceModBase; friend class CoreConfig; public: @@ -111,6 +114,13 @@ public: virtual void OnSourceModPluginsLoaded() { } + + /** + * @brief Called when SourceMod receives a pointer to IServerPluginCallbacks from SourceMM + */ + virtual void OnSourceModVSPReceived(IServerPluginCallbacks *iface) + { + } private: SMGlobalClass *m_pGlobalClassNext; static SMGlobalClass *head; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 387c7a1f..e7af5615 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -16,6 +16,7 @@ #include "sourcemm_api.h" #include "sm_version.h" #include "sourcemod.h" +#include "Logger.h" SourceMod_Core g_SourceMod_Core; IVEngineServer *engine = NULL; @@ -62,6 +63,9 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen } gpGlobals = ismm->pGlobals(); + + ismm->AddListener(this, this); + ismm->EnableVSPListener(); return g_SourceMod.InitializeSourceMod(error, maxlen, late); } @@ -125,3 +129,21 @@ const char *SourceMod_Core::GetLogTag() { return "SM"; } + +void SourceMod_Core::OnVSPListening(IServerPluginCallbacks *iface) +{ + /* This shouldn't happen */ + if (!iface) + { + g_Logger.LogFatal("Metamod:Source version is out of date. SourceMod requires 1.4 or greater."); + return; + } + + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModVSPReceived(iface); + pBase = pBase->m_pGlobalClassNext; + } +} diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 8e3b7612..2428ff62 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -28,7 +28,9 @@ * @file Contains wrappers around required Metamod:Source API exports */ -class SourceMod_Core : public ISmmPlugin +class SourceMod_Core : + public ISmmPlugin, + public IMetamodListener { public: bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); @@ -45,6 +47,8 @@ public: const char *GetVersion(); const char *GetDate(); const char *GetLogTag(); +public: + void OnVSPListening(IServerPluginCallbacks *iface); }; extern SourceMod_Core g_SourceMod_Core; diff --git a/core/sourcemod.h b/core/sourcemod.h index 57ef3ef7..a2ca1f84 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -74,8 +74,8 @@ public: unsigned int GetGlobalTarget() const; /** - * @brief Sets whether if SoureMod needs to check player auths. - */ + * @brief Sets whether if SoureMod needs to check player auths. + */ void SetAuthChecking(bool set); public: // SMGlobalClass ConfigResult OnSourceModConfigChanged(const char *key, From 3bec29a1fefece47cc2bb17458cc0cac152ec2fe Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 9 Apr 2007 03:05:53 +0000 Subject: [PATCH 0651/1664] GET_V_IFACE_* will work from SDK_OnMetamodLoad now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40682 --- public/sample_ext/extension.cpp | 1 + public/sample_ext/extension.h | 2 +- public/sample_ext/smsdk_ext.cpp | 4 ++-- public/sample_ext/smsdk_ext.h | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/public/sample_ext/extension.cpp b/public/sample_ext/extension.cpp index 112d06ca..dd6b36b7 100644 --- a/public/sample_ext/extension.cpp +++ b/public/sample_ext/extension.cpp @@ -9,3 +9,4 @@ Sample g_Sample; /**< Global singleton for your extension's main interface */ SMEXT_LINK(&g_Sample); + diff --git a/public/sample_ext/extension.h b/public/sample_ext/extension.h index 4851c32c..e88b3494 100644 --- a/public/sample_ext/extension.h +++ b/public/sample_ext/extension.h @@ -58,7 +58,7 @@ public: * Read smext_base.h for documentation on these. */ - //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); #endif diff --git a/public/sample_ext/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp index 2e060a7f..ed2de4ae 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/public/sample_ext/smsdk_ext.cpp @@ -198,7 +198,7 @@ bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, m_SourceMMLoaded = true; - return SDK_OnMetamodLoad(error, maxlen, late); + return SDK_OnMetamodLoad(ismm, error, maxlen, late); } bool SDKExtension::Unload(char *error, size_t maxlen) @@ -287,7 +287,7 @@ const char *SDKExtension::GetVersion() return GetExtensionVerString(); } -bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) { return true; } diff --git a/public/sample_ext/smsdk_ext.h b/public/sample_ext/smsdk_ext.h index 8d23c32e..d763460e 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/public/sample_ext/smsdk_ext.h @@ -82,7 +82,7 @@ public: * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. From c8895152636b375ce60f947f6ac5f7dc13799185 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Apr 2007 15:05:56 +0000 Subject: [PATCH 0652/1664] fixed amb186 (state changing crashes) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40683 --- core/HalfLife2.cpp | 8 +++++++- core/HalfLife2.h | 6 +++--- core/smn_entities.cpp | 7 ------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 907ef2fa..c2300f21 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -38,11 +38,17 @@ CHalfLife2::~CHalfLife2() m_Tables.clear(); } -#if 0 +CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; + void CHalfLife2::OnSourceModStartup(bool late) { + if (!g_pSharedChangeInfo) + { + g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); + } } +#if 0 void CHalfLife2::OnSourceModAllShutdown() { } diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 3f03ff99..dc3ec36b 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -29,14 +29,14 @@ struct DataTableInfo Trie *lookup; }; -class CHalfLife2 +class CHalfLife2 : public SMGlobalClass { public: CHalfLife2(); ~CHalfLife2(); public: - /*void OnSourceModStartup(bool late); - void OnSourceModAllShutdown();*/ + void OnSourceModStartup(bool late); + /*void OnSourceModAllShutdown();*/ public: SendProp *FindInSendTable(const char *classname, const char *offset); ServerClass *FindServerClass(const char *classname); diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index dc7ed320..e8652c8e 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -464,8 +464,6 @@ IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() return engine->GetChangeAccessor( (const edict_t *)this ); } -CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; - static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) { edict_t *pEdict = GetEdict(params[1]); @@ -475,11 +473,6 @@ static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Edict %d is invalid", params[1]); } - if (!g_pSharedChangeInfo) - { - g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); - } - if (params[2]) { pEdict->StateChanged(params[2]); From e3b3180099d98739b9dea52f94d016741ce42489 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Apr 2007 15:28:08 +0000 Subject: [PATCH 0653/1664] moved another CBaseEdict helper to HalfLife2.cpp --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40684 --- core/HalfLife2.cpp | 5 +++++ core/smn_entities.cpp | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index c2300f21..08d91514 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -48,6 +48,11 @@ void CHalfLife2::OnSourceModStartup(bool late) } } +IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() +{ + return engine->GetChangeAccessor( (const edict_t *)this ); +} + #if 0 void CHalfLife2::OnSourceModAllShutdown() { diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index e8652c8e..f3d85102 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -459,11 +459,6 @@ static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) return 1; } -IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() -{ - return engine->GetChangeAccessor( (const edict_t *)this ); -} - static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) { edict_t *pEdict = GetEdict(params[1]); From 3474ba74a521e0677d57b5c57e0c55ef28e61474 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Apr 2007 16:07:44 +0000 Subject: [PATCH 0654/1664] removed unused libraries section added tag section for sawce --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40685 --- public/sourcepawn/sp_file_headers.h | 9 +++++++++ sourcepawn/compiler/msvc8/spcomp.vcproj | 2 +- sourcepawn/compiler/pawncc.c | 26 ++++++++++++++++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h index eb0bab53..0b4be064 100644 --- a/public/sourcepawn/sp_file_headers.h +++ b/public/sourcepawn/sp_file_headers.h @@ -134,6 +134,15 @@ typedef struct sp_file_pubvars_s uint32_t name; /**< Index into nametable */ } sp_file_pubvars_t; +/** + * @brief File-encoded tag info. + */ +typedef struct sp_file_tag_s +{ + uint32_t tag_id; /**< Tag ID from compiler */ + uint32_t name; /**< Index into nametable */ +} sp_file_tag_t; + #if defined __linux__ #pragma pack() /* reset default packing */ #else diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index af32cd24..8d1fa240 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -305,7 +305,7 @@ > pubvars - hdr->libraries) / hdr->defsize; - if (sections[FS_Libraries]) + sections[FS_Tags] = (hdr->nametable - hdr->tags) / hdr->defsize; + if (sections[FS_Tags]) { - spfw_add_section(spf, ".libraries"); + spfw_add_section(spf, ".tags"); } spfw_add_section(spf, ".names"); @@ -260,6 +260,22 @@ int main(int argc, char *argv[]) spfw_next_section(spf); } + if (sections[FS_Tags]) + { + uint32_t numTags = (uint32_t)sections[FS_Tags]; + AMX_FUNCSTUBNT *stub; + sp_file_tag_t tag; + + for (i=0; itags + (i * hdr->defsize)); + tag.tag_id = stub->address; + tag.name = stub->nameofs - (hdr->nametable + sizeof(uint16_t)); + sfwrite(&tag, sizeof(sp_file_tag_t), 1, spf); + } + spfw_next_section(spf); + } + if (sections[FS_Nametable]) { unsigned char *base; From e42773b07dbae2b27356b3324e3b21bbfda4bd78 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Apr 2007 16:24:50 +0000 Subject: [PATCH 0655/1664] added strncmp renamed StrCompare to strcmp --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40686 --- core/smn_string.cpp | 16 ++++++++++++++++ plugins/include/string.inc | 24 +++++++++++++++++++++++- public/sm_platform.h | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index ca1bf21b..fbeb139f 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -74,6 +74,21 @@ static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params) return (func(str1, str2)); } +static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params) +{ + char *str1, *str2; + + pCtx->LocalToString(params[1], &str1); + pCtx->LocalToString(params[2], &str2); + + if (params[4]) + { + return strncmp(str1, str2, (size_t)params[3]); + } else { + return strncasecmp(str1, str2, (size_t)params[3]); + } +} + static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params) { char *dest, *src; @@ -316,6 +331,7 @@ REGISTER_NATIVES(basicStrings) {"StrBreak", StrBreak}, {"StrContains", sm_contain}, {"StrCompare", sm_strcmp}, + {"StrCompareN", sm_strncmp}, {"StrCopy", sm_strcopy}, {"StringToInt", sm_strconvint}, {"IntToString", sm_numtostr}, diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 4eef8021..5060a0bf 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -55,7 +55,29 @@ native StrContains(const String:str[], const String:substr[], bool:caseSensitive * 0 if str1 == str2 * 1 if str1 > str2 */ -native StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=true); +native strcmp(const String:str1[], const String:str2[], bool:caseSensitive=true); + +/** + * Compares two strings parts lexographically. + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param num Number of characters to compare. + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return -1 if str1 < str2 + * 0 if str1 == str2 + * 1 if str1 > str2 + */ +native strncmp(const String:str1[], const String:str2[], num, bool:caseSensitive=true); + +/** + * Backwards compatible stock - StrCompare is now strcmp + */ +stock StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=true) +{ + return strcmp(str1, str2, caseSensitive); +} /** * Returns whether two strings are equal. diff --git a/public/sm_platform.h b/public/sm_platform.h index 499050f3..d78b3c75 100644 --- a/public/sm_platform.h +++ b/public/sm_platform.h @@ -34,6 +34,7 @@ #define stat _stat #endif #define strcasecmp strcmpi +#define strncasecmp strnicmp #include #include #define PLATFORM_LIB_EXT "dll" From 4ecb7a985fc36649aa74646b7d4b59fd391bbabb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 11 Apr 2007 20:07:20 +0000 Subject: [PATCH 0656/1664] renamed another native, fixed backwards compat --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40687 --- core/smn_string.cpp | 8 +++++--- plugins/include/string.inc | 12 +++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index fbeb139f..cca8271f 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -330,9 +330,11 @@ REGISTER_NATIVES(basicStrings) {"strlen", sm_strlen}, {"StrBreak", StrBreak}, {"StrContains", sm_contain}, - {"StrCompare", sm_strcmp}, - {"StrCompareN", sm_strncmp}, - {"StrCopy", sm_strcopy}, + {"strcmp", sm_strcmp}, + {"StrCompare", sm_strcmp}, /* Backwards compat shim */ + {"strncmp", sm_strncmp}, + {"strcopy", sm_strcopy}, + {"StrCopy", sm_strcopy}, /* Backwards compat shim */ {"StringToInt", sm_strconvint}, {"IntToString", sm_numtostr}, {"StringToFloat", sm_strtofloat}, diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 5060a0bf..3821209d 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -73,6 +73,7 @@ native strncmp(const String:str1[], const String:str2[], num, bool:caseSensitive /** * Backwards compatible stock - StrCompare is now strcmp + * @deprecated Renamed to strcmp */ stock StrCompare(const String:str1[], const String:str2[], bool:caseSensitive=true) { @@ -104,7 +105,16 @@ stock bool:StrEqual(const String:str1[], const String:str2[], bool:caseSensitive * @param source Source string buffer to copy from. * @return Number of cells written. */ -native StrCopy(String:dest[], destLen, const String:source[]); +native strcopy(String:dest[], destLen, const String:source[]); + +/** + * Backwards compatibility stock - use strcopy + * @deprecated Renamed to strcopy + */ +stock StrCopy(String:dest[], destLen, const String:source[]) +{ + return strcopy(dest, destLen, source); +} /** * Formats a string according to the SourceMod format rules (see documentation). From 21923d7871e7c823018bce86e52f4f72de92b82c Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 12 Apr 2007 00:45:53 +0000 Subject: [PATCH 0657/1664] added datamap property offset native added clientofuserid native for fast userid to client id translation fixed a memory leek (some tries weren't being deleted) added createdialog native added 2 million inetchannelinfo wrappers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40688 --- core/HalfLife2.cpp | 75 ++++++++++++- core/HalfLife2.h | 10 ++ core/PlayerManager.cpp | 12 +++ core/PlayerManager.h | 2 + core/msvc8/sourcemod_mm.vcproj | 2 +- core/smn_entities.cpp | 69 ++++++++++++ core/smn_halflife.cpp | 43 ++++++++ core/smn_keyvalues.cpp | 27 +++++ core/smn_player.cpp | 187 +++++++++++++++++++++++++++++++++ core/sourcemod.h | 1 + plugins/include/clients.inc | 114 ++++++++++++++++++++ plugins/include/entity.inc | 170 ++++++++++++++++++++++++++++-- plugins/include/sourcemod.inc | 16 ++- public/IForwardSys.h | 14 +-- public/IPlayerHelpers.h | 8 ++ public/ISourceMod.h | 40 ++++--- 16 files changed, 757 insertions(+), 33 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 08d91514..5e712f61 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -17,6 +17,21 @@ CHalfLife2 g_HL2; +namespace SourceHook +{ + template<> + int HashFunction(datamap_t * const &k) + { + return reinterpret_cast(k); + } + + template<> + int Compare(datamap_t * const &k1, datamap_t * const &k2) + { + return (k1-k2); + } +} + CHalfLife2::CHalfLife2() { m_pClasses = sm_trie_create(); @@ -36,6 +51,18 @@ CHalfLife2::~CHalfLife2() } m_Tables.clear(); + + THash::iterator h_iter; + for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++) + { + if (h_iter->val.trie) + { + sm_trie_destroy(h_iter->val.trie); + h_iter->val.trie = NULL; + } + } + + m_Maps.clear(); } CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; @@ -85,6 +112,31 @@ SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name) return NULL; } +typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name) +{ + while (pMap) + { + for (int i=0; idataNumFields; i++) + { + if (strcmp(name, pMap->dataDesc[i].fieldName) == 0) + { + return &(pMap->dataDesc[i]); + } + if (pMap->dataDesc[i].td) + { + typedescription_t *_td; + if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL) + { + return _td; + } + } + } + pMap = pMap->baseMap; + } + + return NULL; +} + ServerClass *CHalfLife2::FindServerClass(const char *classname) { DataTableInfo *pInfo = _FindServerClass(classname); @@ -111,6 +163,7 @@ DataTableInfo *CHalfLife2::_FindServerClass(const char *classname) pInfo->lookup = sm_trie_create(); pInfo->sc = sc; sm_trie_insert(m_pClasses, classname, pInfo); + m_Tables.push_back(pInfo); break; } sc = sc->m_pNext; @@ -133,7 +186,7 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) return NULL; } - SendProp *pProp; + SendProp *pProp = NULL; if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp)) { if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL) @@ -144,3 +197,23 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) return pProp; } + +typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset) +{ + typedescription_t *td = NULL; + DataMapTrie &val = m_Maps[pMap]; + + if (!val.trie) + { + val.trie = sm_trie_create(); + } + if (!sm_trie_retrieve(val.trie, offset, (void **)&td)) + { + if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL) + { + sm_trie_insert(val.trie, offset, td); + } + } + + return td; +} diff --git a/core/HalfLife2.h b/core/HalfLife2.h index dc3ec36b..0f7df3b2 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -16,10 +16,12 @@ #define _INCLUDE_SOURCEMOD_CHALFLIFE2_H_ #include +#include #include "sm_trie.h" #include "sm_globals.h" #include "dt_send.h" #include "server_class.h" +#include "datamap.h" using namespace SourceHook; @@ -29,6 +31,12 @@ struct DataTableInfo Trie *lookup; }; +struct DataMapTrie +{ + DataMapTrie() : trie(NULL) {} + Trie *trie; +}; + class CHalfLife2 : public SMGlobalClass { public: @@ -40,11 +48,13 @@ public: public: SendProp *FindInSendTable(const char *classname, const char *offset); ServerClass *FindServerClass(const char *classname); + typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset); private: DataTableInfo *_FindServerClass(const char *classname); private: Trie *m_pClasses; List m_Tables; + THash m_Maps; }; extern CHalfLife2 g_HL2; diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 12569f78..8f4e9ca9 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -31,11 +31,15 @@ PlayerManager::PlayerManager() { m_AuthQueue = NULL; m_FirstPass = true; + + m_UserIdLookUp = new int[USHRT_MAX]; + memset(m_UserIdLookUp, 0, sizeof(int) * USHRT_MAX); } PlayerManager::~PlayerManager() { delete [] m_AuthQueue; + delete [] m_UserIdLookUp; } void PlayerManager::OnSourceModAllInitialized() @@ -212,6 +216,8 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const RETURN_META_VALUE(MRES_SUPERCEDE, false); } + m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client; + return true; } @@ -353,6 +359,7 @@ void PlayerManager::OnClientDisconnect(edict_t *pEntity) } m_Players[client].Disconnect(); + m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = 0; } void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity) @@ -425,6 +432,11 @@ int PlayerManager::GetNumPlayers() return m_PlayerCount; } +int PlayerManager::GetClientOfUserId(int userid) +{ + return (userid < 0 || userid > USHRT_MAX) ? 0 : m_UserIdLookUp[userid]; +} + void PlayerManager::AddClientListener(IClientListener *listener) { m_hooks.push_back(listener); diff --git a/core/PlayerManager.h b/core/PlayerManager.h index ac4ebb90..56811de2 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -95,6 +95,7 @@ public: //IPlayerManager IGamePlayer *GetGamePlayer(edict_t *pEdict); int GetMaxClients(); int GetNumPlayers(); + int GetClientOfUserId(int userid); public: inline int MaxClients() { @@ -117,6 +118,7 @@ private: IForward *m_clauth; IForward *m_onActivate; CPlayer *m_Players; + int *m_UserIdLookUp; int m_maxClients; int m_PlayerCount; bool m_FirstPass; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 3126cad1..78cab260 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ (&pThisPtr); + void **vtable = *reinterpret_cast(pThisPtr); + void *vfunc = vtable[offset]; + + union + { + datamap_t *(VEmptyClass::*mfpnew)(); +#ifndef PLATFORM_POSIX + void *addr; + } u; + u.addr = vfunc; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = vfunc; + u.s.adjustor = 0; +#endif + + return (datamap_t *)(reinterpret_cast(this_ptr)->*u.mfpnew)(); +} + +inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity) +{ + int offset; + + if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset) + { + return NULL; + } + + return VGetDataDescMap(pEntity, offset); +} + static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) { return gpGlobals->maxEntities; @@ -494,6 +535,33 @@ static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params) return pSend->GetOffset(); } +static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + datamap_t *pMap; + typedescription_t *td; + char *offset; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL) + { + return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset"); + } + + pContext->LocalToString(params[2], &offset); + if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL) + { + return -1; + } + + return td->fieldOffset[TD_OFFSET_NORMAL]; +} + REGISTER_NATIVES(entityNatives) { {"ChangeEdictState", ChangeEdictState}, @@ -517,5 +585,6 @@ REGISTER_NATIVES(entityNatives) {"SetEntDataEnt", SetEntDataEnt}, {"SetEntDataFloat", SetEntDataFloat}, {"SetEntDataVector", SetEntDataVector}, + {"FindDataMapOffs", FindDataMapOffs}, {NULL, NULL} }; diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index e9a2bf5e..833dc0e0 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -16,6 +16,18 @@ #include "sourcemod.h" #include "sourcemm_api.h" #include "PlayerManager.h" +#include "HandleSys.h" + +IServerPluginCallbacks *g_VSP = NULL; + +class HalfLifeNatives : public SMGlobalClass +{ +public: //SMGlobalClass + void OnSourceModVSPReceived(IServerPluginCallbacks *iface) + { + g_VSP = iface; + } +}; static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params) { @@ -229,6 +241,36 @@ static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t smn_CreateDialog(IPluginContext *pContext, const cell_t *params) +{ + KeyValues *pKV; + HandleError herr; + Handle_t hndl = static_cast(params[2]); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + pKV = g_SourceMod.ReadKeyValuesHandle(hndl, &herr, true); + if (herr != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + serverpluginhelpers->CreateMessage(pPlayer->GetEdict(), static_cast(params[3]), pKV, g_VSP); + + return 1; +} + +static HalfLifeNatives s_HalfLifeNatives; + REGISTER_NATIVES(halflifeNatives) { {"CreateFakeClient", CreateFakeClient}, @@ -252,5 +294,6 @@ REGISTER_NATIVES(halflifeNatives) {"PrecacheSound", PrecacheSound}, {"IsSoundPrecached", IsSoundPrecached}, {"FakeClientCommand", FakeClientCommand}, + {"CreateDialog", smn_CreateDialog}, {NULL, NULL}, }; diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 745756f1..d0aae516 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -48,6 +48,33 @@ public: } }; +KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root) +{ + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + if (err) + { + *err = herr; + } + return NULL; + } + + if (err) + { + *err = HandleError_None; + } + + return (root) ? pStk->pBase : pStk->pCurRoot.front(); +} + static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 6f0a055b..042b21d8 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -15,6 +15,7 @@ #include "PlayerManager.h" #include "AdminCache.h" #include "sm_stringutil.h" +#include static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) { @@ -637,6 +638,182 @@ static cell_t GetHealth(IPluginContext *pContext, const cell_t *params) return pInfo->GetHealth(); } +static cell_t GetTimeConnected(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetTimeConnected()); +} + +static cell_t GetDataRate(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return pInfo->GetDataRate(); +} + +static cell_t IsTimingOut(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return pInfo->IsTimingOut() ? 1 : 0; +} + +static cell_t GetLatency(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetLatency(params[2])); +} + +static cell_t GetAvgLatency(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetAvgLatency(params[2])); +} + +static cell_t GetAvgLoss(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetAvgLoss(params[2])); +} + +static cell_t GetAvgChoke(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetAvgChoke(params[2])); +} + +static cell_t GetAvgData(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetAvgData(params[2])); +} + +static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid client", client); + } else if (!pPlayer->IsInGame()) { + return pContext->ThrowNativeError("Player %d is not in game", client); + } else if (pPlayer->IsFakeClient()) { + return pContext->ThrowNativeError("Player %d is a bot", client); + } + + INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client); + + return sp_ftoc(pInfo->GetAvgPackets(params[2])); +} + +static cell_t GetClientOfUserId(IPluginContext *pContext, const cell_t *params) +{ + return g_Players.GetClientOfUserId(params[1]); +} + REGISTER_NATIVES(playernatives) { {"AddUserFlags", AddUserFlags}, @@ -668,5 +845,15 @@ REGISTER_NATIVES(playernatives) {"GetClientWeapon", GetWeaponName}, {"GetClientModel", GetModelName}, {"GetClientHealth", GetHealth}, + {"GetTimeConnected", GetTimeConnected}, + {"GetDataRate", GetDataRate}, + {"IsTimingOut", IsTimingOut}, + {"GetLatency", GetLatency}, + {"GetAvgLatency", GetAvgLatency}, + {"GetAvgLoss", GetAvgLoss}, + {"GetAvgChoke", GetAvgChoke}, + {"GetAvgData", GetAvgData}, + {"GetAvgPackets", GetAvgPackets}, + {"GetClientOfUserId", GetClientOfUserId}, {NULL, NULL} }; diff --git a/core/sourcemod.h b/core/sourcemod.h index a2ca1f84..f7a80ac3 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -93,6 +93,7 @@ public: // ISourceMod IDataPack *CreateDataPack(); void FreeDataPack(IDataPack *pack); HandleType_t GetDataPackHandleType(bool readonly=false); + KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false); private: /** * @brief Loading plugins diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index bfcfa590..f2f169d4 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -18,6 +18,13 @@ #endif #define _clients_included +enum NetFlow +{ + NetFlow_Outgoing = 0, /**< Outgoing traffic */ + NetFlow_Incoming, /**< Incoming traffic */ + NetFlow_Both /**< Incoming and outgoing traffic */ +}; + /** * Called on client connection. * @@ -380,3 +387,110 @@ native GetClientDeaths(client); * @error Invalid client index, client not in game, or no mod support. */ native GetClientFrags(client); + +/** + * Returns the client's send data rate in bytes/sec. + * + * @param client Player's index. + * @return Data rate. + * @error Invalid client index, client not in game, or fake client. + */ +native GetDataRate(client); + +/** + * Returns if a client is timing out + * + * @param client Player's index. + * @return True if client is timing out, false otherwise. + * @error Invalid client index, client not in game, or fake client. + */ +native bool:IsTimingOut(client); + +/** + * Returns the client's connection time in seconds. + * + * @param client Player's index. + * @return Connection time. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetTimeConnected(client); + +/** + * Returns the client's current latency (RTT), more accurate than GetAvgLatency but jittering. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Latency. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetLatency(client, NetFlow:flow); + +/** + * Returns the client's average packet latency in seconds. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Average latency. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetAvgLatency(client, NetFlow:flow); + +/** + * Returns the client's average packet loss, values go from 0 to 1 (for percentages). + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Average packet loss. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetAvgLoss(client, NetFlow:flow); + +/** + * Returns the client's average packet choke, values go from 0 to 1 (for percentages). + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Average packet choke. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetAvgChoke(client, NetFlow:flow); + +/** + * Returns the client's data flow in bytes/sec. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Data flow. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetAvgData(client, NetFlow:flow); + +/** + * Returns the client's average packet frequency in packets/sec. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Packet frequency. + * @error Invalid client index, client not in game, or fake client. + */ +native Float:GetAvgPackets(client, NetFlow:flow); + +/** + * Translates an userid index to the real player index. + * + * @param userid Userid value. + * @return Client value. + * @error Returns 0 if invalid userid. + */ +native GetClientOfUserId(userid); + +/** + * Executes a client command on the server without being networked. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @noreturn + * @error Invalid client index, or client not connected. + */ +native FakeClientCommand(client, const String:fmt[], any:...); diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 986503ac..f2e0eced 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -289,6 +289,16 @@ native SetEntDataVector(entity, offset, const Float:vec[3], bool:changeState=fal */ native FindSendPropOffs(const String:cls[], const String:prop[]); +/** + * Given an entity, finds a datamap property offset. + * This information is cached for future calls. + * + * @param entity Entity index. + * @param prop Property name. + * @return An offset, or -1 on failure. + */ +native FindDataMapOffs(entity, const String:prop[]); + /** * Wrapper function for finding a send property for a particular entity. * @@ -320,11 +330,29 @@ stock GetEntSendPropOffs(ent, const String:prop[]) */ stock GetEntProp(entity, PropType:type, const String:prop[], size=4) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return GetEntData(entity, offs, size); } @@ -340,11 +368,29 @@ stock GetEntProp(entity, PropType:type, const String:prop[], size=4) */ stock SetEntProp(entity, PropType:type, const String:prop[], value, size=4) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return SetEntData(entity, offs, value, size, true); } @@ -359,11 +405,29 @@ stock SetEntProp(entity, PropType:type, const String:prop[], value, size=4) */ stock Float:GetEntPropFloat(entity, PropType:type, const String:prop[]) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return GetEntDataFloat(entity, offs); } @@ -379,11 +443,29 @@ stock Float:GetEntPropFloat(entity, PropType:type, const String:prop[]) */ stock SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return SetEntDataFloat(entity, offs, value, true); } @@ -398,11 +480,29 @@ stock SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value) */ stock GetEntPropEnt(entity, PropType:type, const String:prop[]) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return GetEntDataEnt(entity, offs); } @@ -418,11 +518,29 @@ stock GetEntPropEnt(entity, PropType:type, const String:prop[]) */ stock SetEntPropEnt(entity, PropType:type, const String:prop[], other) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return SetEntDataEnt(entity, offs, other, true); } @@ -440,11 +558,29 @@ stock SetEntPropEnt(entity, PropType:type, const String:prop[], other) */ stock GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3]) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return GetEntDataVector(entity, offs, vec); } @@ -462,10 +598,28 @@ stock GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3]) */ stock SetEntPropVector(entity, PropType:type, const String:prop[], const Float:vec[3]) { - new offs = GetEntSendPropOffs(entity, prop); + new offs; + + switch (type) + { + case Prop_Send: + { + offs = GetEntSendPropOffs(entity, prop); + } + case Prop_Data: + { + offs = FindDataMapOffs(entity, prop); + } + default: + { + ThrowError("Invalid Property type %d", type); + } + } + if (offs == -1) { ThrowError("Property \"%s\" not found for entity %d", prop, entity); } + return SetEntDataVector(entity, offs, vec, true); } diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 4fca185f..e1949353 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -45,6 +45,14 @@ struct Plugin #include #include +enum DialogType +{ + DialogType_Msg = 0, /**< just an on screen message */ + DialogType_Menu, /**< an options menu */ + DialogType_Text, /**< a richtext dialog */ + DialogType_Entry /**< an entry box */ +}; + /** * Declare this as a struct in your plugin to expose its information. * Example: @@ -388,15 +396,15 @@ native bool:PrecacheSound(const String:sound[], bool:preload=false); native bool:IsSoundPrecached(const String:sound[]); /** - * Executes a client command on the server without being networked. + * Creates different types of ingame messages. * * @param client Index of the client. - * @param fmt Format of the client command. - * @param ... Format parameters + * @param kv KeyValues handle to set the menu keys and options. (Check iserverplugin.h for more information). + * @param type Message type to display ingame. * @noreturn * @error Invalid client index, or client not connected. */ -native FakeClientCommand(client, const String:fmt[], any:...); +native CreateDialog(client, Handle:kv, DialogType:type); #include #include diff --git a/public/IForwardSys.h b/public/IForwardSys.h index 478670aa..ab3d553b 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -229,13 +229,13 @@ namespace SourceMod virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; /** - * @brief Removes a function from the call list. - * NOTE: Only removes one instance. - * - * @param ctx Context to use as a look-up. - * @param index Function id to add. - * @return Whether or not the function was removed. - */ + * @brief Removes a function from the call list. + * NOTE: Only removes one instance. + * + * @param ctx Context to use as a look-up. + * @param index Function id to add. + * @return Whether or not the function was removed. + */ virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index) =0; }; diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 1d120a9a..4fed6ef8 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -244,6 +244,14 @@ namespace SourceMod * @return Current number of connected clients. */ virtual int GetNumPlayers() =0; + + /** + * @brief Returns the client index by its userid. + * + * @param userid Userid of the client. + * @return Client index, or 0 if invalid userid passed. + */ + virtual int GetClientOfUserId(int userid) =0; }; } diff --git a/public/ISourceMod.h b/public/ISourceMod.h index d9e3b270..aca741d9 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -23,13 +23,18 @@ * @brief Defines miscellanious helper functions useful to extensions. */ -#include +#include #include #include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" #define SMINTERFACE_SOURCEMOD_VERSION 1 +/** +* @brief Forward declaration of the KeyValues class. +*/ +class KeyValues; + namespace SourceMod { /** @@ -133,18 +138,29 @@ namespace SourceMod */ virtual void FreeDataPack(IDataPack *pack) =0; - /** - * @brief Returns the automated data pack handle type. - * - * The readonly data type is the parent of the writable type. - * Note that calling CloseHandle() on either type will release the data pack. - * The readonly type is inheritable, but due to limitations of the Handle System, - * the writable type is not. - * - * @param readonly If true, the readonly type will be returned. - * @return The Handle type for storing generic data packs. - */ + /** + * @brief Returns the automated data pack handle type. + * + * The readonly data type is the parent of the writable type. + * Note that calling CloseHandle() on either type will release the data pack. + * The readonly type is inheritable, but due to limitations of the Handle System, + * the writable type is not. + * + * @param readonly If true, the readonly type will be returned. + * @return The Handle type for storing generic data packs. + */ virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; + + /** + * @brief Retrieves a KeyValues pointer from a handle. + * + * @param hndl Handle_t from which to retrieve contents. + * @param err Optional address to store a possible handle error. + * @param root If true it will return the root KeyValues pointer for the whole structure. + * + * @return The KeyValues pointer, or NULL for any error encountered. + */ + virtual KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false) =0; }; } From 3b8864193d5b9eaf08cc7afe4b240897ec45ae82 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 12 Apr 2007 02:16:09 +0000 Subject: [PATCH 0658/1664] Fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40689 --- core/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Makefile b/core/Makefile index 9c3f34a2..650c5912 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,8 +19,8 @@ BINARY = sourcemod_mm_i486.so HL2PUB = $(HL2SDK)/public HL2LIB = $(HL2SDK)/linux_sdk -OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp \ - DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ +OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \ + Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ sourcemm_api.cpp sourcemod.cpp From 4e6834a7a4b65f52169ba8073d5d85fd7542bfca Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 12 Apr 2007 07:51:05 +0000 Subject: [PATCH 0659/1664] Fixed amb190 - Crash with Mani's spawn protection and GetEvent (which exposed re-entrancy problems in EventManager) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40690 --- core/EventManager.cpp | 32 ++++++++++++++++++++++---------- core/EventManager.h | 5 +++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 082fe522..eba1a86a 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -25,7 +25,7 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; typedef List EventHookList; -EventManager::EventManager() : m_EventType(0), m_NotifyPlugins(true), m_EventCopy(NULL) +EventManager::EventManager() : m_EventType(0), m_NotifyPlugins(true) { /* Create an event lookup trie */ m_EventHooks = sm_trie_create(); @@ -322,6 +322,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) { EventHook *pHook; IChangeableForward *pForward; + const char *name; cell_t res = Pl_Continue; if (!m_NotifyPlugins) @@ -330,9 +331,11 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) } /* Get the event name, we're going to need this for passing to post hooks */ - m_EventName = pEvent->GetName(); + name = pEvent->GetName(); - if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + m_EventNames.push(name); + + if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast(&pHook))) { pForward = pHook->pPreHook; @@ -342,7 +345,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); pForward->PushCell(hndl); - pForward->PushString(m_EventName); + pForward->PushString(name); pForward->PushCell(bDontBroadcast); pForward->Execute(&res, NULL); @@ -352,7 +355,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) if (pHook->postCopy) { - m_EventCopy = gameevents->DuplicateEvent(pEvent); + pHook->pEventCopy = gameevents->DuplicateEvent(pEvent); } if (res) @@ -368,8 +371,10 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) /* IGameEventManager2::FireEvent post hook */ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) { + IGameEvent *pEventCopy; EventHook *pHook; IChangeableForward *pForward; + const char *name; Handle_t hndl = 0; if (!m_NotifyPlugins) @@ -380,7 +385,9 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) RETURN_META_VALUE(MRES_IGNORED, true); } - if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + name = m_EventNames.front(); + + if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast(&pHook))) { pForward = pHook->pPostHook; @@ -388,14 +395,17 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) { if (pHook->postCopy) { - EventInfo info = {m_EventCopy, false}; + pEventCopy = pHook->pEventCopy; + + EventInfo info = {pEventCopy, false}; hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); + pForward->PushCell(hndl); } else { pForward->PushCell(BAD_HANDLE); } - pForward->PushString(m_EventName); + pForward->PushString(name); pForward->PushCell(bDontBroadcast); pForward->Execute(NULL); @@ -406,11 +416,13 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) g_HandleSys.FreeHandle(hndl, &sec); /* Free event structure */ - gameevents->FreeEvent(m_EventCopy); - m_EventCopy = NULL; + gameevents->FreeEvent(pEventCopy); + pHook->pEventCopy = NULL; } } } + m_EventNames.pop(); + RETURN_META_VALUE(MRES_IGNORED, true); } diff --git a/core/EventManager.h b/core/EventManager.h index 588b87ed..deb8c5ec 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -42,11 +42,13 @@ struct EventHook pPreHook = NULL; pPostHook = NULL; postCopy = false; + pEventCopy = NULL; refCount = 0; } IChangeableForward *pPreHook; IChangeableForward *pPostHook; bool postCopy; + IGameEvent *pEventCopy; unsigned int refCount; }; @@ -102,10 +104,9 @@ private: // IGameEventManager2 hooks private: HandleType_t m_EventType; bool m_NotifyPlugins; - const char *m_EventName; - IGameEvent *m_EventCopy; Trie *m_EventHooks; CStack m_FreeEvents; + CStack m_EventNames; }; extern EventManager g_EventManager; From ccdddc16fb6b7fb43cdf1eb5da9105040a3536b6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Apr 2007 16:28:29 +0000 Subject: [PATCH 0660/1664] fixed using newer engine functions on The Ship because Valve can't version properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40691 --- core/HalfLife2.cpp | 24 +++++++++++++++++------- core/HalfLife2.h | 3 +++ core/smn_entities.cpp | 15 +++++---------- core/sourcemod.h | 4 ++-- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 5e712f61..cc61b462 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -16,6 +16,7 @@ #include "sourcemm_api.h" CHalfLife2 g_HL2; +bool g_IsOriginalEngine = false; namespace SourceHook { @@ -69,7 +70,7 @@ CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; void CHalfLife2::OnSourceModStartup(bool late) { - if (!g_pSharedChangeInfo) + if (!g_IsOriginalEngine && !g_pSharedChangeInfo) { g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); } @@ -80,12 +81,6 @@ IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() return engine->GetChangeAccessor( (const edict_t *)this ); } -#if 0 -void CHalfLife2::OnSourceModAllShutdown() -{ -} -#endif - SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name) { const char *pname; @@ -217,3 +212,18 @@ typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset return td; } + +void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) +{ + if (!g_IsOriginalEngine) + { + if (offset) + { + pEdict->StateChanged(offset); + } else { + pEdict->StateChanged(); + } + } else { + pEdict->m_fStateFlags |= FL_EDICT_CHANGED; + } +} diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 0f7df3b2..bdf8de22 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -22,6 +22,7 @@ #include "dt_send.h" #include "server_class.h" #include "datamap.h" +#include "edict.h" using namespace SourceHook; @@ -49,6 +50,7 @@ public: SendProp *FindInSendTable(const char *classname, const char *offset); ServerClass *FindServerClass(const char *classname); typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset); + void SetEdictStateChanged(edict_t *pEdict, unsigned short offset); private: DataTableInfo *_FindServerClass(const char *classname); private: @@ -58,5 +60,6 @@ private: }; extern CHalfLife2 g_HL2; +extern bool g_IsOriginalEngine; #endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_ diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index e4208eda..26311228 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -298,7 +298,7 @@ static cell_t SetEntData(IPluginContext *pContext, const cell_t *params) if (params[5]) { - pEdict->StateChanged(offset); + g_HL2.SetEdictStateChanged(pEdict, offset); } switch (params[4]) @@ -366,7 +366,7 @@ static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params) if (params[4]) { - pEdict->StateChanged(offset); + g_HL2.SetEdictStateChanged(pEdict, offset); } return 1; @@ -427,7 +427,7 @@ static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params) if (params[4]) { - pEdict->StateChanged(offset); + g_HL2.SetEdictStateChanged(pEdict, offset); } return 1; @@ -494,7 +494,7 @@ static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) if (params[4]) { - pEdict->StateChanged(offset); + g_HL2.SetEdictStateChanged(pEdict, offset); } return 1; @@ -509,12 +509,7 @@ static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Edict %d is invalid", params[1]); } - if (params[2]) - { - pEdict->StateChanged(params[2]); - } else { - pEdict->StateChanged(); - } + g_HL2.SetEdictStateChanged(pEdict, params[2]); return 1; } diff --git a/core/sourcemod.h b/core/sourcemod.h index f7a80ac3..5c282ec5 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -116,7 +116,7 @@ private: }; extern SourceModBase g_SourceMod; -extern HandleType_t g_WrBitBufType; -extern HandleType_t g_RdBitBufType; +extern HandleType_t g_WrBitBufType; //:TODO: find a better place for this +extern HandleType_t g_RdBitBufType; //:TODO: find a better place for this #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ From 9542cf51134b2a3bb9bf26a15071dff0dc5c58f9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Apr 2007 19:08:01 +0000 Subject: [PATCH 0661/1664] Added some redirection and exception handling --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40692 --- tools/builder/Main.cs | 9 ++++++++- tools/builder/Win32Builder.cs | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/builder/Main.cs b/tools/builder/Main.cs index 1a6629ed..5fb74963 100644 --- a/tools/builder/Main.cs +++ b/tools/builder/Main.cs @@ -33,7 +33,14 @@ namespace builder bld = new Win32Builder(cfg); } - bld.BuildPackage(new PkgCore()); + try + { + bld.BuildPackage(new PkgCore()); + } + catch (System.Exception e) + { + Console.WriteLine("Build failed: " + e.Message); + } } } } diff --git a/tools/builder/Win32Builder.cs b/tools/builder/Win32Builder.cs index c3e72aa2..0d1b5ddb 100644 --- a/tools/builder/Win32Builder.cs +++ b/tools/builder/Win32Builder.cs @@ -76,6 +76,8 @@ namespace builder info.WorkingDirectory = path; info.FileName = cfg.BuilderPath; info.UseShellExecute = false; + info.RedirectStandardOutput = true; + info.RedirectStandardError = true; if (cfg.BuildOptions != null) { @@ -85,6 +87,7 @@ namespace builder info.Arguments += "/rebuild " + lib.ReleaseBuild + " " + projectFile; Process p = Process.Start(info); + Console.WriteLine(p.StandardOutput.ReadToEnd()); p.WaitForExit(); p.Close(); From 7b74745ceb1f92c3214418c707f8ed6800ad556c Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 12 Apr 2007 19:49:49 +0000 Subject: [PATCH 0662/1664] CancelCreatedEvent actually does what it is supposed to do now... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40693 --- core/EventManager.cpp | 12 ++++++++++++ core/EventManager.h | 1 + core/smn_events.cpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index eba1a86a..a84b2561 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -317,6 +317,18 @@ void EventManager::FireEvent(EventInfo *pInfo, int flags, bool bDontBroadcast) m_FreeEvents.push(pInfo); } +void EventManager::CancelCreatedEvent(EventInfo *pInfo) +{ + /* Free event from IGameEventManager2 */ + gameevents->FreeEvent(pInfo->pEvent); + + /* IGameEvent is free at this point, so no one owns this */ + pInfo->pOwner = NULL; + + /* Add EventInfo struct to free event stack */ + m_FreeEvents.push(pInfo); +} + /* IGameEventManager2::FireEvent hook */ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) { diff --git a/core/EventManager.h b/core/EventManager.h index deb8c5ec..e0ab28da 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -98,6 +98,7 @@ public: EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventInfo *CreateEvent(IPluginContext *pContext, const char *name); void FireEvent(EventInfo *pInfo, int flags=0, bool bDontBroadcast=false); + void CancelCreatedEvent(EventInfo *pInfo); private: // IGameEventManager2 hooks bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 2eb1fb2a..b3cc7508 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -126,6 +126,8 @@ static cell_t sm_CancelCreatedEvent(IPluginContext *pContext, const cell_t *para return pContext->ThrowNativeError("Game event \"%s\" could not be canceled because it was not created by this plugin", pInfo->pEvent->GetName()); } + g_EventManager.CancelCreatedEvent(pInfo); + /* Free handle on game event */ HandleSecurity sec = {pContext->GetIdentity(), g_pCoreIdent}; g_HandleSys.FreeHandle(hndl, &sec); From f3da8efe102a936d78bfda77f6baa6d00b3e0077 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Apr 2007 20:18:24 +0000 Subject: [PATCH 0663/1664] fixed amb193 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40694 --- core/sourcemod.cpp | 116 ++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index b1dda3d9..13656177 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -45,6 +45,7 @@ IdentityToken_t *g_pCoreIdent = NULL; float g_LastTime = 0.0f; float g_LastAuthCheck = 0.0f; IForward *g_pOnGameFrame = NULL; +bool g_Loaded = false; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef unsigned int (*GETEXPORTCOUNT)(); @@ -188,15 +189,20 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) return false; } - StartSourceMod(late); + /* Hook this now so we can detect startup without calling StartSourceMod() */ + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); + + /* Only load if we're not late */ + if (!late) + { + StartSourceMod(false); + } return true; } void SourceModBase::StartSourceMod(bool late) { - /* First initialize the global hooks we need */ - SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); @@ -224,10 +230,20 @@ void SourceModBase::StartSourceMod(bool late) /* Add us now... */ g_ShareSys.AddInterface(NULL, this); + + /* We're loaded! */ + g_Loaded = true; } bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { + /* If we're not loaded... */ + if (!g_Loaded) + { + /* Do all global initialization now */ + StartSourceMod(true); + } + m_IsMapLoading = true; m_ExecPluginReload = true; g_LastTime = 0.0f; @@ -358,52 +374,56 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c void SourceModBase::CloseSourceMod() { - if (g_pOnGameFrame) - { - g_Forwards.ReleaseForward(g_pOnGameFrame); - } - - /* Notify! */ - SMGlobalClass *pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - /* Delete all data packs */ - CStack::iterator iter; - CDataPack *pd; - for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) - { - pd = (*iter); - delete pd; - } - m_freepacks.popall(); - - /* Notify! */ - pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModAllShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - if (enginePatch) - { - SH_RELEASE_CALLCLASS(enginePatch); - enginePatch = NULL; - } - - if (gamedllPatch) - { - SH_RELEASE_CALLCLASS(gamedllPatch); - gamedllPatch = NULL; - } - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); + + if (g_Loaded) + { + if (g_pOnGameFrame) + { + g_Forwards.ReleaseForward(g_pOnGameFrame); + } + + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModShutdown(); + pBase = pBase->m_pGlobalClassNext; + } + + /* Delete all data packs */ + CStack::iterator iter; + CDataPack *pd; + for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) + { + pd = (*iter); + delete pd; + } + m_freepacks.popall(); + + /* Notify! */ + pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModAllShutdown(); + pBase = pBase->m_pGlobalClassNext; + } + + if (enginePatch) + { + SH_RELEASE_CALLCLASS(enginePatch); + enginePatch = NULL; + } + + if (gamedllPatch) + { + SH_RELEASE_CALLCLASS(gamedllPatch); + gamedllPatch = NULL; + } + + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); + } /* Rest In Peace */ ShutdownJIT(); From 7125585125b7e23e42cf5c21a88589619e7038d2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 12 Apr 2007 20:48:33 +0000 Subject: [PATCH 0664/1664] all tags get exported now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40695 --- sourcepawn/compiler/sc6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 184116b5..ea090bb2 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -745,11 +745,11 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) /* count number of public tags */ numtags=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { - if ((constptr->value & PUBLICTAG)!=0) { + /*if ((constptr->value & PUBLICTAG)!=0) {*/ assert(strlen(constptr->name)>0); numtags++; nametablesize+=strlen(constptr->name)+1; - } /* if */ + /*} if */ } /* for */ /* pad the header to sc_dataalign @@ -915,7 +915,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) /* write the public tagnames table */ count=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { - if ((constptr->value & PUBLICTAG)!=0) { + /*if ((constptr->value & PUBLICTAG)!=0) {*/ assert(strlen(constptr->name)>0); func.address=constptr->value & TAGMASK; func.nameofs=nameofs; @@ -929,7 +929,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) pc_writebin(fout,constptr->name,strlen(constptr->name)+1); nameofs+=strlen(constptr->name)+1; count++; - } /* if */ + /*} if */ } /* for */ /* write the "maximum name length" field in the name table */ From ab4f11e4f5ca8b2da77b6ba039de8ea472defa60 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 13 Apr 2007 05:07:01 +0000 Subject: [PATCH 0665/1664] Fixed linux build... GCC likes to complain. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40696 --- core/EventManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index a84b2561..cf5e14fb 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -383,7 +383,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) /* IGameEventManager2::FireEvent post hook */ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) { - IGameEvent *pEventCopy; + IGameEvent *pEventCopy = NULL; EventHook *pHook; IChangeableForward *pForward; const char *name; From c7db1854003fda74463729bfe04f23747cd948c6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 13 Apr 2007 07:17:52 +0000 Subject: [PATCH 0666/1664] function names now follow convention --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40697 --- core/smn_player.cpp | 18 +++++++++--------- plugins/include/clients.inc | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 042b21d8..c093848d 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -845,15 +845,15 @@ REGISTER_NATIVES(playernatives) {"GetClientWeapon", GetWeaponName}, {"GetClientModel", GetModelName}, {"GetClientHealth", GetHealth}, - {"GetTimeConnected", GetTimeConnected}, - {"GetDataRate", GetDataRate}, - {"IsTimingOut", IsTimingOut}, - {"GetLatency", GetLatency}, - {"GetAvgLatency", GetAvgLatency}, - {"GetAvgLoss", GetAvgLoss}, - {"GetAvgChoke", GetAvgChoke}, - {"GetAvgData", GetAvgData}, - {"GetAvgPackets", GetAvgPackets}, + {"GetClientTime", GetTimeConnected}, + {"GetClientDataRate", GetDataRate}, + {"IsClentTimingOut", IsTimingOut}, + {"GetClientLatency", GetLatency}, + {"GetClientAvgLatency", GetAvgLatency}, + {"GetClientAvgLoss", GetAvgLoss}, + {"GetClientAvgChoke", GetAvgChoke}, + {"GetClientAvgData", GetAvgData}, + {"GetClientAvgPackets", GetAvgPackets}, {"GetClientOfUserId", GetClientOfUserId}, {NULL, NULL} }; diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index f2f169d4..a01280a6 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -395,7 +395,7 @@ native GetClientFrags(client); * @return Data rate. * @error Invalid client index, client not in game, or fake client. */ -native GetDataRate(client); +native GetClientDataRate(client); /** * Returns if a client is timing out @@ -404,7 +404,7 @@ native GetDataRate(client); * @return True if client is timing out, false otherwise. * @error Invalid client index, client not in game, or fake client. */ -native bool:IsTimingOut(client); +native bool:IsClientTimingOut(client); /** * Returns the client's connection time in seconds. @@ -413,7 +413,7 @@ native bool:IsTimingOut(client); * @return Connection time. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetTimeConnected(client); +native Float:GetClientTime(client); /** * Returns the client's current latency (RTT), more accurate than GetAvgLatency but jittering. @@ -423,7 +423,7 @@ native Float:GetTimeConnected(client); * @return Latency. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetLatency(client, NetFlow:flow); +native Float:GetClientLatency(client, NetFlow:flow); /** * Returns the client's average packet latency in seconds. @@ -433,7 +433,7 @@ native Float:GetLatency(client, NetFlow:flow); * @return Average latency. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetAvgLatency(client, NetFlow:flow); +native Float:GetClientAvgLatency(client, NetFlow:flow); /** * Returns the client's average packet loss, values go from 0 to 1 (for percentages). @@ -443,7 +443,7 @@ native Float:GetAvgLatency(client, NetFlow:flow); * @return Average packet loss. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetAvgLoss(client, NetFlow:flow); +native Float:GetClientAvgLoss(client, NetFlow:flow); /** * Returns the client's average packet choke, values go from 0 to 1 (for percentages). @@ -453,7 +453,7 @@ native Float:GetAvgLoss(client, NetFlow:flow); * @return Average packet choke. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetAvgChoke(client, NetFlow:flow); +native Float:GetClientAvgChoke(client, NetFlow:flow); /** * Returns the client's data flow in bytes/sec. @@ -463,7 +463,7 @@ native Float:GetAvgChoke(client, NetFlow:flow); * @return Data flow. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetAvgData(client, NetFlow:flow); +native Float:GetClientAvgData(client, NetFlow:flow); /** * Returns the client's average packet frequency in packets/sec. @@ -473,7 +473,7 @@ native Float:GetAvgData(client, NetFlow:flow); * @return Packet frequency. * @error Invalid client index, client not in game, or fake client. */ -native Float:GetAvgPackets(client, NetFlow:flow); +native Float:GetClientAvgPackets(client, NetFlow:flow); /** * Translates an userid index to the real player index. From 3f25c996531774c82cdf5d342bca53dd3ea6e5de Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 13 Apr 2007 17:12:25 +0000 Subject: [PATCH 0667/1664] fixed a corruption bug when toggling debug mode --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40698 --- core/vm/sp_vm_basecontext.cpp | 66 ++++++++++++++++++++++++++--------- core/vm/sp_vm_basecontext.h | 5 ++- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index d855a624..9b2eab0d 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -42,9 +42,12 @@ BaseContext::BaseContext(sp_context_t *_ctx) m_InExec = false; m_CustomMsg = false; m_funcsnum = ctx->vmbase->FunctionCount(ctx); +#if 0 m_priv_funcs = NULL; +#endif m_pub_funcs = NULL; +#if 0 /** * Note: Since the m_plugin member will never change, * it is safe to assume the function count will never change @@ -56,6 +59,7 @@ BaseContext::BaseContext(sp_context_t *_ctx) } else { m_priv_funcs = NULL; } +#endif if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) { @@ -66,44 +70,72 @@ BaseContext::BaseContext(sp_context_t *_ctx) } } -void BaseContext::FlushFunctionCache(bool remove) +void BaseContext::FlushFunctionCache() { if (m_pub_funcs) { for (uint32_t i=0; iplugin->info.publics_num; i++) { - if (remove) - { - delete m_pub_funcs[i]; - m_pub_funcs[i] = NULL; - } else if (m_pub_funcs[i]) { - m_pub_funcs[i]->Invalidate(); - } + delete m_pub_funcs[i]; + m_pub_funcs[i] = NULL; } } +#if 0 if (m_priv_funcs) { for (unsigned int i=0; iInvalidate(); - } + delete m_priv_funcs[i]; + m_priv_funcs[i] = NULL; } } +#endif +} + +void BaseContext::RefreshFunctionCache() +{ + if (m_pub_funcs) + { + sp_public_t *pub; + for (uint32_t i=0; iplugin->info.publics_num; i++) + { + if (!m_pub_funcs[i]) + { + continue; + } + if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE) + { + continue; + } + m_pub_funcs[i]->Set(pub->code_offs, this); + } + } + +#if 0 + if (m_priv_funcs) + { + for (unsigned int i=0; i + } + } +#endif } BaseContext::~BaseContext() { - FlushFunctionCache(true); + FlushFunctionCache(); delete [] m_pub_funcs; m_pub_funcs = NULL; +#if 0 delete [] m_priv_funcs; m_priv_funcs = NULL; +#endif } void BaseContext::SetContext(sp_context_t *_ctx) @@ -115,7 +147,7 @@ void BaseContext::SetContext(sp_context_t *_ctx) ctx = _ctx; ctx->context = this; ctx->dbreak = GlobalDebugBreak; - FlushFunctionCache(false); + RefreshFunctionCache(); } IVirtualMachine *BaseContext::GetVirtualMachine() diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index e84ca66c..15977543 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -78,7 +78,8 @@ namespace SourcePawn void SetContext(sp_context_t *_ctx); private: void SetErrorMessage(const char *msg, va_list ap); - void FlushFunctionCache(bool remove); + void FlushFunctionCache(); + void RefreshFunctionCache(); private: sp_context_t *ctx; #if defined SOURCEMOD_BUILD @@ -88,7 +89,9 @@ namespace SourcePawn bool m_CustomMsg; bool m_InExec; unsigned int m_funcsnum; +#if 0 CFunction **m_priv_funcs; +#endif CFunction **m_pub_funcs; }; }; From f335c318bfa5c785da14af68c5d0d941b18fb50d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 13 Apr 2007 17:18:41 +0000 Subject: [PATCH 0668/1664] Fixed a bug where natives were not rebound on debug toggle --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40699 --- core/systems/PluginSys.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index fd67bb5d..0c0886c1 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -486,6 +486,13 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) new_ctx->context = m_ctx.ctx->context; memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user)); + uint32_t nativeCount = m_plugin->info.natives_num; + for (uint32_t i=0; inatives[i].pfn = m_ctx.ctx->natives[i].pfn; + new_ctx->natives[i].status = m_ctx.ctx->natives[i].status; + } + g_pVM->FreeContext(m_ctx.ctx); m_ctx.ctx = new_ctx; m_ctx.base->SetContext(new_ctx); From b56de5d546718e1d78b3ab39a2eba4716165ba9f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sat, 14 Apr 2007 02:24:23 +0000 Subject: [PATCH 0669/1664] added entity string natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40700 --- core/smn_entities.cpp | 212 +++++++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 56 +++++++++- 2 files changed, 266 insertions(+), 2 deletions(-) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 26311228..93e0f662 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -19,6 +19,13 @@ #include "PlayerManager.h" #include "HalfLife2.h" #include "GameConfigs.h" +#include "sm_stringutil.h" + +enum PropType +{ + Prop_Send = 0, + Prop_Data +}; inline edict_t *GetEdict(cell_t num) { @@ -557,6 +564,207 @@ static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params) return td->fieldOffset[TD_OFFSET_NORMAL]; } +static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + size_t len; + char *src = (char *)((uint8_t *)pEntity + offset); + pContext->StringToLocalUTF8(params[3], params[4], src, &len); + + return len; +} + +static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + int offset = params[2]; + if (offset < 0 || offset > 32768) + { + return pContext->ThrowNativeError("Offset %d is invalid", offset); + } + + char *src; + char *dest = (char *)((uint8_t *)pEntity + offset); + + pContext->LocalToString(params[3], &src); + size_t len = strncopy(dest, src, params[4]); + + if (params[5]) + { + g_HL2.SetEdictStateChanged(pEdict, offset); + } + + return len; +} + +static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + char *prop; + int offset; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + switch (params[2]) + { + case Prop_Data: + { + datamap_t *pMap; + typedescription_t *td; + if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL) + { + return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset"); + } + pContext->LocalToString(params[3], &prop); + if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL) + { + return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]); + } + if (td->fieldType != FIELD_CHARACTER) + { + return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); + } + offset = td->fieldOffset[TD_OFFSET_NORMAL]; + break; + } + case Prop_Send: + { + char *prop; + IServerNetworkable *pNet = pEdict->GetNetworkable(); + if (!pNet) + { + return pContext->ThrowNativeError("The edict is not networkable"); + } + pContext->LocalToString(params[3], &prop); + SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop); + if (!pSend) + { + return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]); + } + if (pSend->GetType() != DPT_String) + { + return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); + } + offset = pSend->GetOffset(); + break; + } + default: + { + return pContext->ThrowNativeError("Invalid Property type %d", params[2]); + } + } + + size_t len; + char *src = (char *)((uint8_t *)pEntity + offset); + pContext->StringToLocalUTF8(params[4], params[5], src, &len); + + return len; +} + +static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + char *prop; + int offset; + int maxlen; + bool is_sendprop = false; + edict_t *pEdict = GetEntity(params[1], &pEntity); + + if (!pEdict || !pEntity) + { + return pContext->ThrowNativeError("Entity %d is invalid", params[1]); + } + + switch (params[2]) + { + case Prop_Data: + { + datamap_t *pMap; + typedescription_t *td; + if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL) + { + return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset"); + } + pContext->LocalToString(params[3], &prop); + if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL) + { + return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]); + } + if (td->fieldType != FIELD_CHARACTER) + { + return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); + } + offset = td->fieldOffset[TD_OFFSET_NORMAL]; + maxlen = td->fieldSize; + break; + } + case Prop_Send: + { + char *prop; + IServerNetworkable *pNet = pEdict->GetNetworkable(); + if (!pNet) + { + return pContext->ThrowNativeError("The edict is not networkable"); + } + pContext->LocalToString(params[3], &prop); + SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop); + if (!pSend) + { + return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]); + } + if (pSend->GetType() != DPT_String) + { + return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); + } + offset = pSend->GetOffset(); + maxlen = DT_MAX_STRING_BUFFERSIZE; + is_sendprop = true; + break; + } + default: + { + return pContext->ThrowNativeError("Invalid Property type %d", params[2]); + } + } + + char *src; + char *dest = (char *)((uint8_t *)pEntity + offset); + + pContext->LocalToString(params[4], &src); + size_t len = strncopy(dest, src, maxlen); + + if (is_sendprop) + { + g_HL2.SetEdictStateChanged(pEdict, offset); + } + + return len; +} + REGISTER_NATIVES(entityNatives) { {"ChangeEdictState", ChangeEdictState}, @@ -581,5 +789,9 @@ REGISTER_NATIVES(entityNatives) {"SetEntDataFloat", SetEntDataFloat}, {"SetEntDataVector", SetEntDataVector}, {"FindDataMapOffs", FindDataMapOffs}, + {"GetEntDataString", GetEntDataString}, + {"SetEntDataString", SetEntDataString}, + {"GetEntPropString", GetEntPropString}, + {"SetEntPropString", SetEntPropString}, {NULL, NULL} }; diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index f2e0eced..38eb7cdb 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -234,7 +234,7 @@ native SetEntDataFloat(entity, offset, Float:value, bool:changeState=false); native GetEntDataEnt(entity, offset); /** - * Peeks into an entity's object data and sest the entity handle info + * Peeks into an entity's object data and sets the entity handle info * at the given offset. * * @param entity Edict index. @@ -275,6 +275,33 @@ native GetEntDataVector(entity, offset, Float:vec[3]); */ native SetEntDataVector(entity, offset, const Float:vec[3], bool:changeState=false); +/** + * Peeks into an entity's object data and retrieves the string at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return Number of non-null bytes written. + * @error Invalid entity or offset out of reasonable bounds. + */ +native GetEntDataString(entity, offset, String:buffer[], maxlen); + +/** + * Peeks into an entity's object data and sets the string at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param buffer String to set. + * @param maxlen Maximum length of bytes to write. + * @param changeState If true, change will be sent over the network. + * @return Number of non-null bytes written. + * @error Invalid entity or offset out of reasonable bounds. + */ +native SetEntDataString(entity, offset, const String:buffer[], maxlen, bool:changeState=false); + /** * @endsection */ @@ -400,7 +427,7 @@ stock SetEntProp(entity, PropType:type, const String:prop[], value, size=4) * @param entity Edict index. * @param type Property type. * @param prop Property to use. - * @return Value at the given property offset.. + * @return Value at the given property offset. * @error Invalid entity or offset out of reasonable bounds. */ stock Float:GetEntPropFloat(entity, PropType:type, const String:prop[]) @@ -623,3 +650,28 @@ stock SetEntPropVector(entity, PropType:type, const String:prop[], const Float:v return SetEntDataVector(entity, offs, vec, true); } + +/** + * Gets a network property as a string. + * + * @param entity Edict index. + * @param type Property type. + * @param prop Property to use. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return Number of non-null bytes written. + * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. + */ +native GetEntPropString(entity, PropType:type, const String:prop[], String:buffer[], maxlen); + +/** + * Sets a network property as a string. + * + * @param entity Edict index. + * @param type Property type. + * @param prop Property to use. + * @param buffer String to set. + * @return Number of non-null bytes written. + * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. + */ +native SetEntPropString(entity, PropType:type, const String:prop[], const String:buffer[]); From c8f507561cb9c98138595ea6309e3a29828f6d12 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 14 Apr 2007 04:19:58 +0000 Subject: [PATCH 0670/1664] Empty strings can now properly be passed via PushString and StringToLocal --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40701 --- core/vm/sp_vm_basecontext.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 9b2eab0d..823f094f 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -693,26 +693,27 @@ int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *st return SP_ERROR_NONE; } -int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *source) +int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) { char *dest; - int len; + size_t len; if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; } + if (bytes == 0) + { + return SP_ERROR_NONE; + } + len = strlen(source); dest = (char *)(ctx->memory + local_addr); - if ((size_t)len >= chars) + if ((size_t)len >= bytes) { - len = chars - 1; - } - if (len <= 0) - { - return SP_ERROR_NONE; + len = bytes - 1; } memcpy(dest, source, len); @@ -762,13 +763,18 @@ inline int __CheckValidChar(char *c) int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) { char *dest; - int len; + size_t len; bool needtocheck = false; if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { return SP_ERROR_INVALID_ADDRESS; } + + if (maxbytes == 0) + { + return SP_ERROR_NONE; + } len = strlen(source); dest = (char *)(ctx->memory + local_addr); @@ -778,10 +784,6 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha len = maxbytes - 1; needtocheck = true; } - if (len <= 0) - { - return SP_ERROR_NONE; - } memcpy(dest, source, len); if ((dest[len-1] & 1<<7) && needtocheck) From 77e49c855f518c6026b413cd86d03d5151e57bbe Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 14 Apr 2007 04:27:47 +0000 Subject: [PATCH 0671/1664] Added client convar querying :o Also added ISourceMod::GetModFolderName() for returning the name of the mod directory by itself --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40702 --- core/ConVarManager.cpp | 123 +++++++++++++++++++++++++++++++--- core/ConVarManager.h | 30 ++++++++- core/GameConfigs.cpp | 23 +------ core/HalfLife2.cpp | 7 +- core/smn_console.cpp | 44 ++++++++++++ core/sourcemod.cpp | 21 +++++- core/sourcemod.h | 2 + core/vm/sp_vm_basecontext.cpp | 2 +- plugins/include/console.inc | 52 ++++++++++++++ plugins/include/core.inc | 2 +- public/ISourceMod.h | 53 ++++++++------- 11 files changed, 297 insertions(+), 62 deletions(-) diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 46c76b81..3f669e86 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -13,6 +13,7 @@ */ #include "ConVarManager.h" +#include "HalfLife2.h" #include "PluginSys.h" #include "ForwardSys.h" #include "HandleSys.h" @@ -22,10 +23,13 @@ ConVarManager g_ConVarManager; +SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *); +SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *); + const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String}; typedef List ConVarList; -ConVarManager::ConVarManager() : m_ConVarType(0) +ConVarManager::ConVarManager() : m_ConVarType(0), m_VSPIface(NULL), m_CanQueryConVars(false) { /* Create a convar lookup trie */ m_ConVarCache = sm_trie_create(); @@ -49,6 +53,13 @@ ConVarManager::~ConVarManager() void ConVarManager::OnSourceModAllInitialized() { + /* Only valid with ServerGameDLL006 or greater */ + if (g_SMAPI->GetGameDLLVersion() >= 6) + { + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false); + m_CanQueryConVars = true; + } + HandleAccess sec; /* Set up access rights for the 'ConVar' handle type */ @@ -65,13 +76,19 @@ void ConVarManager::OnSourceModAllInitialized() void ConVarManager::OnSourceModShutdown() { + if (m_CanQueryConVars) + { + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false); + SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, m_VSPIface, this, &ConVarManager::OnQueryCvarValueFinished, false); + } + IChangeableForward *fwd; List::iterator i; /* Iterate list of ConVarInfo structures */ for (i = m_ConVars.begin(); i != m_ConVars.end(); i++) { - fwd = (*i)->changeForward; + fwd = (*i)->pChangeForward; /* Free any convar-change forwards that still exist */ if (fwd) @@ -87,6 +104,29 @@ void ConVarManager::OnSourceModShutdown() g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } +void ConVarManager::OnSourceModVSPReceived(IServerPluginCallbacks *iface) +{ + /* This will be called after OnSourceModAllInitialized(), so... + * + * If we haven't been able to hook the IServerGameDLL version at this point, + * then use hook IServerPluginCallbacks version from the engine. + */ + + /* The Ship currently only supports ServerPluginCallbacks001, but we need 002 */ + if (g_IsOriginalEngine) + { + return; + } + + if (!m_CanQueryConVars) + { + m_VSPIface = iface; + + SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, iface, this, &ConVarManager::OnQueryCvarValueFinished, false); + m_CanQueryConVars = true; + } +} + void ConVarManager::OnPluginUnloaded(IPlugin *plugin) { ConVarList *pConVarList; @@ -190,7 +230,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, pInfo = new ConVarInfo(); pInfo->handle = hndl; pInfo->sourceMod = false; - pInfo->changeForward = NULL; + pInfo->pChangeForward = NULL; pInfo->origCallback = pConVar->GetCallback(); /* Insert struct into caches */ @@ -201,7 +241,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, } } - // To prevent creating a convar that has the same name as a console command... ugh + /* To prevent creating a convar that has the same name as a console command... ugh */ ConCommandBase *pBase = icvar->GetCommands(); while (pBase) @@ -227,7 +267,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, pInfo = new ConVarInfo(); pInfo->handle = hndl; pInfo->sourceMod = true; - pInfo->changeForward = NULL; + pInfo->pChangeForward = NULL; pInfo->origCallback = NULL; /* Insert struct into caches */ @@ -265,7 +305,7 @@ Handle_t ConVarManager::FindConVar(const char *name) pInfo = new ConVarInfo(); pInfo->handle = hndl; pInfo->sourceMod = false; - pInfo->changeForward = NULL; + pInfo->pChangeForward = NULL; pInfo->origCallback = pConVar->GetCallback(); /* Insert struct into our caches */ @@ -284,13 +324,13 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo)) { /* Get the forward */ - pForward = pInfo->changeForward; + pForward = pInfo->pChangeForward; /* If forward does not exist, create it */ if (!pForward) { pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS); - pInfo->changeForward = pForward; + pInfo->pChangeForward = pForward; /* Install our own callback */ pConVar->InstallChangeCallback(OnConVarChanged); @@ -311,7 +351,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo)) { /* Get the forward */ - pForward = pInfo->changeForward; + pForward = pInfo->pChangeForward; /* If the forward doesn't exist, we can't unhook anything */ if (!pForward) @@ -332,7 +372,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti { /* Free this forward */ g_Forwards.ReleaseForward(pForward); - pInfo->changeForward = NULL; + pInfo->pChangeForward = NULL; /* Put back the original convar callback */ pConVar->InstallChangeCallback(pInfo->origCallback); @@ -340,6 +380,24 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti } } +QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl) +{ + QueryCvarCookie_t cookie; + + /* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */ + if (!m_VSPIface) + { + cookie = engine->StartQueryCvarValue(pPlayer, name); + } else { + cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name); + } + + ConVarQuery query = {cookie, pCallback, hndl}; + m_ConVarQueries.push_back(query); + + return cookie; +} + void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar) { ConVarList *pConVarList; @@ -388,7 +446,7 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) sm_trie_retrieve(pCache, pConVar->GetName(), (void **)&pInfo); FnChangeCallback origCallback = pInfo->origCallback; - IChangeableForward *pForward = pInfo->changeForward; + IChangeableForward *pForward = pInfo->pChangeForward; /* If there was a change callback installed previously, call it */ if (origCallback) @@ -403,6 +461,49 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) pForward->Execute(NULL); } +void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue) +{ + IPluginFunction *pCallback = NULL; + cell_t value = 0; + List::iterator iter; + + for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++) + { + ConVarQuery &query = (*iter); + + if (query.cookie == cookie) + { + pCallback = query.pCallback; + value = query.value; + + break; + } + } + + if (pCallback) + { + cell_t ret; + + pCallback->PushCell(cookie); + pCallback->PushCell(engine->IndexOfEdict(pPlayer)); + pCallback->PushCell(result); + pCallback->PushString(cvarName); + + if (result == eQueryCvarValueStatus_ValueIntact) + { + pCallback->PushString(cvarValue); + } else { + pCallback->PushString("\0"); + } + + pCallback->PushCell(value); + pCallback->Execute(&ret); + + m_ConVarQueries.erase(iter); + } +} + + static int s_YamagramState = 0; void _YamagramPrinterTwoPointOhOh(int yamagram) diff --git a/core/ConVarManager.h b/core/ConVarManager.h index b22938e1..191ceb48 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -33,10 +33,20 @@ struct ConVarInfo { Handle_t handle; /**< Handle to convar */ bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */ - IChangeableForward *changeForward; /**< Forward associated with convar */ + IChangeableForward *pChangeForward; /**< Forward associated with convar */ FnChangeCallback origCallback; /**< The original callback function */ }; +/** + * Holds information about a client convar query + */ +struct ConVarQuery +{ + QueryCvarCookie_t cookie; /**< Cookie that identifies query */ + IPluginFunction *pCallback; /**< Function that will be called when query is finished */ + cell_t value; /**< Optional value passed to query function */ +}; + class ConVarManager : public SMGlobalClass, public IHandleTypeDispatch, @@ -49,6 +59,7 @@ public: public: // SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); + void OnSourceModVSPReceived(IServerPluginCallbacks *iface); public: // IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); public: // IPluginsListener @@ -92,6 +103,12 @@ public: * Remove a function from the forward that will be called when the specified convar changes. */ void UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction); + + /** + * Starts a query to find the value of a client convar. + */ + QueryCvarCookie_t QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, + Handle_t hndl); private: /** * Adds a convar to a plugin's list. @@ -99,13 +116,22 @@ private: static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar); /** - * Static callback that Valve's ConVar class executes when the convar's value changes. + * Static callback that Valve's ConVar object executes when the convar's value changes. */ static void OnConVarChanged(ConVar *pConVar, const char *oldValue); + + /** + * Callback for when StartQueryCvarValue() has finished. + */ + void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, + const char *cvarName, const char *cvarValue); private: HandleType_t m_ConVarType; List m_ConVars; + List m_ConVarQueries; Trie *m_ConVarCache; + IServerPluginCallbacks *m_VSPIface; + bool m_CanQueryConVars; }; extern ConVarManager g_ConVarManager; diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index 53cf6150..a6a22300 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -301,28 +301,7 @@ void GameConfigManager::OnSourceModStartup(bool late) { LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); - char mod[255]; - engine->GetGameDir(mod, sizeof(mod)); - - g_mod[0] = '\0'; - size_t len = strlen(mod); - for (size_t i=len-1; i>=0 && iGetSharedEdictChangeInfo(); } } diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 7975098a..8399ff18 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -13,6 +13,7 @@ */ #include "sm_globals.h" +#include "HalfLife2.h" #include "sourcemm_api.h" #include "HandleSys.h" #include "ConVarManager.h" @@ -342,6 +343,48 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) return 1; } +static bool s_QueryAlreadyWarned = false; + +static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer; + char *name; + IPluginFunction *pCallback; + + if (g_IsOriginalEngine) + { + if (!s_QueryAlreadyWarned) + { + s_QueryAlreadyWarned = true; + return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)"); + } + + return 0; + } + + pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected() || pPlayer->IsFakeClient()) + { + return pContext->ThrowNativeError("Player %d is either not connected or a bot", params[1]); + } + + pContext->LocalToString(params[2], &name); + pCallback = pContext->GetFunctionById(params[3]); + + if (!pCallback) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[3]); + } + + return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]); +} + static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params) { char *name,*help; @@ -584,6 +627,7 @@ REGISTER_NATIVES(consoleNatives) {"GetConVarMin", sm_GetConVarMin}, {"GetConVarMax", sm_GetConVarMax}, {"ResetConVar", sm_ResetConVar}, + {"QueryClientConVar", sm_QueryClientConVar}, {"RegServerCmd", sm_RegServerCmd}, {"RegConsoleCmd", sm_RegConsoleCmd}, {"GetCmdArgString", sm_GetCmdArgString}, diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 13656177..79202339 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -100,7 +100,21 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) { - g_BaseDir.assign(g_SMAPI->GetBaseDir()); + const char *gamepath = g_SMAPI->GetBaseDir(); + + /* Store full path to game */ + g_BaseDir.assign(gamepath); + + /* Store name of game directory by itself */ + size_t len = strlen(gamepath); + for (size_t i = len - 1; i >= 0; i--) + { + if (gamepath[i] == PLATFORM_SEP_CHAR) + { + strncopy(m_ModDir, &gamepath[++i], sizeof(m_ModDir)); + break; + } + } /* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */ g_CoreConfig.Initialize(); @@ -528,6 +542,11 @@ Handle_t SourceModBase::GetDataPackHandleType(bool readonly) return 0; } +const char *SourceModBase::GetModFolderName() const +{ + return m_ModDir; +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index 5c282ec5..ff1cf734 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -94,6 +94,7 @@ public: // ISourceMod void FreeDataPack(IDataPack *pack); HandleType_t GetDataPackHandleType(bool readonly=false); KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false); + const char *GetModFolderName() const; private: /** * @brief Loading plugins @@ -108,6 +109,7 @@ private: CStack m_freepacks; char m_SMBaseDir[PLATFORM_MAX_PATH]; char m_SMRelDir[PLATFORM_MAX_PATH]; + char m_ModDir[32]; bool m_IsMapLoading; bool m_ExecPluginReload; unsigned int m_target; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 823f094f..d1424119 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -711,7 +711,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour len = strlen(source); dest = (char *)(ctx->memory + local_addr); - if ((size_t)len >= bytes) + if (len >= bytes) { len = bytes - 1; } diff --git a/plugins/include/console.inc b/plugins/include/console.inc index d5eb3d79..312ca21a 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -18,6 +18,17 @@ #endif #define _console_included +/** + * Console variable query result values. + */ +enum ConVarQueryResult +{ + ConVarQuery_Okay = 0, /**< Retrieval of client convar value was successful. */ + ConVarQuery_NotFound, /**< Client convar was not found. */ + ConVarQuery_NotValid, /**< A console command with the same name was found, but there is no convar. */ + ConVarQuery_Protected /**< Client convar was found, but it is protected. The server cannot retrieve its value. */ +}; + /** * @section Flags for console commands and console variables. The descriptions * for each constant come directly from the Source SDK. @@ -398,3 +409,44 @@ native bool:GetConVarMax(Handle:convar, &Float:max); * @error Invalid or corrupt Handle. */ native ResetConVar(Handle:convar); + +funcenum ConVarQueryFinished +{ + /** + * Called when a query to retrieve a client's console variable has finished. + * + * @param cookie Unique identifier of query. + * @param client Player index. + * @param result Result of query that tells one whether or not query was successful. + * See ConVarQueryResult enum for more details. + * @param convarName Name of client convar that was queried. + * @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. + * @param value Value that was passed when query was started. + * @noreturn + */ + public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[], any:value), + + /** + * Called when a query to retrieve a client's console variable has finished. + * + * @param cookie Unique identifier of query. + * @param client Player index. + * @param result Result of query that tells one whether or not query was successful. + * See ConVarQueryResult enum for more details. + * @param convarName Name of client convar that was queried. + * @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. + * @noreturn + */ + public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[]) +}; + +/** + * Starts a query to retrieve the value of a client's console variable. + * + * @param client Player index. + * @param name Name of client convar to query. + * @param callback A function to use as a callback when the query has finished. + * @param value Optional value to pass to the callback function. + * @return A cookie that uniquely identifies the query. + */ +native QueryCookie:QueryClientConVar(client, const String:cvarName[], ConVarQueryFinished:callback, any:value=0); diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 9e2272d3..6cc01675 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -28,7 +28,7 @@ struct PlVers }; /** - * Function helper values + * Function helper values. */ enum Function { diff --git a/public/ISourceMod.h b/public/ISourceMod.h index aca741d9..9263c327 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -28,7 +28,7 @@ #include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" -#define SMINTERFACE_SOURCEMOD_VERSION 1 +#define SMINTERFACE_SOURCEMOD_VERSION 2 /** * @brief Forward declaration of the KeyValues class. @@ -138,29 +138,36 @@ namespace SourceMod */ virtual void FreeDataPack(IDataPack *pack) =0; - /** - * @brief Returns the automated data pack handle type. - * - * The readonly data type is the parent of the writable type. - * Note that calling CloseHandle() on either type will release the data pack. - * The readonly type is inheritable, but due to limitations of the Handle System, - * the writable type is not. - * - * @param readonly If true, the readonly type will be returned. - * @return The Handle type for storing generic data packs. - */ - virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; + /** + * @brief Returns the automated data pack handle type. + * + * The readonly data type is the parent of the writable type. + * Note that calling CloseHandle() on either type will release the data pack. + * The readonly type is inheritable, but due to limitations of the Handle System, + * the writable type is not. + * + * @param readonly If true, the readonly type will be returned. + * @return The Handle type for storing generic data packs. + */ + virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; - /** - * @brief Retrieves a KeyValues pointer from a handle. - * - * @param hndl Handle_t from which to retrieve contents. - * @param err Optional address to store a possible handle error. - * @param root If true it will return the root KeyValues pointer for the whole structure. - * - * @return The KeyValues pointer, or NULL for any error encountered. - */ - virtual KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false) =0; + /** + * @brief Retrieves a KeyValues pointer from a handle. + * + * @param hndl Handle_t from which to retrieve contents. + * @param err Optional address to store a possible handle error. + * @param root If true it will return the root KeyValues pointer for the whole structure. + * + * @return The KeyValues pointer, or NULL for any error encountered. + */ + virtual KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false) =0; + + /** + * @brief Returns the name of the directory in which the mod or game's gameinfo.txt resides. + * + * @return A string containing the name of the mod directory. + */ + virtual const char *GetModFolderName() const =0; }; } From 93be4e29b8256cc0c53981d6b6c51ef56bee3691 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 14 Apr 2007 04:49:08 +0000 Subject: [PATCH 0672/1664] Oh forgot this - QueryClientConVar returns 0 on bots now. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40703 --- core/smn_console.cpp | 10 ++++++++-- plugins/include/console.inc | 11 ++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 8399ff18..c9c5d81a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -369,9 +369,15 @@ static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *param return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); } - if (!pPlayer->IsConnected() || pPlayer->IsFakeClient()) + if (!pPlayer->IsConnected()) { - return pContext->ThrowNativeError("Player %d is either not connected or a bot", params[1]); + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + /* Trying a query on a bot results in callback not be fired, so don't bother */ + if (pPlayer->IsFakeClient()) + { + return 0; } pContext->LocalToString(params[2], &name); diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 312ca21a..22c83749 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -18,6 +18,14 @@ #endif #define _console_included +/** + * Console variable query helper values. + */ +enum QueryCookie +{ + QUERYCOOKIE_FAILED = 0, +} + /** * Console variable query result values. */ @@ -447,6 +455,7 @@ funcenum ConVarQueryFinished * @param name Name of client convar to query. * @param callback A function to use as a callback when the query has finished. * @param value Optional value to pass to the callback function. - * @return A cookie that uniquely identifies the query. + * @return A cookie that uniquely identifies the query. + * Returns QUERYCOOKIE_FAILED on failure, such as when used on a bot. */ native QueryCookie:QueryClientConVar(client, const String:cvarName[], ConVarQueryFinished:callback, any:value=0); From 43856e7dc47c4aebb3dd569314c96b7007a2434b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 15 Apr 2007 05:43:43 +0000 Subject: [PATCH 0673/1664] User message functions now use SourceMM 1.4's new API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40704 --- core/UserMessages.cpp | 25 ++++--------------------- core/UserMessages.h | 1 - core/smn_usermsgs.cpp | 24 +++++++----------------- public/IUserMessages.h | 4 ---- 4 files changed, 11 insertions(+), 43 deletions(-) diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 7c21c88f..32b0d4ca 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -19,8 +19,6 @@ UserMessages g_UserMsgs; SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); -//:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time - UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500) { m_Names = sm_trie_create(); @@ -63,35 +61,20 @@ void UserMessages::OnSourceModAllShutdown() int UserMessages::GetMessageIndex(const char *msg) { int msgid; + if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid))) { - char buf[255]; - int dummy; - msgid = 0; + msgid = g_SMAPI->FindUserMessage(msg); - while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy)) + if (msgid != INVALID_MESSAGE_ID) { - if (strcmp(msg, buf) == 0) - { - sm_trie_insert(m_Names, msg, reinterpret_cast(msgid)); - return msgid; - } - msgid++; + sm_trie_insert(m_Names, msg, reinterpret_cast(msgid)); } - - return INVALID_MESSAGE_ID; } return msgid; } -bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const -{ - int dummy; - - return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy); -} - bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) { bf_write *buffer; diff --git a/core/UserMessages.h b/core/UserMessages.h index 2d3b1d9b..17571479 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -48,7 +48,6 @@ public: //SMGlobalClass void OnSourceModAllShutdown(); public: //IUserMessages int GetMessageIndex(const char *msg); - bool GetMessageName(int msgid, char *buffer, size_t maxlen) const; bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags); diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 1d40e90a..f7570802 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -303,28 +303,22 @@ static UsrMessageNatives s_UsrMessageNatives; static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) { char *msgname; - int err; - if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE) - { - pCtx->ThrowNativeErrorEx(err, NULL); - return 0; - } + pCtx->LocalToString(params[1], &msgname); return g_UserMsgs.GetMessageIndex(msgname); } static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params) { - char *msgname; + const char *msgname = g_SMAPI->GetUserMessage(params[1]); - pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname); - - if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3])) + if (msgname == NULL) { - msgname = ""; return 0; } + pCtx->StringToLocalUTF8(params[2], params[3], msgname, NULL); + return 1; } @@ -332,7 +326,7 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) { char *msgname; cell_t *cl_array; - int msgid, err; + int msgid; bf_write *pBitBuf; if (g_IsMsgInExec) @@ -340,11 +334,7 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress"); } - if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE) - { - pCtx->ThrowNativeErrorEx(err, NULL); - return 0; - } + pCtx->LocalToString(params[1], &msgname); if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID) { diff --git a/public/IUserMessages.h b/public/IUserMessages.h index 52e22648..1362482f 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -97,10 +97,6 @@ namespace SourceMod public: /** * @brief Finds a message id by name. - * - * Note: due to a bug in Valve's earlier SDK versions, this - * may cause crashes alongside IServerGameDLL003 if the message is - * not found. * * @param msg Case-sensitive string containing the message. * @return A message index, or -1 on failure. From 5811c5b29feb9c0b8cebc932794d35e2368494d7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Apr 2007 16:53:48 +0000 Subject: [PATCH 0674/1664] fixed a re-entrancy bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40705 --- core/smn_fakenatives.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 0ab4ee23..8df20220 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -79,10 +79,10 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD } /* Restore everything from the stack if necessary */ + s_curnative = pSaveNative; + s_curcaller = pSaveCaller; if (pSaveNative != NULL) { - s_curnative = pSaveNative; - s_curcaller = pSaveCaller; for (cell_t i=0; i<=save_params[0]; i++) { s_curparams[i] = save_params[i]; From efa6067669b5aac356e234dc0546079c117d905e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 20 Apr 2007 18:32:33 +0000 Subject: [PATCH 0675/1664] Basic signature scanning has arrived! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40706 --- core/Makefile | 2 +- core/MemoryUtils.cpp | 199 +++++++++++++++++++++++++++++++++ core/MemoryUtils.h | 42 +++++++ core/msvc8/sourcemod_mm.vcproj | 14 ++- public/IMemoryUtils.h | 53 +++++++++ public/IShareSys.h | 2 +- 6 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 core/MemoryUtils.cpp create mode 100644 core/MemoryUtils.h create mode 100644 public/IMemoryUtils.h diff --git a/core/Makefile b/core/Makefile index 650c5912..26ca408b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -21,7 +21,7 @@ HL2LIB = $(HL2SDK)/linux_sdk OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \ Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ - PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ + MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ sourcemm_api.cpp sourcemod.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ diff --git a/core/MemoryUtils.cpp b/core/MemoryUtils.cpp new file mode 100644 index 00000000..a34c0e4e --- /dev/null +++ b/core/MemoryUtils.cpp @@ -0,0 +1,199 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "MemoryUtils.h" +#include "sm_platform.h" +#ifdef PLATFORM_LINUX +#include +#include +#endif + +MemoryUtils g_MemUtils; + +MemoryUtils::MemoryUtils() +{ +#ifdef PLATFORM_WINDOWS + + /* This might be used in the future? */ + #if 0 + SYSTEM_INFO info; + GetSystemInfo(&info); + + m_PageSize = info.dwPageSize; + #endif + +#elif defined PLATFORM_POSIX + + m_PageSize = sysconf(_SC_PAGE_SIZE); + +#endif +} + +void *MemoryUtils::FindPattern(void *libPtr, const char *pattern, size_t len) +{ + DynLibInfo lib; + bool found; + char *ptr, *end; + + memset(&lib, 0, sizeof(DynLibInfo)); + + if (!GetLibraryInfo(libPtr, lib)) + { + return NULL; + } + + ptr = reinterpret_cast(lib.baseAddress); + end = ptr + lib.memorySize; + + while (ptr < end) + { + found = true; + for (register size_t i = 0; i < len; i++) + { + if (pattern[i] != '\x2A' && pattern[i] != ptr[i]) + { + found = false; + break; + } + } + + if (found) + return ptr; + + ptr++; + } + + return NULL; +} + +bool MemoryUtils::GetLibraryInfo(void *libPtr, DynLibInfo &lib) +{ + unsigned long baseAddr; + + if (libPtr == NULL) + { + return false; + } + +#ifdef PLATFORM_WINDOWS + + MEMORY_BASIC_INFORMATION info; + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *pe; + IMAGE_FILE_HEADER *file; + IMAGE_OPTIONAL_HEADER *opt; + + if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) + { + return false; + } + + baseAddr = reinterpret_cast(info.AllocationBase); + + /* All this is for our insane sanity checks :o */ + dos = reinterpret_cast(baseAddr); + pe = reinterpret_cast(baseAddr + dos->e_lfanew); + file = &pe->FileHeader; + opt = &pe->OptionalHeader; + + /* Check PE magic and signature */ + if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + return false; + } + + /* Check architecture, which is 32-bit/x86 right now + * Should change this for 64-bit if Valve gets their act together + */ + if (file->Machine != IMAGE_FILE_MACHINE_I386) + { + return false; + } + + /* For our purposes, this must be a dynamic library */ + if ((file->Characteristics & IMAGE_FILE_DLL) == 0) + { + return false; + } + + /* Finally, we can do this */ + lib.memorySize = opt->SizeOfImage; + +#elif defined PLATFORM_LINUX + + Dl_info info; + Elf32_Ehdr *file; + Elf32_Phdr *phdr; + uint16_t phdrCount; + + if (!dladdr(libPtr, &info)) + { + return false; + } + + if (!info.dli_fbase || !info.dli_fname) + { + return false; + } + + /* This is for our insane sanity checks :o */ + baseAddr = reinterpret_cast(info.dli_fbase); + file = reinterpret_cast(baseAddr); + + /* Check ELF magic */ + if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) + { + return false; + } + + /* Check ELF version */ + if (file->e_ident[EI_VERSION] != EV_CURRENT) + { + return false; + } + + /* Check ELF architecture, which is 32-bit/x86 right now + * Should change this for 64-bit if Valve gets their act together + */ + if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB) + { + return false; + } + + /* For our purposes, this must be a dynamic library/shared object */ + if (file->e_type != ET_DYN) + { + return false; + } + + phdrCount = file->e_phnum; + phdr = reinterpret_cast(baseAddr + file->e_phoff); + + /* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */ + for (uint16_t i = 0; i < phdrCount; i++) + { + Elf32_Phdr &hdr = phdr[i]; + + if (hdr.p_type == PT_LOAD) + { + lib.memorySize += hdr.p_memsz; + } + } + +#endif + + lib.baseAddress = reinterpret_cast(baseAddr); + + return true; +} diff --git a/core/MemoryUtils.h b/core/MemoryUtils.h new file mode 100644 index 00000000..ecb9e278 --- /dev/null +++ b/core/MemoryUtils.h @@ -0,0 +1,42 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ +#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ + +#include + +using namespace SourceMod; + +struct DynLibInfo +{ + void *baseAddress; + size_t memorySize; +}; + +class MemoryUtils : public IMemoryUtils +{ +public: + MemoryUtils(); +public: + void *FindPattern(void *libPtr, const char *pattern, size_t len); +private: + bool GetLibraryInfo(void *libPtr, DynLibInfo &lib); +private: + size_t m_PageSize; +}; + +extern MemoryUtils g_MemUtils; + +#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 78cab260..dc0f2b06 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -325,6 +329,10 @@ RelativePath="..\Logger.h" > + + @@ -425,6 +433,10 @@ RelativePath="..\..\public\ILibrarySys.h" > + + diff --git a/public/IMemoryUtils.h b/public/IMemoryUtils.h new file mode 100644 index 00000000..29e1d9fb --- /dev/null +++ b/public/IMemoryUtils.h @@ -0,0 +1,53 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_BINARYUTILS_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_BINARYUTILS_H_ + +#include + +#define SMINTERFACE_MEMORYUTILS_NAME "IMemoryUtils" +#define SMINTERFACE_MEMORYUTILS_VERSION 1 + +namespace SourceMod +{ + class IMemoryUtils : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_MEMORYUTILS_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_MEMORYUTILS_VERSION; + } + public: + /** + * @brief Searches for a pattern of bytes within the memory of a dynamic library. + * + * @param libPtr Pointer to any chunk of memory that resides in the dynamic library. + * @param pattern Pattern of bytes to search for. 0x2A can be used as a wildcard. + * @param len Size of the pattern in bytes. + * @return Pointer to pattern found in memory, NULL if not found. + */ + virtual void *FindPattern(void *libPtr, const char *pattern, size_t len) =0; + }; +} + +#endif // _INCLUDE_SOURCEMOD_INTERFACE_MEMORYUTILS_H_ diff --git a/public/IShareSys.h b/public/IShareSys.h index 99cbf7a7..c70912b2 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -58,7 +58,7 @@ namespace SourceMod virtual const char *GetInterfaceName() =0; /** - * @brief Must return whether the requested version number is backwards comaptible. + * @brief Must return whether the requested version number is backwards compatible. * Note: This can be overridden for breaking changes or custom versioning. * * @param version Version number to compare against. From 199d8391220c802c10557a0693e3aee9c722c2b5 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 20 Apr 2007 18:50:52 +0000 Subject: [PATCH 0676/1664] Made libPtr param const. Doesn't get modified so why not. Also removed some unneccessary code (for now) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40707 --- core/MemoryUtils.cpp | 9 ++++----- core/MemoryUtils.h | 8 ++------ public/IMemoryUtils.h | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/core/MemoryUtils.cpp b/core/MemoryUtils.cpp index a34c0e4e..828077ae 100644 --- a/core/MemoryUtils.cpp +++ b/core/MemoryUtils.cpp @@ -21,17 +21,15 @@ MemoryUtils g_MemUtils; +#if 0 MemoryUtils::MemoryUtils() { #ifdef PLATFORM_WINDOWS - /* This might be used in the future? */ - #if 0 SYSTEM_INFO info; GetSystemInfo(&info); m_PageSize = info.dwPageSize; - #endif #elif defined PLATFORM_POSIX @@ -39,8 +37,9 @@ MemoryUtils::MemoryUtils() #endif } +#endif -void *MemoryUtils::FindPattern(void *libPtr, const char *pattern, size_t len) +void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len) { DynLibInfo lib; bool found; @@ -77,7 +76,7 @@ void *MemoryUtils::FindPattern(void *libPtr, const char *pattern, size_t len) return NULL; } -bool MemoryUtils::GetLibraryInfo(void *libPtr, DynLibInfo &lib) +bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib) { unsigned long baseAddr; diff --git a/core/MemoryUtils.h b/core/MemoryUtils.h index ecb9e278..cda16574 100644 --- a/core/MemoryUtils.h +++ b/core/MemoryUtils.h @@ -28,13 +28,9 @@ struct DynLibInfo class MemoryUtils : public IMemoryUtils { public: - MemoryUtils(); -public: - void *FindPattern(void *libPtr, const char *pattern, size_t len); + void *FindPattern(const void *libPtr, const char *pattern, size_t len); private: - bool GetLibraryInfo(void *libPtr, DynLibInfo &lib); -private: - size_t m_PageSize; + bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); }; extern MemoryUtils g_MemUtils; diff --git a/public/IMemoryUtils.h b/public/IMemoryUtils.h index 29e1d9fb..828ffe68 100644 --- a/public/IMemoryUtils.h +++ b/public/IMemoryUtils.h @@ -46,7 +46,7 @@ namespace SourceMod * @param len Size of the pattern in bytes. * @return Pointer to pattern found in memory, NULL if not found. */ - virtual void *FindPattern(void *libPtr, const char *pattern, size_t len) =0; + virtual void *FindPattern(const void *libPtr, const char *pattern, size_t len) =0; }; } From 7ce1ef6ea19c8bdfd46808c3a9650b17eab7efd4 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 21 Apr 2007 17:03:28 +0000 Subject: [PATCH 0677/1664] Wow, how did I forget this - exported IMemoryUtils interface --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40708 --- core/MemoryUtils.cpp | 7 ++++++- core/MemoryUtils.h | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/MemoryUtils.cpp b/core/MemoryUtils.cpp index 828077ae..2ef9eeed 100644 --- a/core/MemoryUtils.cpp +++ b/core/MemoryUtils.cpp @@ -13,7 +13,7 @@ */ #include "MemoryUtils.h" -#include "sm_platform.h" +#include "ShareSys.h" #ifdef PLATFORM_LINUX #include #include @@ -39,6 +39,11 @@ MemoryUtils::MemoryUtils() } #endif +void MemoryUtils::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, this); +} + void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len) { DynLibInfo lib; diff --git a/core/MemoryUtils.h b/core/MemoryUtils.h index cda16574..34799091 100644 --- a/core/MemoryUtils.h +++ b/core/MemoryUtils.h @@ -16,6 +16,7 @@ #define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ #include +#include "sm_globals.h" using namespace SourceMod; @@ -25,9 +26,13 @@ struct DynLibInfo size_t memorySize; }; -class MemoryUtils : public IMemoryUtils +class MemoryUtils : + public IMemoryUtils, + public SMGlobalClass { -public: +public: // SMGlobalClass + void OnSourceModAllInitialized(); +public: // IMemoryUtils void *FindPattern(const void *libPtr, const char *pattern, size_t len); private: bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); From b0e21c9da098176a257668149294ef31c426cab2 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 22 Apr 2007 18:25:10 +0000 Subject: [PATCH 0678/1664] added game config file natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40709 --- core/msvc8/sourcemod_mm.vcproj | 4 ++ core/smn_gameconfigs.cpp | 122 +++++++++++++++++++++++++++++++++ core/smn_keyvalues.cpp | 4 +- plugins/include/sourcemod.inc | 29 ++++++++ public/IGameConfigs.h | 26 +------ 5 files changed, 159 insertions(+), 26 deletions(-) create mode 100644 core/smn_gameconfigs.cpp diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index dc0f2b06..d945d2af 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -761,6 +761,10 @@ RelativePath="..\smn_functions.cpp" > + + diff --git a/core/smn_gameconfigs.cpp b/core/smn_gameconfigs.cpp new file mode 100644 index 00000000..5102d9d6 --- /dev/null +++ b/core/smn_gameconfigs.cpp @@ -0,0 +1,122 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sourcemod.h" +#include "HandleSys.h" +#include "GameConfigs.h" + +HandleType_t g_GameConfigsType; + +class GameConfigsNatives : + public IHandleTypeDispatch, + public SourceModBase +{ +public: + void OnSourceModAllInitialized() + { + g_GameConfigsType = g_HandleSys.CreateType("GameConfigs", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_GameConfigsType, g_pCoreIdent); + g_GameConfigsType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + g_GameConfigs.CloseGameConfigFile(reinterpret_cast(object)); + } +}; + +static cell_t smn_LoadGameConfigFile(IPluginContext *pCtx, const cell_t *params) +{ + IGameConfig *gc; + char *filename; + char error[128]; + + pCtx->LocalToString(params[1], &filename); + if (!g_GameConfigs.LoadGameConfigFile(filename, &gc, error, sizeof(error))) + { + return pCtx->ThrowNativeError("Unable to open %s: %s", filename, error); + } + + return g_HandleSys.CreateHandle(g_GameConfigsType, gc, pCtx->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t smn_GameConfGetOffset(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IGameConfig *gc; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr); + } + + char *key; + int val; + pCtx->LocalToString(params[2], &key); + + if (!gc->GetOffset(key, &val)) + { + return -1; + } + + return val; +} + +static cell_t smn_GameConfGetKeyValue(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IGameConfig *gc; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr); + } + + char *key; + const char *val; + pCtx->LocalToString(params[2], &key); + + if ((val=gc->GetKeyValue(key)) == NULL) + { + return 0; + } + + pCtx->StringToLocalUTF8(params[3], params[4], val, NULL); + + return 1; +} + +static GameConfigsNatives s_GameConfigsNatives; + +REGISTER_NATIVES(gameconfignatives) +{ + {"LoadGameConfigFile", smn_LoadGameConfigFile}, + {"GameConfGetOffset", smn_GameConfGetOffset}, + {"GameConfGetKeyValue", smn_GameConfGetKeyValue}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index d0aae516..82d3d657 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -26,7 +26,7 @@ struct KeyValueStack CStack pCurRoot; }; -class KeyValuekNatives : +class KeyValueNatives : public SMGlobalClass, public IHandleTypeDispatch { @@ -636,7 +636,7 @@ static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *param return 1; } -static KeyValuekNatives s_KeyValuekNatives; +static KeyValueNatives s_KeyValueNatives; REGISTER_NATIVES(keyvaluenatives) { diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e1949353..425bb70a 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -406,5 +406,34 @@ native bool:IsSoundPrecached(const String:sound[]); */ native CreateDialog(client, Handle:kv, DialogType:type); +/** + * Loads a game config file. + * + * @param file File to load. The path must be relative to the 'gamedata' folder under the config folder + * and the extension should be omitted. + * @return A handle to the game config file or INVALID_HANDLE in failure. + */ +native Handle:LoadGameConfigFile(const String:file[]); + +/** + * Returns an offset value. + * + * @param gc Game config handle. + * @param key Key to retrieve from the offset section. + * @return An offset, or -1 on failure. + */ +native GameConfGetOffset(Handle:gc, const String:key[]); + +/** + * Gets the value of a key from the "Keys" section. + * + * @param gc Game config handle. + * @param key Key to retrieve from the Keys section. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return True if key existed, false otherwise. + */ +native bool:GameConfGetKeyValue(Handle:gc, const String:key[], String:buffer[], maxlen); + #include #include diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h index a98b7930..d9fb3cdf 100644 --- a/public/IGameConfigs.h +++ b/public/IGameConfigs.h @@ -33,28 +33,6 @@ class SendProp; namespace SourceMod { - /** - * @brief Details the property types. - */ - enum PropType - { - PropType_Unknown = 0, /**< Property type is not known */ - PropType_Send = 1, /**< Property type is a networkable property */ - PropType_Data = 2, /**< Property type is a data/save property */ - }; - - /** - * @brief Details the property states. - */ - enum PropError - { - PropError_Okay = 0, /**< No error */ - PropError_NotSet, /**< Property is not set in the config file */ - PropError_NotFound, /**< Property was not found in the game */ - }; - - #define INVALID_PROPERTY_VALUE -1 /**< Property value is not valid */ - /** * @brief Describes a game private data config file */ @@ -74,7 +52,7 @@ namespace SourceMod * @brief Returns information about a dynamic offset. * * @param key Key to retrieve from the property section. - * @return A PropError error code. + * @return A SendProp pointer, or NULL if not found. */ virtual SendProp *GetSendProp(const char *key) =0; @@ -106,7 +84,7 @@ namespace SourceMod * @brief Loads or finds an already loaded game config file. * * @param file File to load. The path must be relative to the 'gamedata' - * folder under the config folder, and the extension should be ommitted. + * folder under the config folder, and the extension should be omitted. * @param pConfig Pointer to store the game config pointer. Pointer will be valid even on failure. * @param error Optional error message buffer. * @param maxlength Maximum length of the error buffer. From cc44e1416a80b388e151bd2c02edd7aad09f58a1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Apr 2007 03:50:06 +0000 Subject: [PATCH 0679/1664] added menu control strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40710 --- translations/core.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/translations/core.cfg b/translations/core.cfg index 9bfadc53..e9a44559 100644 --- a/translations/core.cfg +++ b/translations/core.cfg @@ -5,4 +5,19 @@ "en" "You do not have access to this command" } + "Back" + { + "en" "Back" + } + + "Next" + { + "en" "Next" + } + + "Exit" + { + "en" "Exit" + } + } From 960bee31da5b372925f7a045f63179e40cff3b24 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Apr 2007 22:20:39 +0000 Subject: [PATCH 0681/1664] jit helpers are now public --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40712 --- {sourcepawn => public}/jit/jit_helpers.h | 0 {sourcepawn => public}/jit/x86/x86_macros.h | 0 sourcepawn/jit/x86/jit_x86.cpp | 2 +- sourcepawn/jit/x86/jit_x86.h | 2 +- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 6 +++++- 5 files changed, 7 insertions(+), 3 deletions(-) rename {sourcepawn => public}/jit/jit_helpers.h (100%) rename {sourcepawn => public}/jit/x86/x86_macros.h (100%) diff --git a/sourcepawn/jit/jit_helpers.h b/public/jit/jit_helpers.h similarity index 100% rename from sourcepawn/jit/jit_helpers.h rename to public/jit/jit_helpers.h diff --git a/sourcepawn/jit/x86/x86_macros.h b/public/jit/x86/x86_macros.h similarity index 100% rename from sourcepawn/jit/x86/x86_macros.h rename to public/jit/x86/x86_macros.h diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 95b08304..d151e597 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -17,7 +17,7 @@ #include #include "jit_x86.h" #include "opcode_helpers.h" -#include "x86_macros.h" +#include #include "jit_version.h" #if defined USE_UNGEN_OPCODES diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index c5278209..b348b483 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -17,7 +17,7 @@ #include #include -#include "../jit_helpers.h" +#include using namespace SourcePawn; diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index e5e623e2..b4e41221 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -208,6 +208,10 @@ RelativePath="..\dll_exports.h" > + + @@ -225,7 +229,7 @@ > From d30f82d3fa0d52f56064d6ed0188be00119a973c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Apr 2007 22:42:39 +0000 Subject: [PATCH 0682/1664] updated linux build to new layout --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40713 --- sourcepawn/jit/x86/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/Makefile b/sourcepawn/jit/x86/Makefile index 13bc56a1..55148aac 100644 --- a/sourcepawn/jit/x86/Makefile +++ b/sourcepawn/jit/x86/Makefile @@ -19,7 +19,8 @@ OBJECTS = dll_exports.cpp jit_x86.cpp opcode_helpers.cpp LINK = -static-libgcc -INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn +INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn \ + -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 ifeq "$(DEBUG)" "true" BIN_DIR = Debug From 053029af87121861596c6a5eaaa8106834fa4976 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 27 Apr 2007 00:21:21 +0000 Subject: [PATCH 0683/1664] fixed comment --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40714 --- plugins/include/console.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 22c83749..ece28d03 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -136,7 +136,7 @@ native PrintToConsole(client, const String:format[], any:...); * Called when a server-only command is invoked. * * @params args Number of arguments that were in the argument string. - * @return A Result value. Not handling the command + * @return An Action value. Not handling the command * means that Source will report it as "not found." */ functag SrvCmd Action:public(args); @@ -158,7 +158,7 @@ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:descriptio * * @param client Index of the client, or 0 from the server. * @param args Number of arguments that were in the argument string. - * @return A Result value. Not handling the command + * @return An Action value. Not handling the command * means that Source will report it as "not found." */ functag ConCmd Action:public(client, args); From d7cf6dbba9caf87d7b2f04c037f216696d5adc91 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 27 Apr 2007 01:51:34 +0000 Subject: [PATCH 0684/1664] fixed a bug where typedescription_t searching could crash --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40715 --- core/HalfLife2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 422aa7de..97551376 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -118,6 +118,10 @@ typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name) { for (int i=0; idataNumFields; i++) { + if (pMap->dataDesc[i].fieldName == NULL) + { + continue; + } if (strcmp(name, pMap->dataDesc[i].fieldName) == 0) { return &(pMap->dataDesc[i]); From ba17aafb8a7e6556caecf9a11adc953e07684d5b Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 27 Apr 2007 11:25:30 +0000 Subject: [PATCH 0685/1664] synced linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40716 --- core/Makefile | 2 +- core/smn_gameconfigs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Makefile b/core/Makefile index 26ca408b..fc813335 100644 --- a/core/Makefile +++ b/core/Makefile @@ -26,7 +26,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC sourcemm_api.cpp sourcemod.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ - smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ + smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \ smn_usermsgs.cpp OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ diff --git a/core/smn_gameconfigs.cpp b/core/smn_gameconfigs.cpp index 5102d9d6..bc52a4eb 100644 --- a/core/smn_gameconfigs.cpp +++ b/core/smn_gameconfigs.cpp @@ -119,4 +119,4 @@ REGISTER_NATIVES(gameconfignatives) {"GameConfGetOffset", smn_GameConfGetOffset}, {"GameConfGetKeyValue", smn_GameConfGetKeyValue}, {NULL, NULL} -}; \ No newline at end of file +}; From 1b5bcc48362de4f496d2fa79d444a19ffd33c96b Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 30 Apr 2007 18:02:28 +0000 Subject: [PATCH 0686/1664] Fixed amb238 - BuildPath native didn't accept format arguments properly --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40717 --- core/smn_filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 4e59c426..f1cfd782 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -451,7 +451,7 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params) { char path[PLATFORM_MAX_PATH], *fmt, *buffer; - int arg = 4; + int arg = 5; pContext->LocalToString(params[2], &buffer); pContext->LocalToString(params[4], &fmt); From 473e1d41358370290b828436d9994b4806406434 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 30 Apr 2007 22:03:28 +0000 Subject: [PATCH 0687/1664] Removed flags from FireEvent() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40718 --- core/EventManager.cpp | 20 ++------------------ core/EventManager.h | 6 +----- core/smn_events.cpp | 2 +- plugins/include/events.inc | 8 +------- 4 files changed, 5 insertions(+), 31 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index cf5e14fb..db97f207 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -25,7 +25,7 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; typedef List EventHookList; -EventManager::EventManager() : m_EventType(0), m_NotifyPlugins(true) +EventManager::EventManager() : m_EventType(0) { /* Create an event lookup trie */ m_EventHooks = sm_trie_create(); @@ -302,11 +302,8 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name) return NULL; } -void EventManager::FireEvent(EventInfo *pInfo, int flags, bool bDontBroadcast) +void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast) { - /* Should SourceMod plugins be notified of this event? */ - m_NotifyPlugins = (flags & EVENT_PASSTHRU_ALL) ? true : false; - /* Actually fire event now */ gameevents->FireEvent(pInfo->pEvent, bDontBroadcast); @@ -336,11 +333,6 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) IChangeableForward *pForward; const char *name; cell_t res = Pl_Continue; - - if (!m_NotifyPlugins) - { - RETURN_META_VALUE(MRES_IGNORED, true); - } /* Get the event name, we're going to need this for passing to post hooks */ name = pEvent->GetName(); @@ -389,14 +381,6 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) const char *name; Handle_t hndl = 0; - if (!m_NotifyPlugins) - { - /* Reset plugin notification state */ - m_NotifyPlugins = true; - - RETURN_META_VALUE(MRES_IGNORED, true); - } - name = m_EventNames.front(); if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast(&pHook))) diff --git a/core/EventManager.h b/core/EventManager.h index e0ab28da..0c796284 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -26,9 +26,6 @@ using namespace SourceHook; -//#define EVENT_PASSTHRU (1<<0) -#define EVENT_PASSTHRU_ALL (1<<1) - struct EventInfo { IGameEvent *pEvent; @@ -97,14 +94,13 @@ public: EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventInfo *CreateEvent(IPluginContext *pContext, const char *name); - void FireEvent(EventInfo *pInfo, int flags=0, bool bDontBroadcast=false); + void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false); void CancelCreatedEvent(EventInfo *pInfo); private: // IGameEventManager2 hooks bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); private: HandleType_t m_EventType; - bool m_NotifyPlugins; Trie *m_EventHooks; CStack m_FreeEvents; CStack m_EventNames; diff --git a/core/smn_events.cpp b/core/smn_events.cpp index b3cc7508..95a2648d 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -99,7 +99,7 @@ static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Game event \"%s\" could not be fired because it was not created by this plugin", pInfo->pEvent->GetName()); } - g_EventManager.FireEvent(pInfo, params[2], params[3] ? true : false); + g_EventManager.FireEvent(pInfo, params[2] ? true : false); /* Free handle on game event */ HandleSecurity sec = {pContext->GetIdentity(), g_pCoreIdent}; diff --git a/plugins/include/events.inc b/plugins/include/events.inc index ba1f297c..34088948 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -18,11 +18,6 @@ #endif #define _events_included -/** - * Flags for firing game events - */ -#define EVENT_PASSTHRU_ALL (1<<1) /**< Event will pass through other SourceMM plugins AND SourceMod */ - /** * Event hook modes determining how hooking should be handled */ @@ -94,12 +89,11 @@ native Handle:CreateEvent(const String:name[]); * Fires a game event. * * @param event Handle to the event. - * @param flags Optional bitstring flags. See EVENT_* constants for more details. * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. * @noreturn * @error Invalid or corrupt Handle. */ -native FireEvent(Handle:event, flags=0, bool:dontBroadcast=false); +native FireEvent(Handle:event, bool:dontBroadcast=false); /** * Cancels a previously created game event that has not been fired. From 523e3d042d6a3173e1332d1915080e474501409c Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 30 Apr 2007 22:53:27 +0000 Subject: [PATCH 0688/1664] Added paramater to CreateEvent to determine whether or not creation should be forced even if nothing is hooking/listening to the event. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40719 --- core/EventManager.cpp | 4 ++-- core/EventManager.h | 2 +- core/smn_events.cpp | 2 +- plugins/include/events.inc | 7 +++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index db97f207..b0c08460 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -277,10 +277,10 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun return EventHookErr_Okay; } -EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name) +EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name, bool force) { EventInfo *pInfo; - IGameEvent *pEvent = gameevents->CreateEvent(name, true); + IGameEvent *pEvent = gameevents->CreateEvent(name, force); if (pEvent) { diff --git a/core/EventManager.h b/core/EventManager.h index 0c796284..90dee518 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -93,7 +93,7 @@ public: public: EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); - EventInfo *CreateEvent(IPluginContext *pContext, const char *name); + EventInfo *CreateEvent(IPluginContext *pContext, const char *name, bool force=false); void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false); void CancelCreatedEvent(EventInfo *pInfo); private: // IGameEventManager2 hooks diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 95a2648d..679c4efe 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -71,7 +71,7 @@ static cell_t sm_CreateEvent(IPluginContext *pContext, const cell_t *params) pContext->LocalToString(params[1], &name); - pInfo = g_EventManager.CreateEvent(pContext, name); + pInfo = g_EventManager.CreateEvent(pContext, name, params[2] ? true : false); if (pInfo) { diff --git a/plugins/include/events.inc b/plugins/include/events.inc index 34088948..d1fd81d9 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -81,9 +81,12 @@ native UnhookEvent(const String:name[], EventHook:callback, EventHookMode:mode=E * Creates a game event to be fired later. * * @param name Name of event. - * @return Handle to event or INVALID_HANDLE if event doesn't exist. + * @param force If set to true, this forces the event to be created even if it's not being hooked. + * Note that this will not force it if the event doesn't exist at all. + * @return Handle to event. INVALID_HANDLE is returned if the event doesn't exist or isn't + being hooked (unless force is true). */ -native Handle:CreateEvent(const String:name[]); +native Handle:CreateEvent(const String:name[], bool:force=false); /** * Fires a game event. From 41e473a60c2ed09b878284e8602de20d10c133fa Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 1 May 2007 05:29:37 +0000 Subject: [PATCH 0689/1664] - Removed GetConVarMin/Max() and replaced them with GetConVarBounds() - Added SetConVarBounds() to set convar constraints after convar has already been created --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40720 --- core/convar_sm.h | 30 ++++++++++++++++--- core/smn_console.cpp | 59 ++++++++++++++++++++++++------------- plugins/include/console.inc | 52 +++++++++++++++++++------------- 3 files changed, 97 insertions(+), 44 deletions(-) diff --git a/core/convar_sm.h b/core/convar_sm.h index 01f51e9e..114786e9 100644 --- a/core/convar_sm.h +++ b/core/convar_sm.h @@ -200,8 +200,14 @@ protected: static IConCommandBaseAccessor *s_pAccessor; public: // Hackalicous - int GetFlags() { return m_nFlags; } - void SetFlags(int flags) { m_nFlags = flags; } + inline int GetFlags() + { + return m_nFlags; + } + inline void SetFlags(int flags) + { + m_nFlags = flags; + } }; //----------------------------------------------------------------------------- @@ -246,7 +252,10 @@ private: FnCommandCompletionCallback m_fnCompletionCallback; bool m_bHasCompletionCallback; public: // Hackalicous - FnCommandCallback GetCallback() { return m_fnCommandCallback; } + inline FnCommandCallback GetCallback() + { + return m_fnCommandCallback; + } }; //----------------------------------------------------------------------------- @@ -360,7 +369,20 @@ private: // Call this function when ConVar changes FnChangeCallback m_fnChangeCallback; public: // Hackalicous - FnChangeCallback GetCallback() { return m_fnChangeCallback; } + inline FnChangeCallback GetCallback() + { + return m_fnChangeCallback; + } + inline void SetMin(bool set, float min) + { + m_bHasMin = set; + m_fMinVal = min; + } + inline void SetMax(bool set, float max) + { + m_bHasMax = set; + m_fMaxVal = max; + } }; diff --git a/core/smn_console.cpp b/core/smn_console.cpp index c9c5d81a..8032fc91 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -22,6 +22,12 @@ #include "sm_stringutil.h" #include "PlayerManager.h" +enum ConVarBounds +{ + ConVarBound_Upper = 0, + ConVarBound_Lower +}; + static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params) { char *name, *defaultVal, *helpText; @@ -261,7 +267,7 @@ static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params) return 1; } -static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) +static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; @@ -274,18 +280,28 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) } cell_t *addr; - bool hasMin; - float min; + bool hasBound; + float bound; - pContext->LocalToPhysAddr(params[2], &addr); + switch (params[2]) + { + case ConVarBound_Upper: + hasBound = pConVar->GetMax(bound); + break; + case ConVarBound_Lower: + hasBound = pConVar->GetMin(bound); + break; + default: + return pContext->ThrowNativeError("Invalid ConVarBounds value %d"); + } + + pContext->LocalToPhysAddr(params[3], &addr); + *addr = sp_ftoc(bound); - hasMin = pConVar->GetMin(min); - *addr = sp_ftoc(min); - - return hasMin; + return hasBound; } -static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) +static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; @@ -297,16 +313,19 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err); } - cell_t *addr; - bool hasMax; - float max; + switch (params[2]) + { + case ConVarBound_Upper: + pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4])); + break; + case ConVarBound_Lower: + pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4])); + break; + default: + return pContext->ThrowNativeError("Invalid ConVarBounds value %d"); + } - pContext->LocalToPhysAddr(params[2], &addr); - - hasMax = pConVar->GetMax(max); - *addr = sp_ftoc(max); - - return hasMax; + return 1; } static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params) @@ -630,8 +649,8 @@ REGISTER_NATIVES(consoleNatives) {"GetConVarFlags", sm_GetConVarFlags}, {"SetConVarFlags", sm_SetConVarFlags}, {"GetConVarName", sm_GetConVarName}, - {"GetConVarMin", sm_GetConVarMin}, - {"GetConVarMax", sm_GetConVarMax}, + {"GetConVarBounds", sm_GetConVarBounds}, + {"SetConVarBounds", sm_SetConVarBounds}, {"ResetConVar", sm_ResetConVar}, {"QueryClientConVar", sm_QueryClientConVar}, {"RegServerCmd", sm_RegServerCmd}, diff --git a/plugins/include/console.inc b/plugins/include/console.inc index ece28d03..120a42eb 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -18,6 +18,15 @@ #endif #define _console_included +/** + * Console variable bound values used with Get/SetConVarBounds() + */ +enum ConVarBounds +{ + ConVarBound_Upper = 0, + ConVarBound_Lower +}; + /** * Console variable query helper values. */ @@ -378,6 +387,29 @@ native GetConVarFlags(Handle:convar); */ native SetConVarFlags(Handle:convar, flags); +/** + * Retrieves the specified bound of a console variable. + * + * @param convar Handle to the convar. + * @param type Type of bound to retrieve, ConVarBound_Lower or ConVarBound_Upper. + * @param value By-reference cell to store the specified floating point bound value. + * @return True if the convar has the specified bound set, false otherwise. + * @error Invalid or corrupt Handle. + */ +native bool:GetConVarBounds(Handle:convar, ConVarBounds:type, &Float:value); + +/** + * Sets the specified bound of a console variable. + * + * @param convar Handle to the convar. + * @param type Type of bound to set, ConVarBound_Lower or ConVarBound_Upper + * @param set If set to true, convar will use specified bound. If false, bound will be removed. + * @param value Floating point value to use as the specified bound. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetConVarBounds(Handle:convar, ConVarBounds:type, bool:set, Float:value=0.0); + /** * Retrieves the name of a console variable. * @@ -389,26 +421,6 @@ native SetConVarFlags(Handle:convar, flags); */ native GetConVarName(Handle:convar, const String:name[], maxlength); -/** - * Retrieves the minimum floating point value that a console variable can contain. - * - * @param convar Handle to the convar. - * @param min By-reference cell to store the minimum floating point value. - * @return True if the convar has a minimum value set, false otherwise. - * @error Invalid or corrupt Handle. - */ -native bool:GetConVarMin(Handle:convar, &Float:min); - -/** - * Retrieves the maximum floating point value that a console variable can contain. - * - * @param convar Handle to the convar. - * @param min By-reference cell to store the maximum floating point value. - * @return True if the convar has a maximum value set, false otherwise. - * @error Invalid or corrupt Handle. - */ -native bool:GetConVarMax(Handle:convar, &Float:max); - /** * Resets the console variable to its default value. * From 462fe04f95d8516fc05ca4b850b5089fa3e641f7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 02:13:15 +0000 Subject: [PATCH 0690/1664] added SOURCEMOD_BUILD define for extensions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40721 --- public/sourcepawn/sp_vm_api.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 634e346d..f4da9310 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -30,6 +30,10 @@ /** SourcePawn VM API Version */ #define SOURCEPAWN_VM_API_VERSION 2 +#if !defined SOURCEMOD_BUILD +#define SOURCEMOD_BUILD +#endif + #if defined SOURCEMOD_BUILD namespace SourceMod { From d432dc0cbd17e9150e3f55cc6e156797d2f77413 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 02:15:45 +0000 Subject: [PATCH 0691/1664] fixups to a few include files --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40722 --- plugins/include/bitbuffer.inc | 4 ++-- plugins/include/timers.inc | 6 +++--- plugins/include/usermessages.inc | 9 ++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/include/bitbuffer.inc b/plugins/include/bitbuffer.inc index db7cd4ec..c9732d07 100644 --- a/plugins/include/bitbuffer.inc +++ b/plugins/include/bitbuffer.inc @@ -229,11 +229,11 @@ native Float:BfReadFloat(Handle:bf); * @param bf bf_read handle to read from. * @param buffer Destination string buffer. * @param maxlength Maximum length of output string buffer. - * @param Line If true the buffer will be copied until it reaches a '\n' or a null terminator. + * @param line If true the buffer will be copied until it reaches a '\n' or a null terminator. * @noreturn * @error Invalid or incorrect Handle, destination string buffer was too short. */ -native BfReadString(Handle:bf, String:buffer[], maxlength, bool:Line=false); +native BfReadString(Handle:bf, String:buffer[], maxlength, bool:line=false); /** * Reads an entity from a readable bitbuffer (bf_read). diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index 58dd6944..ce920395 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -46,7 +46,7 @@ funcenum Timer * @return Plugin_Stop to stop a repeating timer, any other value for * default behavior. */ - Action:public(Handle:timer, value), + Action:public(Handle:timer, any:value), /** * Called when the timer interval has elapsed. @@ -67,7 +67,7 @@ funcenum Timer * @param flags Flags to set (such as repeatability or auto-Handle closing). * @return Handle to the timer object. You do not need to call CloseHandle(). */ -native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value=INVALID_HANDLE, flags=0); +native Handle:CreateTimer(Float:interval, Timer:func, any:value=INVALID_HANDLE, flags=0); /** * Kills a timer. Use this instead of CloseHandle() if you need more options. @@ -99,7 +99,7 @@ native TriggerTimer(Handle:timer, bool:reset=false); * @param flags Timer flags. * @return Handle to the timer object. You do not need to call CloseHandle(). */ -stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:data, flags) +stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:data, flags=0) { data = CreateDataPack(); flags |= TIMER_HNDL_CLOSE; diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 6acca67f..c7677115 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -26,10 +26,13 @@ enum UserMsg INVALID_MESSAGE_ID = -1, }; -#define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */ -#define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */ -#define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */ +#define USERMSG_PASSTHRU (1<<0) /**< (DEPRECATED, NO EFFECT) */ +#define USERMSG_PASSTHRU_ALL (1<<1) /**< (DEPRECATED, NO EFFECT) */ +#define USERMSG_RELIABLE (1<<2) /**< Message will be set on the reliable stream */ #define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */ +#define USERMSG_BLOCK_MM (1<<4) /**< Message will be blocked from going through MM:S hooks */ +#define USERMSG_BLOCK_SM (1<<5) /**< Message will be blocked from going through SourceMod hooks */ +#define USERMSG_BLOCK_ALL (1<<6) /**< Message will be blocked from going through any hooks */ /** * Returns the ID of a given message, or -1 on failure. From d57f5438206d40024f5b90e414fb3e9dbdff6390 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 17:45:09 +0000 Subject: [PATCH 0692/1664] renamed OnServerLoad to OnMapStart --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40723 --- core/PlayerManager.cpp | 3 +++ core/PlayerManager.h | 1 + plugins/include/sourcemod.inc | 10 +++++----- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 8f4e9ca9..56fff760 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -66,6 +66,7 @@ void PlayerManager::OnSourceModAllInitialized() m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String); m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL); + m_onActivate2 = g_Forwards.CreateForward("OnMapStart", ET_Ignore, 0, NULL); } void PlayerManager::OnSourceModShutdown() @@ -87,6 +88,7 @@ void PlayerManager::OnSourceModShutdown() g_Forwards.ReleaseForward(m_clinfochanged); g_Forwards.ReleaseForward(m_clauth); g_Forwards.ReleaseForward(m_onActivate); + g_Forwards.ReleaseForward(m_onActivate2); delete [] m_Players; } @@ -105,6 +107,7 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1)); } m_onActivate->Execute(NULL); + m_onActivate2->Execute(NULL); } void PlayerManager::RunAuthChecks() diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 56811de2..30986ac9 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -117,6 +117,7 @@ private: IForward *m_clinfochanged; IForward *m_clauth; IForward *m_onActivate; + IForward *m_onActivate2; CPlayer *m_Players; int *m_UserIdLookUp; int m_maxClients; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 425bb70a..9e548a34 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -114,12 +114,12 @@ forward OnPluginPauseChange(bool:pause); forward OnGameFrame(); /** - * Called when the map is loaded and configs have been parsed. - * Note that commands are processed per-frame, and thus config - * files may not be fully loaded until a few seconds later. - * This function will be called on each mapchange. + * Called when the map is loaded. + * + * Note: This used to be OnServerLoad(), which is now deprecated. + * Plugins still using the old forward will work. */ -forward OnServerLoad(); +forward OnMapStart(); /** * Returns the calling plugin's Handle. From 3c3906b49497026bfd9b72863fca2671b1be122c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 17:49:23 +0000 Subject: [PATCH 0693/1664] added request amb234 (OnMapEnd) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40724 --- core/sourcemod.cpp | 16 ++++++++++++++++ plugins/include/sourcemod.inc | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 79202339..aeaaa1ff 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -45,6 +45,7 @@ IdentityToken_t *g_pCoreIdent = NULL; float g_LastTime = 0.0f; float g_LastAuthCheck = 0.0f; IForward *g_pOnGameFrame = NULL; +IForward *g_pOnMapEnd = NULL; bool g_Loaded = false; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); @@ -288,6 +289,11 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL); } + if (!g_pOnMapEnd) + { + g_pOnMapEnd = g_Forwards.CreateForward("OnMapEnd", ET_Ignore, 0, NULL); + } + RETURN_META_VALUE(MRES_IGNORED, true); } @@ -319,6 +325,11 @@ void SourceModBase::GameFrame(bool simulating) void SourceModBase::LevelShutdown() { + if (g_pOnMapEnd) + { + g_pOnMapEnd->Execute(NULL); + } + if (m_ExecPluginReload) { g_PluginSys.ReloadOrUnloadPlugins(); @@ -396,6 +407,11 @@ void SourceModBase::CloseSourceMod() { g_Forwards.ReleaseForward(g_pOnGameFrame); } + + if (g_pOnMapEnd) + { + g_Forwards.ReleaseForward(g_pOnMapEnd); + } /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 9e548a34..8568fd6d 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -121,6 +121,11 @@ forward OnGameFrame(); */ forward OnMapStart(); +/** + * Called right before a map ends. + */ +forward OnMapEnd(); + /** * Returns the calling plugin's Handle. * From 4f66cfbf9fb1d255a06fc39fc8df7b7c752c1e7a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 19:14:26 +0000 Subject: [PATCH 0694/1664] fixed issue amb235 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40725 --- core/PlayerManager.cpp | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 56fff760..6c8cf613 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -108,6 +108,9 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl } m_onActivate->Execute(NULL); m_onActivate2->Execute(NULL); + + static int g_userid_test = 1; + int client = GetClientOfUserId(++g_userid_test); } void PlayerManager::RunAuthChecks() @@ -437,7 +440,46 @@ int PlayerManager::GetNumPlayers() int PlayerManager::GetClientOfUserId(int userid) { - return (userid < 0 || userid > USHRT_MAX) ? 0 : m_UserIdLookUp[userid]; + if (userid < 0 || userid > USHRT_MAX) + { + return 0; + } + + int client = m_UserIdLookUp[userid]; + + /* Verify the userid. The cache can get messed up with older + * Valve engines. :TODO: If this gets fixed, do an old engine + * check before invoking this backwards compat code. + */ + if (client) + { + CPlayer *player = GetPlayerByIndex(client); + if (player && player->IsConnected()) + { + int realUserId = engine->GetPlayerUserId(player->GetEdict()); + if (realUserId == userid) + { + return client; + } + } + } + + /* If we can't verify the userid, we have to do a manual loop */ + CPlayer *player; + for (int i = 1; i <= m_maxClients; i++) + { + player = GetPlayerByIndex(i); + if (!player || !player->IsConnected()) + { + continue; + } + if (engine->GetPlayerUserId(player->GetEdict()) == userid) + { + return i; + } + } + + return 0; } void PlayerManager::AddClientListener(IClientListener *listener) From 5c6ba68e4b5a90f2cd92b076a3f3a342622caa79 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 19:20:34 +0000 Subject: [PATCH 0695/1664] userid cache gets repopulated now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40726 --- core/PlayerManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 6c8cf613..05c1e455 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -475,6 +475,7 @@ int PlayerManager::GetClientOfUserId(int userid) } if (engine->GetPlayerUserId(player->GetEdict()) == userid) { + m_UserIdLookUp[userid] = i; return i; } } From 3cdd3c0d0d23597afbb32fbabaeb24cc55d795d3 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 2 May 2007 19:33:51 +0000 Subject: [PATCH 0696/1664] Added GetGameFolderName() native --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40727 --- core/smn_halflife.cpp | 11 +++++++++++ plugins/include/sourcemod.inc | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 833dc0e0..709bb12e 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -140,6 +140,16 @@ static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params) return numBytes; } +static cell_t GetGameFolderName(IPluginContext *pContext, const cell_t *params) +{ + const char *name = g_SourceMod.GetModFolderName(); + size_t numBytes; + + pContext->StringToLocalUTF8(params[1], params[2], name, &numBytes); + + return numBytes; +} + static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) { size_t bytes; @@ -277,6 +287,7 @@ REGISTER_NATIVES(halflifeNatives) {"GetCurrentMap", GetCurrentMap}, {"GetEngineTime", GetEngineTime}, {"GetGameDescription", GetGameDescription}, + {"GetGameFolderName", GetGameFolderName}, {"GetGameTime", GetGameTime}, {"GetRandomFloat", GetRandomFloat}, {"GetRandomInt", GetRandomInt}, diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 8568fd6d..cedd2aab 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -314,6 +314,16 @@ native Float:GetGameTime(); */ native GetGameDescription(String:buffer[], maxlength, bool:original=false); +/** + * Returns the name of the game's directory. + * + * @param buffer Buffer to store the directory name. + * @param maxlength Maximum size of the buffer. + * + * return Number of bytes written to the buffer (UTF-8 safe). + */ +native GetGameFolderName(String:buffer[], maxlength); + /** * Returns the current map name. * From f498af0190843d17fce48036e93511dae46f49d8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 20:30:29 +0000 Subject: [PATCH 0697/1664] removed debug code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40728 --- core/PlayerManager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 05c1e455..b5367e9d 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -108,9 +108,6 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl } m_onActivate->Execute(NULL); m_onActivate2->Execute(NULL); - - static int g_userid_test = 1; - int client = GetClientOfUserId(++g_userid_test); } void PlayerManager::RunAuthChecks() From a5c018724a5f7adcb1800d4cc5cf186108320573 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 20:44:35 +0000 Subject: [PATCH 0698/1664] added amb217 (server.cfg forward) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40729 --- core/ConCmdManager.cpp | 73 +++++++++++++++++++++++++++++++++++ core/ConCmdManager.h | 7 ++++ plugins/include/sourcemod.inc | 12 +++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 958c8b49..f2bdcd69 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -31,12 +31,17 @@ struct PlCmdInfo CmdType type; }; typedef List CmdList; + void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info); ConCmdManager::ConCmdManager() : m_Strings(1024) { m_pCmds = sm_trie_create(); m_pCmdGrps = sm_trie_create(); + m_bServerCfgDone = true; + m_pExecCmd = NULL; + m_pServerCfgFile = NULL; + m_pServerCfgFwd = NULL; } ConCmdManager::~ConCmdManager() @@ -50,15 +55,73 @@ void ConCmdManager::OnSourceModAllInitialized() g_PluginSys.AddPluginsListener(this); g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this); SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); + + ConCommandBase *pCmd = icvar->GetCommands(); + while (pCmd) + { + if (pCmd->IsCommand() + && strcmp(pCmd->GetName(), "exec") == 0) + { + m_pExecCmd = (ConCommand *)pCmd; + break; + } + pCmd = const_cast(pCmd->GetNext()); + } + + if (m_pExecCmd) + { + m_pServerCfgFile = (ConVar *)icvar->FindVar("servercfgfile"); + SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pExecCmd, this, &ConCmdManager::OnExecCmd, true); + m_pServerCfgFwd = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL); + } } void ConCmdManager::OnSourceModShutdown() { + if (m_pExecCmd) + { + SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pExecCmd, this, &ConCmdManager::OnExecCmd, true); + g_Forwards.ReleaseForward(m_pServerCfgFwd); + m_pServerCfgFwd = NULL; + m_pExecCmd = NULL; + } + /* All commands should already be removed by the time we're done */ SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false); g_RootMenu.RemoveRootConsoleCommand("cmds", this); } +void ConCmdManager::OnSourceModPluginsLoaded() +{ + m_bServerCfgDone = false; +} + +void ConCmdManager::OnExecCmd() +{ + const char *arg = engine->Cmd_Argv(1); + const char *cfgfile = "server.cfg"; + + if (m_pServerCfgFile) + { + cfgfile = m_pServerCfgFile->GetString(); + } + + if (strcmp(arg, cfgfile) == 0) + { + engine->ServerCommand("sm cmds internal 1\n"); + } +} + +void ConCmdManager::NotifyExecDone(const char *file) +{ + if (file == NULL && !m_bServerCfgDone) + { + /* Server-cfg file */ + m_bServerCfgDone = true; + m_pServerCfgFwd->Execute(NULL); + } +} + void ConCmdManager::RemoveConCmds(List &cmdlist, IPluginContext *pContext) { List::iterator iter = cmdlist.begin(); @@ -732,6 +795,16 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco if (argcount >= 3) { const char *text = engine->Cmd_Argv(2); + + if (strcmp(text, "internal") == 0) + { + const char *num = engine->Cmd_Argv(3); + if (atoi(num) == 1) + { + g_ConCmds.NotifyExecDone(NULL); + } + } + int id = atoi(text); CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(id); diff --git a/core/ConCmdManager.h b/core/ConCmdManager.h index e14ec711..bc6ccff4 100644 --- a/core/ConCmdManager.h +++ b/core/ConCmdManager.h @@ -84,6 +84,7 @@ public: public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); + void OnSourceModPluginsLoaded(); public: //IPluginsListener void OnPluginDestroyed(IPlugin *plugin); public: //IRootConsoleCommand @@ -99,6 +100,7 @@ public: int flags); ResultType DispatchClientCommand(int client, ResultType type); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits); + void NotifyExecDone(const char *file); private: void InternalDispatch(); ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args); @@ -108,12 +110,17 @@ private: void RemoveConCmd(ConCmdInfo *info); void RemoveConCmds(List &cmdlist, IPluginContext *pContext); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); + void OnExecCmd(); private: Trie *m_pCmds; /* command lookup */ Trie *m_pCmdGrps; /* command group lookup */ List m_CmdList; /* command list */ int m_CmdClient; /* current client */ BaseStringTable m_Strings; /* string table */ + ConVar *m_pServerCfgFile; /* servercfgfile cvar */ + ConCommand *m_pExecCmd; /* "exec" command */ + IForward *m_pServerCfgFwd; /* server config forward */ + bool m_bServerCfgDone; /* marks whether a servercfg was detected */ }; extern ConCmdManager g_ConCmds; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index cedd2aab..6a7e4eda 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -116,7 +116,7 @@ forward OnGameFrame(); /** * Called when the map is loaded. * - * Note: This used to be OnServerLoad(), which is now deprecated. + * @note This used to be OnServerLoad(), which is now deprecated. * Plugins still using the old forward will work. */ forward OnMapStart(); @@ -126,6 +126,16 @@ forward OnMapStart(); */ forward OnMapEnd(); +/** + * Called when the map has loaded and the servercfgfile has finished + * executing. This is usually 'server.cfg' but most mods allow it to + * be set via 'servercfgfile'. + * + * @note If server.cfg is executed more than once per map, this forward + * will only be called the first time (per map). + */ +forward OnServerCfg(); + /** * Returns the calling plugin's Handle. * From 2489044d8b3b44cf6646970f0c4a30f9535dc2eb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 20:46:21 +0000 Subject: [PATCH 0699/1664] oops, we can reference this implicitly now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40730 --- core/ConCmdManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index f2bdcd69..e7a54e06 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -801,7 +801,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco const char *num = engine->Cmd_Argv(3); if (atoi(num) == 1) { - g_ConCmds.NotifyExecDone(NULL); + NotifyExecDone(NULL); } } From 45d5518b111a3be69c467cbace1a73941b207fad Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 20:51:28 +0000 Subject: [PATCH 0700/1664] these should be default as the comments imply so --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40731 --- plugins/include/keyvalues.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index 56ac067f..edfcd6ce 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -43,7 +43,7 @@ enum KvDataTypes * @param firstValue If firstKey is non-empty, specifies the first key's value. * @return A Handle to a new KeyValues structure. */ -native Handle:CreateKeyValues(const String:name[], const String:firstkey[], const String:firstValue[]); +native Handle:CreateKeyValues(const String:name[], const String:firstkey[]="", const String:firstValue[]=""); /** * Sets a string value of a KeyValues key. From 9219fbb96caa2886ee79afbc0af3f11cda4775b2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 21:00:13 +0000 Subject: [PATCH 0701/1664] fixed a bug where KvJumpToKey did not obey the internal path stack --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40732 --- core/smn_keyvalues.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 82d3d657..6cde5b9b 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -378,7 +378,8 @@ static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params) pCtx->LocalToString(params[2], &name); - KeyValues *pSubKey = pStk->pBase->FindKey(name, (params[3]) ? true : false); + KeyValues *pSubKey = pStk->pCurRoot.front(); + pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false); if (!pSubKey) { return 0; From b8d3ea519678ffc57d76e7bb3ac4ee2aa41961c4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 22:35:51 +0000 Subject: [PATCH 0702/1664] attempted fix for amb243, timers now simulate ticks if gameframe doesn't give changed curtimes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40733 --- core/TimerSys.cpp | 30 +++++++++++++++------ core/TimerSys.h | 8 ++++++ core/sourcemod.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 8 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 3ce7839d..667ac3b9 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -15,6 +15,17 @@ #include "TimerSys.h" TimerSystem g_Timers; +TickInfo g_SimTicks; + +inline float GetSimulatedTime() +{ + if (g_SimTicks.ticking) + { + return gpGlobals->curtime; + } else { + return g_SimTicks.ticktime; + } +} void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags) { @@ -52,10 +63,11 @@ void TimerSystem::RunFrame() ITimer *pTimer; TimerIter iter; + float curtime = GetSimulatedTime(); for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); ) { pTimer = (*iter); - if (gpGlobals->curtime >= pTimer->m_ToExec) + if (curtime >= pTimer->m_ToExec) { pTimer->m_InExec = true; pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); @@ -71,7 +83,7 @@ void TimerSystem::RunFrame() for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); ) { pTimer = (*iter); - if (gpGlobals->curtime >= pTimer->m_ToExec) + if (curtime >= pTimer->m_ToExec) { pTimer->m_InExec = true; res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); @@ -83,19 +95,19 @@ void TimerSystem::RunFrame() continue; } pTimer->m_InExec = false; - pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + pTimer->m_ToExec = curtime + pTimer->m_Interval; } iter++; } - m_LastExecTime = gpGlobals->curtime; + m_LastExecTime = curtime; } ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) { ITimer *pTimer; TimerIter iter; - float to_exec = gpGlobals->curtime + fInterval; + float to_exec = GetSimulatedTime() + fInterval; if (m_FreeTimers.empty()) { @@ -160,7 +172,7 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) { if (delayExec) { - pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; + pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval; } pTimer->m_InExec = false; return; @@ -203,12 +215,14 @@ void TimerSystem::MapChange() for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) { pTimer = (*iter); - pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime; + pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime(); } for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++) { pTimer = (*iter); - pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime; + pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime(); } + + m_LastExecTime = GetSimulatedTime(); } diff --git a/core/TimerSys.h b/core/TimerSys.h index 4078b6a3..884bdaf2 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -27,6 +27,13 @@ using namespace SourceMod; typedef List TimerList; typedef List::iterator TimerIter; +struct TickInfo +{ + bool ticking; /* true=game is ticking, false=we're ticking */ + unsigned int tickcount; /* number of simulated ticks we've done */ + float ticktime; /* tick time we're maintaining */ +}; + class SourceMod::ITimer { public: @@ -64,5 +71,6 @@ private: }; extern TimerSystem g_Timers; +extern TickInfo g_SimTicks; #endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_ diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index aeaaa1ff..15c09a05 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -47,6 +47,8 @@ float g_LastAuthCheck = 0.0f; IForward *g_pOnGameFrame = NULL; IForward *g_pOnMapEnd = NULL; bool g_Loaded = false; +int g_StillFrames = 0; +float g_StillTime = 0.0f; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef unsigned int (*GETEXPORTCOUNT)(); @@ -263,6 +265,10 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_ExecPluginReload = true; g_LastTime = 0.0f; g_LastAuthCheck = 0.0f; + g_SimTicks.ticking = true; + g_SimTicks.tickcount = 0; + g_StillTime = 0.0f; + g_StillFrames = 0; /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -297,6 +303,27 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch RETURN_META_VALUE(MRES_IGNORED, true); } +void StartTickSimulation() +{ + g_SimTicks.ticking = false; + g_SimTicks.tickcount = 0; + g_SimTicks.ticktime = gpGlobals->curtime; +} + +void StopTickSimulation() +{ + g_SimTicks.ticking = true; + g_Timers.MapChange(); + g_StillFrames = 0; + g_LastTime = gpGlobals->curtime; +} + +void SimulateTick() +{ + g_SimTicks.tickcount++; + g_SimTicks.ticktime = g_StillTime + (g_SimTicks.tickcount * gpGlobals->interval_per_tick); +} + void SourceModBase::GameFrame(bool simulating) { /** @@ -304,6 +331,46 @@ void SourceModBase::GameFrame(bool simulating) * precious CPU cycles. */ float curtime = gpGlobals->curtime; + int framecount = gpGlobals->framecount; + + /* Verify that we're still ticking */ + if (g_SimTicks.ticking) + { + if (g_StillFrames == 0) + { + g_StillFrames = framecount; + g_StillTime = curtime; + } else { + /* Try to detect when we've stopped ticking. + * We do this once 10 frames pass and there have been no ticks. + */ + if (g_StillTime == curtime) + { + if (framecount - g_StillFrames >= 5) + { + StartTickSimulation(); + return; + } + } else { + /* We're definitely ticking we get here, + * but update everything as a precaution */ + g_StillFrames = framecount; + g_StillTime = curtime; + } + } + } else { + /* We need to make sure we should still be simulating. */ + if (g_StillTime != curtime) + { + /* Wow, we're ticking again! It's time to revert. */ + StopTickSimulation(); + return; + } + /* Nope, not ticking. Simulate! */ + SimulateTick(); + curtime = g_SimTicks.ticktime; + } + if (curtime - g_LastTime >= 0.1f) { if (m_CheckingAuth From 39110a7a517d04e2578b2d247ef8cb9eceaaadca Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 May 2007 22:49:28 +0000 Subject: [PATCH 0703/1664] added a translation helper --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40734 --- core/sm_stringutil.cpp | 21 ++++++++++++++------- core/sm_stringutil.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 6af95646..5fbab016 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -33,16 +33,23 @@ return 0; \ } -inline bool TryServerLanguage(const char *serverlang, unsigned int *langid) +size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const char *phrase, void **params) { - if (!g_Translator.GetLanguageByCode(serverlang, langid)) + Translation pTrans; + TransError err; + + err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans); + if (err != Trans_Okay && g_Translator.GetServerLanguage() != LANG_ENGLISH) { - if (!g_Translator.GetLanguageByCode("en", langid)) - { - return false; - } + err = g_pCorePhrases->GetTranslation(phrase, LANG_ENGLISH, &pTrans); } - return true; + + if (err != Trans_Okay) + { + return UTIL_Format(buffer, maxlength, "%s", phrase); + } + + return g_Translator.Translate(buffer, maxlength, params, &pTrans); } inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans) diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 2515dd1c..77cfbac9 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -32,5 +32,6 @@ size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); char *sm_strdup(const char *str); +size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const char *phrase, void **params); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ From de9dc9ed9986549f1e41705a6eb94c9d34e6e0f6 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 3 May 2007 03:45:53 +0000 Subject: [PATCH 0704/1664] Various pointless things of no importance: - Renamed ISourceMod::GetModPath() to GetGamePath() - Renamed ISourceMod::GetModFolderName() to GetGameFolderName() - Various spelling corrections (why did I do this?) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40735 --- core/AdminCache.cpp | 10 +++++----- core/AdminCache.h | 6 +++--- core/ConCmdManager.cpp | 2 +- core/ConVarManager.cpp | 2 +- core/CoreConfig.cpp | 2 +- core/GameConfigs.cpp | 2 +- core/HalfLife2.cpp | 2 +- core/PlayerManager.cpp | 2 +- core/sm_trie.cpp | 4 ++-- core/smn_halflife.cpp | 2 +- core/sourcemod.cpp | 6 +++--- core/sourcemod.h | 4 ++-- core/systems/ForwardSys.cpp | 4 ++-- core/systems/HandleSys.h | 2 +- public/IAdminSystem.h | 14 +++++++------- public/IExtensionSys.h | 2 +- public/IForwardSys.h | 6 +++--- public/IPlayerHelpers.h | 2 +- public/ISourceMod.h | 22 +++++++++++----------- public/ITextParsers.h | 8 ++++---- public/sourcepawn/sp_vm_types.h | 4 ++-- 21 files changed, 54 insertions(+), 54 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index e5ddaa75..f89b859a 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -1184,7 +1184,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target) { /** * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails. - * First, if the targetted AdminId is INVALID_ADMIN_ID, targeting succeeds. + * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. */ if (id == INVALID_ADMIN_ID) @@ -1210,21 +1210,21 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target) } /** - * Second, if the targeting admin is root, targeting suceeds. + * Second, if the targeting admin is root, targeting succeeds. */ if (pUser->eflags & ADMFLAG_ROOT) { return true; } - /** Fourth, if the targetted admin has global immunity, targeting fails. */ + /** Fourth, if the targeted admin has global immunity, targeting fails. */ if (pTarget->immune_global) { return false; } /** - * Fifth, if the targetted admin has default immunity + * Fifth, if the targeted admin has default immunity * and the admin belongs to no groups, targeting fails. */ if (pTarget->immune_default && pUser->grp_count < 1) @@ -1233,7 +1233,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target) } /** - * Sixth, if the targetted admin has specific immunity from the + * Sixth, if the targeted admin has specific immunity from the * targeting admin via group immunities, targeting fails. */ //:TODO: speed this up... maybe with trie hacks. diff --git a/core/AdminCache.h b/core/AdminCache.h index e75e653d..c1ba0e88 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -35,7 +35,7 @@ struct AdminGroup uint32_t magic; /* Magic flag, for memory validation (ugh) */ bool immune_global; /* Global immunity? */ bool immune_default; /* Default immunity? */ - /* Immune from target table (-1 = nonexistant) + /* Immune from target table (-1 = nonexistent) * [0] = number of entries * [1...N] = immune targets */ @@ -70,8 +70,8 @@ struct AdminUser unsigned int grp_count; /* Number of groups */ unsigned int grp_size; /* Size of groups table */ int grp_table; /* Group table itself */ - int next_user; /* Next user in ze list */ - int prev_user; /* Prev user in the list */ + int next_user; /* Next user in the list */ + int prev_user; /* Previous user in the list */ UserAuth auth; /* Auth method for this user */ bool immune_global; /* Whether globally immune */ bool immune_default; /* Whether defaultly immune */ diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index e7a54e06..ed04aa6f 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -910,7 +910,7 @@ void _IntExt_CallYams() { if (strcasecmp(arg, "mock") == 0) { - g_RootMenu.ConsolePrint("You mock BAILOPAN's pronounciation. In a fit of rage, "); + g_RootMenu.ConsolePrint("You mock BAILOPAN's pronunciation. In a fit of rage, "); g_RootMenu.ConsolePrint("he sticks an INT 3 call into your chest, rendering you broken."); g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER."); g_yam_state = 0; diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 3f669e86..e298711c 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -301,7 +301,7 @@ Handle_t ConVarManager::FindConVar(const char *name) /* If we don't have a handle, then create a new one */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); - /* Create and initilize ConVarInfo structure */ + /* Create and initialize ConVarInfo structure */ pInfo = new ConVarInfo(); pInfo->handle = hndl; pInfo->sourceMod = false; diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index f969b271..d64fd671 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -79,7 +79,7 @@ void CoreConfig::Initialize() } /* Format path to config file */ - g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetModPath(), corecfg); + g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg); /* Parse config file */ if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay) diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index a6a22300..ac26aa5c 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -301,7 +301,7 @@ void GameConfigManager::OnSourceModStartup(bool late) { LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); - strncopy(g_mod, g_SourceMod.GetModFolderName(), sizeof(g_mod)); + strncopy(g_mod, g_SourceMod.GetGameFolderName(), sizeof(g_mod)); } void GameConfigManager::OnSourceModAllInitialized() diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 97551376..3f3c16bc 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -72,7 +72,7 @@ CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; void CHalfLife2::OnSourceModStartup(bool late) { /* The Ship currently is the only known game to use an older version of the engine */ - if (strcasecmp(g_SourceMod.GetModFolderName(), "ship") == 0) + if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0) { /* :TODO: Better engine versioning - perhaps something added to SourceMM? */ g_IsOriginalEngine = true; diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index b5367e9d..44163e11 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -158,7 +158,7 @@ void PlayerManager::RunAuthChecks() /* Clean up the queue */ if (removed) { - /* We don't have to compcat the list if it's empty */ + /* We don't have to compact the list if it's empty */ if (removed != m_AuthQueue[0]) { unsigned int diff = 0; diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 24c003b1..c7dbfa4e 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -21,7 +21,7 @@ * Double Array Trie algorithm, based on: * An Efficient Implementation of Trie Structures, by * Jun-ichi Aoe and Katsushi Maromoto, and Takashi Sato - * from Sofiware - Practice and Experience, Vol. 22(9), 695-721 (September 1992) + * from Software - Practice and Experience, Vol. 22(9), 695-721 (September 1992) * * A Trie is a simple data structure which stores strings as DFAs, with each * transition state being a string entry. For example, observe the following strings: @@ -47,7 +47,7 @@ * * BASE[] is an array where each member is a node in the Trie. The node can either be UNUSED (empty), an ARC * (containing an offset to the next set of ARCs), or a TERMINATOR (contains the rest of a string). - * Each node has an index which must be interpeted based on the node type. If the node is a TERMINATOR, then the + * Each node has an index which must be interpreted based on the node type. If the node is a TERMINATOR, then the * index is an index into a string table, to find the rest of the string. * If the node is an ARC, the index is another index into BASE. For each possible token that can follow the * current token, the value of those tokens can be added to the index given in the ARC. Thus, given a current diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 709bb12e..da95ccf6 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -142,7 +142,7 @@ static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params) static cell_t GetGameFolderName(IPluginContext *pContext, const cell_t *params) { - const char *name = g_SourceMod.GetModFolderName(); + const char *name = g_SourceMod.GetGameFolderName(); size_t numBytes; pContext->StringToLocalUTF8(params[1], params[2], name, &numBytes); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 15c09a05..af31ef5d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -449,7 +449,7 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c const char *base = NULL; if (type == Path_Game) { - base = GetModPath(); + base = GetGamePath(); } else if (type == Path_SM) { base = GetSourceModPath(); } else if (type == Path_SM_Rel) { @@ -580,7 +580,7 @@ const char *SourceModBase::GetSourceModPath() const return m_SMBaseDir; } -const char *SourceModBase::GetModPath() const +const char *SourceModBase::GetGamePath() const { return g_BaseDir.c_str(); } @@ -625,7 +625,7 @@ Handle_t SourceModBase::GetDataPackHandleType(bool readonly) return 0; } -const char *SourceModBase::GetModFolderName() const +const char *SourceModBase::GetGameFolderName() const { return m_ModDir; } diff --git a/core/sourcemod.h b/core/sourcemod.h index ff1cf734..3564ef00 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -84,7 +84,7 @@ public: // SMGlobalClass char *error, size_t maxlength); public: // ISourceMod - const char *GetModPath() const; + const char *GetGamePath() const; const char *GetSourceModPath() const; size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); void LogMessage(IExtension *pExt, const char *format, ...); @@ -94,7 +94,7 @@ public: // ISourceMod void FreeDataPack(IDataPack *pack); HandleType_t GetDataPackHandleType(bool readonly=false); KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false); - const char *GetModFolderName() const; + const char *GetGameFolderName() const; private: /** * @brief Loading plugins diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index dc2a650e..12daf0de 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,4 +1,4 @@ -/** +Genesis/** * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. @@ -22,7 +22,7 @@ CForwardManager g_Forwards; /** - * Gensis turns to its source, reduction occurs stepwise although the essence is all one. + * Genesis turns to its source, reduction occurs stepwise although the essence is all one. * End of line. FTL system check. * * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 819cd1c0..826c88b7 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -157,7 +157,7 @@ protected: bool identity=false); /** - * Frees a primitive handle. Does no object freeing, only reference count, bookkeepping, + * Frees a primitive handle. Does no object freeing, only reference count, bookkeeping, * and linked list maintenance. * If used on an Identity handle, destroys all Handles under that identity. */ diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index ea247439..1aa121b3 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -148,12 +148,12 @@ namespace SourceMod typedef int AdminId; /** - * @brief Represents an invalid/nonexistant group or an erroneous operation. + * @brief Represents an invalid/nonexistent group or an erroneous operation. */ #define INVALID_GROUP_ID -1 /** - * @brief Represents an invalid/nonexistant user or an erroneous operation. + * @brief Represents an invalid/nonexistent user or an erroneous operation. */ #define INVALID_ADMIN_ID -1 @@ -571,12 +571,12 @@ namespace SourceMod * @brief Checks whether an AdminId can target another AdminId. * * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails. - * First, if the targetted AdminId is INVALID_ADMIN_ID, targeting succeeds. - * Second, if the targeting admin is root, targeting suceeds. - * Third, if the targetted admin has global immunity, targeting fails. - * Fourth, if the targetted admin has default immunity, + * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. + * Second, if the targeting admin is root, targeting succeeds. + * Third, if the targeted admin has global immunity, targeting fails. + * Fourth, if the targeted admin has default immunity, * and the admin belongs to no groups, targeting fails. - * Fifth, if the targetted admin has specific immunity from the + * Fifth, if the targeted admin has specific immunity from the * targeting admin via group immunities, targeting fails. * Sixth, targeting succeeds if it passes these tests. * diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index b3e76250..8dfab75d 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -175,7 +175,7 @@ namespace SourceMod } /** - * @brief Return false to tell Core that your extension should be considered unsable. + * @brief Return false to tell Core that your extension should be considered usable. * * @param error Error buffer. * @param maxlength Size of error buffer. diff --git a/public/IForwardSys.h b/public/IForwardSys.h index ab3d553b..05b9b470 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -208,9 +208,9 @@ namespace SourceMod /** * @brief Adds a function to the call list. - * NOTE: Cannot be used during an incompleted call. + * NOTE: Cannot be used during an incomplete call. * NOTE: If used during a call, function is temporarily queued until calls are over. - * NOTE: Adding mulitple copies of the same function is illegal. + * NOTE: Adding multiple copies of the same function is illegal. * * @param func Function to add. * @return True on success, otherwise false. @@ -219,7 +219,7 @@ namespace SourceMod /** * @brief Adds a function to the call list. - * NOTE: Cannot be used during an incompleted call. + * NOTE: Cannot be used during an incomplete call. * NOTE: If used during a call, function is temporarily queued until calls are over. * * @param ctx Context to use as a look-up. diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 4fed6ef8..252e3b20 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -176,7 +176,7 @@ namespace SourceMod } /** - * @brief Called when a client has recieved authorization. + * @brief Called when a client has received authorization. * * @param client Index of the client. * @param authstring Authorization string. diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 9263c327..1291130d 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -20,7 +20,7 @@ /** * @file ISourceMod.h - * @brief Defines miscellanious helper functions useful to extensions. + * @brief Defines miscellaneous helper functions useful to extensions. */ #include @@ -64,11 +64,11 @@ namespace SourceMod } public: /** - * @brief Returns the full path to the mod directory. + * @brief Returns the full path to the game directory. * - * @return A string containing the full mod path. + * @return A string containing the full game path. */ - virtual const char *GetModPath() const =0; + virtual const char *GetGamePath() const =0; /** * @brief Returns the full path to the SourceMod directory. @@ -111,7 +111,7 @@ namespace SourceMod * @brief Formats a string from a native. * * @param buffer Buffer to store message. - * @param maxlength Maximum length of buffer (inculding null terminator). + * @param maxlength Maximum length of buffer (including null terminator). * @param pContext Pointer to the plugin's context. * @param params Parameter array that was passed to the native. * @param param Parameter index where format string and variable arguments begin. @@ -141,12 +141,12 @@ namespace SourceMod /** * @brief Returns the automated data pack handle type. * - * The readonly data type is the parent of the writable type. + * The read-only data type is the parent of the writable type. * Note that calling CloseHandle() on either type will release the data pack. - * The readonly type is inheritable, but due to limitations of the Handle System, + * The read-only type is inheritable, but due to limitations of the Handle System, * the writable type is not. * - * @param readonly If true, the readonly type will be returned. + * @param readonly If true, the read-only type will be returned. * @return The Handle type for storing generic data packs. */ virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; @@ -163,11 +163,11 @@ namespace SourceMod virtual KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false) =0; /** - * @brief Returns the name of the directory in which the mod or game's gameinfo.txt resides. + * @brief Returns the name of the game directory. * - * @return A string containing the name of the mod directory. + * @return A string containing the name of the game directory. */ - virtual const char *GetModFolderName() const =0; + virtual const char *GetGameFolderName() const =0; }; } diff --git a/public/ITextParsers.h b/public/ITextParsers.h index 923c65cd..ef4880a8 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -50,7 +50,7 @@ namespace SourceMod * Where KEY is an IDENTIFIER and VALUE is a STRING. * * WHITESPACE should always be omitted. - * COMMENTS should be stripped, and are defined as text occuring in: + * COMMENTS should be stripped, and are defined as text occurring in: * ; * * Example file below. Note that @@ -161,7 +161,7 @@ namespace SourceMod * For an example, see configs/permissions.cfg * * WHITESPACE should be ignored. - * Comments are text occuring inside the following tokens, and should be stripped + * Comments are text occurring inside the following tokens, and should be stripped * unless they are inside literal strings: * ; * // @@ -308,7 +308,7 @@ namespace SourceMod * @param ini_listener Event handler for reading file. * @param line If non-NULL, will contain last line parsed (0 if file could not be opened). * @param col If non-NULL, will contain last column parsed (undefined if file could not be opened). - * @return True if parsing succeded, false if file couldn't be opened or there was a syntax error. + * @return True if parsing succeeded, false if file couldn't be opened or there was a syntax error. */ virtual bool ParseFile_INI(const char *file, ITextListener_INI *ini_listener, @@ -333,7 +333,7 @@ namespace SourceMod unsigned int *col) =0; /** - * @brief Converts an SMCParseError to a stirng. + * @brief Converts an SMCParseError to a string. * * @param err SMCParseError. * @return String error message, or NULL if none. diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 7d73bf33..4c3e1be5 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -45,7 +45,7 @@ typedef uint32_t funcid_t; /**< Function index code */ #define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */ #define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */ #define SP_ERROR_INDEX 7 /**< Invalid index parameter */ -#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */ +#define SP_ERROR_STACKLOW 8 /**< Not enough space left on the stack */ #define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */ #define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */ #define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */ @@ -220,7 +220,7 @@ typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; typedef struct sp_debug_symbol_s { uint32_t codestart; /**< Relocated code address */ - uint32_t codeend; /**< relocated code end address */ + uint32_t codeend; /**< Relocated code end address */ const char * name; /**< Relocated name */ sp_debug_arraydim_t *dims; /**< Relocated dimension struct, if any */ sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */ From dc6a5fc4d9e04635f819b5f6f39cbc4a660cd6a0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 3 May 2007 03:54:44 +0000 Subject: [PATCH 0705/1664] This averted my eyes... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40736 --- core/systems/ForwardSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 12daf0de..5087f253 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -1,4 +1,4 @@ -Genesis/** +/** * vim: set ts=4 : * =============================================================== * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. From 44d1ea5f09d52d4dcce4d7cf6069577dfec8419b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 May 2007 05:26:10 +0000 Subject: [PATCH 0706/1664] added LANG_ENGLISH define --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40737 --- core/Translator.h | 1 + 1 file changed, 1 insertion(+) diff --git a/core/Translator.h b/core/Translator.h index 63498f62..9f3d2625 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -23,6 +23,7 @@ #include "ITextParsers.h" #define MAX_TRANSLATE_PARAMS 32 +#define LANG_ENGLISH 0 /* :TODO: write a templatized version of tries? */ From 01b04327765ad4e1070d7077da8dabb4213ba1f2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 May 2007 05:27:22 +0000 Subject: [PATCH 0707/1664] changed LANG_ENGLISH to CORELANG_ENGLISH --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40738 --- core/Translator.h | 2 +- core/sm_stringutil.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Translator.h b/core/Translator.h index 9f3d2625..065b48cb 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -23,7 +23,7 @@ #include "ITextParsers.h" #define MAX_TRANSLATE_PARAMS 32 -#define LANG_ENGLISH 0 +#define CORELANG_ENGLISH 0 /* :TODO: write a templatized version of tries? */ diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 5fbab016..8b6b8363 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -39,9 +39,9 @@ size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const cha TransError err; err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans); - if (err != Trans_Okay && g_Translator.GetServerLanguage() != LANG_ENGLISH) + if (err != Trans_Okay && g_Translator.GetServerLanguage() != CORELANG_ENGLISH) { - err = g_pCorePhrases->GetTranslation(phrase, LANG_ENGLISH, &pTrans); + err = g_pCorePhrases->GetTranslation(phrase, CORELANG_ENGLISH, &pTrans); } if (err != Trans_Okay) From d8c7af77a36530f154136150c7914c5f213b4f44 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 May 2007 01:28:08 +0000 Subject: [PATCH 0708/1664] exposed the sourcepawn and JIT interfaces with pointers --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40739 --- core/sourcemod.cpp | 10 ++++++++++ core/sourcemod.h | 2 ++ public/ISourceMod.h | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index af31ef5d..8de6ab61 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -630,6 +630,16 @@ const char *SourceModBase::GetGameFolderName() const return m_ModDir; } +ISourcePawnEngine *SourceModBase::GetScriptingEngine() +{ + return g_pSourcePawn; +} + +IVirtualMachine *SourceModBase::GetScriptingVM() +{ + return g_pVM; +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index 3564ef00..6f3460bf 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -95,6 +95,8 @@ public: // ISourceMod HandleType_t GetDataPackHandleType(bool readonly=false); KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false); const char *GetGameFolderName() const; + ISourcePawnEngine *GetScriptingEngine(); + IVirtualMachine *GetScriptingVM(); private: /** * @brief Loading plugins diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 1291130d..c983baf0 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -168,6 +168,20 @@ namespace SourceMod * @return A string containing the name of the game directory. */ virtual const char *GetGameFolderName() const =0; + + /** + * @brief Returns the scripting engine interface. + * + * @return A pointer to the scripting engine interface. + */ + virtual SourcePawn::ISourcePawnEngine *GetScriptingEngine() =0; + + /** + * @brief Returns the JIT interface. + * + * @return A pointer to the JIT interface. + */ + virtual SourcePawn::IVirtualMachine *GetScriptingVM() =0; }; } From 1f97a66fbf40c00b42415a7b3aa0468709c3e32c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 4 May 2007 02:36:11 +0000 Subject: [PATCH 0709/1664] fixed makefile for jit/sp stuff --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40740 --- public/sample_ext/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/sample_ext/Makefile b/public/sample_ext/Makefile index 22ff9208..e65ffeb1 100644 --- a/public/sample_ext/Makefile +++ b/public/sample_ext/Makefile @@ -36,7 +36,7 @@ INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/t -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ -CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti ################################################ From 539d09c9b0a9561971766e61dd3e5b3c48d0bd8d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 4 May 2007 02:45:10 +0000 Subject: [PATCH 0710/1664] bumped version no --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40741 --- public/ISourceMod.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/ISourceMod.h b/public/ISourceMod.h index c983baf0..69c1596c 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -28,7 +28,7 @@ #include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" -#define SMINTERFACE_SOURCEMOD_VERSION 2 +#define SMINTERFACE_SOURCEMOD_VERSION 3 /** * @brief Forward declaration of the KeyValues class. From b91f1b21ba09bc16f72d63c31e4e39d8f97cbc6b Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 May 2007 20:03:51 +0000 Subject: [PATCH 0711/1664] fixed bug in amb249 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40742 --- core/systems/PluginSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 0c0886c1..fbfa8ee9 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -300,7 +300,7 @@ void CPlugin::Call_OnPluginStart() void CPlugin::Call_OnPluginEnd() { - if (m_status < Plugin_Paused) + if (m_status > Plugin_Paused) { return; } From cc7a4904c50bda60844b2e5c85c6d51d9769aff4 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 4 May 2007 20:52:35 +0000 Subject: [PATCH 0712/1664] Added missing return... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40743 --- core/ConCmdManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index ed04aa6f..77d43e9b 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -803,6 +803,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argco { NotifyExecDone(NULL); } + return; } int id = atoi(text); From 1205de4e6798a5a7956854046430a38ae467d3ff Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 4 May 2007 21:21:55 +0000 Subject: [PATCH 0713/1664] Normal daily and error logs now use YYYYMMDD date format in their file names (like AMXX 1.8 will) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40744 --- core/Logger.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/Logger.cpp b/core/Logger.cpp index 5ffea1c4..9433afc1 100644 --- a/core/Logger.cpp +++ b/core/Logger.cpp @@ -107,7 +107,7 @@ void Logger::_NewMapFile() while (true) { - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i); FILE *fp = fopen(_filename, "r"); if (!fp) { @@ -127,7 +127,7 @@ void Logger::_NewMapFile() } else { char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); - fprintf(fp, "L %s: SourceMod log file started (file \"logs_%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SVN_FULL_VERSION); + fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SVN_FULL_VERSION); fclose(fp); } } @@ -177,7 +177,7 @@ void Logger::InitLogger(LoggingMode mode) m_CurDay = curtime->tm_mday; char _filename[256]; - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%02d%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); m_ErrFileName.assign(_filename); switch (m_Mode) @@ -192,7 +192,7 @@ void Logger::InitLogger(LoggingMode mode) } case LoggingMode_Daily: { - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_DailyPrintHdr = true; break; @@ -261,7 +261,7 @@ void Logger::LogMessage(const char *vafmt, ...) if (m_CurDay != curtime->tm_mday) { char _filename[256]; - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/logs_%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); m_NrmFileName.assign(_filename); m_CurDay = curtime->tm_mday; m_DailyPrintHdr = true; @@ -274,7 +274,7 @@ void Logger::LogMessage(const char *vafmt, ...) if (m_DailyPrintHdr) { m_DailyPrintHdr = false; - fprintf(fp, "L %s: SourceMod log file session started (file \"logs_%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, SVN_FULL_VERSION); + fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SVN_FULL_VERSION); } fprintf(fp, "L %s: %s\n", date, msg); fclose(fp); @@ -306,7 +306,7 @@ void Logger::LogError(const char *vafmt, ...) if (curtime->tm_mday != m_CurDay) { char _filename[256]; - g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%02d%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); m_ErrFileName.assign(_filename); m_CurDay = curtime->tm_mday; m_ErrMapStart = false; @@ -324,7 +324,7 @@ void Logger::LogError(const char *vafmt, ...) if (!m_ErrMapStart) { fprintf(fp, "L %s: SourceMod error session started\n", date); - fprintf(fp, "L %s: Info (map \"%s\") (log file \"errors_%02d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_mon + 1, curtime->tm_mday, curtime->tm_year - 100); + fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); m_ErrMapStart = true; } fprintf(fp, "L %s: %s\n", date, msg); From 1592f77fc309a0e16741a726f954832e623c42d6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 May 2007 21:39:05 +0000 Subject: [PATCH 0714/1664] added new function calling module, wow --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40745 --- extensions/bintools/CallMaker.cpp | 52 ++ extensions/bintools/CallMaker.h | 48 ++ extensions/bintools/CallWrapper.cpp | 91 ++++ extensions/bintools/CallWrapper.h | 58 +++ extensions/bintools/Makefile | 87 ++++ extensions/bintools/extension.cpp | 39 ++ extensions/bintools/extension.h | 86 +++ extensions/bintools/jit_call.cpp | 609 ++++++++++++++++++++++ extensions/bintools/jit_call.h | 27 + extensions/bintools/msvc8/bintools.sln | 20 + extensions/bintools/msvc8/bintools.vcproj | 253 +++++++++ extensions/bintools/smsdk_config.h | 33 ++ extensions/bintools/smsdk_ext.cpp | 333 ++++++++++++ extensions/bintools/smsdk_ext.h | 196 +++++++ public/extensions/IBinTools.h | 178 +++++++ public/jit/x86/x86_macros.h | 91 ++++ 16 files changed, 2201 insertions(+) create mode 100644 extensions/bintools/CallMaker.cpp create mode 100644 extensions/bintools/CallMaker.h create mode 100644 extensions/bintools/CallWrapper.cpp create mode 100644 extensions/bintools/CallWrapper.h create mode 100644 extensions/bintools/Makefile create mode 100644 extensions/bintools/extension.cpp create mode 100644 extensions/bintools/extension.h create mode 100644 extensions/bintools/jit_call.cpp create mode 100644 extensions/bintools/jit_call.h create mode 100644 extensions/bintools/msvc8/bintools.sln create mode 100644 extensions/bintools/msvc8/bintools.vcproj create mode 100644 extensions/bintools/smsdk_config.h create mode 100644 extensions/bintools/smsdk_ext.cpp create mode 100644 extensions/bintools/smsdk_ext.h create mode 100644 public/extensions/IBinTools.h diff --git a/extensions/bintools/CallMaker.cpp b/extensions/bintools/CallMaker.cpp new file mode 100644 index 00000000..2a966fa9 --- /dev/null +++ b/extensions/bintools/CallMaker.cpp @@ -0,0 +1,52 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "CallMaker.h" +#include "CallWrapper.h" +#include "jit_call.h" + +ICallWrapper *CallMaker::CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) +{ + CallWrapper *pWrapper = new CallWrapper(cv, paramInfo, retInfo, numParams); + pWrapper->m_Addrs[ADDR_CALLEE] = address; + + JIT_Compile(pWrapper, FuncAddr_Direct); + + return pWrapper; +} + +ICallWrapper *CallMaker::CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) +{ + CallWrapper *pWrapper = new CallWrapper(CallConv_ThisCall, paramInfo, retInfo, numParams); + pWrapper->m_VtInfo.thisOffs = thisOffs; + pWrapper->m_VtInfo.vtblIdx = vtblIdx; + pWrapper->m_VtInfo.vtblOffs = vtblOffs; + + JIT_Compile(pWrapper, FuncAddr_VTable); + + return pWrapper; +} \ No newline at end of file diff --git a/extensions/bintools/CallMaker.h b/extensions/bintools/CallMaker.h new file mode 100644 index 00000000..d142a683 --- /dev/null +++ b/extensions/bintools/CallMaker.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CALLMAKER_H_ +#define _INCLUDE_SOURCEMOD_CALLMAKER_H_ + +#include + +using namespace SourceMod; + +enum FuncAddrMethod +{ + FuncAddr_Direct, + FuncAddr_VTable +}; + +class CallMaker : public IBinTools +{ +public: //IBinTools + ICallWrapper *CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams); + ICallWrapper *CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams); +}; + +#endif //_INCLUDE_SOURCEMOD_CALLMAKER_H_ diff --git a/extensions/bintools/CallWrapper.cpp b/extensions/bintools/CallWrapper.cpp new file mode 100644 index 00000000..15018160 --- /dev/null +++ b/extensions/bintools/CallWrapper.cpp @@ -0,0 +1,91 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "extension.h" +#include "CallWrapper.h" + +CallWrapper::CallWrapper(CallConvention cv, const PassInfo *paramInfo, const PassInfo *retInfo, unsigned int numParams) +{ + m_Cv = cv; + + if (numParams) + { + m_Params = new PassEncode[numParams]; + for (size_t i=0; iExecFree(m_Addrs[ADDR_CODEBASE]); +} + +CallConvention CallWrapper::GetCallConvention() +{ + return m_Cv; +} + +const PassEncode *CallWrapper::GetParamInfo(unsigned int num) +{ + return (num+1 > m_NumParams) ? NULL : &m_Params[num]; +} + +const PassInfo *CallWrapper::GetReturnInfo() +{ + return m_RetParam; +} + +unsigned int CallWrapper::GetParamCount() +{ + return m_NumParams; +} + +void CallWrapper::Execute(void *vParamStack, void *retBuffer) +{ + typedef void (*CALL_EXECUTE)(void *, void *); + CALL_EXECUTE fn = (CALL_EXECUTE)m_Addrs[ADDR_CODEBASE]; + fn(vParamStack, retBuffer); +} diff --git a/extensions/bintools/CallWrapper.h b/extensions/bintools/CallWrapper.h new file mode 100644 index 00000000..397ee7f0 --- /dev/null +++ b/extensions/bintools/CallWrapper.h @@ -0,0 +1,58 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ +#define _INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ + +#include + +using namespace SourceMod; + +#define ADDR_CALLEE 0 +#define ADDR_CODEBASE 1 + +struct VtableInfo +{ + unsigned int vtblIdx; + unsigned int vtblOffs; + unsigned int thisOffs; +}; + +class CallWrapper : public ICallWrapper +{ +public: + CallWrapper(CallConvention cv, const PassInfo *paramInfo, const PassInfo *retInfo, unsigned int numParams); + ~CallWrapper(); +public: //ICallWrapper + CallConvention GetCallConvention(); + const PassEncode *GetParamInfo(unsigned int num); + const PassInfo *GetReturnInfo(); + unsigned int GetParamCount(); + void Execute(void *vParamStack, void *retBuffer); +public: + inline void deleteThis() { delete this; } + void *m_Addrs[4]; + VtableInfo m_VtInfo; +private: + CallConvention m_Cv; + PassEncode *m_Params; + PassInfo *m_RetParam; + unsigned int m_NumParams; +}; + +#endif //_INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ \ No newline at end of file diff --git a/extensions/bintools/Makefile b/extensions/bintools/Makefile new file mode 100644 index 00000000..e65ffeb1 --- /dev/null +++ b/extensions/bintools/Makefile @@ -0,0 +1,87 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = sample + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/extensions/bintools/extension.cpp b/extensions/bintools/extension.cpp new file mode 100644 index 00000000..e1786feb --- /dev/null +++ b/extensions/bintools/extension.cpp @@ -0,0 +1,39 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "extension.h" +#include "CallMaker.h" + +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + +BinTools g_BinTools; /**< Global singleton for your extension's main interface */ +CallMaker g_CallMaker; +ISourcePawnEngine *g_SPEngine; + +SMEXT_LINK(&g_BinTools); + +bool BinTools::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + g_SPEngine = g_pSM->GetScriptingEngine(); + g_pShareSys->AddInterface(myself, &g_CallMaker); + + return true; +} diff --git a/extensions/bintools/extension.h b/extensions/bintools/extension.h new file mode 100644 index 00000000..148e1e16 --- /dev/null +++ b/extensions/bintools/extension.h @@ -0,0 +1,86 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +/** + * @file extension.h + * @brief Sample extension code header. + */ + + +#include "smsdk_ext.h" + + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class BinTools : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + //virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual void QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * Read smext_base.h for documentation on these. + */ + + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif +}; + +extern ISourcePawnEngine *g_SPEngine; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp new file mode 100644 index 00000000..f756c75b --- /dev/null +++ b/extensions/bintools/jit_call.cpp @@ -0,0 +1,609 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include "extension.h" +#include +#include +#include "jit_call.h" + +jit_uint32_t g_StackUsage = 0; +jit_uint32_t g_RegDecoder = 0; + +/******************** + * Assembly Helpers * + ********************/ + +inline jit_uint8_t _DecodeRegister3(jit_uint32_t val) +{ + switch (val % 3) + { + case 0: + { + return REG_EAX; + } + case 1: + { + return REG_EDX; + } + case 2: + { + return REG_ECX; + } + } + + /* Should never happen */ + return 0xFF; +} + +/******************** + * Assembly Opcodes * + ********************/ + +inline void Write_Execution_Prologue(JitWriter *jit, bool is_void, bool has_params) +{ + //push ebp + //mov ebp, esp + //if !is_void + // push edi + // mov edi, [ebp+12] + //if has_params + // push ebx + // mov ebx, [ebp+8] + IA32_Push_Reg(jit, REG_EBP); + IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG); + if (!is_void) + { + IA32_Push_Reg(jit, REG_EDI); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EBP, 12); + } + if (has_params) + { + IA32_Push_Reg(jit, REG_EBX); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EBX, REG_EBP, 8); + } +} + +inline void Write_Function_Epilogue(JitWriter *jit, bool is_void, bool has_params) +{ + //if has_params + // pop ebx + //if !is_void + // pop edi + //mov esp, ebp + //pop ebp + //ret + if (has_params) + { + IA32_Pop_Reg(jit, REG_EBX); + } + if (!is_void) + { + IA32_Pop_Reg(jit, REG_EDI); + } + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBP, MOD_REG); + IA32_Pop_Reg(jit, REG_EBP); + IA32_Return(jit); +} + +inline void Write_PushPOD(JitWriter *jit, const PassEncode *pEnc) +{ + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + + if (pEnc->info.flags & PASSFLAG_BYVAL) + { + switch (pEnc->info.size) + { + case 1: + { + //xor reg, reg + //mov reg, BYTE PTR [ebx+] + //push reg + IA32_Xor_Reg_Rm(jit, reg, reg, MOD_REG); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg8_Rm8_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg8_Rm8(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg8_Rm8_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 2: + { + //xor reg, reg + //mov reg, WORD PTR [ebx+] + //push reg + IA32_Xor_Reg_Rm(jit, reg, reg, MOD_REG); + jit->write_ubyte(IA32_16BIT_PREFIX); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 4: + { + //mov reg, DWORD PTR [ebx+] + //push reg + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 8: + { + //mov reg, DWORD PTR [ebx++4] + //mov reg2, DWORD PTR [ebx+] + //push reg + //push reg2 + jit_uint8_t reg2 = _DecodeRegister3(g_RegDecoder++); + + if (pEnc->offset+4 < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)(pEnc->offset+4)); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset+4); + } + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg2, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg2, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + IA32_Push_Reg(jit, reg2); + + g_StackUsage += 8; + break; + } + } + } else if (pEnc->info.flags & PASSFLAG_BYREF) { + //lea reg, [ebx+] + //push reg + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushFloat(JitWriter *jit, const PassEncode *pEnc) +{ + if (pEnc->info.flags & PASSFLAG_BYVAL) + { + switch (pEnc->info.size) + { + case 4: + { + //fld DWORD PTR [ebx+] + //push reg + //fstp DWORD PTR [esp] + if (pEnc->offset < SCHAR_MAX) + { + IA32_Fld_Mem32_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Fld_Mem32_Disp32(jit, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, _DecodeRegister3(g_RegDecoder++)); + IA32_Fstp_Mem32(jit, REG_ESP, REG_NOIDX, NOSCALE); + g_StackUsage += 4; + break; + } + case 8: + { + //fld QWORD PTR [ebx+] + //sub esp, 8 + //fstp QWORD PTR [esp] + if (pEnc->offset < SCHAR_MAX) + { + IA32_Fld_Mem64_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Fld_Mem64_Disp32(jit, REG_EBX, pEnc->offset); + } + IA32_Sub_Rm_Imm8(jit, REG_ESP, 8, MOD_REG); + IA32_Fstp_Mem64(jit, REG_ESP, REG_NOIDX, NOSCALE); + g_StackUsage += 8; + break; + } + } + } else if (pEnc->info.flags & PASSFLAG_BYREF) { + //lea reg, [ebx+] + //push reg + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushObject(JitWriter *jit, const PassEncode *pEnc) +{ + if (pEnc->info.flags & PASSFLAG_BYVAL) + { +#ifdef PLATFORM_POSIX + if (pEnc->info.flags & PASSFLAG_ODTOR) + { + goto push_byref; + } +#endif + jit_uint32_t dwords = pEnc->info.size >> 2; + jit_uint32_t bytes = pEnc->info.size & 0x3; + + //sub esp, + //cld + //push edi + //push esi + //lea edi, [esp+8] + //lea esi, [ebx+] + //if dwords + // mov ecx, + // rep movsd + //if bytes + // mov ecx, + // rep movsb + //pop esi + //pop edi + if (pEnc->info.size < SCHAR_MAX) + { + IA32_Sub_Rm_Imm8(jit, REG_ESP, (jit_int8_t)pEnc->info.size, MOD_REG); + } else { + IA32_Sub_Rm_Imm32(jit, REG_ESP, pEnc->info.size, MOD_REG); + } + IA32_Cld(jit); + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_ESI); + IA32_Lea_Reg_DispRegMultImm8(jit, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, REG_ESI, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, REG_ESI, REG_EBX, MOD_REG); + } else { + IA32_Lea_DispRegImm32(jit, REG_ESI, REG_EBX, pEnc->offset); + } + if (dwords) + { + IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords); + IA32_Rep(jit); + IA32_Movsd(jit); + } + if (bytes) + { + IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes); + IA32_Rep(jit); + IA32_Movsb(jit); + } + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EDI); + + g_StackUsage += pEnc->info.size; + } else if (pEnc->info.flags & PASSFLAG_BYREF) { +#ifdef PLATFORM_POSIX +push_byref: +#endif + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + + //lea reg, [ebx+] + //push reg + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushThisPtr(JitWriter *jit) +{ +#ifdef PLATFORM_POSIX + //mov reg, [ebx] + //push reg + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; +#elif defined PLATFORM_WINDOWS + //mov ecx, [ebx] + IA32_Mov_Reg_Rm(jit, REG_ECX, REG_EBX, MOD_MEM_REG); +#endif +} + +inline void Write_PushRetBuffer(JitWriter *jit) +{ + //push edi + IA32_Push_Reg(jit, REG_EDI); +} + +inline void Write_CallFunction(JitWriter *jit, FuncAddrMethod method, CallWrapper *pWrapper) +{ + if (method == FuncAddr_Direct) + { + //call + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, pWrapper->m_Addrs[ADDR_CALLEE]); + } else if (method == FuncAddr_VTable) { + //*(this + thisOffs + vtblOffs)[vtblIdx] + //mov edx, [ebx] + //mov eax, [edx++] + //mov edx, [eax+*4] + //call edx + jit_uint32_t total_offs = pWrapper->m_VtInfo.thisOffs + pWrapper->m_VtInfo.vtblOffs; + jit_uint32_t vfunc_pos = pWrapper->m_VtInfo.vtblIdx * 4; + + IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EBX, MOD_MEM_REG); + if (total_offs < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, (jit_int8_t)total_offs); + } else if (!total_offs) { + IA32_Mov_Reg_Rm(jit, REG_EAX, REG_EDX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, REG_EAX, REG_EDX, total_offs); + } + if (vfunc_pos < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, (jit_int8_t)vfunc_pos); + } else if (!vfunc_pos) { + IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EAX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, REG_EDX, REG_EAX, vfunc_pos); + } + IA32_Call_Reg(jit, REG_EDX); + } +} + +inline void Write_RectifyStack(JitWriter *jit, jit_uint32_t value) +{ + //add esp, + if (value < SCHAR_MAX) + { + IA32_Add_Rm_Imm8(jit, REG_ESP, (jit_int8_t)value, MOD_REG); + } else { + IA32_Add_Rm_Imm32(jit, REG_ESP, value, MOD_REG); + } +} + +inline void Write_MovRet2Buf(JitWriter *jit, const PassInfo *pRet) +{ + if (pRet->type == PassType_Float) + { + switch (pRet->size) + { + case 4: + { + //fstp DWORD PTR [edi] + IA32_Fstp_Mem32(jit, REG_EDI, REG_NOIDX, NOSCALE); + break; + } + case 8: + { + //fstp QWORD PTR [edi] + IA32_Fstp_Mem64(jit, REG_EDI, REG_NOIDX, NOSCALE); + break; + } + } + return; + } + + switch (pRet->size) + { + case 1: + { + //mov BYTE PTR [edi], al + IA32_Mov_Rm8_Reg8(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 2: + { + //mov WORD PTR [edi], ax + jit->write_ubyte(IA32_16BIT_PREFIX); + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 4: + { + //mov DWORD PTR [edi], eax + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 8: + { + //mov DWORD PTR [edi], eax + //mov DWORD PTR [edi+4], edx + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EDI, REG_EDX, 4); + break; + } + } +} + +/****************************** + * Assembly Compiler Function * + ******************************/ + +void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method) +{ + JitWriter writer; + JitWriter *jit = &writer; + + jit_uint32_t CodeSize = 0; + bool Needs_Retbuf = false; + CallConvention Convention = pWrapper->GetCallConvention(); + jit_uint32_t ParamCount = pWrapper->GetParamCount(); + const PassInfo *pRet = pWrapper->GetReturnInfo(); + + writer.outbase = NULL; + writer.outptr = NULL; + +jit_rewind: + /* Write function prologue */ + Write_Execution_Prologue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + + /* Write parameter push code */ + for (jit_int32_t i=ParamCount-1; i>=0; i--) + { + const PassEncode *pEnc = pWrapper->GetParamInfo(i); + switch (pEnc->info.type) + { + case PassType_Basic: + { + Write_PushPOD(jit, pEnc); + break; + } + case PassType_Float: + { + Write_PushFloat(jit, pEnc); + break; + } + case PassType_Object: + { + Write_PushObject(jit, pEnc); + break; + } + } + } + + /* Prepare the this ptr if applicable */ + if (Convention == CallConv_ThisCall) + { + Write_PushThisPtr(jit); + } + + /* Skip the return buffer stuff if this is a void function */ + if (!pRet) + { + goto skip_retbuffer; + } + + if ((pRet->type == PassType_Object) && (pRet->flags & PASSFLAG_BYVAL)) + { +#ifdef PLATFORM_POSIX + Needs_Retbuf = true; +#elif defined PLATFORM_WINDOWS + if ((Convention == CallConv_ThisCall) || + ((Convention == CallConv_Cdecl) && + ((pRet->size > 8) || (pRet->flags & PASSFLAG_ODTOR|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP)))) + { + Needs_Retbuf = true; + } +#endif + } + + /* Prepare the return buffer in case we are returning objects by value. */ + if (Needs_Retbuf) + { + Write_PushRetBuffer(jit); + } + +skip_retbuffer: + /* Write the calling code */ + Write_CallFunction(jit, method, pWrapper); + + /* Clean up the calling stack */ +#ifdef PLATFORM_WINDOWS + if ((ParamCount || Needs_Retbuf) && (Convention == CallConv_Cdecl)) + { + /* Pop all parameters from the stack + hidden return pointer */ + jit_uint32_t total = (Needs_Retbuf) ? g_StackUsage + sizeof(void *) : g_StackUsage; + Write_RectifyStack(jit, total); +#elif defined PLATFORM_POSIX + if (ParamCount) + { + /* Pop all parameters from the stack */ + Write_RectifyStack(jit, g_StackUsage); +#endif + } + + /* Copy the return type to the return buffer if the function is not void */ + if (pRet && !Needs_Retbuf) + { + Write_MovRet2Buf(jit, pRet); + } + + /* Write Function Epilogue */ + Write_Function_Epilogue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + + if (writer.outbase == NULL) + { + CodeSize = writer.get_outputpos(); + writer.outbase = (jitcode_t)g_SPEngine->ExecAlloc(CodeSize); + writer.outptr = writer.outbase; + pWrapper->m_Addrs[ADDR_CODEBASE] = writer.outbase; + g_StackUsage = 0; + g_RegDecoder = 0; + Needs_Retbuf = false; + goto jit_rewind; + } +} diff --git a/extensions/bintools/jit_call.h b/extensions/bintools/jit_call.h new file mode 100644 index 00000000..5efc8a93 --- /dev/null +++ b/extensions/bintools/jit_call.h @@ -0,0 +1,27 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_JIT_CALL_H_ +#define _INCLUDE_SOURCEMOD_JIT_CALL_H_ + +#include "CallMaker.h" +#include "CallWrapper.h" + +void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method); + +#endif //_INCLUDE_SOURCEMOD_JIT_CALL_H_ \ No newline at end of file diff --git a/extensions/bintools/msvc8/bintools.sln b/extensions/bintools/msvc8/bintools.sln new file mode 100644 index 00000000..44048bb2 --- /dev/null +++ b/extensions/bintools/msvc8/bintools.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bintools", "bintools.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/bintools/msvc8/bintools.vcproj b/extensions/bintools/msvc8/bintools.vcproj new file mode 100644 index 00000000..18fece5e --- /dev/null +++ b/extensions/bintools/msvc8/bintools.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/bintools/smsdk_config.h b/extensions/bintools/smsdk_config.h new file mode 100644 index 00000000..dfc8a925 --- /dev/null +++ b/extensions/bintools/smsdk_config.h @@ -0,0 +1,33 @@ +// vim: set ts=4 : +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "Sample Extension" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SAMPLE" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +//#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/bintools/smsdk_ext.cpp b/extensions/bintools/smsdk_ext.cpp new file mode 100644 index 00000000..ed2de4ae --- /dev/null +++ b/extensions/bintools/smsdk_ext.cpp @@ -0,0 +1,333 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + + if (SDK_OnLoad(error, err_max, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/extensions/bintools/smsdk_ext.h b/extensions/bintools/smsdk_ext.h new file mode 100644 index 00000000..d763460e --- /dev/null +++ b/extensions/bintools/smsdk_ext.h @@ -0,0 +1,196 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/public/extensions/IBinTools.h b/public/extensions/IBinTools.h new file mode 100644 index 00000000..a18affea --- /dev/null +++ b/public/extensions/IBinTools.h @@ -0,0 +1,178 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SMEXT_BINTOOLS_H_ +#define _INCLUDE_SMEXT_BINTOOLS_H_ + +#include + +#define SMINTERFACE_BINTOOLS_NAME "IBinTools" +#define SMINTERFACE_BINTOOLS_VERSION 1 + +/** + * @brief Function calling encoding utilities + * @file IBinTools.h + */ + +namespace SourceMod +{ + /** + * @brief Supported calling conventions + */ + enum CallConvention + { + CallConv_ThisCall, /**< This call (object pointer required) */ + CallConv_Cdecl, /**< Standard C call */ + }; + + /** + * @brief Describes how a parameter should be passed + */ + enum PassType + { + PassType_Basic, /**< Plain old register data (pointers, integers) */ + PassType_Float, /**< Floating point data */ + PassType_Object, /**< Object or structure */ + }; + + #define PASSFLAG_BYVAL (1<<0) /**< Passing by value */ + #define PASSFLAG_BYREF (1<<1) /**< Passing by reference */ + #define PASSFLAG_ODTOR (1<<2) /**< Object has a destructor */ + #define PASSFLAG_OCTOR (1<<3) /**< Object has a constructor */ + #define PASSFLAG_OASSIGNOP (1<<4) /**< Object has an assignment operator */ + + /** + * @brief Parameter passing information + */ + struct PassInfo + { + PassType type; /**< PassType value */ + unsigned int flags; /**< Pass/return flags */ + size_t size; /**< Size of the data being passed */ + }; + + /** + * @brief Parameter encoding information + */ + struct PassEncode + { + PassInfo info; /**< Parameter information */ + size_t offset; /**< Offset into the virtual stack */ + }; + + /** + * @brief Wraps a C/C++ call. + */ + class ICallWrapper + { + public: + /** + * @brief Returns the calling convention. + * + * @return CallConvention value. + */ + virtual CallConvention GetCallConvention() =0; + + /** + * @brief Returns parameter info. + * + * @param num Parameter number to get (starting from 0). + * @return A PassInfo pointer. + */ + virtual const PassEncode *GetParamInfo(unsigned int num) =0; + + /** + * @brief Returns return type info. + * + * @return A PassInfo pointer. + */ + virtual const PassInfo *GetReturnInfo() =0; + + /** + * @brief Returns the number of parameters. + */ + virtual unsigned int GetParamCount() =0; + + /** + * @brief Execute the contained function. + */ + virtual void Execute(void *vParamStack, void *retBuffer) =0; + }; + + /** + * @brief Binary tools interface. + */ + class IBinTools : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_BINTOOLS_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_BINTOOLS_VERSION; + } + public: + /** + * @brief Creates a call decoder. + * + * Note: CallConv_ThisCall requires an implicit first parameter + * of PassType_Basic / PASSFLAG_BYVAL / sizeof(void *). However, + * this should only be given to the Execute() function, and never + * listed in the paramInfo array. + * + * @param address Address to use as a call. + * @param cv Calling convention. + * @param retInfo Return type information, or NULL for void. + * @param paramInfo Array of parameters. + * @param numParams Number of parameters in the array. + * @return A new ICallWrapper function. + */ + virtual ICallWrapper *CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) =0; + + /** + * @brief Creates a vtable call decoder. + * + * Note: CallConv_ThisCall requires an implicit first parameter + * of PassType_Basic / PASSFLAG_BYVAL / sizeof(void *). However, + * this should only be given to the Execute() function, and never + * listed in the paramInfo array. + * + * @param vtblIdx Index into the virtual table. + * @param vtblOffs Offset of the virtual table. + * @param thisOffs Offset of the this pointer of the virtual table. + * @param retInfo Return type information, or NULL for void. + * @param paramInfo Array of parameters. + * @param numParams Number of parameters in the array. + * @return A new ICallWrapper function. + */ + virtual ICallWrapper *CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) =0; + }; +} + +#endif //_INCLUDE_SMEXT_BINTOOLS_H_ diff --git a/public/jit/x86/x86_macros.h b/public/jit/x86/x86_macros.h index 0f020b32..7f307a8d 100644 --- a/public/jit/x86/x86_macros.h +++ b/public/jit/x86/x86_macros.h @@ -92,6 +92,8 @@ #define IA32_MOV_RM8_REG 0x88 // encoding is /r #define IA32_MOV_RM_REG 0x89 // encoding is /r #define IA32_MOV_REG_MEM 0x8B // encoding is /r +#define IA32_MOV_REG8_RM8 0x8A // encoding is /r +#define IA32_MOV_RM8_REG8 0x88 // encoding is /r #define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 #define IA32_CMP_RM_IMM32 0x81 // encoding is /7 #define IA32_CMP_RM_IMM8 0x83 // encoding is /7 @@ -149,6 +151,10 @@ #define IA32_POPAD 0x61 // no extra encoding #define IA32_NOP 0x90 // no extra encoding #define IA32_INT3 0xCC // no extra encoding +#define IA32_FSTP_MEM32 0xD9 // encoding is /3 +#define IA32_FSTP_MEM64 0xDD // encoding is /3 +#define IA32_FLD_MEM32 0xD9 // encoding is /0 +#define IA32_FLD_MEM64 0xDD // encoding is /0 inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -629,6 +635,19 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit->write_byte(val); } +inline void IA32_Lea_Reg_DispRegMultImm32(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t scale, + jit_int32_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); + jit->write_int32(val); +} + inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_index, @@ -716,6 +735,12 @@ inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } +inline void IA32_Mov_Reg8_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -723,6 +748,13 @@ inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp); +} + inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -738,6 +770,13 @@ inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_int32(disp); } +inline void IA32_Mov_Reg8_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); + jit->write_int32(disp); +} + inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, @@ -784,6 +823,12 @@ inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_MOV_RM8_REG8); + jit->write_ubyte(ia32_modrm(mode, src, dest)); +} + inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_RM_REG); @@ -890,6 +935,52 @@ inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit, jit->write_int32(val); } +/** +* Floating Point Instructions +*/ + +inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale) +{ + jit->write_ubyte(IA32_FSTP_MEM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + +inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale) +{ + jit->write_ubyte(IA32_FSTP_MEM64); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + +inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(val); +} + +inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(val); +} + /** * Branching/Jumping */ From b97dfd32043e80648f36eb8cf2c3e9fc4822296f Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 May 2007 22:53:40 +0000 Subject: [PATCH 0715/1664] added linux support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40746 --- extensions/bintools/CallMaker.cpp | 2 +- extensions/bintools/CallWrapper.h | 2 +- extensions/bintools/Makefile | 7 ++++--- extensions/bintools/jit_call.h | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/extensions/bintools/CallMaker.cpp b/extensions/bintools/CallMaker.cpp index 2a966fa9..c8941e7e 100644 --- a/extensions/bintools/CallMaker.cpp +++ b/extensions/bintools/CallMaker.cpp @@ -49,4 +49,4 @@ ICallWrapper *CallMaker::CreateVCall(unsigned int vtblIdx, JIT_Compile(pWrapper, FuncAddr_VTable); return pWrapper; -} \ No newline at end of file +} diff --git a/extensions/bintools/CallWrapper.h b/extensions/bintools/CallWrapper.h index 397ee7f0..3e7b2d2e 100644 --- a/extensions/bintools/CallWrapper.h +++ b/extensions/bintools/CallWrapper.h @@ -55,4 +55,4 @@ private: unsigned int m_NumParams; }; -#endif //_INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ \ No newline at end of file +#endif //_INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ diff --git a/extensions/bintools/Makefile b/extensions/bintools/Makefile index e65ffeb1..f87eb55a 100644 --- a/extensions/bintools/Makefile +++ b/extensions/bintools/Makefile @@ -9,12 +9,12 @@ SOURCEMM = ../../../../sourcemm ### EDIT BELOW FOR OTHER PROJECTS ### ##################################### -PROJECT = sample +PROJECT = bintools #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp +OBJECTS = extension.cpp smsdk_ext.cpp jit_call.cpp CallWrapper.cpp CallMaker.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -34,7 +34,8 @@ LINK = $(LINK_HL2) -static-libgcc INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ - -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions -I$(SMSDK)/public/jit \ + -I$(SMSDK)/public/jit/x86 CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti diff --git a/extensions/bintools/jit_call.h b/extensions/bintools/jit_call.h index 5efc8a93..2534600e 100644 --- a/extensions/bintools/jit_call.h +++ b/extensions/bintools/jit_call.h @@ -24,4 +24,4 @@ void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method); -#endif //_INCLUDE_SOURCEMOD_JIT_CALL_H_ \ No newline at end of file +#endif //_INCLUDE_SOURCEMOD_JIT_CALL_H_ From a99485744424378cf10f0336959d02007a63320e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 6 May 2007 03:24:54 +0000 Subject: [PATCH 0716/1664] Couple of random of things --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40747 --- core/systems/ShareSys.h | 2 +- extensions/bintools/msvc8/bintools.vcproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index 829f5ad3..4627ad35 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -48,7 +48,7 @@ public: //IShareSys bool AddInterface(IExtension *myself, SMInterface *pIface); bool RequestInterface(const char *iface_name, unsigned int iface_vers, - IExtension *mysql, + IExtension *myself, SMInterface **pIface); void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives); IdentityType_t CreateIdentType(const char *name); diff --git a/extensions/bintools/msvc8/bintools.vcproj b/extensions/bintools/msvc8/bintools.vcproj index 18fece5e..bc4a9c58 100644 --- a/extensions/bintools/msvc8/bintools.vcproj +++ b/extensions/bintools/msvc8/bintools.vcproj @@ -1,7 +1,7 @@ Date: Sun, 6 May 2007 05:28:45 +0000 Subject: [PATCH 0717/1664] Fixed calling thiscall functions with 0 parameters --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40748 --- extensions/bintools/jit_call.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp index f756c75b..bb747830 100644 --- a/extensions/bintools/jit_call.cpp +++ b/extensions/bintools/jit_call.cpp @@ -509,7 +509,7 @@ void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method) jit_rewind: /* Write function prologue */ - Write_Execution_Prologue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + Write_Execution_Prologue(jit, (pRet) ? false : true, (ParamCount || Convention == CallConv_ThisCall)); /* Write parameter push code */ for (jit_int32_t i=ParamCount-1; i>=0; i--) From 70130722363984b9f08febae9b7a69449b6d93fe Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 06:15:48 +0000 Subject: [PATCH 0718/1664] added request amb251 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40749 --- core/smn_keyvalues.cpp | 68 +++++++++++++++++++++++++++++++++++ plugins/include/keyvalues.inc | 20 +++++++++++ 2 files changed, 88 insertions(+) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 6cde5b9b..622c4506 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -637,6 +637,72 @@ static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *param return 1; } +static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + KeyValues *pValues = pStk->pCurRoot.front(); + pStk->pCurRoot.pop(); + pStk->pCurRoot.front()->RemoveSubKey(pValues); + pValues->deleteThis(); + + return 1; +} + +static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + char *keyName; + pContext->LocalToString(params[2], &keyName); + + KeyValues *pRoot = pStk->pCurRoot.front(); + KeyValues *pValues = pRoot->FindKey(keyName); + if (!pValues) + { + return 0; + } + + pRoot->RemoveSubKey(pValues); + pValues->deleteThis(); + + return 1; +} + static KeyValueNatives s_KeyValueNatives; REGISTER_NATIVES(keyvaluenatives) @@ -663,5 +729,7 @@ REGISTER_NATIVES(keyvaluenatives) {"KeyValuesToFile", smn_KeyValuesToFile}, {"FileToKeyValues", smn_FileToKeyValues}, {"KvSetEscapeSequences", smn_KvSetEscapeSequences}, + {"KvDeleteThis", smn_KvDeleteThis}, + {"KvDeleteKey", smn_KvDeleteKey}, {NULL, NULL} }; diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index edfcd6ce..9082bfec 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -192,6 +192,26 @@ native bool:KvJumpFirstSubKey(Handle:kv); */ native bool:KvJumpNextSubKey(Handle:kv); +/** + * Removes the given key from the current position. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @return True on success, false if key did not exist. + * @error Invalid Handle. + */ +native bool:KvDeleteKey(Handle:kv, const String:key[]); + +/** + * Removes the current sub-key and jumps back one position, using the previous + * position as the search point. This will not work if used on the root node. + * + * @param kv KeyValues Handle. + * @return True on success, false if there was no sub key. + * @error Invalid Handle. + */ +native bool:KvDeleteThis(Handle:kv); + /** * Jumps back to the previous position. Returns false if there are no * previous positions (i.e., at the root node). This should be called From 16fa9e0fa62fd915d1b1a3b9ad246eef28f575bb Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 6 May 2007 06:44:18 +0000 Subject: [PATCH 0719/1664] Oh, I forgot about this --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40750 --- extensions/bintools/jit_call.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp index bb747830..28066981 100644 --- a/extensions/bintools/jit_call.cpp +++ b/extensions/bintools/jit_call.cpp @@ -503,13 +503,14 @@ void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method) CallConvention Convention = pWrapper->GetCallConvention(); jit_uint32_t ParamCount = pWrapper->GetParamCount(); const PassInfo *pRet = pWrapper->GetReturnInfo(); + bool hasParams = (ParamCount || Convention == CallConv_ThisCall); writer.outbase = NULL; writer.outptr = NULL; jit_rewind: /* Write function prologue */ - Write_Execution_Prologue(jit, (pRet) ? false : true, (ParamCount || Convention == CallConv_ThisCall)); + Write_Execution_Prologue(jit, (pRet) ? false : true, hasParams); /* Write parameter push code */ for (jit_int32_t i=ParamCount-1; i>=0; i--) @@ -593,7 +594,7 @@ skip_retbuffer: } /* Write Function Epilogue */ - Write_Function_Epilogue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + Write_Function_Epilogue(jit, (pRet) ? false : true, hasParams); if (writer.outbase == NULL) { From b8e2b6cf68a7eda50700dcce65d84df0c6a72875 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 19:13:39 +0000 Subject: [PATCH 0720/1664] fixed bug amb259 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40751 --- sourcepawn/compiler/sc1.c | 2 +- sourcepawn/compiler/sc3.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 2bd8e569..f5b7892c 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -3985,7 +3985,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc if (matchtoken(';')) { sym->usage|=uFORWARD; if (!sc_needsemicolon) - error(218); /* old style prototypes used with optional semicolumns */ + error(10); /* old style prototypes used with optional semicolumns */ delete_symbols(&loctab,0,TRUE,TRUE); /* prototype is done; forget everything */ return TRUE; } /* if */ diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index ce8182d3..d4e780c5 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -2674,9 +2674,12 @@ static int nesting=0; if ((sym->usage & uNATIVE)==0) totalsize++; /* add "call" opcode */ totalsize+=nest_stkusage; - assert(curfunc!=NULL); - if (curfunc->x.stacksizex.stacksize=totalsize; + if (curfunc != NULL) { + if (curfunc->x.stacksizex.stacksize=totalsize; + } else { + error(10); + } nest_stkusage-=nargs+heapalloc+1; /* stack/heap space, +1 for argcount param */ /* if there is a syntax error in the script, the stack calculation is * probably incorrect; but we may not allow it to drop below zero From a247f402ca3d83a4d67eac655e382709280d295f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 19:45:46 +0000 Subject: [PATCH 0721/1664] builder now creates a data folder --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40752 --- tools/builder/PkgCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index adacf38a..9e6d0b4c 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -29,7 +29,7 @@ namespace builder */ public override string [] GetFolders() { - string [] folders = new string[7]; + string [] folders = new string[8]; folders[0] = "bin"; folders[1] = "plugins/disabled"; @@ -38,6 +38,7 @@ namespace builder folders[4] = "logs"; folders[5] = "extensions"; folders[6] = "scripting/include"; + folders[7] = "data"; return folders; } From ffe0867d1aaa1cc0ced5e90b1f2c83a3f77b3265 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 19:52:00 +0000 Subject: [PATCH 0722/1664] fixed amb254 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40753 --- core/smn_textparse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index 91c8b450..f18f997c 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -47,7 +47,7 @@ public: if (parse_end) { cell_t result; - parse_start->PushCell(handle); + parse_end->PushCell(handle); parse_end->PushCell(halted ? 1 : 0); parse_end->PushCell(failed ? 1 : 0); parse_end->Execute(&result); From eb5b94ec4449fd7428d97b083b629c7c35cc4c30 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 23:12:54 +0000 Subject: [PATCH 0723/1664] more string natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40754 --- core/smn_string.cpp | 91 +++++++++++++++++++++++++++- plugins/include/string.inc | 121 ++++++++++++++++++++++++++++++++++--- 2 files changed, 203 insertions(+), 9 deletions(-) diff --git a/core/smn_string.cpp b/core/smn_string.cpp index cca8271f..a4eba5ed 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -17,6 +17,7 @@ #include "sm_globals.h" #include "sm_stringutil.h" #include "TextParsers.h" +#include inline const char *_strstr(const char *str, const char *substr) { @@ -325,8 +326,97 @@ static cell_t StrBreak(IPluginContext *pContext, const cell_t *params) return inptr - input; } +static cell_t GetCharBytes(IPluginContext *pContext, const cell_t *params) +{ + char *str; + pContext->LocalToString(params[1], &str); + + return _GetUTF8CharBytes(str); +}; + +static cell_t IsCharAlpha(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + if (_GetUTF8CharBytes(&chr) != 1) + { + return 0; + } + + return isalpha(chr); +} + +static cell_t IsCharNumeric(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + if (_GetUTF8CharBytes(&chr) != 1) + { + return 0; + } + + return isdigit(chr); +} + +static cell_t IsCharSpace(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + if (_GetUTF8CharBytes(&chr) != 1) + { + return 0; + } + + return isspace(chr); +} + +static cell_t IsCharMB(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + unsigned int bytes = _GetUTF8CharBytes(&chr); + if (bytes == 1) + { + return 0; + } + + return bytes; +} + +static cell_t IsCharUpper(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + if (_GetUTF8CharBytes(&chr) != 1) + { + return 0; + } + + return isupper(chr); +} + +static cell_t IsCharLower(IPluginContext *pContext, const cell_t *params) +{ + char chr = params[1]; + + if (_GetUTF8CharBytes(&chr) != 1) + { + return 0; + } + + return islower(chr); +} + REGISTER_NATIVES(basicStrings) { + {"GetCharBytes", GetCharBytes}, + {"IntToString", sm_numtostr}, + {"IsCharAlpha", IsCharAlpha}, + {"IsCharLower", IsCharLower}, + {"IsCharMB", IsCharMB}, + {"IsCharNumeric", IsCharNumeric}, + {"IsCharSpace", IsCharSpace}, + {"IsCharUpper", IsCharUpper}, {"strlen", sm_strlen}, {"StrBreak", StrBreak}, {"StrContains", sm_contain}, @@ -336,7 +426,6 @@ REGISTER_NATIVES(basicStrings) {"strcopy", sm_strcopy}, {"StrCopy", sm_strcopy}, /* Backwards compat shim */ {"StringToInt", sm_strconvint}, - {"IntToString", sm_numtostr}, {"StringToFloat", sm_strtofloat}, {"FloatToString", sm_floattostr}, {"Format", sm_format}, diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 3821209d..d4bae793 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -19,9 +19,10 @@ #define _string_included /** - * @global Unless otherwise noted, all string functions which take in a writable buffer - * and maximum length should have the null terminator INCLUDED in the length. This means - * that this is valid: StrCopy(string, sizeof(string), ...) + * @global Unless otherwise noted, all string functions which take in a + * writable buffer and maximum length should have the null terminator INCLUDED + * in the length. This means that this is valid: + * StrCopy(string, sizeof(string), ...) */ /** @@ -129,8 +130,9 @@ native Format(String:buffer[], maxlength, const String:format[], any:...); /** * Formats a string according to the SourceMod format rules (see documentation). - * @note This is the same as Format(), except none of the input buffers can overlap the same - * memory as the output buffer. Since this security check is removed, it is slightly faster. + * @note This is the same as Format(), except none of the input buffers can + * overlap the same memory as the output buffer. Since this security + * check is removed, it is slightly faster. * * @param buffer Destination string buffer. * @param maxlength Maximum length of output string buffer. @@ -142,9 +144,9 @@ native FormatEx(String:buffer[], maxlength, const String:format[], any:...); /** * Formats a string according to the SourceMod format rules (see documentation). - * @note This is the same as Format(), except it grabs parameters from a parent parameter - * stack, rather than a local. This is useful for implementing your own variable - * argument functions. + * @note This is the same as Format(), except it grabs parameters from a + * parent parameter stack, rather than a local. This is useful for + * implementing your own variable argument functions. * * @param buffer Destination string buffer. * @param maxlength Maximum length of output string buffer. @@ -205,3 +207,106 @@ native FloatToString(Float:num, String:str[], maxlength); * @return Index to next piece of string, or -1 if none. */ native StrBreak(const String:source[], String:arg[], argLen); + +/** + * Returns the number of bytes a character is using. This is + * for multi-byte characters (UTF-8). For normal ASCII characters, + * this will return 1. + * + * @param source Source input string. + * @return Number of bytes the current character uses. + */ +native GetCharBytes(const String:source[]); + +/** + * Returns whether a character is an ASCII alphabet character. + * + * @note Multi-byte characters will always return false. + * + * @param char Character to test. + * @return True if character is alphabetical, otherwise false. + */ +native bool:IsCharAlpha(chr); + +/** + * Returns whether a character is numeric. + * + * @note Multi-byte characters will always return false. + * + * @param char Character to test. + * @return True if character is numeric, otherwise false. + */ +native bool:IsCharNumeric(chr); + +/** + * Returns whether a character is whitespace. + * + * @note Multi-byte characters will always return false. + * + * @param char Character to test. + * @return True if character is whitespace, otherwise false. + */ +native bool:IsCharSpace(chr); + +/** + * Returns if a character is multi-byte or not. + * + * @param char Character to test. + * @return 0 for a normal 7-bit ASCII character, + * otherwise number of bytes in multi-byte character. + */ +native IsCharMB(chr); + +/** + * Returns whether an alphabetic character is uppercase. + * + * @note Multi-byte characters will always return false. + * + * @param char Character to test. + * @return True if character is uppercase, otherwise false. + */ +native bool:IsCharUpper(chr); + +/** + * Returns whether an alphabetic character is lowercase. + * + * @note Multi-byte characters will always return false. + * + * @param char Character to test. + * @return True if character is lowercase, otherwise false. + */ +native bool:IsCharLower(chr); + +/** + * Returns an uppercase character to a lowercase character. + * + * @param chr Characer to convert. + * @return Lowercase character on success, + * no change on failure. + */ +stock CharToUpper(chr) +{ + if (IsCharLower(chr)) + { + return (chr & ~(1<<5)); + } + return chr; +} + +/** + * Returns a lowercase character to an uppercase character. + * + * @param chr Characer to convert. + * @return Uppercase character on success, + * no change on failure. + */ +stock CharToLower(chr) +{ + if (IsCharUpper(chr)) + { + return (chr | (1<<5)); + } + return chr; +} + + From 67a0cdf1c306952a28a25216cd0afde8d658bb13 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 6 May 2007 23:35:45 +0000 Subject: [PATCH 0724/1664] added StrCat stock --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40755 --- plugins/include/string.inc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index d4bae793..7509dbd8 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -208,6 +208,20 @@ native FloatToString(Float:num, String:str[], maxlength); */ native StrBreak(const String:source[], String:arg[], argLen); +/** + * Finds the first "argument" in a string; either a set of space + * terminated characters, or a fully quoted string. After the + * argument is found, whitespace is read until the next portion + * of the string is reached. If nothing remains, -1 is returned. + * Otherwise, the index to the first character is returned. + * + * @param source Source input string. + * @param arg Stores argument read from string. + * @param argLen Maximum length of argument buffer. + * @return Index to next piece of string, or -1 if none. + */ +native StrBreak(const String:source[], String:arg[], argLen); + /** * Returns the number of bytes a character is using. This is * for multi-byte characters (UTF-8). For normal ASCII characters, @@ -309,4 +323,21 @@ stock CharToLower(chr) return chr; } - +/** + * Concatenates one string onto another. + * + * @param buffer String to append to. + * @param maxlength Maximum length of entire buffer. + * @param source Source string to concatenate. + * @return Number of bytes written. + */ +stock StrCat(String:buffer[], maxlength, const String:source[]) +{ + new len = strlen(source); + if (len >= maxlength) + { + return 0; + } + + return Format(buffer[len], maxlength-len, "%s", source); +} From e69edf05ebe2b2e6dab9c61d0574c19d83c16879 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 00:02:33 +0000 Subject: [PATCH 0725/1664] added amb260 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40756 --- core/smn_keyvalues.cpp | 20 ++++++++++++++++++++ plugins/include/keyvalues.inc | 11 +++++++++++ 2 files changed, 31 insertions(+) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 622c4506..71e9d505 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -637,6 +637,25 @@ static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *param return 1; } +static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + return pStk->pCurRoot.size(); +} + static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -731,5 +750,6 @@ REGISTER_NATIVES(keyvaluenatives) {"KvSetEscapeSequences", smn_KvSetEscapeSequences}, {"KvDeleteThis", smn_KvDeleteThis}, {"KvDeleteKey", smn_KvDeleteKey}, + {"KvNodesInStack", smn_KvNodesInStack}, {NULL, NULL} }; diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index 9082bfec..bb373d67 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -298,3 +298,14 @@ native bool:FileToKeyValues(Handle:kv, const String:file[]); * @error Invalid Handle. */ native KvSetEscapeSequences(Handle:kv, bool:useEscapes); + +/** + * Returns the position in the jump stack; I.e. the number of calls + * required for KvGoBack to return to the root node. If at the root node, + * 0 is returned. + * + * @param kv KeyValues Handle. + * @return Number of non-root nodes in the jump stack. + * @error Invalid Handle. + */ +native KvNodesInStack(Handle:kv); \ No newline at end of file From ca7ebffc8a3e21e12e035670dee65279c646a26e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 00:03:37 +0000 Subject: [PATCH 0726/1664] oops --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40757 --- core/smn_keyvalues.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 71e9d505..8803f177 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -653,7 +653,7 @@ static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params) return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); } - return pStk->pCurRoot.size(); + return pStk->pCurRoot.size() - 1; } static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) From 2f14014f3f7af7dcc04edad630a38f68b4b33755 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 00:11:10 +0000 Subject: [PATCH 0727/1664] oops, how did this happen --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40758 --- plugins/include/string.inc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 7509dbd8..6bbe3263 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -208,20 +208,6 @@ native FloatToString(Float:num, String:str[], maxlength); */ native StrBreak(const String:source[], String:arg[], argLen); -/** - * Finds the first "argument" in a string; either a set of space - * terminated characters, or a fully quoted string. After the - * argument is found, whitespace is read until the next portion - * of the string is reached. If nothing remains, -1 is returned. - * Otherwise, the index to the first character is returned. - * - * @param source Source input string. - * @param arg Stores argument read from string. - * @param argLen Maximum length of argument buffer. - * @return Index to next piece of string, or -1 if none. - */ -native StrBreak(const String:source[], String:arg[], argLen); - /** * Returns the number of bytes a character is using. This is * for multi-byte characters (UTF-8). For normal ASCII characters, From 34934677718051aec37377fdab1ddf9fe7cfd95a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 02:58:58 +0000 Subject: [PATCH 0728/1664] small rewrite of how keyvalues iterator and get deleted. phew! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40759 --- core/smn_keyvalues.cpp | 109 +++++++++++++++++++++++++++++++--- plugins/include/keyvalues.inc | 36 +++++++++-- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 8803f177..95073117 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -389,7 +389,7 @@ static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) +static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError herr; @@ -406,7 +406,14 @@ static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) } KeyValues *pSubKey = pStk->pCurRoot.front(); - KeyValues *pFirstSubKey = pSubKey->GetFirstSubKey(); + KeyValues *pFirstSubKey; + if (params[2]) + { + pFirstSubKey = pSubKey->GetFirstTrueSubKey(); + } else { + pFirstSubKey = pSubKey->GetFirstSubKey(); + } + if (!pFirstSubKey) { return 0; @@ -416,6 +423,39 @@ static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + if (params[2]) + { + pSubKey = pSubKey->GetNextKey(); + } else { + pSubKey = pSubKey->GetNextTrueSubKey(); + } + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.pop(); + pStk->pCurRoot.push(pSubKey); + + return 1; +} + static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -679,10 +719,35 @@ static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) KeyValues *pValues = pStk->pCurRoot.front(); pStk->pCurRoot.pop(); - pStk->pCurRoot.front()->RemoveSubKey(pValues); - pValues->deleteThis(); + KeyValues *pRoot = pStk->pCurRoot.front(); - return 1; + /* We have to manually verify this since Valve sucks + * :TODO: make our own KeyValues.h file and make + * the sub stuff private so we can do this ourselves! + */ + KeyValues *sub = pRoot->GetFirstSubKey(); + while (sub) + { + if (sub == pValues) + { + KeyValues *pNext = pValues->GetNextKey(); + pRoot->RemoveSubKey(pValues); + pValues->deleteThis(); + if (pNext) + { + pStk->pCurRoot.push(pNext); + return 1; + } else { + return -1; + } + } + sub = sub->GetNextKey(); + } + + /* Push this back on :( */ + pStk->pCurRoot.push(pValues); + + return 0; } static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) @@ -722,6 +787,33 @@ static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + KeyValues *pValues = pStk->pCurRoot.front(); + pStk->pCurRoot.push(pValues); + + return 1; +} + static KeyValueNatives s_KeyValueNatives; REGISTER_NATIVES(keyvaluenatives) @@ -738,8 +830,10 @@ REGISTER_NATIVES(keyvaluenatives) {"KvGetUint64", smn_KvGetUint64}, {"CreateKeyValues", smn_CreateKeyValues}, {"KvJumpToKey", smn_KvJumpToKey}, - {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey}, - {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, + {"KvGotoNextKey", smn_KvGotoNextKey}, + {"KvJumpFirstSubKey", smn_KvGotoFirstSubKey}, /* BACKWARDS COMPAT SHIM */ + {"KvGotoFirstSubKey", smn_KvGotoFirstSubKey}, + {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, /* BACKWARDS COMPAT SHIM */ {"KvGoBack", smn_KvGoBack}, {"KvRewind", smn_KvRewind}, {"KvGetSectionName", smn_KvGetSectionName}, @@ -751,5 +845,6 @@ REGISTER_NATIVES(keyvaluenatives) {"KvDeleteThis", smn_KvDeleteThis}, {"KvDeleteKey", smn_KvDeleteKey}, {"KvNodesInStack", smn_KvNodesInStack}, + {"KvSavePosition", smn_KvSavePosition}, {NULL, NULL} }; diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index bb373d67..6c816319 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -176,21 +176,37 @@ native bool:KvJumpToKey(Handle:kv, const String:key[], bool:create=false); /** * Sets the current position in the KeyValues tree to the first sub key. + * This native adds to the internal traversal stack. * * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). * @return True on success, false if there was no first sub key. * @error Invalid Handle. */ -native bool:KvJumpFirstSubKey(Handle:kv); +native bool:KvGotoFirstSubKey(Handle:kv, bool:keyOnly=true); /** * Sets the current position in the KeyValues tree to the next sub key. + * This native does NOT add to the internal traversal stack, and thus + * KvGoBack() is not needed for each successive call to this function. * * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). * @return True on success, false if there was no next sub key. * @error Invalid Handle. */ -native bool:KvJumpNextSubKey(Handle:kv); +native bool:KvGotoNextKey(Handle:kv, bool:keyOnly=true); + +/** + * Saves the current position in the traversal stack onto the traversal + * stack. This can be useful if you wish to use KvGotoNextKey() and + * have the previous key saved for backwards traversal. + * + * @param kv KeyValues Handle. + * @noreturn + * @error Invalid Handle. + */ +native KvSavePosition(Handle:kv); /** * Removes the given key from the current position. @@ -203,19 +219,27 @@ native bool:KvJumpNextSubKey(Handle:kv); native bool:KvDeleteKey(Handle:kv, const String:key[]); /** - * Removes the current sub-key and jumps back one position, using the previous - * position as the search point. This will not work if used on the root node. + * Removes the current sub-key and attempts to set the position + * to the sub-key after the removed one. If no such sub-key exists, + * the position will be the parent key in the traversal stack. + * Given the sub-key having position "N" in the traversal stack, the + * removal will always take place from position "N-1." * * @param kv KeyValues Handle. - * @return True on success, false if there was no sub key. + * @return 1 if removal succeeded and there was another key. + * 0 if the current node was not contained in the + * previous node, or no previous node exists. + * -1 if removal succeeded and there were no more keys, + * thus the state is as if KvGoBack() was called. * @error Invalid Handle. */ -native bool:KvDeleteThis(Handle:kv); +native KvDeleteThis(Handle:kv); /** * Jumps back to the previous position. Returns false if there are no * previous positions (i.e., at the root node). This should be called * once for each successful Jump call, in order to return to the top node. + * This function pops one node off the internal traversal stack. * * @param kv KeyValues Handle. * @return True on success, false if there is no higher node. From 45d058958568087fd724bc9904e4010fff444997 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 04:17:24 +0000 Subject: [PATCH 0729/1664] fixed a serious codegen bug where for loops with no variable declarations would misalign the internal stack tracker of the compiler --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40760 --- sourcepawn/compiler/sc1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index f5b7892c..0e62d854 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -5868,6 +5868,8 @@ static int dofor(void) declared=save_decl; delete_symbols(&loctab,nestlevel,FALSE,TRUE); nestlevel=save_nestlevel; /* reset 'compound statement' nesting level */ + } else { + popstacklist(0); } /* if */ index=endlessloop ? tENDLESS : tFOR; From 3851dc9243179db07018f63bec4c4695fd30f0e4 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Tue, 8 May 2007 00:21:44 +0000 Subject: [PATCH 0730/1664] Renamed err_max to maxlength. Yes, I am crazy. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40761 --- core/sourcemod.cpp | 26 +++++++++++++------------- core/sourcemod.h | 2 +- core/systems/ExtensionSys.cpp | 16 ++++++++-------- core/systems/ExtensionSys.h | 2 +- core/systems/LibrarySys.cpp | 14 +++++++------- core/systems/LibrarySys.h | 4 ++-- core/systems/PluginSys.cpp | 16 ++++++++-------- core/systems/PluginSys.h | 4 ++-- public/IExtensionSys.h | 10 +++++----- public/ILibrarySys.h | 8 ++++---- public/IPluginSys.h | 4 ++-- 11 files changed, 53 insertions(+), 53 deletions(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 8de6ab61..a0576d71 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -101,7 +101,7 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, return ConfigResult_Ignore; } -bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) +bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late) { const char *gamepath = g_SMAPI->GetBaseDir(); @@ -141,9 +141,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror)); if (!g_pJIT) { - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "%s (failed to load bin/sourcepawn.jit.x86.%s)", + snprintf(error, maxlength, "%s (failed to load bin/sourcepawn.jit.x86.%s)", myerror, PLATFORM_LIB_EXT); } @@ -155,9 +155,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) if (!jit_init) { ShutdownJIT(); - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "Failed to find GiveEnginePointer in JIT!"); + snprintf(error, maxlength, "Failed to find GiveEnginePointer in JIT!"); } return false; } @@ -165,9 +165,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) if ((err=jit_init(g_pSourcePawn)) != 0) { ShutdownJIT(); - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "GiveEnginePointer returned %d in the JIT", err); + snprintf(error, maxlength, "GiveEnginePointer returned %d in the JIT", err); } return false; } @@ -177,9 +177,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) if (!jit_get) { ShutdownJIT(); - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "JIT is missing a necessary export!"); + snprintf(error, maxlength, "JIT is missing a necessary export!"); } return false; } @@ -188,9 +188,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) if (!num || ((g_pVM=jit_get(0)) == NULL)) { ShutdownJIT(); - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "JIT did not export any virtual machines!"); + snprintf(error, maxlength, "JIT did not export any virtual machines!"); } return false; } @@ -199,9 +199,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) if (api != SOURCEPAWN_VM_API_VERSION) { ShutdownJIT(); - if (error && err_max) + if (error && maxlength) { - snprintf(error, err_max, "JIT is not a compatible version"); + snprintf(error, maxlength, "JIT is not a compatible version"); } return false; } diff --git a/core/sourcemod.h b/core/sourcemod.h index 6f3460bf..c675d22d 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -36,7 +36,7 @@ public: /** * @brief Initializes SourceMod, or returns an error on failure. */ - bool InitializeSourceMod(char *error, size_t err_max, bool late); + bool InitializeSourceMod(char *error, size_t maxlength, bool late); /** * @brief Starts everything SourceMod needs to run diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 6be78c36..b09aefd8 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -25,7 +25,7 @@ CExtensionManager g_Extensions; IdentityType_t g_ExtType; -CExtension::CExtension(const char *filename, char *error, size_t err_max) +CExtension::CExtension(const char *filename, char *error, size_t maxlength) { m_File.assign(filename); m_pAPI = NULL; @@ -37,7 +37,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename); - m_pLib = g_LibSys.OpenLibrary(path, error, err_max); + m_pLib = g_LibSys.OpenLibrary(path, error, maxlength); if (m_pLib == NULL) { @@ -51,7 +51,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) { m_pLib->CloseLibrary(); m_pLib = NULL; - snprintf(error, err_max, "Unable to find extension entry point"); + snprintf(error, maxlength, "Unable to find extension entry point"); return; } @@ -60,19 +60,19 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) { m_pLib->CloseLibrary(); m_pLib = NULL; - snprintf(error, err_max, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION); + snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION); return; } if (m_pAPI->IsMetamodExtension()) { bool already; - m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, err_max); + m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, maxlength); } m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType); - if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, !g_SourceMod.IsMapLoading())) + if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading())) { if (m_pAPI->IsMetamodExtension()) { @@ -403,7 +403,7 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext) return NULL; } -IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max) +IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t maxlength) { IExtension *pAlready; if ((pAlready=FindExtensionByFile(file)) != NULL) @@ -411,7 +411,7 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime return pAlready; } - CExtension *pExt = new CExtension(file, error, err_max); + CExtension *pExt = new CExtension(file, error, maxlength); /* :NOTE: lifetime is currently ignored */ diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index ae294182..e714cb8b 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -78,7 +78,7 @@ public: //IExtensionManager IExtension *LoadExtension(const char *path, ExtensionLifetime lifetime, char *error, - size_t err_max); + size_t maxlength); bool UnloadExtension(IExtension *pExt); IExtension *FindExtensionByFile(const char *file); IExtension *FindExtensionByName(const char *ext); diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 63784c88..76e2f2df 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -252,9 +252,9 @@ IDirectory *LibrarySystem::OpenDirectory(const char *path) return dir; } -void LibrarySystem::GetPlatformError(char *error, size_t err_max) +void LibrarySystem::GetPlatformError(char *error, size_t maxlength) { - if (error && err_max) + if (error && maxlength) { #if defined PLATFORM_WINDOWS DWORD dw = GetLastError(); @@ -264,10 +264,10 @@ void LibrarySystem::GetPlatformError(char *error, size_t err_max) dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)error, - err_max, + maxlength, NULL); #elif defined PLATFORM_POSIX - snprintf(error, err_max, "%s", strerror(errno)); + snprintf(error, maxlength, "%s", strerror(errno)); #endif } } @@ -277,21 +277,21 @@ void LibrarySystem::CloseDirectory(IDirectory *dir) delete dir; } -ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t err_max) +ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength) { LibraryHandle lib; #if defined PLATFORM_WINDOWS lib = LoadLibraryA(path); if (!lib) { - GetPlatformError(error, err_max); + GetPlatformError(error, maxlength); return false; } #elif defined PLATFORM_POSIX lib = dlopen(path, RTLD_NOW); if (!lib) { - GetPlatformError(error, err_max); + GetPlatformError(error, maxlength); return false; } #endif diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index df35b2f7..7b15e062 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -66,13 +66,13 @@ private: class LibrarySystem : public ILibrarySys { public: - ILibrary *OpenLibrary(const char *path, char *error, size_t err_max); + ILibrary *OpenLibrary(const char *path, char *error, size_t maxlength); IDirectory *OpenDirectory(const char *path); void CloseDirectory(IDirectory *dir); bool PathExists(const char *path); bool IsPathFile(const char *path); bool IsPathDirectory(const char *path); - void GetPlatformError(char *error, size_t err_max); + void GetPlatformError(char *error, size_t maxlength); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); }; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index fbfa8ee9..9fc1615a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -748,7 +748,7 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa } //well i have discovered that gabe newell is very fat, so i wrote this comment now -LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max) +LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength) { /** * Does this plugin already exist? @@ -771,7 +771,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de } } - pPlugin = CPlugin::CreatePlugin(path, error, err_max); + pPlugin = CPlugin::CreatePlugin(path, error, maxlength); assert(pPlugin != NULL); @@ -807,7 +807,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de { if (error) { - snprintf(error, err_max, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); + snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); } pPlugin->CancelMyCompile(); co = NULL; @@ -829,10 +829,10 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de { AddCoreNativesToPlugin(pPlugin); pPlugin->InitIdentity(); - if (pPlugin->Call_AskPluginLoad(error, err_max)) + if (pPlugin->Call_AskPluginLoad(error, maxlength)) { /* Autoload any modules */ - LoadOrRequireExtensions(pPlugin, 1, error, err_max); + LoadOrRequireExtensions(pPlugin, 1, error, maxlength); } } @@ -848,13 +848,13 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure; } -IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max, bool *wasloaded) +IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded) { CPlugin *pl; LoadRes res; *wasloaded = false; - if ((res=_LoadPlugin(&pl, path, debug, type, error, err_max)) == LoadRes_Failure) + if ((res=_LoadPlugin(&pl, path, debug, type, error, maxlength)) == LoadRes_Failure) { delete pl; return NULL; @@ -871,7 +871,7 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ /* Run second pass if we need to */ if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded) { - if (!RunSecondPass(pl, error, err_max)) + if (!RunSecondPass(pl, error, maxlength)) { UnloadPlugin(pl); return NULL; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 075c738a..ba0a2b5f 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -281,7 +281,7 @@ public: //IPluginManager bool debug, PluginType type, char error[], - size_t err_max, + size_t maxlength, bool *wasloaded); bool UnloadPlugin(IPlugin *plugin); IPlugin *FindPluginByContext(const sp_context_t *ctx); @@ -363,7 +363,7 @@ public: void AddFunctionsToForward(const char *name, IChangeableForward *pForward); private: - LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); + LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength); void LoadAutoPlugin(const char *plugin); diff --git a/public/IExtensionSys.h b/public/IExtensionSys.h index 8dfab75d..d8ce50dd 100644 --- a/public/IExtensionSys.h +++ b/public/IExtensionSys.h @@ -124,14 +124,14 @@ namespace SourceMod * @param me Pointer back to extension. * @param sys Pointer to interface sharing system of SourceMod. * @param error Error buffer to print back to, if any. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @param late If this extension was loaded "late" (i.e. manually). * @return True if load should continue, false otherwise. */ virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, - size_t err_max, + size_t maxlength, bool late) =0; /** @@ -175,7 +175,7 @@ namespace SourceMod } /** - * @brief Return false to tell Core that your extension should be considered usable. + * @brief Return false to tell Core that your extension should be considered unusable. * * @param error Error buffer. * @param maxlength Size of error buffer. @@ -229,13 +229,13 @@ namespace SourceMod * @param path Path to extension file, relative to the extensions folder. * @param lifetime Lifetime of the extension (currently ignored). * @param error Error buffer. - * @param err_max Maximum error buffer length. + * @param maxlength Maximum error buffer length. * @return New IExtension on success, NULL on failure. */ virtual IExtension *LoadExtension(const char *path, ExtensionLifetime lifetime, char *error, - size_t err_max) =0; + size_t maxlength) =0; /** * @brief Attempts to unload a module. diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index 18dfbc1a..2af2d162 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -116,10 +116,10 @@ namespace SourceMod * * @param path Path to library file (.dll/.so). * @param error Buffer for any error message (may be NULL). - * @param err_max Maximum length of error buffer. + * @param maxlength Maximum length of error buffer. * @return Pointer to an ILibrary, NULL if failed. */ - virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max) =0; + virtual ILibrary *OpenLibrary(const char *path, char *error, size_t maxlength) =0; /** * @brief Opens a directory for reading. @@ -158,9 +158,9 @@ namespace SourceMod * POSIX equivalent: errno + strerror() * * @param error Error message buffer. - * @param err_max Maximum length of error buffer. + * @param maxlength Maximum length of error buffer. */ - virtual void GetPlatformError(char *error, size_t err_max) =0; + virtual void GetPlatformError(char *error, size_t maxlength) =0; /** * @brief Formats a string similar to snprintf(), except diff --git a/public/IPluginSys.h b/public/IPluginSys.h index f9154c3d..451f4334 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -279,7 +279,7 @@ namespace SourceMod * @param debug Whether or not to default the plugin into debug mode. * @param type Lifetime of the plugin. * @param error Buffer to hold any error message. - * @param err_max Maximum length of error message buffer. + * @param maxlength Maximum length of error message buffer. * @param wasloaded Stores if the plugin is already loaded. * @return A new plugin pointer on success, false otherwise. */ @@ -287,7 +287,7 @@ namespace SourceMod bool debug, PluginType type, char error[], - size_t err_max, + size_t maxlength, bool *wasloaded) =0; /** From 9d9369079afc7330566432b30f6cd35db69e5607 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Tue, 8 May 2007 22:26:30 +0000 Subject: [PATCH 0731/1664] fixed bug for amb266 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40762 --- core/smn_player.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index c093848d..38e6d34b 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -589,7 +589,8 @@ static cell_t GetWeaponName(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("IPlayerInfo not supported by game"); } - pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pInfo->GetWeaponName(), NULL); + const char *weapon = pInfo->GetWeaponName(); + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), weapon ? weapon : "", NULL); return 1; } @@ -612,7 +613,8 @@ static cell_t GetModelName(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("IPlayerInfo not supported by game"); } - pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pInfo->GetModelName(), NULL); + const char *model = pInfo->GetModelName(); + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), model ? model : "", NULL); return 1; } From 9decd4196aff1061f3159582493c45e81319a80f Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 9 May 2007 05:20:03 +0000 Subject: [PATCH 0732/1664] Whew, massive-ish reorgranization for extensions and such. I will inevitably be shot for this. (Yes, bail, it all compiles on both platforms) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40763 --- extensions/batsupport/Makefile | 12 +- extensions/batsupport/extension.cpp | 28 +- extensions/batsupport/extension.h | 47 ++- extensions/batsupport/msvc8/batsupport.sln | 10 +- extensions/batsupport/msvc8/batsupport.vcproj | 181 +--------- extensions/batsupport/sdk/smsdk_config.h | 48 +++ .../sdk}/smsdk_ext.cpp | 27 +- .../batsupport/sdk}/smsdk_ext.h | 65 ++-- extensions/batsupport/smsdk_config.h | 33 -- extensions/bintools/CallMaker.cpp | 21 +- extensions/bintools/CallMaker.h | 21 +- extensions/bintools/CallWrapper.cpp | 21 +- extensions/bintools/CallWrapper.h | 21 +- extensions/bintools/Makefile | 10 +- extensions/bintools/extension.cpp | 27 +- extensions/bintools/extension.h | 65 +++- extensions/bintools/jit_call.cpp | 21 +- extensions/bintools/jit_call.h | 21 +- extensions/bintools/msvc8/bintools.sln | 10 +- extensions/bintools/msvc8/bintools.vcproj | 55 ++- extensions/bintools/sdk/smsdk_config.h | 48 +++ .../bintools/sdk}/smsdk_ext.cpp | 27 +- extensions/bintools/{ => sdk}/smsdk_ext.h | 65 ++-- extensions/bintools/smsdk_config.h | 33 -- extensions/geoip/Makefile | 12 +- extensions/geoip/extension.cpp | 17 +- extensions/geoip/extension.h | 55 ++- extensions/geoip/msvc8/geoip.sln | 10 +- extensions/geoip/msvc8/geoip.vcproj | 34 +- extensions/geoip/sdk/smsdk_config.h | 49 +++ extensions/geoip/sdk/smsdk_ext.cpp | 334 ++++++++++++++++++ .../{batsupport => geoip/sdk}/smsdk_ext.h | 65 ++-- extensions/geoip/smsdk_config.h | 48 --- extensions/geoip/smsdk_ext.cpp | 324 ----------------- extensions/geoip/smsdk_ext.h | 158 --------- extensions/threader/Makefile | 17 +- extensions/threader/extension.cpp | 13 +- extensions/threader/extension.h | 54 ++- extensions/threader/msvc8/threader.vcproj | 33 +- extensions/threader/sdk/smsdk_config.h | 49 +++ .../sdk}/smsdk_ext.cpp | 29 +- extensions/threader/{ => sdk}/smsdk_ext.h | 105 ++++-- extensions/threader/smsdk_config.h | 47 --- extensions/threader/thread/BaseWorker.cpp | 6 +- extensions/threader/thread/BaseWorker.h | 6 +- extensions/threader/thread/PosixThreads.cpp | 7 +- extensions/threader/thread/PosixThreads.h | 6 +- extensions/threader/thread/ThreadSupport.h | 6 +- extensions/threader/thread/ThreadWorker.cpp | 6 +- extensions/threader/thread/ThreadWorker.h | 6 +- extensions/threader/thread/WinThreads.cpp | 7 +- extensions/threader/thread/WinThreads.h | 6 +- modules.versions | 2 +- public/sample_ext/Makefile | 10 +- public/sample_ext/extension.cpp | 27 +- public/sample_ext/extension.h | 66 +++- public/sample_ext/msvc8/sdk.vcproj | 33 +- public/sample_ext/sdk/smsdk_config.h | 48 +++ .../sample_ext/sdk}/smsdk_ext.cpp | 62 ++-- public/sample_ext/sdk/smsdk_ext.h | 213 +++++++++++ public/sample_ext/smsdk_config.h | 33 -- 61 files changed, 1665 insertions(+), 1255 deletions(-) create mode 100644 extensions/batsupport/sdk/smsdk_config.h rename extensions/{bintools => batsupport/sdk}/smsdk_ext.cpp (84%) rename {public/sample_ext => extensions/batsupport/sdk}/smsdk_ext.h (73%) delete mode 100644 extensions/batsupport/smsdk_config.h create mode 100644 extensions/bintools/sdk/smsdk_config.h rename {public/sample_ext => extensions/bintools/sdk}/smsdk_ext.cpp (84%) rename extensions/bintools/{ => sdk}/smsdk_ext.h (73%) delete mode 100644 extensions/bintools/smsdk_config.h create mode 100644 extensions/geoip/sdk/smsdk_config.h create mode 100644 extensions/geoip/sdk/smsdk_ext.cpp rename extensions/{batsupport => geoip/sdk}/smsdk_ext.h (72%) delete mode 100644 extensions/geoip/smsdk_config.h delete mode 100644 extensions/geoip/smsdk_ext.cpp delete mode 100644 extensions/geoip/smsdk_ext.h create mode 100644 extensions/threader/sdk/smsdk_config.h rename extensions/{batsupport => threader/sdk}/smsdk_ext.cpp (82%) rename extensions/threader/{ => sdk}/smsdk_ext.h (56%) delete mode 100644 extensions/threader/smsdk_config.h create mode 100644 public/sample_ext/sdk/smsdk_config.h rename {extensions/threader => public/sample_ext/sdk}/smsdk_ext.cpp (68%) create mode 100644 public/sample_ext/sdk/smsdk_ext.h delete mode 100644 public/sample_ext/smsdk_config.h diff --git a/extensions/batsupport/Makefile b/extensions/batsupport/Makefile index 1e9d6a22..8ea51205 100644 --- a/extensions/batsupport/Makefile +++ b/extensions/batsupport/Makefile @@ -12,9 +12,9 @@ SOURCEMM = ../../../../sourcemm PROJECT = batsupport #Uncomment for SourceMM-enabled extensions -#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so +LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -32,7 +32,7 @@ SMM_TRUNK = $(SOURCEMM)/trunk LINK = $(LINK_HL2) -static-libgcc -INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ +INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ @@ -65,11 +65,10 @@ $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< all: - mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/sdk ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so $(MAKE) extension - rm -rf $(BINARY) extension: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) @@ -81,7 +80,8 @@ default: all clean: rm -rf Release/*.o + rm -rf Release/sdk/*.o rm -rf Release/$(BINARY) rm -rf Debug/*.o + rm -rf Debug/sdk/*.o rm -rf Debug/$(BINARY) - diff --git a/extensions/batsupport/extension.cpp b/extensions/batsupport/extension.cpp index 96ef66cc..73e92c08 100644 --- a/extensions/batsupport/extension.cpp +++ b/extensions/batsupport/extension.cpp @@ -1,4 +1,26 @@ -// vim: set ts=4 : +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod BAT Support Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include #include #include "extension.h" @@ -8,7 +30,7 @@ IAdminSystem *admins = NULL; IPlayerManager *players = NULL; SMEXT_LINK(&g_BatSupport); -bool BatSupport::SDK_OnLoad(char *error, size_t err_max, bool late) +bool BatSupport::SDK_OnLoad(char *error, size_t maxlength, bool late) { SM_GET_IFACE(ADMINSYS, admins); SM_GET_IFACE(PLAYERMANAGER, players); @@ -35,7 +57,7 @@ void BatSupport::SDK_OnUnload() m_hooks.clear(); } -bool BatSupport::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +bool BatSupport::SDK_OnMetamodLoad(char *error, size_t maxlength, bool late) { g_SMAPI->AddListener(this, this); diff --git a/extensions/batsupport/extension.h b/extensions/batsupport/extension.h index ce234f0a..5b946719 100644 --- a/extensions/batsupport/extension.h +++ b/extensions/batsupport/extension.h @@ -1,7 +1,34 @@ -// vim: set ts=4 : +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod BAT Support Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +/** + * @file extension.h + * @brief BAT Support extension code header. + */ + #include "smsdk_ext.h" #include "BATInterface.h" #include @@ -22,25 +49,25 @@ class BatSupport : public AdminInterface, public IClientListener { -public: //SDKExtension - bool SDK_OnLoad(char *error, size_t err_max, bool late); +public: // SDKExtension + bool SDK_OnLoad(char *error, size_t maxlength, bool late); void SDK_OnUnload(); - bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); -public: //IMetamodListener + bool SDK_OnMetamodLoad(char *error, size_t maxlength, bool late); +public: // IMetamodListener void *OnMetamodQuery(const char *iface, int *ret); -public: //AdminInterface - bool RegisterFlag(const char *Class,const char *Flag,const char *Description); +public: // AdminInterface + bool RegisterFlag(const char *Class, const char *Flag, const char *Description); bool IsClient(int id); - bool HasFlag(int id,const char *Flag); + bool HasFlag(int id, const char *Flag); int GetInterfaceVersion(); const char* GetModName(); void AddEventListner(AdminInterfaceListner *ptr); void RemoveListner(AdminInterfaceListner *ptr); -public: //IClientListener +public: // IClientListener void OnClientAuthorized(int client, const char *authstring); private: List m_hooks; List m_flags; }; -#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/batsupport/msvc8/batsupport.sln b/extensions/batsupport/msvc8/batsupport.sln index 6f8ed540..cabbd260 100644 --- a/extensions/batsupport/msvc8/batsupport.sln +++ b/extensions/batsupport/msvc8/batsupport.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BatSupport", "BatSupport.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BatSupport", "BatSupport.vcproj", "{E2FDA25A-3F36-46CE-A4EB-F4AB60011386}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -9,10 +9,10 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + {E2FDA25A-3F36-46CE-A4EB-F4AB60011386}.Debug|Win32.ActiveCfg = Debug|Win32 + {E2FDA25A-3F36-46CE-A4EB-F4AB60011386}.Debug|Win32.Build.0 = Debug|Win32 + {E2FDA25A-3F36-46CE-A4EB-F4AB60011386}.Release|Win32.ActiveCfg = Release|Win32 + {E2FDA25A-3F36-46CE-A4EB-F4AB60011386}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/extensions/batsupport/msvc8/batsupport.vcproj b/extensions/batsupport/msvc8/batsupport.vcproj index 43e91d83..45c21f06 100644 --- a/extensions/batsupport/msvc8/batsupport.vcproj +++ b/extensions/batsupport/msvc8/batsupport.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="8.00" Name="BatSupport" - ProjectGUID="{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" + ProjectGUID="{E2FDA25A-3F36-46ce-A4EB-F4AB60011386}" RootNamespace="BatSupport" Keyword="Win32Proj" > @@ -40,161 +40,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/extensions/batsupport/sdk/smsdk_config.h b/extensions/batsupport/sdk/smsdk_config.h new file mode 100644 index 00000000..a2af61bd --- /dev/null +++ b/extensions/batsupport/sdk/smsdk_config.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "BAT Support" +#define SMEXT_CONF_DESCRIPTION "Adds support for BAT's AdminInterface" +#define SMEXT_CONF_VERSION "1.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "BATSUPPORT" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/bintools/smsdk_ext.cpp b/extensions/batsupport/sdk/smsdk_ext.cpp similarity index 84% rename from extensions/bintools/smsdk_ext.cpp rename to extensions/batsupport/sdk/smsdk_ext.cpp index ed2de4ae..d7d3ba02 100644 --- a/extensions/bintools/smsdk_ext.cpp +++ b/extensions/batsupport/sdk/smsdk_ext.cpp @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -44,7 +46,7 @@ SDKExtension::SDKExtension() #endif } -bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) { g_pShareSys = sys; myself = me; @@ -56,7 +58,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, { if (error) { - snprintf(error, err_max, "Metamod attach failed"); + snprintf(error, maxlength, "Metamod attach failed"); } return false; } @@ -66,7 +68,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(SOURCEMOD, g_pSM); SM_GET_IFACE(FORWARDMANAGER, g_pForwards); - if (SDK_OnLoad(error, err_max, late)) + if (SDK_OnLoad(error, maxlength, late)) { #if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; @@ -142,7 +144,7 @@ const char *SDKExtension::GetExtensionURL() return SMEXT_CONF_URL; } -bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) { return true; } @@ -287,17 +289,17 @@ const char *SDKExtension::GetVersion() return GetExtensionVerString(); } -bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) { return true; } -bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) { return true; } -bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) { return true; } @@ -330,4 +332,3 @@ void operator delete[](void * ptr) free(ptr); } #endif - diff --git a/public/sample_ext/smsdk_ext.h b/extensions/batsupport/sdk/smsdk_ext.h similarity index 73% rename from public/sample_ext/smsdk_ext.h rename to extensions/batsupport/sdk/smsdk_ext.h index d763460e..808e9759 100644 --- a/public/sample_ext/smsdk_ext.h +++ b/extensions/batsupport/sdk/smsdk_ext.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -52,11 +54,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -78,21 +80,21 @@ public: * @brief Called when Metamod is attached, before the extension version is called. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. * NOTE: By default this is blocked unless sent from SourceMod. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); /** * @brief Called when Metamod's pause state is changing. @@ -100,14 +102,14 @@ public: * * @param paused Pause state being set. * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif -public: //IExtensionInterface - virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); +public: // IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); virtual void OnExtensionUnload(); virtual void OnExtensionsAllLoaded(); @@ -136,9 +138,9 @@ public: //IExtensionInterface /** Returns date string */ virtual const char *GetExtensionDateString(); #if defined SMEXT_CONF_METAMOD -public: //ISmmPlugin +public: // ISmmPlugin /** Called when the extension is attached to Metamod. */ - virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); /** Returns the author to MM */ virtual const char *GetAuthor(); /** Returns the name to MM */ @@ -185,12 +187,27 @@ extern IServerGameDLL *gamedll; /** Creates a SourceMod interface macro pair */ #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION /** Automates retrieving SourceMod interfaces */ -#define SM_GET_IFACE(prefix,addr) \ - if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ - if (error) { \ - snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ - } \ - return false; \ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ } -#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/batsupport/smsdk_config.h b/extensions/batsupport/smsdk_config.h deleted file mode 100644 index 0454a055..00000000 --- a/extensions/batsupport/smsdk_config.h +++ /dev/null @@ -1,33 +0,0 @@ -// vim: set ts=4 : -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -/** - * @file smsdk_config.h - * @brief Contains macros for configuring basic extension information. - */ - -/* Basic information exposed publically */ -#define SMEXT_CONF_NAME "BAT Support" -#define SMEXT_CONF_DESCRIPTION "Adds support for BAT's AdminInterface" -#define SMEXT_CONF_VERSION "1.0.0.0" -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "BATSUPPORT" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING __DATE__ - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - * NOTE: This is enabled automatically if a Metamod build is chosen in - * the Visual Studio project. - */ -#define SMEXT_CONF_METAMOD - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/bintools/CallMaker.cpp b/extensions/bintools/CallMaker.cpp index c8941e7e..ba1a814a 100644 --- a/extensions/bintools/CallMaker.cpp +++ b/extensions/bintools/CallMaker.cpp @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/CallMaker.h b/extensions/bintools/CallMaker.h index d142a683..a7e31ca8 100644 --- a/extensions/bintools/CallMaker.h +++ b/extensions/bintools/CallMaker.h @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/CallWrapper.cpp b/extensions/bintools/CallWrapper.cpp index 15018160..8437a643 100644 --- a/extensions/bintools/CallWrapper.cpp +++ b/extensions/bintools/CallWrapper.cpp @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/CallWrapper.h b/extensions/bintools/CallWrapper.h index 3e7b2d2e..df880b23 100644 --- a/extensions/bintools/CallWrapper.h +++ b/extensions/bintools/CallWrapper.h @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/Makefile b/extensions/bintools/Makefile index f87eb55a..6272ffe0 100644 --- a/extensions/bintools/Makefile +++ b/extensions/bintools/Makefile @@ -14,7 +14,7 @@ PROJECT = bintools #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp jit_call.cpp CallWrapper.cpp CallMaker.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp jit_call.cpp CallWrapper.cpp CallMaker.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -32,7 +32,7 @@ SMM_TRUNK = $(SOURCEMM)/trunk LINK = $(LINK_HL2) -static-libgcc -INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ +INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions -I$(SMSDK)/public/jit \ -I$(SMSDK)/public/jit/x86 @@ -66,11 +66,10 @@ $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< all: - mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/sdk ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so $(MAKE) extension - rm -rf $(BINARY) extension: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) @@ -82,7 +81,8 @@ default: all clean: rm -rf Release/*.o + rm -rf Release/sdk/*.o rm -rf Release/$(BINARY) rm -rf Debug/*.o + rm -rf Debug/sdk/*.o rm -rf Debug/$(BINARY) - diff --git a/extensions/bintools/extension.cpp b/extensions/bintools/extension.cpp index e1786feb..2bac45a0 100644 --- a/extensions/bintools/extension.cpp +++ b/extensions/bintools/extension.cpp @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ @@ -21,16 +26,16 @@ /** * @file extension.cpp - * @brief Implement extension code here. + * @brief Implements BinTools extension code. */ -BinTools g_BinTools; /**< Global singleton for your extension's main interface */ +BinTools g_BinTools; /**< Global singleton for extension's main interface */ CallMaker g_CallMaker; ISourcePawnEngine *g_SPEngine; SMEXT_LINK(&g_BinTools); -bool BinTools::SDK_OnLoad(char *error, size_t err_max, bool late) +bool BinTools::SDK_OnLoad(char *error, size_t maxlength, bool late) { g_SPEngine = g_pSM->GetScriptingEngine(); g_pShareSys->AddInterface(myself, &g_CallMaker); diff --git a/extensions/bintools/extension.h b/extensions/bintools/extension.h index 148e1e16..0b875fdc 100644 --- a/extensions/bintools/extension.h +++ b/extensions/bintools/extension.h @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ @@ -24,12 +29,11 @@ * @brief Sample extension code header. */ - #include "smsdk_ext.h" /** - * @brief Sample implementation of the SDK Extension. + * @brief Implementation of the BinTools extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. */ class BinTools : public SDKExtension @@ -39,11 +43,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -65,22 +69,45 @@ public: * @brief this is called when Core wants to know if your extension is working. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @return True if working, false otherwise. */ - //virtual void QueryRunning(char *error, size_t maxlength); + //virtual bool QueryRunning(char *error, size_t maxlength); public: #if defined SMEXT_CONF_METAMOD /** - * Read smext_base.h for documentation on these. + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. */ + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); - //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); - //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); - //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif }; extern ISourcePawnEngine *g_SPEngine; -#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp index 28066981..00fa78e7 100644 --- a/extensions/bintools/jit_call.cpp +++ b/extensions/bintools/jit_call.cpp @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/jit_call.h b/extensions/bintools/jit_call.h index 2534600e..83bbbee4 100644 --- a/extensions/bintools/jit_call.h +++ b/extensions/bintools/jit_call.h @@ -1,17 +1,22 @@ /** * vim: set ts=4 : * =============================================================== - * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. - * All rights reserved. + * SourceMod BinTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be - * used or modified under the Terms and Conditions of its License Agreement, - * which is found in public/licenses/LICENSE.txt. As of this notice, derivative - * works must be licensed under the GNU General Public License (version 2 or - * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * To view the latest information, see: http://www.sourcemod.net/license.php + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Version: $Id$ */ diff --git a/extensions/bintools/msvc8/bintools.sln b/extensions/bintools/msvc8/bintools.sln index 44048bb2..61d64d98 100644 --- a/extensions/bintools/msvc8/bintools.sln +++ b/extensions/bintools/msvc8/bintools.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bintools", "bintools.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bintools", "bintools.vcproj", "{E38F65D9-74B2-4373-B46A-DBB76F579F98}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -9,10 +9,10 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + {E38F65D9-74B2-4373-B46A-DBB76F579F98}.Debug|Win32.ActiveCfg = Debug|Win32 + {E38F65D9-74B2-4373-B46A-DBB76F579F98}.Debug|Win32.Build.0 = Debug|Win32 + {E38F65D9-74B2-4373-B46A-DBB76F579F98}.Release|Win32.ActiveCfg = Release|Win32 + {E38F65D9-74B2-4373-B46A-DBB76F579F98}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/extensions/bintools/msvc8/bintools.vcproj b/extensions/bintools/msvc8/bintools.vcproj index bc4a9c58..f069e273 100644 --- a/extensions/bintools/msvc8/bintools.vcproj +++ b/extensions/bintools/msvc8/bintools.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="8.00" Name="bintools" - ProjectGUID="{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" + ProjectGUID="{E38F65D9-74B2-4373-B46A-DBB76F579F98}" RootNamespace="bintools" Keyword="Win32Proj" > @@ -40,7 +40,7 @@ - - - - - - + + + + + + + + + + + + diff --git a/extensions/bintools/sdk/smsdk_config.h b/extensions/bintools/sdk/smsdk_config.h new file mode 100644 index 00000000..af26a061 --- /dev/null +++ b/extensions/bintools/sdk/smsdk_config.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "Sample Extension" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SAMPLE" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +//#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/public/sample_ext/smsdk_ext.cpp b/extensions/bintools/sdk/smsdk_ext.cpp similarity index 84% rename from public/sample_ext/smsdk_ext.cpp rename to extensions/bintools/sdk/smsdk_ext.cpp index ed2de4ae..d7d3ba02 100644 --- a/public/sample_ext/smsdk_ext.cpp +++ b/extensions/bintools/sdk/smsdk_ext.cpp @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -44,7 +46,7 @@ SDKExtension::SDKExtension() #endif } -bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) { g_pShareSys = sys; myself = me; @@ -56,7 +58,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, { if (error) { - snprintf(error, err_max, "Metamod attach failed"); + snprintf(error, maxlength, "Metamod attach failed"); } return false; } @@ -66,7 +68,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(SOURCEMOD, g_pSM); SM_GET_IFACE(FORWARDMANAGER, g_pForwards); - if (SDK_OnLoad(error, err_max, late)) + if (SDK_OnLoad(error, maxlength, late)) { #if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; @@ -142,7 +144,7 @@ const char *SDKExtension::GetExtensionURL() return SMEXT_CONF_URL; } -bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) { return true; } @@ -287,17 +289,17 @@ const char *SDKExtension::GetVersion() return GetExtensionVerString(); } -bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) { return true; } -bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) { return true; } -bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) { return true; } @@ -330,4 +332,3 @@ void operator delete[](void * ptr) free(ptr); } #endif - diff --git a/extensions/bintools/smsdk_ext.h b/extensions/bintools/sdk/smsdk_ext.h similarity index 73% rename from extensions/bintools/smsdk_ext.h rename to extensions/bintools/sdk/smsdk_ext.h index d763460e..808e9759 100644 --- a/extensions/bintools/smsdk_ext.h +++ b/extensions/bintools/sdk/smsdk_ext.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -52,11 +54,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -78,21 +80,21 @@ public: * @brief Called when Metamod is attached, before the extension version is called. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. * NOTE: By default this is blocked unless sent from SourceMod. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); /** * @brief Called when Metamod's pause state is changing. @@ -100,14 +102,14 @@ public: * * @param paused Pause state being set. * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif -public: //IExtensionInterface - virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); +public: // IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); virtual void OnExtensionUnload(); virtual void OnExtensionsAllLoaded(); @@ -136,9 +138,9 @@ public: //IExtensionInterface /** Returns date string */ virtual const char *GetExtensionDateString(); #if defined SMEXT_CONF_METAMOD -public: //ISmmPlugin +public: // ISmmPlugin /** Called when the extension is attached to Metamod. */ - virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); /** Returns the author to MM */ virtual const char *GetAuthor(); /** Returns the name to MM */ @@ -185,12 +187,27 @@ extern IServerGameDLL *gamedll; /** Creates a SourceMod interface macro pair */ #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION /** Automates retrieving SourceMod interfaces */ -#define SM_GET_IFACE(prefix,addr) \ - if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ - if (error) { \ - snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ - } \ - return false; \ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ } -#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/bintools/smsdk_config.h b/extensions/bintools/smsdk_config.h deleted file mode 100644 index dfc8a925..00000000 --- a/extensions/bintools/smsdk_config.h +++ /dev/null @@ -1,33 +0,0 @@ -// vim: set ts=4 : -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -/** - * @file smsdk_config.h - * @brief Contains macros for configuring basic extension information. - */ - -/* Basic information exposed publically */ -#define SMEXT_CONF_NAME "Sample Extension" -#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" -#define SMEXT_CONF_VERSION "0.0.0.0" -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "SAMPLE" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING __DATE__ - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - * NOTE: This is enabled automatically if a Metamod build is chosen in - * the Visual Studio project. - */ -//#define SMEXT_CONF_METAMOD - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/geoip/Makefile b/extensions/geoip/Makefile index 6323db70..b9a013f4 100644 --- a/extensions/geoip/Makefile +++ b/extensions/geoip/Makefile @@ -14,7 +14,7 @@ PROJECT = geoip #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp GeoIP.c +OBJECTS = sdk/smsdk_ext.cpp extension.cpp GeoIP.c ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -32,7 +32,7 @@ SMM_TRUNK = $(SOURCEMM)/trunk LINK = $(LINK_HL2) -static-libgcc -INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ +INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ @@ -60,7 +60,7 @@ endif BINARY = $(PROJECT).ext.so OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) -OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o) $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< @@ -69,11 +69,10 @@ $(BIN_DIR)/%.o: %.c $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< all: - mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/sdk ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so $(MAKE) extension - rm -rf $(BINARY) extension: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) @@ -85,7 +84,8 @@ default: all clean: rm -rf Release/*.o + rm -rf Release/sdk/*.o rm -rf Release/$(BINARY) rm -rf Debug/*.o + rm -rf Debug/sdk/*.o rm -rf Debug/$(BINARY) - diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp index 0fb7b4a0..930289ca 100644 --- a/extensions/geoip/extension.cpp +++ b/extensions/geoip/extension.cpp @@ -1,5 +1,9 @@ /** - * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod GeoIP Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,21 +24,25 @@ #include "extension.h" #include "GeoIP.h" +/** + * @file extension.cpp + * @brief Implement extension code here. + */ GeoIP_Extension g_GeoIP; GeoIP *gi = NULL; SMEXT_LINK(&g_GeoIP); -bool GeoIP_Extension::SDK_OnLoad(char *error, size_t err_max, bool late) +bool GeoIP_Extension::SDK_OnLoad(char *error, size_t maxlength, bool late) { - char path[PLATFORM_MAX_PATH+1]; + char path[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_SM, path, sizeof(path), "configs/geoip/GeoIP.dat"); gi = GeoIP_open(path, GEOIP_MEMORY_CACHE); if (!gi) { - snprintf(error, err_max, "Failed to instantiate GeoIP!"); + snprintf(error, maxlength, "Failed to instantiate GeoIP!"); return false; } @@ -113,4 +121,3 @@ const sp_nativeinfo_t geoip_natives[] = {"GeoipCountry", sm_Geoip_Country}, {NULL, NULL}, }; - diff --git a/extensions/geoip/extension.h b/extensions/geoip/extension.h index 79e313d4..152c5256 100644 --- a/extensions/geoip/extension.h +++ b/extensions/geoip/extension.h @@ -1,5 +1,9 @@ /** - * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod GeoIP Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,12 +24,16 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +/** + * @file extension.h + * @brief GeoIP extension code header. + */ + #include "smsdk_ext.h" -#define GEOIPDATADIR "" /** - * @brief GeoIP implementation of the SDK Extension. + * @brief Implementation of the GeoIP extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. */ class GeoIP_Extension : public SDKExtension @@ -35,11 +43,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -61,22 +69,45 @@ public: * @brief this is called when Core wants to know if your extension is working. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @return True if working, false otherwise. */ - //virtual void QueryRunning(char *error, size_t maxlength); + //virtual bool QueryRunning(char *error, size_t maxlength); public: #if defined SMEXT_CONF_METAMOD /** - * Read smext_base.h for documentation on these. + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. */ + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); - //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); - //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); - //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif }; extern const sp_nativeinfo_t geoip_natives[]; -#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/geoip/msvc8/geoip.sln b/extensions/geoip/msvc8/geoip.sln index 62e8c591..2fb7770a 100644 --- a/extensions/geoip/msvc8/geoip.sln +++ b/extensions/geoip/msvc8/geoip.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "geoip", "geoip.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "geoip", "geoip.vcproj", "{698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -9,10 +9,10 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 - {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + {698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}.Debug|Win32.ActiveCfg = Debug|Win32 + {698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}.Debug|Win32.Build.0 = Debug|Win32 + {698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}.Release|Win32.ActiveCfg = Release|Win32 + {698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/extensions/geoip/msvc8/geoip.vcproj b/extensions/geoip/msvc8/geoip.vcproj index 313793a6..cac3e583 100644 --- a/extensions/geoip/msvc8/geoip.vcproj +++ b/extensions/geoip/msvc8/geoip.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="8.00" Name="geoip" - ProjectGUID="{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" + ProjectGUID="{698EAEE7-0EFC-4017-9B88-ECCAAF42FD5F}" RootNamespace="geoip" Keyword="Win32Proj" > @@ -40,7 +40,7 @@ - - - - - - @@ -229,6 +217,22 @@ > + + + + + + + + diff --git a/extensions/geoip/sdk/smsdk_config.h b/extensions/geoip/sdk/smsdk_config.h new file mode 100644 index 00000000..09025e28 --- /dev/null +++ b/extensions/geoip/sdk/smsdk_config.h @@ -0,0 +1,49 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#include "svn_version.h" + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "GeoIP" +#define SMEXT_CONF_DESCRIPTION "NO IDEA WHAT THIS MODULE DOES" //:TODO: +#define SMEXT_CONF_VERSION SVN_FULL_VERSION +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "GEOIP" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +//#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/geoip/sdk/smsdk_ext.cpp b/extensions/geoip/sdk/smsdk_ext.cpp new file mode 100644 index 00000000..02eb27ee --- /dev/null +++ b/extensions/geoip/sdk/smsdk_ext.cpp @@ -0,0 +1,334 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, maxlength, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + + if (SDK_OnLoad(error, maxlength, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlength) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif diff --git a/extensions/batsupport/smsdk_ext.h b/extensions/geoip/sdk/smsdk_ext.h similarity index 72% rename from extensions/batsupport/smsdk_ext.h rename to extensions/geoip/sdk/smsdk_ext.h index 8d23c32e..808e9759 100644 --- a/extensions/batsupport/smsdk_ext.h +++ b/extensions/geoip/sdk/smsdk_ext.h @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -52,11 +54,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -78,21 +80,21 @@ public: * @brief Called when Metamod is attached, before the extension version is called. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. * NOTE: By default this is blocked unless sent from SourceMod. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); /** * @brief Called when Metamod's pause state is changing. @@ -100,14 +102,14 @@ public: * * @param paused Pause state being set. * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif -public: //IExtensionInterface - virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); +public: // IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); virtual void OnExtensionUnload(); virtual void OnExtensionsAllLoaded(); @@ -136,9 +138,9 @@ public: //IExtensionInterface /** Returns date string */ virtual const char *GetExtensionDateString(); #if defined SMEXT_CONF_METAMOD -public: //ISmmPlugin +public: // ISmmPlugin /** Called when the extension is attached to Metamod. */ - virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); /** Returns the author to MM */ virtual const char *GetAuthor(); /** Returns the name to MM */ @@ -185,12 +187,27 @@ extern IServerGameDLL *gamedll; /** Creates a SourceMod interface macro pair */ #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION /** Automates retrieving SourceMod interfaces */ -#define SM_GET_IFACE(prefix,addr) \ - if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ - if (error) { \ - snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ - } \ - return false; \ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ } -#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/geoip/smsdk_config.h b/extensions/geoip/smsdk_config.h deleted file mode 100644 index 8e77d2ac..00000000 --- a/extensions/geoip/smsdk_config.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * GeoIP SourceMod Extension, (C)2007 AlliedModders LLC. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -#include "svn_version.h" - -/* Basic information exposed publically */ -#define SMEXT_CONF_NAME "GeoIP" -#define SMEXT_CONF_DESCRIPTION "NO IDEA WHAT THIS MODULE DOES" //:TODO: -#define SMEXT_CONF_VERSION SVN_FULL_VERSION -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "GEOIP" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING __DATE__ - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - * NOTE: This is enabled automatically if a Metamod build is chosen in - * the Visual Studio project. - */ -//#define SMEXT_CONF_METAMOD - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/geoip/smsdk_ext.cpp b/extensions/geoip/smsdk_ext.cpp deleted file mode 100644 index 8dfd6db6..00000000 --- a/extensions/geoip/smsdk_ext.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== - * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#include -#include -#include "smsdk_ext.h" - -IShareSys *g_pShareSys = NULL; -IExtension *myself = NULL; -IHandleSys *g_pHandleSys = NULL; -ISourceMod *g_pSM = NULL; -IForwardManager *g_pForwards = NULL; - -PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() -{ - return g_pExtensionIface; -} - -SDKExtension::SDKExtension() -{ -#if defined SMEXT_CONF_METAMOD - m_SourceMMLoaded = false; - m_WeAreUnloaded = false; - m_WeGotPauseChange = false; -#endif -} - -bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) -{ - g_pShareSys = sys; - myself = me; - -#if defined SMEXT_CONF_METAMOD - m_WeAreUnloaded = true; - - if (!m_SourceMMLoaded) - { - if (error) - { - snprintf(error, err_max, "Metamod attach failed"); - } - return false; - } -#endif - - SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); - SM_GET_IFACE(SOURCEMOD, g_pSM); - SM_GET_IFACE(FORWARDMANAGER, g_pForwards); - - if (SDK_OnLoad(error, err_max, late)) - { -#if defined SMEXT_CONF_METAMOD - m_WeAreUnloaded = true; -#endif - return true; - } - - return false; -} - -bool SDKExtension::IsMetamodExtension() -{ -#if defined SMEXT_CONF_METAMOD - return true; -#else - return false; -#endif -} - -void SDKExtension::OnExtensionPauseChange(bool state) -{ -#if defined SMEXT_CONF_METAMOD - m_WeGotPauseChange = true; -#endif - SDK_OnPauseChange(state); -} - -void SDKExtension::OnExtensionsAllLoaded() -{ - SDK_OnAllLoaded(); -} - -void SDKExtension::OnExtensionUnload() -{ -#if defined SMEXT_CONF_METAMOD - m_WeAreUnloaded = true; -#endif - SDK_OnUnload(); -} - -const char *SDKExtension::GetExtensionAuthor() -{ - return SMEXT_CONF_AUTHOR; -} - -const char *SDKExtension::GetExtensionDateString() -{ - return SMEXT_CONF_DATESTRING; -} - -const char *SDKExtension::GetExtensionDescription() -{ - return SMEXT_CONF_DESCRIPTION; -} - -const char *SDKExtension::GetExtensionVerString() -{ - return SMEXT_CONF_VERSION; -} - -const char *SDKExtension::GetExtensionName() -{ - return SMEXT_CONF_NAME; -} - -const char *SDKExtension::GetExtensionTag() -{ - return SMEXT_CONF_LOGTAG; -} - -const char *SDKExtension::GetExtensionURL() -{ - return SMEXT_CONF_URL; -} - -bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) -{ - return true; -} - -void SDKExtension::SDK_OnUnload() -{ -} - -void SDKExtension::SDK_OnPauseChange(bool paused) -{ -} - -void SDKExtension::SDK_OnAllLoaded() -{ -} - -#if defined SMEXT_CONF_METAMOD - -PluginId g_PLID = 0; -ISmmPlugin *g_PLAPI = NULL; -SourceHook::ISourceHook *g_SHPtr = NULL; -ISmmAPI *g_SMAPI = NULL; - -IVEngineServer *engine = NULL; -IServerGameDLL *gamedll = NULL; - -SMM_API void *PL_EXPOSURE(const char *name, int *code) -{ - if (name && !strcmp(name, PLAPI_NAME)) - { - if (code) - { - *code = IFACE_OK; - } - return static_cast(g_pExtensionIface); - } - - if (code) - { - *code = IFACE_FAILED; - } - - return NULL; -} - -bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) -{ - PLUGIN_SAVEVARS(); - - GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); - GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); - - m_SourceMMLoaded = true; - - return SDK_OnMetamodLoad(error, maxlen, late); -} - -bool SDKExtension::Unload(char *error, size_t maxlen) -{ - if (!m_WeAreUnloaded) - { - if (error) - { - snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); - } - return false; - } - - return SDK_OnMetamodUnload(error, maxlen); -} - -bool SDKExtension::Pause(char *error, size_t maxlen) -{ - if (!m_WeGotPauseChange) - { - if (error) - { - snprintf(error, maxlen, "This extension must be paused by SourceMod."); - } - return false; - } - - m_WeGotPauseChange = false; - - return SDK_OnMetamodPauseChange(true, error, maxlen); -} - -bool SDKExtension::Unpause(char *error, size_t maxlen) -{ - if (!m_WeGotPauseChange) - { - if (error) - { - snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); - } - return false; - } - - m_WeGotPauseChange = false; - - return SDK_OnMetamodPauseChange(false, error, maxlen); -} - -const char *SDKExtension::GetAuthor() -{ - return GetExtensionAuthor(); -} - -const char *SDKExtension::GetDate() -{ - return GetExtensionDateString(); -} - -const char *SDKExtension::GetDescription() -{ - return GetExtensionDescription(); -} - -const char *SDKExtension::GetLicense() -{ - return SMEXT_CONF_LICENSE; -} - -const char *SDKExtension::GetLogTag() -{ - return GetExtensionTag(); -} - -const char *SDKExtension::GetName() -{ - return GetExtensionName(); -} - -const char *SDKExtension::GetURL() -{ - return GetExtensionURL(); -} - -const char *SDKExtension::GetVersion() -{ - return GetExtensionVerString(); -} - -bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) -{ - return true; -} - -bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) -{ - return true; -} - -bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) -{ - return true; -} - -#endif - -/* Overload a few things to prevent libstdc++ linking */ -#if defined __linux__ -extern "C" void __cxa_pure_virtual(void) -{ -} - -void *operator new(size_t size) -{ - return malloc(size); -} - -void *operator new[](size_t size) -{ - return malloc(size); -} - -void operator delete(void *ptr) -{ - free(ptr); -} - -void operator delete[](void * ptr) -{ - free(ptr); -} -#endif - diff --git a/extensions/geoip/smsdk_ext.h b/extensions/geoip/smsdk_ext.h deleted file mode 100644 index ce82828a..00000000 --- a/extensions/geoip/smsdk_ext.h +++ /dev/null @@ -1,158 +0,0 @@ -/** - * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. - * =============================================================== - * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ - -#include "smsdk_config.h" -#include -#include -#include -#include -#include -#include - -#if defined SMEXT_CONF_METAMOD -#include -#include -#endif - -using namespace SourceMod; -using namespace SourcePawn; - -class SDKExtension : -#if defined SMEXT_CONF_METAMOD - public ISmmPlugin, -#endif - public IExtensionInterface -{ -public: - SDKExtension(); -public: - /** - * @brief This is called after the initial loading sequence has been processed. - * - * @param error Error message buffer. - * @param err_max Size of error message buffer. - * @param late Whether or not the module was loaded after map load. - * @return True to succeed loading, false to fail. - */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); - - /** - * @brief This is called right before the extension is unloaded. - */ - virtual void SDK_OnUnload(); - - /** - * @brief This is called once all known extensions have been loaded. - */ - virtual void SDK_OnAllLoaded(); - - /** - * @brief Called when the pause state is changed. - */ - virtual void SDK_OnPauseChange(bool paused); - -#if defined SMEXT_CONF_METAMOD - /** - * @brief Called when Metamod is attached, before the extension version is called. - * - * @param error Error buffer. - * @param err_max Maximum size of error buffer. - * @param late Whether or not Metamod considers this a late load. - * @return True to succeed, false to fail. - */ - virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); - - /** - * @brief Called when Metamod is detaching, after the extension version is called. - * NOTE: By default this is blocked unless sent from SourceMod. - * - * @param error Error buffer. - * @param err_max Maximum size of error buffer. - * @return True to succeed, false to fail. - */ - virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); - - /** - * @brief Called when Metamod's pause state is changing. - * NOTE: By default this is blocked unless sent from SourceMod. - * - * @param paused Pause state being set. - * @param error Error buffer. - * @param err_max Maximum size of error buffer. - * @return True to succeed, false to fail. - */ - virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); -#endif - -public: //IExtensionInterface - virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); - virtual void OnExtensionUnload(); - virtual void OnExtensionsAllLoaded(); - virtual bool IsMetamodExtension(); - virtual void OnExtensionPauseChange(bool state); - virtual const char *GetExtensionName(); - virtual const char *GetExtensionURL(); - virtual const char *GetExtensionTag(); - virtual const char *GetExtensionAuthor(); - virtual const char *GetExtensionVerString(); - virtual const char *GetExtensionDescription(); - virtual const char *GetExtensionDateString(); -#if defined SMEXT_CONF_METAMOD -public: //ISmmPlugin - virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); - virtual const char *GetAuthor(); - virtual const char *GetName(); - virtual const char *GetDescription(); - virtual const char *GetURL(); - virtual const char *GetLicense(); - virtual const char *GetVersion(); - virtual const char *GetDate(); - virtual const char *GetLogTag(); - virtual bool Unload(char *error, size_t maxlen); - virtual bool Pause(char *error, size_t maxlen); - virtual bool Unpause(char *error, size_t maxlen); -private: - bool m_SourceMMLoaded; - bool m_WeAreUnloaded; - bool m_WeGotPauseChange; -#endif -}; - -extern SDKExtension *g_pExtensionIface; - -extern IShareSys *g_pShareSys; -extern IExtension *myself; -extern IHandleSys *g_pHandleSys; -extern ISourceMod *g_pSM; -extern IForwardManager *g_pForwards; - -#if defined SMEXT_CONF_METAMOD -PLUGIN_GLOBALVARS(); -extern IVEngineServer *engine; -extern IServerGameDLL *gamedll; -#endif - -#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION -#define SM_GET_IFACE(prefix,addr) \ - if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ - if (error) { \ - snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ - } \ - return false; \ - } - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/threader/Makefile b/extensions/threader/Makefile index a02f6076..af1b4dc2 100644 --- a/extensions/threader/Makefile +++ b/extensions/threader/Makefile @@ -14,7 +14,7 @@ PROJECT = threader #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp \ +OBJECTS = sdk/smsdk_ext.cpp extension.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp \ thread/ThreadWorker.cpp ############################################## @@ -33,7 +33,7 @@ SMM_TRUNK = $(SOURCEMM)/trunk LINK = $(LINK_HL2) -lpthread -static-libgcc -INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ +INCLUDE = -I. -I.. -Isdk -Ithread -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ @@ -61,20 +61,16 @@ endif BINARY = $(PROJECT).ext.so OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) -OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -$(BIN_DIR)/%.o: %.c - $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< - all: + mkdir -p $(BIN_DIR)/sdk mkdir -p $(BIN_DIR)/thread ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so $(MAKE) extension - rm -rf $(BINARY) extension: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) @@ -86,7 +82,10 @@ default: all clean: rm -rf Release/*.o + rm -rf Release/sdk/*.o + rm -rf Release/thread/*.o rm -rf Release/$(BINARY) rm -rf Debug/*.o - rm -rf Debug/$(BINARY) - + rm -rf Debug/sdk/*.o + rm -rf Debug/thread/*.o + rm -rf Debug/$(BINARY) \ No newline at end of file diff --git a/extensions/threader/extension.cpp b/extensions/threader/extension.cpp index b8907529..5ddbb20b 100644 --- a/extensions/threader/extension.cpp +++ b/extensions/threader/extension.cpp @@ -1,5 +1,9 @@ /** - * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threading Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,12 +24,17 @@ #include "extension.h" #include "thread/ThreadSupport.h" +/** + * @file extension.cpp + * @brief Implements threader extension code. + */ + Sample g_Sample; MainThreader g_Threader; SMEXT_LINK(&g_Sample); -bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late) +bool Sample::SDK_OnLoad(char *error, size_t maxlength, bool late) { g_pShareSys->AddInterface(myself, &g_Threader); diff --git a/extensions/threader/extension.h b/extensions/threader/extension.h index f43a8ea1..450a4369 100644 --- a/extensions/threader/extension.h +++ b/extensions/threader/extension.h @@ -1,5 +1,9 @@ /** - * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threading Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,10 +24,15 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +/** + * @file extension.h + * @brief Threader extension code header. + */ + #include "smsdk_ext.h" /** - * @brief Sample implementation of the SDK Extension. + * @brief Implementation of the threader extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. */ class Sample : public SDKExtension @@ -33,11 +42,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -59,20 +68,43 @@ public: * @brief this is called when Core wants to know if your extension is working. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @return True if working, false otherwise. */ - //virtual void QueryRunning(char *error, size_t maxlength); + //virtual bool QueryRunning(char *error, size_t maxlength); public: #if defined SMEXT_CONF_METAMOD /** - * Read smext_base.h for documentation on these. + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. */ + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); - //virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); - //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); - //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif }; -#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/threader/msvc8/threader.vcproj b/extensions/threader/msvc8/threader.vcproj index 0d33669f..18b6b35b 100644 --- a/extensions/threader/msvc8/threader.vcproj +++ b/extensions/threader/msvc8/threader.vcproj @@ -40,7 +40,7 @@ + + + + diff --git a/extensions/threader/sdk/smsdk_config.h b/extensions/threader/sdk/smsdk_config.h new file mode 100644 index 00000000..1c743e7f --- /dev/null +++ b/extensions/threader/sdk/smsdk_config.h @@ -0,0 +1,49 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#include "svn_version.h" + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "Threader" +#define SMEXT_CONF_DESCRIPTION "Provides threading to other modules" +#define SMEXT_CONF_VERSION SVN_FULL_VERSION +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "THREADER" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +//#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/batsupport/smsdk_ext.cpp b/extensions/threader/sdk/smsdk_ext.cpp similarity index 82% rename from extensions/batsupport/smsdk_ext.cpp rename to extensions/threader/sdk/smsdk_ext.cpp index 2e060a7f..d7d3ba02 100644 --- a/extensions/batsupport/smsdk_ext.cpp +++ b/extensions/threader/sdk/smsdk_ext.cpp @@ -5,11 +5,13 @@ * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -44,7 +46,7 @@ SDKExtension::SDKExtension() #endif } -bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) { g_pShareSys = sys; myself = me; @@ -56,7 +58,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, { if (error) { - snprintf(error, err_max, "Metamod attach failed"); + snprintf(error, maxlength, "Metamod attach failed"); } return false; } @@ -66,7 +68,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(SOURCEMOD, g_pSM); SM_GET_IFACE(FORWARDMANAGER, g_pForwards); - if (SDK_OnLoad(error, err_max, late)) + if (SDK_OnLoad(error, maxlength, late)) { #if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; @@ -142,7 +144,7 @@ const char *SDKExtension::GetExtensionURL() return SMEXT_CONF_URL; } -bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) { return true; } @@ -198,7 +200,7 @@ bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, m_SourceMMLoaded = true; - return SDK_OnMetamodLoad(error, maxlen, late); + return SDK_OnMetamodLoad(ismm, error, maxlen, late); } bool SDKExtension::Unload(char *error, size_t maxlen) @@ -287,17 +289,17 @@ const char *SDKExtension::GetVersion() return GetExtensionVerString(); } -bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) { return true; } -bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) { return true; } -bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) { return true; } @@ -330,4 +332,3 @@ void operator delete[](void * ptr) free(ptr); } #endif - diff --git a/extensions/threader/smsdk_ext.h b/extensions/threader/sdk/smsdk_ext.h similarity index 56% rename from extensions/threader/smsdk_ext.h rename to extensions/threader/sdk/smsdk_ext.h index ce82828a..808e9759 100644 --- a/extensions/threader/smsdk_ext.h +++ b/extensions/threader/sdk/smsdk_ext.h @@ -1,13 +1,17 @@ /** + * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -15,6 +19,11 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + #include "smsdk_config.h" #include #include @@ -38,17 +47,18 @@ class SDKExtension : public IExtensionInterface { public: + /** Constructor */ SDKExtension(); public: /** * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -70,21 +80,21 @@ public: * @brief Called when Metamod is attached, before the extension version is called. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. * NOTE: By default this is blocked unless sent from SourceMod. * * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); /** * @brief Called when Metamod's pause state is changing. @@ -92,38 +102,66 @@ public: * * @param paused Pause state being set. * @param error Error buffer. - * @param err_max Maximum size of error buffer. + * @param maxlength Maximum size of error buffer. * @return True to succeed, false to fail. */ - virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif -public: //IExtensionInterface - virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); +public: // IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); virtual void OnExtensionUnload(); virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ virtual const char *GetExtensionName(); + /** Returns URL */ virtual const char *GetExtensionURL(); + /** Returns log tag */ virtual const char *GetExtensionTag(); + /** Returns author */ virtual const char *GetExtensionAuthor(); + /** Returns version string */ virtual const char *GetExtensionVerString(); + /** Returns description string */ virtual const char *GetExtensionDescription(); + /** Returns date string */ virtual const char *GetExtensionDateString(); #if defined SMEXT_CONF_METAMOD -public: //ISmmPlugin - virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); +public: // ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); + /** Returns the author to MM */ virtual const char *GetAuthor(); + /** Returns the name to MM */ virtual const char *GetName(); + /** Returns the description to MM */ virtual const char *GetDescription(); + /** Returns the URL to MM */ virtual const char *GetURL(); + /** Returns the license to MM */ virtual const char *GetLicense(); + /** Returns the version string to MM */ virtual const char *GetVersion(); + /** Returns the date string to MM */ virtual const char *GetDate(); + /** Returns the logtag to MM */ virtual const char *GetLogTag(); + /** Called on unload */ virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ virtual bool Unpause(char *error, size_t maxlen); private: bool m_SourceMMLoaded; @@ -146,13 +184,30 @@ extern IVEngineServer *engine; extern IServerGameDLL *gamedll; #endif +/** Creates a SourceMod interface macro pair */ #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION -#define SM_GET_IFACE(prefix,addr) \ - if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ - if (error) { \ - snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ - } \ - return false; \ +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ } -#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/threader/smsdk_config.h b/extensions/threader/smsdk_config.h deleted file mode 100644 index bd488494..00000000 --- a/extensions/threader/smsdk_config.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * SourceMod Threading Extension, (C)2007 AlliedModders LLC. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Version: $Id$ - */ -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -#include "svn_version.h" - -/* Basic information exposed publically */ -#define SMEXT_CONF_NAME "Threader" -#define SMEXT_CONF_DESCRIPTION "Provides threading to other modules" -#define SMEXT_CONF_VERSION SVN_FULL_VERSION -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "THREADER" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING __DATE__ - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - * NOTE: This is enabled automatically if a Metamod build is chosen in - * the Visual Studio project. - */ -//#define SMEXT_CONF_METAMOD - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/threader/thread/BaseWorker.cpp b/extensions/threader/thread/BaseWorker.cpp index e2881c9e..5f632875 100644 --- a/extensions/threader/thread/BaseWorker.cpp +++ b/extensions/threader/thread/BaseWorker.cpp @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/BaseWorker.h b/extensions/threader/thread/BaseWorker.h index 127e8259..65e875a2 100644 --- a/extensions/threader/thread/BaseWorker.h +++ b/extensions/threader/thread/BaseWorker.h @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/PosixThreads.cpp b/extensions/threader/thread/PosixThreads.cpp index 24e8e5ef..b2a30aca 100644 --- a/extensions/threader/thread/PosixThreads.cpp +++ b/extensions/threader/thread/PosixThreads.cpp @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -295,4 +299,3 @@ void PosixThreader::PosixEventSignal::DestroyThis() { delete this; } - diff --git a/extensions/threader/thread/PosixThreads.h b/extensions/threader/thread/PosixThreads.h index f27b4f27..efa4248a 100644 --- a/extensions/threader/thread/PosixThreads.h +++ b/extensions/threader/thread/PosixThreads.h @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/ThreadSupport.h b/extensions/threader/thread/ThreadSupport.h index f36f6e57..f87cf548 100644 --- a/extensions/threader/thread/ThreadSupport.h +++ b/extensions/threader/thread/ThreadSupport.h @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/ThreadWorker.cpp b/extensions/threader/thread/ThreadWorker.cpp index 7e745e91..32e2e757 100644 --- a/extensions/threader/thread/ThreadWorker.cpp +++ b/extensions/threader/thread/ThreadWorker.cpp @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/ThreadWorker.h b/extensions/threader/thread/ThreadWorker.h index c01a9f39..bdf2e949 100644 --- a/extensions/threader/thread/ThreadWorker.h +++ b/extensions/threader/thread/ThreadWorker.h @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/extensions/threader/thread/WinThreads.cpp b/extensions/threader/thread/WinThreads.cpp index 25c335b2..9798e6db 100644 --- a/extensions/threader/thread/WinThreads.cpp +++ b/extensions/threader/thread/WinThreads.cpp @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -321,4 +325,3 @@ void WinThreader::WinEvent::DestroyThis() { delete this; } - diff --git a/extensions/threader/thread/WinThreads.h b/extensions/threader/thread/WinThreads.h index fd11b932..a5fa4a25 100644 --- a/extensions/threader/thread/WinThreads.h +++ b/extensions/threader/thread/WinThreads.h @@ -1,5 +1,9 @@ /** - * SourceMod Threader API (C)2007 AlliedModders LLC. All rights reserved. + * vim: set ts=4 : + * =============================================================== + * SourceMod Threader API + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/modules.versions b/modules.versions index a0d7008c..d1197ce5 100644 --- a/modules.versions +++ b/modules.versions @@ -26,4 +26,4 @@ out = svn_version.h [threader] folder = extensions/threader in = svn_version.tpl -out = svn_version.h \ No newline at end of file +out = svn_version.h diff --git a/public/sample_ext/Makefile b/public/sample_ext/Makefile index e65ffeb1..8c735d7d 100644 --- a/public/sample_ext/Makefile +++ b/public/sample_ext/Makefile @@ -14,7 +14,7 @@ PROJECT = sample #Uncomment for SourceMM-enabled extensions #LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -OBJECTS = extension.cpp smsdk_ext.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -32,7 +32,7 @@ SMM_TRUNK = $(SOURCEMM)/trunk LINK = $(LINK_HL2) -static-libgcc -INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ +INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ @@ -65,11 +65,10 @@ $(BIN_DIR)/%.o: %.cpp $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< all: - mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/sdk ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so $(MAKE) extension - rm -rf $(BINARY) extension: $(OBJ_LINUX) $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) @@ -81,7 +80,8 @@ default: all clean: rm -rf Release/*.o + rm -rf Release/sdk/*.o rm -rf Release/$(BINARY) rm -rf Debug/*.o + rm -rf Debug/sdk/*.o rm -rf Debug/$(BINARY) - diff --git a/public/sample_ext/extension.cpp b/public/sample_ext/extension.cpp index dd6b36b7..8c7db16c 100644 --- a/public/sample_ext/extension.cpp +++ b/public/sample_ext/extension.cpp @@ -1,4 +1,26 @@ -// vim: set ts=4 : +/** + * vim: set ts=4 : + * =============================================================== + * Sample SourceMod Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #include "extension.h" /** @@ -6,7 +28,6 @@ * @brief Implement extension code here. */ -Sample g_Sample; /**< Global singleton for your extension's main interface */ +Sample g_Sample; /**< Global singleton for extension's main interface */ SMEXT_LINK(&g_Sample); - diff --git a/public/sample_ext/extension.h b/public/sample_ext/extension.h index e88b3494..a1f11ebb 100644 --- a/public/sample_ext/extension.h +++ b/public/sample_ext/extension.h @@ -1,4 +1,26 @@ -// vim: set ts=4 : +/** + * vim: set ts=4 : + * =============================================================== + * Sample SourceMod Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ @@ -7,7 +29,6 @@ * @brief Sample extension code header. */ - #include "smsdk_ext.h" @@ -22,11 +43,11 @@ public: * @brief This is called after the initial loading sequence has been processed. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - //virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + //virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. @@ -48,20 +69,43 @@ public: * @brief this is called when Core wants to know if your extension is working. * * @param error Error message buffer. - * @param err_max Size of error message buffer. + * @param maxlength Size of error message buffer. * @return True if working, false otherwise. */ - //virtual void QueryRunning(char *error, size_t maxlength); + //virtual bool QueryRunning(char *error, size_t maxlength); public: #if defined SMEXT_CONF_METAMOD /** - * Read smext_base.h for documentation on these. + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. */ + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); - //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); - //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); - //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); #endif }; -#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/public/sample_ext/msvc8/sdk.vcproj b/public/sample_ext/msvc8/sdk.vcproj index cb06fd34..444323ad 100644 --- a/public/sample_ext/msvc8/sdk.vcproj +++ b/public/sample_ext/msvc8/sdk.vcproj @@ -40,7 +40,7 @@ - - - - - - + + + + + + + + diff --git a/public/sample_ext/sdk/smsdk_config.h b/public/sample_ext/sdk/smsdk_config.h new file mode 100644 index 00000000..af26a061 --- /dev/null +++ b/public/sample_ext/sdk/smsdk_config.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "Sample Extension" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SAMPLE" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +//#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/threader/smsdk_ext.cpp b/public/sample_ext/sdk/smsdk_ext.cpp similarity index 68% rename from extensions/threader/smsdk_ext.cpp rename to public/sample_ext/sdk/smsdk_ext.cpp index 8dfd6db6..d7d3ba02 100644 --- a/extensions/threader/smsdk_ext.cpp +++ b/public/sample_ext/sdk/smsdk_ext.cpp @@ -1,13 +1,17 @@ /** + * vim: set ts=4 : * =============================================================== - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. * =============================================================== * - * This file is part of the SourceMod/SourcePawn SDK. This file may only be used - * or modified under the Terms and Conditions of its License Agreement, which is found - * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins - * may change at any time. To view the latest information, see: - * http://www.sourcemod.net/license.php + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php * * Version: $Id$ */ @@ -16,12 +20,18 @@ #include #include "smsdk_ext.h" -IShareSys *g_pShareSys = NULL; -IExtension *myself = NULL; -IHandleSys *g_pHandleSys = NULL; -ISourceMod *g_pSM = NULL; -IForwardManager *g_pForwards = NULL; +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() { return g_pExtensionIface; @@ -36,7 +46,7 @@ SDKExtension::SDKExtension() #endif } -bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) { g_pShareSys = sys; myself = me; @@ -48,7 +58,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, { if (error) { - snprintf(error, err_max, "Metamod attach failed"); + snprintf(error, maxlength, "Metamod attach failed"); } return false; } @@ -58,7 +68,7 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, SM_GET_IFACE(SOURCEMOD, g_pSM); SM_GET_IFACE(FORWARDMANAGER, g_pForwards); - if (SDK_OnLoad(error, err_max, late)) + if (SDK_OnLoad(error, maxlength, late)) { #if defined SMEXT_CONF_METAMOD m_WeAreUnloaded = true; @@ -134,7 +144,7 @@ const char *SDKExtension::GetExtensionURL() return SMEXT_CONF_URL; } -bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) { return true; } @@ -153,14 +163,15 @@ void SDKExtension::SDK_OnAllLoaded() #if defined SMEXT_CONF_METAMOD -PluginId g_PLID = 0; -ISmmPlugin *g_PLAPI = NULL; -SourceHook::ISourceHook *g_SHPtr = NULL; -ISmmAPI *g_SMAPI = NULL; +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ -IVEngineServer *engine = NULL; -IServerGameDLL *gamedll = NULL; +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ +/** Exposes the extension to Metamod */ SMM_API void *PL_EXPOSURE(const char *name, int *code) { if (name && !strcmp(name, PLAPI_NAME)) @@ -189,7 +200,7 @@ bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, m_SourceMMLoaded = true; - return SDK_OnMetamodLoad(error, maxlen, late); + return SDK_OnMetamodLoad(ismm, error, maxlen, late); } bool SDKExtension::Unload(char *error, size_t maxlen) @@ -278,17 +289,17 @@ const char *SDKExtension::GetVersion() return GetExtensionVerString(); } -bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late) +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) { return true; } -bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) { return true; } -bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) { return true; } @@ -321,4 +332,3 @@ void operator delete[](void * ptr) free(ptr); } #endif - diff --git a/public/sample_ext/sdk/smsdk_ext.h b/public/sample_ext/sdk/smsdk_ext.h new file mode 100644 index 00000000..24647206 --- /dev/null +++ b/public/sample_ext/sdk/smsdk_ext.h @@ -0,0 +1,213 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlength); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlength); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlength); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/public/sample_ext/smsdk_config.h b/public/sample_ext/smsdk_config.h deleted file mode 100644 index dfc8a925..00000000 --- a/public/sample_ext/smsdk_config.h +++ /dev/null @@ -1,33 +0,0 @@ -// vim: set ts=4 : -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -/** - * @file smsdk_config.h - * @brief Contains macros for configuring basic extension information. - */ - -/* Basic information exposed publically */ -#define SMEXT_CONF_NAME "Sample Extension" -#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" -#define SMEXT_CONF_VERSION "0.0.0.0" -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "SAMPLE" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING __DATE__ - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - * NOTE: This is enabled automatically if a Metamod build is chosen in - * the Visual Studio project. - */ -//#define SMEXT_CONF_METAMOD - -#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ From 4432602e8382504507035ca699aa733bee115c25 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 9 May 2007 05:30:56 +0000 Subject: [PATCH 0733/1664] Oh forgot these, even though they don't matter much --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40764 --- extensions/batsupport/extension.cpp | 5 +++++ extensions/batsupport/extension.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/extensions/batsupport/extension.cpp b/extensions/batsupport/extension.cpp index 73e92c08..f47f90a4 100644 --- a/extensions/batsupport/extension.cpp +++ b/extensions/batsupport/extension.cpp @@ -25,6 +25,11 @@ #include #include "extension.h" +/** + * @file extension.cpp + * @brief Implements BAT Support extension code. + */ + BatSupport g_BatSupport; /**< Global singleton for your extension's main interface */ IAdminSystem *admins = NULL; IPlayerManager *players = NULL; diff --git a/extensions/batsupport/extension.h b/extensions/batsupport/extension.h index 5b946719..16aa0244 100644 --- a/extensions/batsupport/extension.h +++ b/extensions/batsupport/extension.h @@ -43,6 +43,10 @@ struct CustomFlag FlagBits bit; }; +/** + * @brief Implementation of the BAT Support extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ class BatSupport : public SDKExtension, public IMetamodListener, From ec13f1b9984b8d34a9a299bd380fa58415336e18 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 9 May 2007 20:14:56 +0000 Subject: [PATCH 0734/1664] Fixed an issue where unloading and then reloading a plugin that creates convars would make it's convar list blank --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40765 --- core/ConVarManager.cpp | 3 +++ core/msvc8/sourcemod_mm.vcproj | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index e298711c..4e48b6a9 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -218,6 +218,9 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, /* If the convar already exists... */ if (pConVar) { + /* Add convar to plugin's list */ + AddConVarToPluginList(pContext, pConVar); + /* First find out if we already have a handle to it */ if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo)) { diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index d945d2af..a6526fba 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -400,6 +400,7 @@ Date: Wed, 9 May 2007 21:35:24 +0000 Subject: [PATCH 0735/1664] fixed __DATE__ showing up wrong --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40766 --- sourcepawn/compiler/sc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 0e62d854..97e3fc41 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -566,7 +566,7 @@ static void inst_datetime_defines(void) time(&td); curtime = localtime(&td); - strftime(date, 31, "\"%m/%d%Y\"", curtime); + strftime(date, 31, "\"%m/%d%/Y\"", curtime); strftime(ltime, 31, "\"%H:%M:%S\"", curtime); insert_subst("__DATE__", date, 8); From a4d07a2d40ac72597192124f779a87824871d3a8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 10 May 2007 14:13:50 +0000 Subject: [PATCH 0736/1664] stupid bug --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40767 --- sourcepawn/compiler/sc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 97e3fc41..6202762e 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -566,7 +566,7 @@ static void inst_datetime_defines(void) time(&td); curtime = localtime(&td); - strftime(date, 31, "\"%m/%d%/Y\"", curtime); + strftime(date, 31, "\"%m/%d/%Y\"", curtime); strftime(ltime, 31, "\"%H:%M:%S\"", curtime); insert_subst("__DATE__", date, 8); From 4ae67c92137dbb2078d933cce7c2c33a90b104c6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Thu, 10 May 2007 22:51:56 +0000 Subject: [PATCH 0737/1664] added debug code for leak detection on plugins --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40768 --- core/vm/sp_vm_basecontext.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index d1424119..e2d042d8 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -20,6 +20,10 @@ #include "sp_vm_basecontext.h" #include "sp_vm_engine.h" +#ifdef SOURCEMOD_BUILD +#include "Logger.h" +#endif + using namespace SourcePawn; extern SourcePawnEngine g_SourcePawn; @@ -223,11 +227,24 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) */ g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); -#if defined _DEBUG +#if 1//defined _DEBUG + //:TODO: debug code for leak detection, remove before the release? if (err == SP_ERROR_NONE) { - assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); - assert(ctx->hp == save_hp); + if ((ctx->sp - pushcount * sizeof(cell_t)) != save_sp) + { + const char *name; + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); + g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name); + } + if (ctx->hp != save_hp) + { + const char *name; + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); + g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name); + } + //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); + //assert(ctx->hp == save_hp); } #endif if (err != SP_ERROR_NONE) From 1274c0b8bda2edad8557494586f7e848598e9a70 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Fri, 11 May 2007 20:00:29 +0000 Subject: [PATCH 0738/1664] Fixed linux build --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40769 --- core/vm/sp_vm_basecontext.cpp | 1974 ++++++++++++++++----------------- 1 file changed, 987 insertions(+), 987 deletions(-) diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index e2d042d8..6475241e 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -1,987 +1,987 @@ -/** - * vim: set ts=4 : - * ================================================================ - * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. - * ================================================================ - * - * This file is not open source and may not be copied without explicit - * written permission of AlliedModders LLC. This file may not be redistributed - * in whole or significant part. - * For information, see LICENSE.txt or http://www.sourcemod.net/license.php - * - * Version: $Id$ - */ - -#include -#include -#include -#include -#include "sp_vm_api.h" -#include "sp_vm_basecontext.h" -#include "sp_vm_engine.h" - -#ifdef SOURCEMOD_BUILD -#include "Logger.h" -#endif - -using namespace SourcePawn; - -extern SourcePawnEngine g_SourcePawn; - -#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) -#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) - -int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip) -{ - g_SourcePawn.RunTracer(ctx, frm, cip); - - return SP_ERROR_NONE; -} - -BaseContext::BaseContext(sp_context_t *_ctx) -{ - ctx = _ctx; - ctx->context = this; - ctx->dbreak = GlobalDebugBreak; - m_InExec = false; - m_CustomMsg = false; - m_funcsnum = ctx->vmbase->FunctionCount(ctx); -#if 0 - m_priv_funcs = NULL; -#endif - m_pub_funcs = NULL; - -#if 0 - /** - * Note: Since the m_plugin member will never change, - * it is safe to assume the function count will never change - */ - if (m_funcsnum && m_priv_funcs == NULL) - { - m_priv_funcs = new CFunction *[m_funcsnum]; - memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); - } else { - m_priv_funcs = NULL; - } -#endif - - if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) - { - m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; - memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); - } else { - m_pub_funcs = NULL; - } -} - -void BaseContext::FlushFunctionCache() -{ - if (m_pub_funcs) - { - for (uint32_t i=0; iplugin->info.publics_num; i++) - { - delete m_pub_funcs[i]; - m_pub_funcs[i] = NULL; - } - } - -#if 0 - if (m_priv_funcs) - { - for (unsigned int i=0; iplugin->info.publics_num; i++) - { - if (!m_pub_funcs[i]) - { - continue; - } - if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE) - { - continue; - } - m_pub_funcs[i]->Set(pub->code_offs, this); - } - } - -#if 0 - if (m_priv_funcs) - { - for (unsigned int i=0; i - } - } -#endif -} - -BaseContext::~BaseContext() -{ - FlushFunctionCache(); - delete [] m_pub_funcs; - m_pub_funcs = NULL; -#if 0 - delete [] m_priv_funcs; - m_priv_funcs = NULL; -#endif -} - -void BaseContext::SetContext(sp_context_t *_ctx) -{ - if (!_ctx) - { - return; - } - ctx = _ctx; - ctx->context = this; - ctx->dbreak = GlobalDebugBreak; - RefreshFunctionCache(); -} - -IVirtualMachine *BaseContext::GetVirtualMachine() -{ - return (IVirtualMachine *)ctx->vmbase; -} - -sp_context_t *BaseContext::GetContext() -{ - return ctx; -} - -bool BaseContext::IsDebugging() -{ - return (ctx->flags & SPFLAG_PLUGIN_DEBUG); -} - -int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) -{ - if (!IsDebugging()) - { - return SP_ERROR_NOTDEBUGGING; - } - - *oldpfn = ctx->dbreak; - ctx->dbreak = newpfn; - - return SP_ERROR_NONE; -} - -IPluginDebugInfo *BaseContext::GetDebugInfo() -{ - return this; -} - -int BaseContext::Execute(uint32_t code_addr, cell_t *result) -{ - if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) - { - return SP_ERROR_NOT_RUNNABLE; - } - - IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; - - uint32_t pushcount = ctx->pushcount; - int err; - - PushCell(pushcount++); - ctx->pushcount = 0; - - cell_t save_sp = ctx->sp; - cell_t save_hp = ctx->hp; - uint32_t n_idx = ctx->n_idx; - - bool wasExec = m_InExec; - - /* Clear the error state, if any */ - ctx->n_err = SP_ERROR_NONE; - ctx->n_idx = 0; - m_InExec = true; - m_MsgCache[0] = '\0'; - m_CustomMsg = false; - - g_SourcePawn.PushTracer(ctx); - - err = vm->ContextExecute(ctx, code_addr, result); - - m_InExec = wasExec; - - /** - * :TODO: Calling from a plugin in here will erase the cached message... - * Should that be documented? - */ - g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); - -#if 1//defined _DEBUG - //:TODO: debug code for leak detection, remove before the release? - if (err == SP_ERROR_NONE) - { - if ((ctx->sp - pushcount * sizeof(cell_t)) != save_sp) - { - const char *name; - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); - g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name); - } - if (ctx->hp != save_hp) - { - const char *name; - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); - g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name); - } - //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); - //assert(ctx->hp == save_hp); - } -#endif - if (err != SP_ERROR_NONE) - { - ctx->sp = save_sp; - ctx->hp = save_hp; - } - - ctx->n_idx = n_idx; - - return err; -} - -void BaseContext::SetErrorMessage(const char *msg, va_list ap) -{ - m_CustomMsg = true; - - vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); -} - -cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) -{ - if (!m_InExec) - { - return 0; - } - - ctx->n_err = error; - - if (msg) - { - va_list ap; - va_start(ap, msg); - SetErrorMessage(msg, ap); - va_end(ap); - } - - return 0; -} - -cell_t BaseContext::ThrowNativeError(const char *msg, ...) -{ - if (!m_InExec) - { - return 0; - } - - ctx->n_err = SP_ERROR_NATIVE; - - if (msg) - { - va_list ap; - va_start(ap, msg); - SetErrorMessage(msg, ap); - va_end(ap); - } - - return 0; -} - -int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) -{ - cell_t *addr; - ucell_t realmem; - -#if 0 - if (cells > CELLBOUNDMAX) - { - return SP_ERROR_ARAM; - } -#else - assert(cells < CELLBOUNDMAX); -#endif - - realmem = cells * sizeof(cell_t); - - /** - * Check if the space between the heap and stack is sufficient. - */ - if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) - { - return SP_ERROR_HEAPLOW; - } - - addr = (cell_t *)(ctx->memory + ctx->hp); - /* store size of allocation in cells */ - *addr = (cell_t)cells; - addr++; - ctx->hp += sizeof(cell_t); - - *local_addr = ctx->hp; - - if (phys_addr) - { - *phys_addr = addr; - } - - ctx->hp += realmem; - - return SP_ERROR_NONE; -} - -int BaseContext::HeapPop(cell_t local_addr) -{ - cell_t cellcount; - cell_t *addr; - - /* check the bounds of this address */ - local_addr -= sizeof(cell_t); - if (local_addr < ctx->heap_base || local_addr >= ctx->sp) - { - return SP_ERROR_INVALID_ADDRESS; - } - - addr = (cell_t *)(ctx->memory + local_addr); - cellcount = (*addr) * sizeof(cell_t); - /* check if this memory count looks valid */ - if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr; - - return SP_ERROR_NONE; -} - - -int BaseContext::HeapRelease(cell_t local_addr) -{ - if (local_addr < ctx->heap_base) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr - sizeof(cell_t); - - return SP_ERROR_NONE; -} - -int BaseContext::FindNativeByName(const char *name, uint32_t *index) -{ - int high; - - high = ctx->plugin->info.natives_num - 1; - - for (uint32_t i=0; iplugin->info.natives_num; i++) - { - if (strcmp(ctx->natives[i].name, name) == 0) - { - if (index) - { - *index = i; - } - return SP_ERROR_NONE; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) -{ - if (index >= ctx->plugin->info.natives_num) - { - return SP_ERROR_INDEX; - } - - if (native) - { - *native = &(ctx->natives[index]); - } - - return SP_ERROR_NONE; -} - - -uint32_t BaseContext::GetNativesNum() -{ - return ctx->plugin->info.natives_num; -} - -int BaseContext::FindPublicByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.publics_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->publics[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) -{ - if (index >= ctx->plugin->info.publics_num) - { - return SP_ERROR_INDEX; - } - - if (pblic) - { - *pblic = &(ctx->publics[index]); - } - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPublicsNum() -{ - return ctx->plugin->info.publics_num; -} - -int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - if (pubvar) - { - *pubvar = &(ctx->pubvars[index]); - } - - return SP_ERROR_NONE; -} - -int BaseContext::FindPubvarByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.pubvars_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->pubvars[mid].name, name); - if (diff == 0) - { - if (index) - { - *index = mid; - } - return SP_ERROR_NONE; - } else if (diff < 0) { - low = mid + 1; - } else { - high = mid - 1; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - *local_addr = ctx->plugin->info.pubvars[index].address; - *phys_addr = ctx->pubvars[index].offs; - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPubVarsNum() -{ - return ctx->plugin->info.pubvars_num; -} - -int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) -{ - uint32_t i, j, max; - - max = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_BOUND) && !overwrite) - { - continue; - } - - for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) - { - ctx->natives[i].pfn = natives[j].func; - ctx->natives[i].status = SP_NATIVE_BOUND; - } - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::BindNative(const sp_nativeinfo_t *native) -{ - uint32_t index; - int err; - - if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) - { - return err; - } - - ctx->natives[index].pfn = native->func; - ctx->natives[index].status = SP_NATIVE_BOUND; - - return SP_ERROR_NONE; -} - -int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) -{ - uint32_t nativesnum, i; - - nativesnum = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_UNBOUND) - { - ctx->natives[i].pfn = native; - ctx->natives[i].status = SP_NATIVE_BOUND; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (phys_addr) - { - *phys_addr = (cell_t *)(ctx->memory + local_addr); - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCell(cell_t value) -{ - if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) - { - return SP_ERROR_STACKLOW; - } - - ctx->sp -= sizeof(cell_t); - *(cell_t *)(ctx->memory + ctx->sp) = value; - ctx->pushcount++; - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) -{ - unsigned int i; - int err; - - for (i=0; isp += (cell_t)(i * sizeof(cell_t)); - ctx->pushcount -= i; - return err; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) -{ - cell_t *ph_addr; - int err; - - if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - memcpy(ph_addr, array, numcells * sizeof(cell_t)); - - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) - { - HeapRelease(*local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToString(cell_t local_addr, char **addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - *addr = (char *)(ctx->memory + local_addr); - - return SP_ERROR_NONE; -} - -int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) -{ - char *ph_addr; - int err; - unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); - - if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - memcpy(ph_addr, string, len); - ph_addr[len] = '\0'; - - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) - { - HeapRelease(*local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERROR_NONE; -} - -int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) -{ - char *dest; - size_t len; - - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (bytes == 0) - { - return SP_ERROR_NONE; - } - - len = strlen(source); - dest = (char *)(ctx->memory + local_addr); - - if (len >= bytes) - { - len = bytes - 1; - } - - memcpy(dest, source, len); - dest[len] = '\0'; - - return SP_ERROR_NONE; -} - -inline int __CheckValidChar(char *c) -{ - int count; - int bytecount = 0; - - for (count=1; (*c & 0xC0) == 0x80; count++) - { - c--; - } - - switch (*c & 0xF0) - { - case 0xC0: - case 0xD0: - { - bytecount = 2; - break; - } - case 0xE0: - { - bytecount = 3; - break; - } - case 0xF0: - { - bytecount = 4; - break; - } - } - - if (bytecount != count) - { - return count; - } - - return 0; -} - -int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) -{ - char *dest; - size_t len; - bool needtocheck = false; - - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (maxbytes == 0) - { - return SP_ERROR_NONE; - } - - len = strlen(source); - dest = (char *)(ctx->memory + local_addr); - - if ((size_t)len >= maxbytes) - { - len = maxbytes - 1; - needtocheck = true; - } - - memcpy(dest, source, len); - if ((dest[len-1] & 1<<7) && needtocheck) - { - len -= __CheckValidChar(dest+len-1); - } - dest[len] = '\0'; - - if (wrtnbytes) - { - *wrtnbytes = len; - } - - return SP_ERROR_NONE; -} - -#define USHR(x) ((unsigned int)(x)>>1) - -int BaseContext::LookupFile(ucell_t addr, const char **filename) -{ - int high, low, mid; - - high = ctx->plugin->debug.files_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->files[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERROR_NOT_FOUND; - } - - *filename = ctx->files[low].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupFunction(ucell_t addr, const char **name) -{ - uint32_t iter, max = ctx->plugin->debug.syms_num; - - for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) - && (ctx->symbols[iter].codestart <= addr) - && (ctx->symbols[iter].codeend > addr)) - { - break; - } - } - - if (iter >= max) - { - return SP_ERROR_NOT_FOUND; - } - - *name = ctx->symbols[iter].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupLine(ucell_t addr, uint32_t *line) -{ - int high, low, mid; - - high = ctx->plugin->debug.lines_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->lines[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERROR_NOT_FOUND; - } - - /* Since the CIP occurs BEFORE the line, we have to add one */ - *line = ctx->lines[low].line + 1; - - return SP_ERROR_NONE; -} - -IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) -{ - CFunction *pFunc = NULL; - - if (func_id & 1) - { - func_id >>= 1; - if (func_id >= ctx->plugin->info.publics_num) - { - return NULL; - } - pFunc = m_pub_funcs[func_id]; - if (!pFunc) - { - m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); - pFunc = m_pub_funcs[func_id]; - } else if (pFunc->IsInvalidated()) { - pFunc->Set(ctx->publics[func_id].code_offs, this); - } - } else { - /* :TODO: currently not used */ -#if 0 - func_id >>= 1; - unsigned int index; - if (!g_pVM->FunctionLookup(ctx, func_id, &index)) - { - return NULL; - } - pFunc = m_priv_funcs[func_id]; - if (!pFunc) - { - m_priv_funcs[func_id] = new CFunction(save, this); - pFunc = m_priv_funcs[func_id]; - } -#endif - assert(false); - } - - return pFunc; -} - -IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) -{ - uint32_t index; - - if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) - { - return NULL; - } - - CFunction *pFunc = m_pub_funcs[index]; - if (!pFunc) - { - sp_public_t *pub = NULL; - GetPublicByIndex(index, &pub); - if (pub) - { - m_pub_funcs[index] = new CFunction(pub->code_offs, this); - } - pFunc = m_pub_funcs[index]; - } else if (pFunc->IsInvalidated()) { - sp_public_t *pub = NULL; - GetPublicByIndex(index, &pub); - if (pub) - { - pFunc->Set(pub->code_offs, this); - } else { - pFunc = NULL; - } - } - - return pFunc; -} - -#if defined SOURCEMOD_BUILD -SourceMod::IdentityToken_t *BaseContext::GetIdentity() -{ - return m_pToken; -} - -void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) -{ - m_pToken = token; -} -#endif +/** + * vim: set ts=4 : + * ================================================================ + * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. + * ================================================================ + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include +#include +#include "sp_vm_api.h" +#include "sp_vm_basecontext.h" +#include "sp_vm_engine.h" + +#ifdef SOURCEMOD_BUILD +#include "Logger.h" +#endif + +using namespace SourcePawn; + +extern SourcePawnEngine g_SourcePawn; + +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) + +int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip) +{ + g_SourcePawn.RunTracer(ctx, frm, cip); + + return SP_ERROR_NONE; +} + +BaseContext::BaseContext(sp_context_t *_ctx) +{ + ctx = _ctx; + ctx->context = this; + ctx->dbreak = GlobalDebugBreak; + m_InExec = false; + m_CustomMsg = false; + m_funcsnum = ctx->vmbase->FunctionCount(ctx); +#if 0 + m_priv_funcs = NULL; +#endif + m_pub_funcs = NULL; + +#if 0 + /** + * Note: Since the m_plugin member will never change, + * it is safe to assume the function count will never change + */ + if (m_funcsnum && m_priv_funcs == NULL) + { + m_priv_funcs = new CFunction *[m_funcsnum]; + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); + } else { + m_priv_funcs = NULL; + } +#endif + + if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) + { + m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; + memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); + } else { + m_pub_funcs = NULL; + } +} + +void BaseContext::FlushFunctionCache() +{ + if (m_pub_funcs) + { + for (uint32_t i=0; iplugin->info.publics_num; i++) + { + delete m_pub_funcs[i]; + m_pub_funcs[i] = NULL; + } + } + +#if 0 + if (m_priv_funcs) + { + for (unsigned int i=0; iplugin->info.publics_num; i++) + { + if (!m_pub_funcs[i]) + { + continue; + } + if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE) + { + continue; + } + m_pub_funcs[i]->Set(pub->code_offs, this); + } + } + +#if 0 + if (m_priv_funcs) + { + for (unsigned int i=0; i + } + } +#endif +} + +BaseContext::~BaseContext() +{ + FlushFunctionCache(); + delete [] m_pub_funcs; + m_pub_funcs = NULL; +#if 0 + delete [] m_priv_funcs; + m_priv_funcs = NULL; +#endif +} + +void BaseContext::SetContext(sp_context_t *_ctx) +{ + if (!_ctx) + { + return; + } + ctx = _ctx; + ctx->context = this; + ctx->dbreak = GlobalDebugBreak; + RefreshFunctionCache(); +} + +IVirtualMachine *BaseContext::GetVirtualMachine() +{ + return (IVirtualMachine *)ctx->vmbase; +} + +sp_context_t *BaseContext::GetContext() +{ + return ctx; +} + +bool BaseContext::IsDebugging() +{ + return (ctx->flags & SPFLAG_PLUGIN_DEBUG); +} + +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) +{ + if (!IsDebugging()) + { + return SP_ERROR_NOTDEBUGGING; + } + + *oldpfn = ctx->dbreak; + ctx->dbreak = newpfn; + + return SP_ERROR_NONE; +} + +IPluginDebugInfo *BaseContext::GetDebugInfo() +{ + return this; +} + +int BaseContext::Execute(uint32_t code_addr, cell_t *result) +{ + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + { + return SP_ERROR_NOT_RUNNABLE; + } + + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; + + uint32_t pushcount = ctx->pushcount; + int err; + + PushCell(pushcount++); + ctx->pushcount = 0; + + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + uint32_t n_idx = ctx->n_idx; + + bool wasExec = m_InExec; + + /* Clear the error state, if any */ + ctx->n_err = SP_ERROR_NONE; + ctx->n_idx = 0; + m_InExec = true; + m_MsgCache[0] = '\0'; + m_CustomMsg = false; + + g_SourcePawn.PushTracer(ctx); + + err = vm->ContextExecute(ctx, code_addr, result); + + m_InExec = wasExec; + + /** + * :TODO: Calling from a plugin in here will erase the cached message... + * Should that be documented? + */ + g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); + +#if 1//defined _DEBUG + //:TODO: debug code for leak detection, remove before the release? + if (err == SP_ERROR_NONE) + { + if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp) + { + const char *name; + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); + g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name); + } + if (ctx->hp != save_hp) + { + const char *name; + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); + g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name); + } + //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); + //assert(ctx->hp == save_hp); + } +#endif + if (err != SP_ERROR_NONE) + { + ctx->sp = save_sp; + ctx->hp = save_hp; + } + + ctx->n_idx = n_idx; + + return err; +} + +void BaseContext::SetErrorMessage(const char *msg, va_list ap) +{ + m_CustomMsg = true; + + vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); +} + +cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) +{ + if (!m_InExec) + { + return 0; + } + + ctx->n_err = error; + + if (msg) + { + va_list ap; + va_start(ap, msg); + SetErrorMessage(msg, ap); + va_end(ap); + } + + return 0; +} + +cell_t BaseContext::ThrowNativeError(const char *msg, ...) +{ + if (!m_InExec) + { + return 0; + } + + ctx->n_err = SP_ERROR_NATIVE; + + if (msg) + { + va_list ap; + va_start(ap, msg); + SetErrorMessage(msg, ap); + va_end(ap); + } + + return 0; +} + +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) +{ + cell_t *addr; + ucell_t realmem; + +#if 0 + if (cells > CELLBOUNDMAX) + { + return SP_ERROR_ARAM; + } +#else + assert(cells < CELLBOUNDMAX); +#endif + + realmem = cells * sizeof(cell_t); + + /** + * Check if the space between the heap and stack is sufficient. + */ + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) + { + return SP_ERROR_HEAPLOW; + } + + addr = (cell_t *)(ctx->memory + ctx->hp); + /* store size of allocation in cells */ + *addr = (cell_t)cells; + addr++; + ctx->hp += sizeof(cell_t); + + *local_addr = ctx->hp; + + if (phys_addr) + { + *phys_addr = addr; + } + + ctx->hp += realmem; + + return SP_ERROR_NONE; +} + +int BaseContext::HeapPop(cell_t local_addr) +{ + cell_t cellcount; + cell_t *addr; + + /* check the bounds of this address */ + local_addr -= sizeof(cell_t); + if (local_addr < ctx->heap_base || local_addr >= ctx->sp) + { + return SP_ERROR_INVALID_ADDRESS; + } + + addr = (cell_t *)(ctx->memory + local_addr); + cellcount = (*addr) * sizeof(cell_t); + /* check if this memory count looks valid */ + if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr) + { + return SP_ERROR_INVALID_ADDRESS; + } + + ctx->hp = local_addr; + + return SP_ERROR_NONE; +} + + +int BaseContext::HeapRelease(cell_t local_addr) +{ + if (local_addr < ctx->heap_base) + { + return SP_ERROR_INVALID_ADDRESS; + } + + ctx->hp = local_addr - sizeof(cell_t); + + return SP_ERROR_NONE; +} + +int BaseContext::FindNativeByName(const char *name, uint32_t *index) +{ + int high; + + high = ctx->plugin->info.natives_num - 1; + + for (uint32_t i=0; iplugin->info.natives_num; i++) + { + if (strcmp(ctx->natives[i].name, name) == 0) + { + if (index) + { + *index = i; + } + return SP_ERROR_NONE; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) +{ + if (index >= ctx->plugin->info.natives_num) + { + return SP_ERROR_INDEX; + } + + if (native) + { + *native = &(ctx->natives[index]); + } + + return SP_ERROR_NONE; +} + + +uint32_t BaseContext::GetNativesNum() +{ + return ctx->plugin->info.natives_num; +} + +int BaseContext::FindPublicByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.publics_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->publics[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERROR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) +{ + if (index >= ctx->plugin->info.publics_num) + { + return SP_ERROR_INDEX; + } + + if (pblic) + { + *pblic = &(ctx->publics[index]); + } + + return SP_ERROR_NONE; +} + +uint32_t BaseContext::GetPublicsNum() +{ + return ctx->plugin->info.publics_num; +} + +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERROR_INDEX; + } + + if (pubvar) + { + *pubvar = &(ctx->pubvars[index]); + } + + return SP_ERROR_NONE; +} + +int BaseContext::FindPubvarByName(const char *name, uint32_t *index) +{ + int diff, high, low; + uint32_t mid; + + high = ctx->plugin->info.pubvars_num - 1; + low = 0; + + while (low <= high) + { + mid = (low + high) / 2; + diff = strcmp(ctx->pubvars[mid].name, name); + if (diff == 0) + { + if (index) + { + *index = mid; + } + return SP_ERROR_NONE; + } else if (diff < 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return SP_ERROR_NOT_FOUND; +} + +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) +{ + if (index >= ctx->plugin->info.pubvars_num) + { + return SP_ERROR_INDEX; + } + + *local_addr = ctx->plugin->info.pubvars[index].address; + *phys_addr = ctx->pubvars[index].offs; + + return SP_ERROR_NONE; +} + +uint32_t BaseContext::GetPubVarsNum() +{ + return ctx->plugin->info.pubvars_num; +} + +int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) +{ + uint32_t i, j, max; + + max = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status == SP_NATIVE_BOUND) && !overwrite) + { + continue; + } + + for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) + { + ctx->natives[i].pfn = natives[j].func; + ctx->natives[i].status = SP_NATIVE_BOUND; + } + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::BindNative(const sp_nativeinfo_t *native) +{ + uint32_t index; + int err; + + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) + { + return err; + } + + ctx->natives[index].pfn = native->func; + ctx->natives[index].status = SP_NATIVE_BOUND; + + return SP_ERROR_NONE; +} + +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) +{ + uint32_t nativesnum, i; + + nativesnum = ctx->plugin->info.natives_num; + + for (i=0; inatives[i].status == SP_NATIVE_UNBOUND) + { + ctx->natives[i].pfn = native; + ctx->natives[i].status = SP_NATIVE_BOUND; + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) +{ + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + if (phys_addr) + { + *phys_addr = (cell_t *)(ctx->memory + local_addr); + } + + return SP_ERROR_NONE; +} + +int BaseContext::PushCell(cell_t value) +{ + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) + { + return SP_ERROR_STACKLOW; + } + + ctx->sp -= sizeof(cell_t); + *(cell_t *)(ctx->memory + ctx->sp) = value; + ctx->pushcount++; + + return SP_ERROR_NONE; +} + +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) +{ + unsigned int i; + int err; + + for (i=0; isp += (cell_t)(i * sizeof(cell_t)); + ctx->pushcount -= i; + return err; + } + } + + return SP_ERROR_NONE; +} + +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) +{ + cell_t *ph_addr; + int err; + + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) + { + return err; + } + + memcpy(ph_addr, array, numcells * sizeof(cell_t)); + + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) + { + HeapRelease(*local_addr); + return err; + } + + if (phys_addr) + { + *phys_addr = ph_addr; + } + + return SP_ERROR_NONE; +} + +int BaseContext::LocalToString(cell_t local_addr, char **addr) +{ + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + *addr = (char *)(ctx->memory + local_addr); + + return SP_ERROR_NONE; +} + +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) +{ + char *ph_addr; + int err; + unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); + + if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) + { + return err; + } + + memcpy(ph_addr, string, len); + ph_addr[len] = '\0'; + + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) + { + HeapRelease(*local_addr); + return err; + } + + if (phys_addr) + { + *phys_addr = ph_addr; + } + + return SP_ERROR_NONE; +} + +int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) +{ + char *dest; + size_t len; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + if (bytes == 0) + { + return SP_ERROR_NONE; + } + + len = strlen(source); + dest = (char *)(ctx->memory + local_addr); + + if (len >= bytes) + { + len = bytes - 1; + } + + memcpy(dest, source, len); + dest[len] = '\0'; + + return SP_ERROR_NONE; +} + +inline int __CheckValidChar(char *c) +{ + int count; + int bytecount = 0; + + for (count=1; (*c & 0xC0) == 0x80; count++) + { + c--; + } + + switch (*c & 0xF0) + { + case 0xC0: + case 0xD0: + { + bytecount = 2; + break; + } + case 0xE0: + { + bytecount = 3; + break; + } + case 0xF0: + { + bytecount = 4; + break; + } + } + + if (bytecount != count) + { + return count; + } + + return 0; +} + +int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) +{ + char *dest; + size_t len; + bool needtocheck = false; + + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + if (maxbytes == 0) + { + return SP_ERROR_NONE; + } + + len = strlen(source); + dest = (char *)(ctx->memory + local_addr); + + if ((size_t)len >= maxbytes) + { + len = maxbytes - 1; + needtocheck = true; + } + + memcpy(dest, source, len); + if ((dest[len-1] & 1<<7) && needtocheck) + { + len -= __CheckValidChar(dest+len-1); + } + dest[len] = '\0'; + + if (wrtnbytes) + { + *wrtnbytes = len; + } + + return SP_ERROR_NONE; +} + +#define USHR(x) ((unsigned int)(x)>>1) + +int BaseContext::LookupFile(ucell_t addr, const char **filename) +{ + int high, low, mid; + + high = ctx->plugin->debug.files_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->files[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERROR_NOT_FOUND; + } + + *filename = ctx->files[low].name; + + return SP_ERROR_NONE; +} + +int BaseContext::LookupFunction(ucell_t addr, const char **name) +{ + uint32_t iter, max = ctx->plugin->debug.syms_num; + + for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) + && (ctx->symbols[iter].codestart <= addr) + && (ctx->symbols[iter].codeend > addr)) + { + break; + } + } + + if (iter >= max) + { + return SP_ERROR_NOT_FOUND; + } + + *name = ctx->symbols[iter].name; + + return SP_ERROR_NONE; +} + +int BaseContext::LookupLine(ucell_t addr, uint32_t *line) +{ + int high, low, mid; + + high = ctx->plugin->debug.lines_num; + low = -1; + + while (high - low > 1) + { + mid = USHR(low + high); + if (ctx->lines[mid].addr <= addr) + { + low = mid; + } else { + high = mid; + } + } + + if (low == -1) + { + return SP_ERROR_NOT_FOUND; + } + + /* Since the CIP occurs BEFORE the line, we have to add one */ + *line = ctx->lines[low].line + 1; + + return SP_ERROR_NONE; +} + +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) +{ + CFunction *pFunc = NULL; + + if (func_id & 1) + { + func_id >>= 1; + if (func_id >= ctx->plugin->info.publics_num) + { + return NULL; + } + pFunc = m_pub_funcs[func_id]; + if (!pFunc) + { + m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); + pFunc = m_pub_funcs[func_id]; + } else if (pFunc->IsInvalidated()) { + pFunc->Set(ctx->publics[func_id].code_offs, this); + } + } else { + /* :TODO: currently not used */ +#if 0 + func_id >>= 1; + unsigned int index; + if (!g_pVM->FunctionLookup(ctx, func_id, &index)) + { + return NULL; + } + pFunc = m_priv_funcs[func_id]; + if (!pFunc) + { + m_priv_funcs[func_id] = new CFunction(save, this); + pFunc = m_priv_funcs[func_id]; + } +#endif + assert(false); + } + + return pFunc; +} + +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) +{ + uint32_t index; + + if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) + { + return NULL; + } + + CFunction *pFunc = m_pub_funcs[index]; + if (!pFunc) + { + sp_public_t *pub = NULL; + GetPublicByIndex(index, &pub); + if (pub) + { + m_pub_funcs[index] = new CFunction(pub->code_offs, this); + } + pFunc = m_pub_funcs[index]; + } else if (pFunc->IsInvalidated()) { + sp_public_t *pub = NULL; + GetPublicByIndex(index, &pub); + if (pub) + { + pFunc->Set(pub->code_offs, this); + } else { + pFunc = NULL; + } + } + + return pFunc; +} + +#if defined SOURCEMOD_BUILD +SourceMod::IdentityToken_t *BaseContext::GetIdentity() +{ + return m_pToken; +} + +void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) +{ + m_pToken = token; +} +#endif From 47e359d1951cbd8c59d98f01fc133c43773a45f3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 May 2007 02:14:12 +0000 Subject: [PATCH 0739/1664] fixed typo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40770 --- plugins/include/functions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index 82928120..aa42c3c8 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -339,7 +339,7 @@ functag NativeCall public(Handle:plugin, numParams); * else you risk not having your native shared with other plugins. * * @param name Name of the dynamic native; must be unique amongst - * all other registered dynamic native.s + * all other registered dynamic natives. * @param func Function to use as the dynamic native. * @noreturn */ From a9abbed7dcf5f35f4149fc4b8173a484663278f9 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 12 May 2007 04:47:58 +0000 Subject: [PATCH 0740/1664] User message functions now fallback on IServerGameDLL::GetUserMessageInfo() if SourceMM was unable to get the message list for some reason. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40771 --- core/UserMessages.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++ core/UserMessages.h | 3 +++ core/smn_usermsgs.cpp | 11 +++-------- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 32b0d4ca..53e786a8 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -13,6 +13,7 @@ */ #include "UserMessages.h" +#include "sm_stringutil.h" UserMessages g_UserMsgs; @@ -41,6 +42,12 @@ UserMessages::~UserMessages() m_FreeListeners.popall(); } +void UserMessages::OnSourceModStartup(bool late) +{ + /* -1 means SourceMM was unable to get the user message list */ + m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1); +} + void UserMessages::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); @@ -64,6 +71,23 @@ int UserMessages::GetMessageIndex(const char *msg) if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid))) { + if (m_FallbackSearch) + { + char msgbuf[64]; + int size; + msgid = 0; + + while (gamedll->GetUserMessageInfo(msgid, msgbuf, sizeof(msgbuf), size)) + { + if (strcmp(msgbuf, msg) == 0) + { + sm_trie_insert(m_Names, msg, reinterpret_cast(msgid)); + return msgid; + } + msgid++; + } + } + msgid = g_SMAPI->FindUserMessage(msg); if (msgid != INVALID_MESSAGE_ID) @@ -75,6 +99,26 @@ int UserMessages::GetMessageIndex(const char *msg) return msgid; } +bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const +{ + if (m_FallbackSearch) + { + printf("hello"); + int size; + return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size); + } + printf("hello2"); + const char *msg = g_SMAPI->GetUserMessage(msgid); + + if (msg) + { + strncopy(buffer, msg, maxlength); + return true; + } + + return false; +} + bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) { bf_write *buffer; diff --git a/core/UserMessages.h b/core/UserMessages.h index 17571479..222f2a25 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -44,10 +44,12 @@ public: UserMessages(); ~UserMessages(); public: //SMGlobalClass + void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModAllShutdown(); public: //IUserMessages int GetMessageIndex(const char *msg); + bool GetMessageName(int msgid, char *buffer, size_t maxlength) const; bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags); @@ -71,6 +73,7 @@ private: size_t m_HookCount; bool m_InHook; bool m_BlockEndPost; + bool m_FallbackSearch; Trie *m_Names; CellRecipientFilter m_CellRecFilter; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index f7570802..5e45f17e 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -310,16 +310,11 @@ static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params) { - const char *msgname = g_SMAPI->GetUserMessage(params[1]); + char *msgname; - if (msgname == NULL) - { - return 0; - } + pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname); - pCtx->StringToLocalUTF8(params[2], params[3], msgname, NULL); - - return 1; + return g_UserMsgs.GetMessageName(params[1], msgname, params[3]); } static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) From a11f687f2a7c7b84c134bae064eac6f1adf326e4 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 12 May 2007 04:49:40 +0000 Subject: [PATCH 0741/1664] Oh, wow, removed some debug messages. Nice going DS. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40772 --- core/UserMessages.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 53e786a8..6583418a 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -103,11 +103,10 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con { if (m_FallbackSearch) { - printf("hello"); int size; return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size); } - printf("hello2"); + const char *msg = g_SMAPI->GetUserMessage(msgid); if (msg) From e76b4cd255949c9a5f73f89fcb78ec76c59a831c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 May 2007 22:52:25 +0000 Subject: [PATCH 0742/1664] whoa, added a new template function --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40773 --- core/sm_fastlink.h | 192 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 core/sm_fastlink.h diff --git a/core/sm_fastlink.h b/core/sm_fastlink.h new file mode 100644 index 00000000..507a9926 --- /dev/null +++ b/core/sm_fastlink.h @@ -0,0 +1,192 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + + +#ifndef _INCLUDE_SOURCEMOD_FASTLINK_H_ +#define _INCLUDE_SOURCEMOD_FASTLINK_H_ + +template +class FastLink +{ + friend class iterator; +public: + struct FastLinkNode + { + unsigned int prev; + unsigned int next; + unsigned int freeNode; + T obj; + }; +public: + FastLink(unsigned int maxsize) : m_Size(0), m_FirstLink(0), m_FreeNodes(0), m_LastLink(0) + { + m_MaxSize = maxsize; + m_Nodes = new FastLinkNode[m_MaxSize+1]; + } +public: + bool push_back(const T & obj) + { + unsigned int new_node = GetFreeIndex(); + if (!new_node) + { + return false; + } + m_Nodes[new_node].obj = obj; + m_Nodes[new_node].next = 0; + if (!m_FirstLink) + { + m_Nodes[new_node].prev = 0; + m_FirstLink = new_node; + m_LastLink = new_node; + } else { + m_Nodes[new_node].prev = m_LastLink; + m_Nodes[m_LastLink].next = new_node; + m_LastLink = new_node; + } + m_Size++; + return true; + } + size_t size() const + { + return m_Size; + } +private: + unsigned int GetFreeIndex() + { + if (m_FreeNodes) + { + return m_Nodes[m_FreeNodes--].freeNode; + } else { + if (m_LastLink >= m_MaxSize) + { + return 0; + } + return m_LastLink + 1; + } + } +public: + class iterator + { + friend class FastLink; + public: + iterator() + { + link = NULL; + position = 0; + } + iterator(const FastLink *_link, unsigned int _position) + { + link = _link; + position = _position; + } + public: + bool operator ==(const iterator &where) const + { + return (link == link && position == position); + } + bool operator !=(const iterator &where) const + { + return (link != link || position != position); + } + T & operator *() + { + return link->m_Nodes[position].obj; + } + const T & operator *() const + { + return link->m_Nodes[position].obj; + } + iterator & operator++() + { + position = link->m_Nodes[position].next; + return *this; + } + private: + const FastLink *link; + unsigned int position; + }; +public: + iterator begin() const + { + return iterator(this, m_FirstLink); + } + iterator end() const + { + return iterator(this, 0); + } + void remove(const T & obj) + { + for (iterator iter=begin(); iter!=end(); ++iter) + { + if ((*iter) == obj) + { + erase(iter); + return; + } + } + } + iterator erase(const iterator &where) + { + /* Whoa, this better be right! */ + assert(where.link == this); + + iterator iter(where.link, where.position); + ++iter; + + unsigned int index = where.position; + + /* Each case is different, we have no sentinel. + * CASE: We're the HEAD AND the TAIL */ + if (index == m_FirstLink + && index == m_LastLink) + { + m_FirstLink = 0; + m_LastLink = 0; + } + /* We're the HEAD */ + else if (index == m_FirstLink) + { + m_FirstLink = m_Nodes[index].next; + m_Nodes[index].prev = 0; + } + /* We're the TAIL */ + else if (index == m_LastLink) + { + m_LastLink = m_Nodes[index].prev; + m_Nodes[index].next = 0; + } + /* We're in the middle! */ + else + { + /* Patch forward reference */ + m_Nodes[m_Nodes[index].next].prev = m_Nodes[index].prev; + /* Patch backward reference */ + m_Nodes[m_Nodes[index].prev].next = m_Nodes[index].next; + } + + /* Add us to the free list */ + m_Nodes[++m_FreeNodes].freeNode = index; + + return iter; + } +private: + size_t m_Size; + unsigned int m_FirstLink; + unsigned int m_LastLink; + unsigned int m_FreeNodes; + unsigned int m_MaxSize; + FastLinkNode *m_Nodes; +}; + +#endif //_INCLUDE_SOURCEMOD_FASTLINK_H_ From 30f50e6ded06bf36467635370c08c88e86dce37f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 May 2007 23:45:36 +0000 Subject: [PATCH 0743/1664] Initial import of menu API --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40774 --- public/IMenuManager.h | 647 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 647 insertions(+) create mode 100644 public/IMenuManager.h diff --git a/public/IMenuManager.h b/public/IMenuManager.h new file mode 100644 index 00000000..3f182011 --- /dev/null +++ b/public/IMenuManager.h @@ -0,0 +1,647 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_MENU_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_MENU_SYSTEM_H_ + +#include + +#define SMINTERFACE_MENUMANAGER_NAME "IMenuManager" +#define SMINTERFACE_MENUMANAGER_VERSION 1 + +/** + * @file IMenuManager.h + * @brief Abstracts on-screen menus for clients. + */ + +namespace SourceMod +{ + /** + * @brief Used to determine how an item selection is interpreted. + */ + enum ItemSelection + { + ItemSel_None, /**< Invalid selection */ + ItemSel_Back, /**< Go back one page */ + ItemSel_Next, /**< Go forward one page */ + ItemSel_Exit, /**< Menu was exited */ + ItemSel_Item, /**< Valid item selection */ + }; + + /** + * @brief Used to determine which order to search for items in. + */ + enum ItemOrder + { + ItemOrder_Ascending, /**< Items should be drawn ascendingly */ + ItemOrder_Descending, /**< Items should be drawn descendingly */ + }; + + /** + * @brief Pairs an item type with an item menu position. + */ + struct menu_slots_t + { + ItemSelection type; /**< Item selection type */ + unsigned int item; /**< Item position, if applicable */ + }; + + class IBaseMenu; + class IMenuDisplay; + class IMenuHandler; + + /** + * @brief Describes menu display information. + */ + struct menu_states_t + { + unsigned int apiVers; /**< Must be filled with the API version */ + IBaseMenu *menu; /**< Menu pointer, or NULL if there is only a display */ + IMenuHandler *mh; /**< Menu callbacks handler */ + unsigned int firstItem; /**< MENU ONLY: First item displayed on the last page */ + unsigned int lastItem; /**< MENU ONLY: Last item displayed on the last page */ + menu_slots_t slots[11]; /**< MENU ONLY: Item selection table (first index is 1) */ + }; + + #define ITEMDRAW_DEFAULT (0) /**< Item should be drawn normally */ + #define ITEMDRAW_DISABLED (1<<0) /**< Item is drawn but not selectable */ + #define ITEMDRAW_RAWLINE (1<<1) /**< Item should be a raw line, without a slot */ + #define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ + #define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ + #define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) + + /** + * @brief Information about item drawing. + */ + struct ItemDrawInfo + { + ItemDrawInfo() + { + style = 0; + display = NULL; + } + ItemDrawInfo(const char *DISPLAY, unsigned int STYLE=ITEMDRAW_DEFAULT) + : display(DISPLAY), style(STYLE) + { + } + unsigned int style; /**< ITEMDRAW style flags */ + const char *display; /**< Display text (NULL for none) */ + }; + + /** + * @brief Reasons for a menu dying. + */ + enum MenuCancelReason + { + MenuCancel_Disconnect = -1, /** Client dropped from the server */ + MenuCancel_Interrupt = -2, /** Client was interrupted with another menu */ + MenuCancel_Exit = -3, /** Client selected "exit" on a paginated menu */ + MenuCancel_NoDisplay = -4, /** Menu could not be displayed to the client */ + }; + + #define MENU_NO_PAGINATION -1 /**< Menu should not be paginated (10 items max) */ + #define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ + + #define MENU_DETAIL_NOITEMCOLORS (1<<0) /**< Disables extended colors; menus will be white only */ + + /** + * @brief Extended menu options. + */ + enum MenuOption + { + MenuOption_DetailFlags, /**< INT *: A combination of MENU_DETAIL properties (default=0) */ + MenuOption_IntroMessage, /**< CONST CHAR *: Valve menus only; defaults to: + "You have a menu, hit ESC" + */ + MenuOption_IntroColor, /**< INT[4]: Valve menus only; specifies the intro message colour + using R,G,B,A (defaults to 255,0,0,255) + */ + }; + + /** + * @brief Describes the menu a player is viewing. + */ + enum MenuSource + { + MenuSource_None = 0, /**< No menu is being displayed */ + MenuSource_External = 1, /**< External menu, no pointer */ + MenuSource_BaseMenu = 2, /**< An IBaseMenu pointer. */ + MenuSource_Display = 3, /**< IMenuDisplay source, no pointer */ + }; + + class IMenuStyle; + + /** + * @brief Sets how a raw menu should be drawn. + */ + class IMenuDisplay + { + public: + virtual ~IMenuDisplay() + { + } + public: + /** + * @brief Returns the parent IMenuStyle pointer. + * + * @return IMenuStyle pointer which created + * this object. + */ + virtual IMenuStyle *GetParentStyle() =0; + + /** + * @brief Resets/clears the cached display text. + */ + virtual void Reset() =0; + + /** + * @brief Sets how the title should be drawn. + * + * @param text Text string to display for the title. + * @param onlyIfEmpty Only sets the title if one does not already + * exist. + */ + virtual void DrawTitle(const char *text, bool onlyIfEmpty=false) =0; + + /** + * @brief Adds an item to the menu and returns the position (1-10). + * + * Note: Item will fail to draw if there are too many items, + * or the item is not drawable (for example, invisible). + * + * @return Item draw position, or 0 on failure. + */ + virtual unsigned int DrawItem(const ItemDrawInfo &item) =0; + + /** + * @brief Draws a raw line of text, if supported. The line does not + * need to be newline terminated. + * + * @return True on success, false if not supported. + */ + virtual bool DrawRawLine(const char *rawline) =0; + + /** + * @brief Sets an extended menu option. + * + * @param option Option type. + * @param valuePtr Pointer of the type expected by the option. + * @return True on success, false if option or value is not supported. + */ + virtual bool SetExtOption(MenuOption option, const void *valuePtr) =0; + + /** + * @brief Returns whether the display is capable of rendering an item + * with the given flags. + * + * @param flags ITEMDRAW flags. + * @return True if renderable, false otherwise. + */ + virtual bool CanDrawItem(unsigned int drawFlags) =0; + + /** + * @brief Sends the menu display to a client. + * + * @param client Client index to display to. + * @param handler Menu handler to use. + * @param time Time to hold menu for. + * @return True on success, false otherwise. + */ + virtual bool SendDisplay(int client, IMenuHandler *handler, unsigned int time) =0; + }; + + /** + * @brief Describes a "MenuStyle" system which manages + * menu drawing and construction. + */ + class IMenuStyle + { + public: + /** + * @brief Returns the style API version. + * + * @return API version. + */ + virtual unsigned int GetStyleAPIVersion() + { + return SMINTERFACE_MENUMANAGER_VERSION; + } + + /** + * @brief Returns the name of the menu style. + * + * @return String containing the style name. + */ + virtual const char *GetStyleName() =0; + + /** + * @brief Creates an IMenuDisplay object. + * + * Note: the object should be freed using delete. + * + * @return IMenuDisplay object. + */ + virtual IMenuDisplay *CreateDisplay() =0; + + /** + * @brief Creates an IBaseMenu object of this style. + * + * Note: the object should be freed using IBaseMenu::Destroy. + * + * @return An IBaseMenu pointer. + */ + virtual IBaseMenu *CreateMenu() =0; + + /** + * @brief Returns the maximum number of items per page. + * + * @return Number of items per page. + */ + virtual unsigned int GetMaxPageItems() =0; + + /** + * @brief Returns whether or not a client is viewing a menu. + * + * @param client Client index. + * @param object Optional pointer to retrieve menu object, + * if any. + * @return MenuSource value. + */ + virtual MenuSource GetClientMenu(int client, void **object) =0; + + /** + * @brief Cancels a client's menu. + * + * @param client Client index. + * @param autoIgnore If true, no menus can be created during + * the cancellation process. + * @return True if a menu was cancelled, false otherwise. + */ + virtual bool CancelClientMenu(int client, bool autoIgnore=false) =0; + }; + + /** + * @brief High-level interface for building menus. + */ + class IBaseMenu + { + public: + /** + * @brief Appends an item to the end of a menu. + * + * @param info Item information string. + * @param draw Default drawing information. + * @return True on success, false on item limit reached. + */ + virtual bool AppendItem(const char *info, const ItemDrawInfo &draw) =0; + + /** + * @brief Inserts an item into the menu before a certain position; + * the new item will be at the given position and all next items + * pushed forward. + * + * @param position Position, starting from 0. + * @param info Item information string. + * @param draw Default item draw info. + * @return True on success, false on invalid menu position + */ + virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw) =0; + + /** + * @brief Removes an item from the menu. + * + * @param position Position, starting from 0. + * @return True on success, false on invalid menu position. + */ + virtual bool RemoveItem(unsigned int position) =0; + + /** + * @brief Removes all items from the menu. + */ + virtual void RemoveAllItems() =0; + + /** + * @brief Returns an item's info. + * + * @param position Position, starting from 0. + * @param draw Optional pointer to store a draw information. + * @return Info string pointer, or NULL if position was invalid. + */ + virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw) =0; + + /** + * @brief Returns the number of items. + * + * @return Number of items in the menu. + */ + virtual unsigned int GetItemCount() =0; + + /** + * @brief Sets the menu's pagination,. + * + * @param itemsPerPage Number of items per page, or MENU_NO_PAGINATION. + * @return True on success, false if itemsPerPage is too large. + */ + virtual bool SetPagination(unsigned int itemsPerPage) =0; + + /** + * @brief Returns an item's pagination. + * + * @return Pagination setting. + */ + virtual unsigned int GetPagination() =0; + + /** + * @brief Returns the menu style. + * + * @return Menu style. + */ + virtual IMenuStyle *GetDrawStyle() =0; + + /** + * @brief Sets the menu's display title/message. + * + * @param message Message (format options allowed). + */ + virtual void SetDefaultTitle(const char *message) =0; + + /** + * @brief Returns the menu's display/title message. + * + * @return Message string. + */ + virtual const char *GetDefaultTitle() =0; + + /** + * @brief Sets an extended menu option. + * + * @param option Option type. + * @param valuePtr Pointer of the type expected by the option. + * @return True on success, false if option or value is not supported. + */ + virtual bool SetExtOption(MenuOption option, const void *valuePtr) =0; + + /** + * @brief Creates a new IMenuDisplay object using extended options specific + * to the IMenuStyle parent. Titles, items, etc, are not copied. + * + * Note: The object should be freed with delete. + * + * @return IMenuDisplay pointer. + */ + virtual IMenuDisplay *CreateDisplay() =0; + + /** + * @brief Returns whether or not the menu should have an "Exit" button for + * paginated menus. + * + * @return True to have an exit button, false otherwise. + */ + virtual bool GetExitButton() =0; + + /** + * @brief Sets whether or not the menu should have an "Exit" button for + * paginated menus. + * + * @param set True to enable, false to disable the exit button. + * @return True on success, false if the exit button is + * non-optional. + */ + virtual bool SetExitButton(bool set) =0; + + /** + * @brief Sends the menu to a client. + * + * @param client Client index to display to. + * @param handler Menu handler to use. + * @param time Time to hold menu for. + * @return True on success, false otherwise. + */ + virtual bool Display(int client, IMenuHandler *handler, unsigned int time) =0; + + /** + * @brief Destroys the menu and frees all associated resources.1 + */ + virtual void Destroy() =0; + + /** + * @brief Cancels the menu on all client's displays. While the menu is + * being cancelled, the menu may not be re-displayed to any clients. + * + * @return Number of menus cancelled. + */ + virtual void Cancel() =0; + }; + + /** + * @brief Contains callbacks for menu actions. + */ + class IMenuHandler + { + public: + /** + * @brief Returns the menu api verison. + * + * @return Menu API version. + */ + virtual unsigned int GetMenuAPIVersion2() + { + return SMINTERFACE_MENUMANAGER_VERSION; + } + + /** + * @brief A display/selection cycle has started. + * + * @param menu Menu pointer. + */ + virtual void OnMenuStart(IBaseMenu *menu) + { + } + + /** + * @brief Called before a menu is being displayed. This is where + * you can set an alternate title on the menu. + * + * @param menu Menu pointer. + * @param client Client index. + * @param display IMenuDisplay pointer. + */ + virtual void OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display) + { + } + + /** + * @brief Called when an item is selected. + * + * @param menu Menu pointer. + * @param client Client that selected the item. + * @param item Item number. + */ + virtual void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) + { + } + + /** + * @brief An active menu display was dropped from a client. + * + * @param menu Menu pointer. + * @param client Client that had the menu. + * @param reason Menu cancellation reason. + */ + virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason) + { + } + + /** + * @brief A display/selection cycle has ended. + * + * @param menu Menu pointer. + */ + virtual void OnMenuEnd(IBaseMenu *menu) + { + } + + /** + * @brief Called when requesting how to render an item. + * + * @param menu Menu pointer. + * @param client Client index receiving the menu. + * @param item Item number in the menu. + * @param style ITEMSTYLE flags, by reference for modification. + */ + virtual void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style) + { + } + + /** + * @brief Called when requesting how to draw an item's text. + * + * @param menu Menu pointer. + * @param client Client index receiving the menu. + * @param item Item number in the menu. + * @param display Pointer to the display text string (changeable). + */ + virtual void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display) + { + } + }; + + /** + * @brief Handles a vote menu. + */ + class IMenuVoteHandler : public IMenuHandler + { + public: + /** + * @brief Called when a vote ends. + * + * @param menu Menu pointer. + * @param item Item position that was chosen by a majority. + */ + virtual void OnMenuVoteEnd(IBaseMenu *menu, unsigned int item) =0; + }; + + /** + * @brief Manages menu creation and displaying. + */ + class IMenuManager : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_MENUMANAGER_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_MENUMANAGER_VERSION; + } + public: + /** + * @brief Finds a style by name. + * + * @param name Name of the style (case insensitive). + * @return IMenuStyle pointer, or NULL if not found. + */ + virtual IMenuStyle *FindStyleByName(const char *name) =0; + + /** + * @brief Broadcasts a menu to a number of clients. + * + * @param menu Menu pointer. + * @param handler IMenuHandler pointer. + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param time Time to hold the menu. + * @return Number of clients the menu will be waiting on. + */ + virtual unsigned int BroadcastMenu(IBaseMenu *menu, + IMenuHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time) =0; + + /** + * @brief Broadcasts a menu to a number of clients as a vote menu. + * + * @param menu Menu pointer. + * @param handler IMenuHandler pointer. + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param time Time to hold the menu. + * @return Number of clients the menu will be waiting on. + */ + virtual unsigned int VoteMenu(IBaseMenu *menu, + IMenuVoteHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time) =0; + + /** + * @brief Returns the default draw style Core is using. + * + * @return Menu style pointer. + */ + virtual IMenuStyle *GetDefaultStyle() =0; + + /** + * @brief Sets the default draw style Core uses. + * + * @param style Menu style. + * @return True on success, false on failure. + */ + virtual bool SetDefaultStyle(IMenuStyle *style) =0; + + /** + * @brief Given a set of menu states, converts it to an IDisplay object. + * + * The state parameter is both INPUT and OUTPUT. + * INPUT: menu, mh, firstItem, lastItem + * OUTPUT: display, firstItem, lastItem, slots + * + * @param client Client index. + * @param states Menu states. + * @return IDisplay pointer, or NULL if no items could be + * found in the IBaseMenu pointer, or NULL if any + * other error occurred. Any valid pointer must + * be freed using delete. + */ + virtual IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_MENU_SYSTEM_H_ From d7b2f9a721ca0d6eb544ea756ca3640a2c64cade Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 May 2007 23:45:52 +0000 Subject: [PATCH 0744/1664] behold with your eyes and view upon what are MENUS --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40775 --- core/ConCmdManager.cpp | 1 + core/ConCmdManager.h | 5 + core/MenuManager.cpp | 676 ++++++++++++++++++++++++++++ core/MenuManager.h | 110 +++++ core/MenuStyle_Base.cpp | 162 +++++++ core/MenuStyle_Base.h | 69 +++ core/MenuStyle_Valve.cpp | 796 +++++++++++++++++++++++++++++++++ core/MenuStyle_Valve.h | 127 ++++++ core/PlayerManager.cpp | 7 + core/msvc8/sourcemod_mm.vcproj | 32 ++ core/sourcemod.cpp | 9 + 11 files changed, 1994 insertions(+) create mode 100644 core/MenuManager.cpp create mode 100644 core/MenuManager.h create mode 100644 core/MenuStyle_Base.cpp create mode 100644 core/MenuStyle_Base.h create mode 100644 core/MenuStyle_Valve.cpp create mode 100644 core/MenuStyle_Valve.h diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 77d43e9b..6bf92178 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -42,6 +42,7 @@ ConCmdManager::ConCmdManager() : m_Strings(1024) m_pExecCmd = NULL; m_pServerCfgFile = NULL; m_pServerCfgFwd = NULL; + m_CmdClient = 0; } ConCmdManager::~ConCmdManager() diff --git a/core/ConCmdManager.h b/core/ConCmdManager.h index bc6ccff4..dbfcd0d5 100644 --- a/core/ConCmdManager.h +++ b/core/ConCmdManager.h @@ -111,6 +111,11 @@ private: void RemoveConCmds(List &cmdlist, IPluginContext *pContext); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); void OnExecCmd(); +public: + inline int GetCommandClient() + { + return m_CmdClient; + } private: Trie *m_pCmds; /* command lookup */ Trie *m_pCmdGrps; /* command group lookup */ diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp new file mode 100644 index 00000000..9a2f4468 --- /dev/null +++ b/core/MenuManager.cpp @@ -0,0 +1,676 @@ +#include +#include +#include "MenuManager.h" +#include "sm_stringutil.h" +#include "sourcemm_api.h" +#include "PlayerManager.h" +#include "MenuStyle_Valve.h" + +MenuManager g_Menus; + +/************************************* + ************************************* + **** BROADCAST HANDLING WRAPPERS **** + ************************************* + *************************************/ + +BroadcastHandler::BroadcastHandler(IMenuHandler *handler) : m_pHandler(handler), numClients(0) +{ +} + +unsigned int BroadcastHandler::GetMenuAPIVersion2() +{ + return m_pHandler->GetMenuAPIVersion2(); +} + +void BroadcastHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason) +{ + m_pHandler->OnMenuCancel(menu, client, reason); +} + +void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display) +{ + numClients++; + m_pHandler->OnMenuDisplay(menu, client, display); +} + +void BroadcastHandler::OnBroadcastEnd(IBaseMenu *menu) +{ + g_Menus.FreeBroadcastHandler(this); +} + +void BroadcastHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) +{ + m_pHandler->OnMenuSelect(menu, client, item); +} + +void BroadcastHandler::OnMenuEnd(IBaseMenu *menu) +{ + assert(numClients > 0); + + /* Only fire if all clients have gotten a menu end */ + if (--numClients == 0) + { + IMenuHandler *pHandler = m_pHandler; + OnBroadcastEnd(menu); + pHandler->OnMenuEnd(menu); + } +} + +VoteHandler::VoteHandler(IMenuVoteHandler *handler) +: BroadcastHandler(handler), m_pVoteHandler(handler) +{ +} + +void VoteHandler::Initialize(IBaseMenu *menu) +{ + unsigned int numItems = menu->GetItemCount(); + + if (m_counts.size() >= numItems) + { + for (size_t i=0; i m_counts[highest]) + { + m_ties.clear(); + highest = i; + } else if (m_counts[i] == m_counts[highest]) { + m_ties.push_back(i); + } + } + + if (m_ties.size()) + { + m_ties.push_back(highest); + srand(static_cast(time(NULL))); + highest = m_ties[rand() % m_ties.size()]; + } + + m_pVoteHandler->OnMenuVoteEnd(menu, highest); + + g_Menus.FreeVoteHandler(this); +} + +/******************************* + ******************************* + ******** MENU MANAGER ********* + ******************************* + *******************************/ + +MenuManager::MenuManager() +{ + m_ShowMenu = -1; + m_pDefaultStyle = NULL; +} + +void MenuManager::OnSourceModAllInitialized() +{ + int num = g_SMAPI->GetUserMessageCount(); + if (num >= 1) + { + for (int i=0; iGetUserMessage(i, NULL), "ShowMenu") == 0) + { + m_ShowMenu = i; + break; + } + } + } + + /* :TODO: styles */ + m_Styles.push_back(&g_ValveMenuStyle); + SetDefaultStyle(&g_ValveMenuStyle); +} + +void MenuManager::OnSourceModAllShutdown() +{ + while (!m_BroadcastHandlers.empty()) + { + delete m_BroadcastHandlers.front(); + m_BroadcastHandlers.pop(); + } + + while (!m_VoteHandlers.empty()) + { + delete m_VoteHandlers.front(); + m_VoteHandlers.pop(); + } +} + +bool MenuManager::SetDefaultStyle(IMenuStyle *style) +{ + if (!style) + { + return false; + } + + m_pDefaultStyle = style; + + return true; +} + +IMenuStyle *MenuManager::GetStyle(unsigned int index) +{ + if (index >= GetStyleCount()) + { + return NULL; + } + + return m_Styles[index]; +} + +unsigned int MenuManager::GetStyleCount() +{ + return (unsigned int)m_Styles.size(); +} + +IMenuStyle *MenuManager::FindStyleByName(const char *name) +{ + unsigned int count = GetStyleCount(); + for (unsigned int i=0; iGetStyleName(), name) == 0) + { + return ptr; + } + } + + return NULL; +} + +inline bool IsSlotItem(IMenuDisplay *display, + unsigned int style) +{ + if (!display->CanDrawItem(style)) + { + return false; + } + if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE) + { + return false; + } + if (style & ITEMDRAW_RAWLINE) + { + return false; + } + + return true; +} + +IMenuDisplay *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order) +{ + IBaseMenu *menu = md.menu; + + if (!menu) + { + return NULL; + } + + struct + { + unsigned int position; + ItemDrawInfo draw; + } drawItems[10]; + + /* Figure out how many items to draw */ + IMenuStyle *style = menu->GetDrawStyle(); + unsigned int pgn = menu->GetPagination(); + unsigned int maxItems = style->GetMaxPageItems(); + if (pgn != MENU_NO_PAGINATION) + { + maxItems = pgn; + } + + unsigned int totalItems = menu->GetItemCount(); + unsigned int startItem = 0; + + /* For pagination, find the starting point. */ + if (pgn != MENU_NO_PAGINATION) + { + if (order == ItemOrder_Ascending) + { + startItem = md.lastItem; + /* This shouldn't happen with well-coded menus. + * If the item is out of bounds, switch the order to + * Items_Descending and make us start from the top. + */ + if (startItem >= totalItems) + { + startItem = totalItems - 1; + order = ItemOrder_Descending; + } + } else if (order == ItemOrder_Descending) { + startItem = md.firstItem; + /* This shouldn't happen with well-coded menus. + * If searching backwards doesn't give us enough room, + * start from the beginning and change to ascending. + */ + if (startItem <= maxItems) + { + startItem = 0; + order = ItemOrder_Ascending; + } + } + } + + /* Get our Display pointer and initialize some crap */ + IMenuDisplay *display = menu->CreateDisplay(); + IMenuHandler *mh = md.mh; + bool foundExtra = false; + unsigned int extraItem = 0; + + /** + * We keep searching until: + * 1) There are no more items + * 2) We reach one OVER the maximum number of slot items + * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION + */ + unsigned int i = startItem; + unsigned int foundItems = 0; + while (true) + { + ItemDrawInfo &dr = drawItems[foundItems].draw; + /* Is the item valid? */ + if (menu->GetItemInfo(i, &dr) != NULL) + { + /* Ask the user to change the style, if necessary */ + mh->OnMenuDrawItem(menu, client, i, dr.style); + /* Check if it's renderable */ + if (IsSlotItem(display, dr.style)) + { + /* If we've already found the max number of items, + * This means we should just cancel out and log our + * "last item." + */ + if (foundItems >= maxItems) + { + foundExtra = true; + extraItem = i; + break; + } + drawItems[foundItems++].position = i; + } + } + /* If there's no pagination, stop once the menu is full. */ + if (pgn == MENU_NO_PAGINATION) + { + /* If we've filled up, then stop */ + if (foundItems >= maxItems) + { + break; + } + } + /* If we're descending and this is the first item, stop */ + if (order == ItemOrder_Descending) + { + if (i == 0) + { + break; + } + i--; + } + /* If we're ascending and this is the last item, stop */ + else if (order == ItemOrder_Ascending) + { + if (i >= totalItems - 1) + { + break; + } + i++; + } + } + + /* There were no items to draw! */ + if (!foundItems) + { + delete display; + return NULL; + } + + /* Check initial buttons */ + bool displayPrev = false; + bool displayNext = false; + if (foundExtra) + { + if (order == ItemOrder_Descending) + { + displayPrev = true; + md.firstItem = extraItem; + } else if (order == ItemOrder_Ascending) { + displayNext = true; + md.lastItem = extraItem; + } + } + + /** + * If we're paginated, we have to find if there is another page. + * Sadly, the only way to do this is to try drawing more items! + */ + if (pgn != MENU_NO_PAGINATION) + { + unsigned int lastItem = 0; + ItemDrawInfo dr; + /* Find the last feasible item to search from. */ + if (order == ItemOrder_Descending) + { + lastItem = drawItems[0].position; + if (lastItem >= totalItems - 1) + { + goto skip_search; + } + while (++lastItem < totalItems) + { + if (menu->GetItemInfo(lastItem, &dr) != NULL) + { + mh->OnMenuDrawItem(menu, client, lastItem, dr.style); + if (IsSlotItem(display, dr.style)) + { + displayNext = true; + md.lastItem = lastItem; + break; + } + } + } + } else if (order == ItemOrder_Ascending) { + lastItem = drawItems[0].position; + if (lastItem == 0) + { + goto skip_search; + } + lastItem--; + while (lastItem-- != 0) + { + if (menu->GetItemInfo(lastItem, &dr) != NULL) + { + mh->OnMenuDrawItem(menu, client, lastItem, dr.style); + if (IsSlotItem(display, dr.style)) + { + displayPrev = true; + md.firstItem = lastItem; + break; + } + } + } + } + } +skip_search: + + /* Draw the item according to the order */ + menu_slots_t *slots = md.slots; + unsigned int position = 0; /* Keep track of the last position */ + if (order == ItemOrder_Ascending) + { + for (unsigned int i=0; iGetItemInfo(drawItems[i].position, &dr); + mh->OnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display)); + if ((position = display->DrawItem(dr)) != 0) + { + slots[position].item = drawItems[i].position; + slots[position].type = ItemSel_Item; + } + } + } else if (order == ItemOrder_Descending) { + unsigned int i = foundItems; + /* NOTE: There will always be at least one item because + * of the check earlier. + */ + while (i--) + { + ItemDrawInfo &dr = drawItems[i].draw; + menu->GetItemInfo(drawItems[i].position, &dr); + mh->OnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display)); + if ((position = display->DrawItem(dr)) != 0) + { + slots[position].item = drawItems[i].position; + slots[position].type = ItemSel_Item; + } + } + } + + /* Now, we need to check if we need to add anything extra */ + if (pgn != MENU_NO_PAGINATION) + { + bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED); + bool exitButton = menu->GetExitButton(); + char text[50]; + + /* Calculate how many items we are allowed for control stuff */ + unsigned int padding = style->GetMaxPageItems() - maxItems; + + /* Add the number of available slots */ + padding += (maxItems - foundItems); + + /* Someday, if we are able to re-enable this, we will be very lucky men. */ +#if 0 + if (!style->FeatureExists(MenuStyleFeature_ImplicitExit)) + { +#endif + /* Even if we don't draw an exit button, we invalidate the slot. */ + padding--; +#if 0 + } else { + /* Otherwise, we don't draw anything and leave the slot available */ + exitButton = false; + } +#endif + + /* Subtract two slots for the displayNext/displayPrev padding */ + padding -= 2; + + /** + * We allow next/prev to be undrawn if neither exists. + * Thus, we only need padding if one of them will be drawn, + * or the exit button will be drawn. + */ + ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER); + if (exitButton || (displayNext || displayPrev)) + { + /* Add spacers so we can pad to the end */ + unsigned int null_pos = 0; + for (unsigned int i=0; iDrawItem(padItem); + slots[position].type = ItemSel_None; + } + } + ItemDrawInfo dr(text, 0); + + /* PREVIOUS */ + if (displayPrev || canDrawDisabled) + { + CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); + dr.style = displayPrev ? 0 : ITEMDRAW_DISABLED; + position = display->DrawItem(dr); + slots[position].type = ItemSel_Back; + } else if ((displayNext || canDrawDisabled) || exitButton) { + /* If we can't display this, + * but there is a "next" or "exit" button, we need to pad! + */ + position = display->DrawItem(padItem); + slots[position].type = ItemSel_None; + } + + /* NEXT */ + if (displayNext || canDrawDisabled) + { + CorePlayerTranslate(client, text, sizeof(text), "Next", NULL); + dr.style = displayNext ? 0 : ITEMDRAW_DISABLED; + position = display->DrawItem(dr); + slots[position].type = ItemSel_Next; + } else if (exitButton) { + /* If we can't display this, + * but there is an exit button, we need to pad! + */ + position = display->DrawItem(padItem); + slots[position].type = ItemSel_None; + } + + /* EXIT */ + if (exitButton) + { + CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL); + dr.style = 0; + position = display->DrawItem(dr); + slots[position].type = ItemSel_Exit; + } + } + + /* Lastly, fill in any slots we could have missed */ + for (unsigned int i = position + 1; i < 10; i++) + { + slots[i].type = ItemSel_None; + } + + /* Do title stuff */ + mh->OnMenuDisplay(menu, client, display); + display->DrawTitle(menu->GetDefaultTitle(), true); + + return display; +} + +unsigned int MenuManager::BroadcastMenu(IBaseMenu *menu, + IMenuHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time) +{ + BroadcastHandler *bh; + + if (m_BroadcastHandlers.empty()) + { + bh = new BroadcastHandler(handler); + } else { + bh = m_BroadcastHandlers.front(); + m_BroadcastHandlers.pop(); + bh->m_pHandler = handler; + bh->numClients = 0; + } + + handler->OnMenuStart(menu); + + unsigned int total = 0; + for (unsigned int i=0; iDisplay(clients[i], bh, time)) + { + continue; + } + + /* :TODO: Allow sourcetv only, not all bots */ + CPlayer *player = g_Players.GetPlayerByIndex(clients[i]); + if (player->IsFakeClient()) + { + continue; + } + + total++; + } + + if (!total) + { + /* End the broadcast here */ + handler->OnMenuEnd(menu); + FreeBroadcastHandler(bh); + } + + return total; +} + +unsigned int MenuManager::VoteMenu(IBaseMenu *menu, + IMenuVoteHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time) +{ + VoteHandler *vh; + + if (m_VoteHandlers.empty()) + { + vh = new VoteHandler(handler); + } else { + vh = m_VoteHandlers.front(); + m_VoteHandlers.pop(); + vh->m_pHandler = handler; + vh->numClients = 0; + } + + vh->Initialize(menu); + handler->OnMenuStart(menu); + + unsigned int total = 0; + for (unsigned int i=0; iDisplay(clients[i], vh, time)) + { + continue; + } + + /* :TODO: Allow sourcetv only, not all bots */ + CPlayer *player = g_Players.GetPlayerByIndex(clients[i]); + if (player->IsFakeClient()) + { + continue; + } + + total++; + } + + if (!total) + { + /* End the broadcast here */ + handler->OnMenuEnd(menu); + FreeVoteHandler(vh); + } + + return total; +} + +void MenuManager::FreeBroadcastHandler(BroadcastHandler *bh) +{ + m_BroadcastHandlers.push(bh); +} + +void MenuManager::FreeVoteHandler(VoteHandler *vh) +{ + m_VoteHandlers.push(vh); +} + +IMenuStyle *MenuManager::GetDefaultStyle() +{ + return m_pDefaultStyle; +} + diff --git a/core/MenuManager.h b/core/MenuManager.h new file mode 100644 index 00000000..ebe70320 --- /dev/null +++ b/core/MenuManager.h @@ -0,0 +1,110 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_MENUMANAGER_H_ +#define _INCLUDE_SOURCEMOD_MENUMANAGER_H_ + +#include +#include +#include +#include +#include "sm_memtable.h" +#include "sm_globals.h" + +using namespace SourceMod; +using namespace SourceHook; + +class BroadcastHandler : public IMenuHandler +{ +public: + BroadcastHandler(IMenuHandler *handler); +public: //IMenuHandler + void OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display); + void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); + void OnMenuEnd(IBaseMenu *menu); + void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason); + unsigned int GetMenuAPIVersion2(); +public: + virtual void OnBroadcastEnd(IBaseMenu *menu); +public: + IMenuHandler *m_pHandler; + unsigned int numClients; +}; + +class VoteHandler : public BroadcastHandler +{ +public: + VoteHandler(IMenuVoteHandler *handler); +public: + void Initialize(IBaseMenu *menu); + void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); + void OnBroadcastEnd(IBaseMenu *menu); +private: + CVector m_counts; + CVector m_ties; + unsigned int numItems; + IMenuVoteHandler *m_pVoteHandler; +}; + +class MenuManager : + public IMenuManager, + public SMGlobalClass +{ + friend class BroadcastHandler; + friend class VoteHandler; +public: + MenuManager(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModAllShutdown(); +public: //IMenuManager + virtual const char *GetInterfaceName() + { + return SMINTERFACE_MENUMANAGER_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_MENUMANAGER_VERSION; + } +public: + unsigned int GetStyleCount(); + IMenuStyle *GetStyle(unsigned int index); + IMenuStyle *FindStyleByName(const char *name); + unsigned int BroadcastMenu(IBaseMenu *menu, + IMenuHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time); + unsigned int VoteMenu(IBaseMenu *menu, + IMenuVoteHandler *handler, + int clients[], + unsigned int numClients, + unsigned int time); + IMenuStyle *GetDefaultStyle(); + bool SetDefaultStyle(IMenuStyle *style); + IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order); +protected: + void FreeBroadcastHandler(BroadcastHandler *bh); + void FreeVoteHandler(VoteHandler *vh); +private: + int m_ShowMenu; + IMenuStyle *m_pDefaultStyle; + CStack m_BroadcastHandlers; + CStack m_VoteHandlers; + CVector m_Styles; +}; + +extern MenuManager g_Menus; + +#endif //_INCLUDE_SOURCEMOD_MENUMANAGER_H_ diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp new file mode 100644 index 00000000..79023589 --- /dev/null +++ b/core/MenuStyle_Base.cpp @@ -0,0 +1,162 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ +#include +#include "sm_stringutil.h" +#include "MenuStyle_Base.h" + +CBaseMenu::CBaseMenu(IMenuStyle *pStyle) : +m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true) +{ +} + +CBaseMenu::~CBaseMenu() +{ +} + +bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) +{ + if (m_Pagination == MENU_NO_PAGINATION + && m_items.size() >= m_pStyle->GetMaxPageItems()) + { + return false; + } + + CItem item; + + item.infoString = m_Strings.AddString(info); + if (draw.display) + { + item.displayString = m_Strings.AddString(draw.display); + } + item.style = draw.style; + + + m_items.push_back(item); + + return true; +} + +bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw) +{ + if (m_Pagination == MENU_NO_PAGINATION + && m_items.size() >= m_pStyle->GetMaxPageItems()) + { + return false; + } + + if (position >= m_items.size()) + { + return false; + } + + CItem item; + item.infoString = m_Strings.AddString(info); + if (draw.display) + { + item.displayString = m_Strings.AddString(draw.display); + } + item.style = draw.style; + + CVector::iterator iter = m_items.iterAt(position); + m_items.insert(iter, item); + + return true; +} + +bool CBaseMenu::RemoveItem(unsigned int position) +{ + if (position >= m_items.size()) + { + return false; + } + + m_items.erase(m_items.iterAt(position)); + + if (m_items.size() == 0) + { + m_Strings.Reset(); + } + + return true; +} + +void CBaseMenu::RemoveAllItems() +{ + m_items.clear(); + m_Strings.Reset(); +} + +const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */) +{ + if (position >= m_items.size()) + { + return NULL; + } + + if (draw) + { + draw->display = m_Strings.GetString(m_items[position].displayString); + draw->style = m_items[position].style; + } + + return m_Strings.GetString(m_items[position].infoString); +} + +unsigned int CBaseMenu::GetItemCount() +{ + return m_items.size(); +} + +bool CBaseMenu::SetPagination(unsigned int itemsPerPage) +{ + if (itemsPerPage > 7) + { + return false; + } + + m_Pagination = itemsPerPage; + + return true; +} + +unsigned int CBaseMenu::GetPagination() +{ + return m_Pagination; +} + +IMenuStyle *CBaseMenu::GetDrawStyle() +{ + return m_pStyle; +} + +void CBaseMenu::SetDefaultTitle(const char *message) +{ + m_Title.assign(message); +} + +const char *CBaseMenu::GetDefaultTitle() +{ + return m_Title.c_str(); +} + +bool CBaseMenu::GetExitButton() +{ + return m_ExitButton; +} + +bool CBaseMenu::SetExitButton(bool set) +{ + m_ExitButton = set; + return true; +} diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h new file mode 100644 index 00000000..fdfa8c29 --- /dev/null +++ b/core/MenuStyle_Base.h @@ -0,0 +1,69 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_MENUSTYLE_BASE_H +#define _INCLUDE_MENUSTYLE_BASE_H + +#include +#include +#include +#include "sm_memtable.h" + +using namespace SourceMod; +using namespace SourceHook; + +class CItem +{ +public: + CItem() + { + infoString = -1; + displayString = -1; + style = 0; + } +public: + int infoString; + int displayString; + unsigned int style; +}; + +class CBaseMenu : public IBaseMenu +{ +public: + CBaseMenu(IMenuStyle *pStyle); + virtual ~CBaseMenu(); +public: + virtual bool AppendItem(const char *info, const ItemDrawInfo &draw); + virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw); + virtual bool RemoveItem(unsigned int position); + virtual void RemoveAllItems(); + virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL); + virtual unsigned int GetItemCount(); + virtual bool SetPagination(unsigned int itemsPerPage); + virtual unsigned int GetPagination(); + virtual IMenuStyle *GetDrawStyle(); + virtual void SetDefaultTitle(const char *message); + virtual const char *GetDefaultTitle(); + virtual bool GetExitButton(); + virtual bool SetExitButton(bool set); +protected: + String m_Title; + IMenuStyle *m_pStyle; + unsigned int m_Pagination; + CVector m_items; + BaseStringTable m_Strings; + bool m_ExitButton; +}; + +#endif //_INCLUDE_MENUSTYLE_BASE_H diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp new file mode 100644 index 00000000..c507f39f --- /dev/null +++ b/core/MenuStyle_Valve.cpp @@ -0,0 +1,796 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_stringutil.h" +#include "PlayerManager.h" +#include "MenuStyle_Valve.h" +#include "Translator.h" +#include "PlayerManager.h" +#include "ConCmdManager.h" + +SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *); + +ValveMenuStyle g_ValveMenuStyle; +const char *g_OptionNumTable[]; +const char *g_OptionCmdTable[]; +IServerPluginCallbacks *g_pVSPHandle = NULL; +CallClass *g_pSPHCC = NULL; + +class TestHandler : public IMenuHandler +{ +public: + virtual void OnMenuEnd(IBaseMenu *menu) + { + menu->Destroy(); + } +}; + +ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1]), m_WatchList(256) +{ +} + +bool ValveMenuStyle::OnClientCommand(int client) +{ + const char *cmd = engine->Cmd_Argv(0); + + if (strcmp(cmd, "sm_vmenuselect") == 0) + { + int key_press = atoi(engine->Cmd_Argv(1)); + g_ValveMenuStyle.ClientPressedKey(client, key_press); + return true; + } + + if (strcmp(cmd, "sm_test") == 0) + { + IBaseMenu *menu = g_ValveMenuStyle.CreateMenu(); + menu->AppendItem("test1", ItemDrawInfo("Test #1", 0)); + menu->AppendItem("test2", ItemDrawInfo("Test #2", 0)); + menu->AppendItem("test3", ItemDrawInfo("Test #3", 0)); + menu->AppendItem("test4", ItemDrawInfo("Test #4", 0)); + menu->AppendItem("test5", ItemDrawInfo("Test #5", 0)); + menu->AppendItem("test6", ItemDrawInfo("Test #6", 0)); + menu->AppendItem("test7", ItemDrawInfo("Test #7", 0)); + menu->AppendItem("test8", ItemDrawInfo("Test #8", 0)); + menu->AppendItem("test9", ItemDrawInfo("Test #9", 0)); + menu->AppendItem("test10", ItemDrawInfo("Test #10", 0)); + menu->AppendItem("test11", ItemDrawInfo("Test #11", 0)); + menu->AppendItem("test12", ItemDrawInfo("Test #12", 0)); + menu->AppendItem("test13", ItemDrawInfo("Test #13", 0)); + menu->AppendItem("test14", ItemDrawInfo("Test #14", 0)); + menu->AppendItem("test15", ItemDrawInfo("Test #15", 0)); + menu->AppendItem("test16", ItemDrawInfo("Test #16", 0)); + menu->AppendItem("test17", ItemDrawInfo("Test #17", 0)); + menu->AppendItem("test18", ItemDrawInfo("Test #18", 0)); + menu->AppendItem("test19", ItemDrawInfo("Test #19", 0)); + menu->AppendItem("test20", ItemDrawInfo("Test #20", 0)); + + menu->Display(client, new TestHandler, 20); + return true; + } else if (strcmp(cmd, "gaben") == 0) { + KeyValues *kv = new KeyValues("menu"); + kv->SetString("msg", "hi"); + serverpluginhelpers->CreateMessage(engine->PEntityOfEntIndex(client), DIALOG_MENU, kv, g_pVSPHandle); + kv->deleteThis(); + } + + return false; +} + +void ValveMenuStyle::OnSourceModAllInitialized() +{ + g_Players.AddClientListener(this); + SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false); + g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers); +} + +void ValveMenuStyle::OnSourceModShutdown() +{ + SH_RELEASE_CALLCLASS(g_pSPHCC); + SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false); + g_Players.RemoveClientListener(this); +} + +void ValveMenuStyle::OnClientDisconnected(int client) +{ + CValveMenuPlayer *player = &m_players[client]; + if (!player->bInMenu) + { + return; + } + + menu_states_t &states = player->states; + states.mh->OnMenuCancel(states.menu, client, MenuCancel_Disconnect); + states.mh->OnMenuEnd(states.menu); + + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + + player->bInMenu = false; +} + +void ValveMenuStyle::HookCreateMessage(edict_t *pEdict, + DIALOG_TYPE type, + KeyValues *kv, + IServerPluginCallbacks *plugin) +{ + if (type != DIALOG_MENU) + { + return; + } + + int client = engine->IndexOfEdict(pEdict); + if (client < 1 || client > 256) + { + return; + } + + CValveMenuPlayer *player = &m_players[client]; + + /* We don't care if the player is in a menu because, for all intents and purposes, + * the menu is completely private. Instead, we just figure out the level we'll need + * in order to override it. + */ + player->curPrioLevel = kv->GetInt("level", player->curPrioLevel); + + /* Oh no! What happens if we got a menu that overwrites ours?! */ + if (player->bInMenu) + { + /* Okay, let the external menu survive for now. It may live another + * day to avenge its grandfather, killed in the great Menu Interruption + * battle. + */ + _CancelMenu(client, true); + } +} + +void ValveMenuStyle::OnSourceModVSPReceived(IServerPluginCallbacks *iface) +{ + g_pVSPHandle = iface; +} + +IMenuDisplay *ValveMenuStyle::CreateDisplay() +{ + return new CValveMenuDisplay(); +} + +IBaseMenu *ValveMenuStyle::CreateMenu() +{ + return new CValveMenu(); +} + +const char *ValveMenuStyle::GetStyleName() +{ + return "valve"; +} + +unsigned int ValveMenuStyle::GetMaxPageItems() +{ + return 8; +} + +static int do_lookup[256]; +void ValveMenuStyle::ProcessWatchList() +{ + if (!m_WatchList.size()) + { + return; + } + + FastLink::iterator iter; + + unsigned int total = 0; + for (iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter) + { + do_lookup[total++] = (*iter); + } + + int client; + CValveMenuPlayer *player; + float curTime = gpGlobals->curtime; + for (unsigned int i=0; ibInMenu || !player->menuHoldTime) + { + m_WatchList.remove(i); + continue; + } + if (curTime > player->menuStartTime + player->menuHoldTime) + { + _CancelMenu(i, false); + } + } +} + +void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore) +{ + CValveMenuPlayer *player = &m_players[client]; + menu_states_t &states = player->states; + + bool bOldIgnore = player->bAutoIgnore; + if (bAutoIgnore) + { + player->bAutoIgnore = true; + } + + /* Save states */ + IMenuHandler *mh = states.mh; + IBaseMenu *menu = states.menu; + + /* Clear menu */ + player->bInMenu = false; + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + + /* Fire callbacks */ + mh->OnMenuCancel(menu, client, MenuCancel_Interrupt); + mh->OnMenuEnd(menu); + + if (bAutoIgnore) + { + player->bAutoIgnore = bOldIgnore; + } +} + +void ValveMenuStyle::CancelMenu(CValveMenu *menu) +{ + int maxClients = g_Players.GetMaxClients(); + for (int i=1; i<=maxClients; i++) + { + if (m_players[i].bInMenu) + { + menu_states_t &states = m_players[i].states; + if (states.menu == menu) + { + _CancelMenu(i); + } + } + } +} + +bool ValveMenuStyle::CancelClientMenu(int client, bool autoIgnore) +{ + if (client < 1 || client > 256 || !m_players[client].bInMenu) + { + return false; + } + + _CancelMenu(client, autoIgnore); + + return true; +} + + +void ValveMenuStyle::ClientPressedKey(int client, unsigned int key_press) +{ + CValveMenuPlayer *player = &m_players[client]; + + /* First question: Are we in a menu? */ + if (!player->bInMenu) + { + return; + } + + bool cancel = false; + unsigned int item = 0; + MenuCancelReason reason = MenuCancel_Exit; + menu_states_t &states = player->states; + + assert(states.mh != NULL); + + if (states.menu == NULL) + { + item = key_press; + } else if (key_press < 1 || key_press > 8) { + cancel = true; + } else { + ItemSelection type = states.slots[key_press].type; + + /* For navigational items, we're going to redisplay */ + if (type == ItemSel_Back) + { + if (!RedoClientMenu(client, ItemOrder_Descending)) + { + cancel = true; + reason = MenuCancel_NoDisplay; + } else { + return; + } + } else if (type == ItemSel_Next) { + if (!RedoClientMenu(client, ItemOrder_Ascending)) + { + cancel = true; /* I like Saltines. */ + reason = MenuCancel_NoDisplay; + } else { + return; + } + } else if (type == ItemSel_Exit || type == ItemSel_None) { + cancel = true; + } else { + item = states.slots[key_press].item; + } + } + + /* Save variables */ + IMenuHandler *mh = states.mh; + IBaseMenu *menu = states.menu; + + /* Clear states */ + player->bInMenu = false; + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + + if (cancel) + { + mh->OnMenuCancel(menu, client, reason); + } else { + mh->OnMenuSelect(menu, client, item); + } + + mh->OnMenuEnd(menu); +} + +bool ValveMenuStyle::DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time) +{ + if (!g_pVSPHandle || !mh) + { + return false; + } + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) + { + return false; + } + + CValveMenuPlayer *player = &m_players[client]; + if (player->bAutoIgnore) + { + return false; + } + + /* For the duration of this, we are going to totally ignore whether + * the player is already in a menu or not (except to cancel the old one). + * Instead, we are simply going to ignore any further menu displays, so + * this display can't be interrupted. + */ + player->bAutoIgnore = true; + + /* Cancel any old menus */ + menu_states_t &states = player->states; + if (player->bInMenu) + { + /* We need to cancel the old menu */ + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); + states.mh->OnMenuEnd(states.menu); + } + + states.firstItem = 0; + states.lastItem = 0; + states.menu = NULL; + states.mh = mh; + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; + player->curPrioLevel--; + player->bInMenu = true; + player->menuStartTime = gpGlobals->curtime; + player->menuHoldTime = time; + + if (time) + { + m_WatchList.push_back(client); + } + + /* Draw the display */ + menu->SendRawDisplay(client, player->curPrioLevel, time); + + /* We can be interrupted again! */ + player->bAutoIgnore = false; + + return true; +} + +bool ValveMenuStyle::DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time) +{ + mh->OnMenuStart(menu); + + if (!g_pVSPHandle || !mh) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + CValveMenuPlayer *player = &m_players[client]; + if (player->bAutoIgnore) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + /* For the duration of this, we are going to totally ignore whether + * the player is already in a menu or not (except to cancel the old one). + * Instead, we are simply going to ignore any further menu displays, so + * this display can't be interrupted. + */ + player->bAutoIgnore = true; + + /* Cancel any old menus */ + menu_states_t &states = player->states; + if (player->bInMenu) + { + /* We need to cancel the old menu */ + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); + states.mh->OnMenuEnd(states.menu); + } + + states.firstItem = 0; + states.lastItem = 0; + states.menu = menu; + states.mh = mh; + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; + + IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending); + if (!display) + { + player->bAutoIgnore = false; + player->bInMenu = false; + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + /* Finally, set our states */ + player->curPrioLevel--; + player->bInMenu = true; + player->menuStartTime = gpGlobals->curtime; + player->menuHoldTime = time; + + if (time) + { + m_WatchList.push_back(client); + } + + /* Draw the display */ + CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display; + vDisplay->SendRawDisplay(client, player->curPrioLevel, time); + + /* Free the display pointer */ + delete display; + + /* We can be interrupted again! */ + player->bAutoIgnore = false; + + return true; +} + +bool ValveMenuStyle::RedoClientMenu(int client, ItemOrder order) +{ + CValveMenuPlayer *player = &m_players[client]; + menu_states_t &states = player->states; + + player->bAutoIgnore = true; + IMenuDisplay *display = g_Menus.RenderMenu(client, states, order); + if (!display) + { + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + player->bAutoIgnore = false; + return false; + } + + CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display; + vDisplay->SendRawDisplay(client, --player->curPrioLevel, player->menuHoldTime); + + delete display; + + player->bAutoIgnore = false; + + return true; +} + +MenuSource ValveMenuStyle::GetClientMenu(int client, void **object) +{ + if (client < 1 || client > 256 || !m_players[client].bInMenu) + { + return MenuSource_None; + } + + IBaseMenu *menu; + if ((menu=m_players[client].states.menu) != NULL) + { + if (object) + { + *object = menu; + } + return MenuSource_BaseMenu; + } + + return MenuSource_Display; +} + +CValveMenuDisplay::CValveMenuDisplay() +{ + m_pKv = NULL; + Reset(); +} + +CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu) +{ + m_pKv = NULL; + Reset(); + m_pKv->SetColor("color", pMenu->m_IntroColor); + m_pKv->SetString("title", pMenu->m_IntroMsg); +} + +CValveMenuDisplay::~CValveMenuDisplay() +{ + m_pKv->deleteThis(); +} + +IMenuStyle *CValveMenuDisplay::GetParentStyle() +{ + return &g_ValveMenuStyle; +} + +void CValveMenuDisplay::Reset() +{ + if (m_pKv) + { + m_pKv->deleteThis(); + } + m_pKv = new KeyValues("menu"); + m_NextPos = 1; + m_TitleDrawn = false; +} + +bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr) +{ + if (option == MenuOption_IntroMessage) + { + m_pKv->SetString("title", (const char *)valuePtr); + return true; + } else if (option == MenuOption_IntroColor) { + int *array = (int *)valuePtr; + m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3])); + return true; + } + + return false; +} + +bool CValveMenuDisplay::CanDrawItem(unsigned int drawFlags) +{ + /** + * ITEMDRAW_RAWLINE - We can't draw random text, and this doesn't add a slot, + * so it's completely safe to ignore it. + * ----------------------------------------- + */ + if (drawFlags & ITEMDRAW_RAWLINE) + { + return false; + } + + /** + * Special cases, explained in DrawItem() + */ + if ((drawFlags & ITEMDRAW_NOTEXT) + || (drawFlags & ITEMDRAW_SPACER)) + { + return true; + } + + /** + * We can't draw disabled text. We could bump the position, but we + * want DirectDraw() to find some actual items to display. + */ + if (drawFlags & ITEMDRAW_DISABLED) + { + return false; + } + + return true; +} + +unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item) +{ + if (m_NextPos > 9 || !CanDrawItem(item.style)) + { + return 0; + } + + /** + * For these cases we can't draw anything at all, but + * we can at least bump the position since we were explicitly asked to. + */ + if ((item.style & ITEMDRAW_NOTEXT) + || (item.style & ITEMDRAW_SPACER)) + { + return m_NextPos++; + } + + char buffer[255]; + UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display); + + KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true); + ki->SetString("command", g_OptionCmdTable[m_NextPos]); + ki->SetString("msg", buffer); + + return m_NextPos++; +} + +void CValveMenuDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */) +{ + if (onlyIfEmpty && m_TitleDrawn) + { + return; + } + + m_pKv->SetString("msg", text); + m_TitleDrawn = true; +} + +bool CValveMenuDisplay::DrawRawLine(const char *rawline) +{ + return false; +} + +void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time) +{ + m_pKv->SetInt("level", priority); + m_pKv->SetInt("time", time); + + SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)( + engine->PEntityOfEntIndex(client), + DIALOG_MENU, + m_pKv, + g_pVSPHandle); +} + +bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time) +{ + return g_ValveMenuStyle.DoClientMenu(client, this, handler, time); +} + +CValveMenu::CValveMenu() : CBaseMenu(&g_ValveMenuStyle), + m_IntroColor(255, 0, 0, 255), m_bShouldDelete(false), m_bCancelling(false) +{ + strcpy(m_IntroMsg, "You have a menu, press ESC"); + m_Pagination = 5; +} + +void CValveMenu::Cancel() +{ + if (m_bCancelling) + { + return; + } + + m_bCancelling = true; + g_ValveMenuStyle.CancelMenu(this); + m_bCancelling = false; + + if (m_bShouldDelete) + { + delete this; + } +} + +void CValveMenu::Destroy() +{ + if (!m_bCancelling || m_bShouldDelete) + { + Cancel(); + delete this; + } else { + m_bShouldDelete = true; + } +} + +bool CValveMenu::SetPagination(unsigned int itemsPerPage) +{ + if (itemsPerPage < 1 || itemsPerPage > 5) + { + return false; + } + + CBaseMenu::SetPagination(itemsPerPage); + + return true; +} + +bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr) +{ + if (option == MenuOption_IntroMessage) + { + strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg)); + return true; + } else if (option == MenuOption_IntroColor) { + unsigned int *array = (unsigned int *)valuePtr; + m_IntroColor = Color(array[0], array[1], array[2], array[3]); + return true; + } + + return false; +} + +bool CValveMenu::Display(int client, IMenuHandler *handler, unsigned int time) +{ + if (m_bCancelling) + { + return false; + } + + return g_ValveMenuStyle.DoClientMenu(client, this, handler, time); +} + +IMenuDisplay *CValveMenu::CreateDisplay() +{ + return new CValveMenuDisplay(this); +} + +bool CValveMenu::GetExitButton() +{ + return true; +} + +bool CValveMenu::SetExitButton(bool set) +{ + return false; +} + +static const char *g_OptionNumTable[11] = +{ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" +}; + +static const char *g_OptionCmdTable[11] = +{ + "sm_vmenuselect 0", /* INVALID! */ + "sm_vmenuselect 1", + "sm_vmenuselect 2", + "sm_vmenuselect 3", + "sm_vmenuselect 4", + "sm_vmenuselect 5", + "sm_vmenuselect 6", + "sm_vmenuselect 7", + "sm_vmenuselect 8", + "sm_vmenuselect 9", + "sm_vmenuselect 10" +}; diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h new file mode 100644 index 00000000..4f45c2fa --- /dev/null +++ b/core/MenuStyle_Valve.h @@ -0,0 +1,127 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_MENUSTYLE_VALVE_H +#define _INCLUDE_MENUSTYLE_VALVE_H + +#include "sm_globals.h" +#include "MenuManager.h" +#include "MenuStyle_Base.h" +#include "sourcemm_api.h" +#include "KeyValues.h" +#include +#include "sm_fastlink.h" + +using namespace SourceMod; + +class CValveMenuPlayer +{ +public: + CValveMenuPlayer() : bInMenu(false), bAutoIgnore(false), curPrioLevel(1) + { + } + menu_states_t states; + bool bInMenu; + bool bAutoIgnore; + int curPrioLevel; + float menuStartTime; + unsigned int menuHoldTime; +}; + +class CValveMenu; +class CValveMenuDisplay; + +class ValveMenuStyle : + public SMGlobalClass, + public IMenuStyle, + public IClientListener +{ +public: + ValveMenuStyle(); + bool DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time); + bool DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time); + void ClientPressedKey(int client, unsigned int key_press); + bool OnClientCommand(int client); + void CancelMenu(CValveMenu *menu); + void ProcessWatchList(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); + void OnSourceModVSPReceived(IServerPluginCallbacks *iface); +public: //IClientListener + void OnClientDisconnected(int client); +public: //IMenuStyle + const char *GetStyleName(); + IMenuDisplay *CreateDisplay(); + IBaseMenu *CreateMenu(); + unsigned int GetMaxPageItems(); + MenuSource GetClientMenu(int client, void **object); + bool CancelClientMenu(int client, bool autoIgnore=false); +private: + bool RedoClientMenu(int client, ItemOrder order); + void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); + void _CancelMenu(int client, bool bAutoIgnore=false); +private: + CValveMenuPlayer *m_players; + FastLink m_WatchList; +}; + +class CValveMenu; + +class CValveMenuDisplay : public IMenuDisplay +{ +public: + CValveMenuDisplay(); + CValveMenuDisplay(CValveMenu *pMenu); + ~CValveMenuDisplay(); +public: + IMenuStyle *GetParentStyle(); + void Reset(); + void DrawTitle(const char *text, bool onlyIfEmpty=false); + unsigned int DrawItem(const ItemDrawInfo &item); + bool DrawRawLine(const char *rawline); + bool SendDisplay(int client, IMenuHandler *handler, unsigned int time); + bool SetExtOption(MenuOption option, const void *valuePtr); + bool CanDrawItem(unsigned int drawFlags); + void SendRawDisplay(int client, int priority, unsigned int time); +private: + KeyValues *m_pKv; + unsigned int m_NextPos; + bool m_TitleDrawn; +}; + +class CValveMenu : public CBaseMenu +{ + friend class CValveMenuDisplay; +public: + CValveMenu(); +public: + bool SetExtOption(MenuOption option, const void *valuePtr); + IMenuDisplay *CreateDisplay(); + bool GetExitButton(); + bool SetExitButton(bool set); + bool SetPagination(unsigned int itemsPerPage); + bool Display(int client, IMenuHandler *handler, unsigned int time); + void Cancel(); + void Destroy(); +private: + Color m_IntroColor; + char m_IntroMsg[128]; + bool m_bCancelling; + bool m_bShouldDelete; +}; + +extern ValveMenuStyle g_ValveMenuStyle; + +#endif //_INCLUDE_MENUSTYLE_VALVE_H diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 44163e11..6260285e 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -17,6 +17,7 @@ #include "ShareSys.h" #include "AdminCache.h" #include "ConCmdManager.h" +#include "MenuStyle_Valve.h" PlayerManager g_Players; @@ -398,6 +399,12 @@ void PlayerManager::OnClientCommand(edict_t *pEntity) RETURN_META(MRES_SUPERCEDE); } + bool result = g_ValveMenuStyle.OnClientCommand(client); + if (result) + { + res = Pl_Handled; + } + res = g_ConCmds.DispatchClientCommand(client, (ResultType)res); if (res >= Pl_Handled) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a6526fba..09667d5a 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -227,6 +227,18 @@ RelativePath="..\MemoryUtils.cpp" > + + + + + + @@ -333,6 +345,18 @@ RelativePath="..\MemoryUtils.h" > + + + + + + @@ -341,6 +365,10 @@ RelativePath="..\sm_autonatives.h" > + + @@ -438,6 +466,10 @@ RelativePath="..\..\public\IMemoryUtils.h" > + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index a0576d71..95eaaf8a 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -29,6 +29,7 @@ #include "Translator.h" #include "ForwardSys.h" #include "TimerSys.h" +#include "MenuStyle_Valve.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -43,6 +44,7 @@ ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; IVirtualMachine *g_pVM; IdentityToken_t *g_pCoreIdent = NULL; float g_LastTime = 0.0f; +float g_LastMenuTime = 0.0f; float g_LastAuthCheck = 0.0f; IForward *g_pOnGameFrame = NULL; IForward *g_pOnMapEnd = NULL; @@ -264,6 +266,7 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_IsMapLoading = true; m_ExecPluginReload = true; g_LastTime = 0.0f; + g_LastMenuTime = 0.0f; g_LastAuthCheck = 0.0f; g_SimTicks.ticking = true; g_SimTicks.tickcount = 0; @@ -384,6 +387,12 @@ void SourceModBase::GameFrame(bool simulating) g_LastTime = curtime; } + if (g_SimTicks.tickcount && (curtime - g_LastMenuTime >= 1.0f)) + { + g_ValveMenuStyle.ProcessWatchList(); + g_LastMenuTime = curtime; + } + if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount()) { g_pOnGameFrame->Execute(NULL); From e3b3d89bc8a5163b6a7e77f7063163245fe11df7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 May 2007 23:50:04 +0000 Subject: [PATCH 0746/1664] test of properties --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40777 --- core/MenuStyle_Base.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index 79023589..e0728dc6 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -11,6 +11,7 @@ * * Version: $Id$ */ + #include #include "sm_stringutil.h" #include "MenuStyle_Base.h" From abb434f63aaf85c478b09b1fd95291a960950d99 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 00:18:04 +0000 Subject: [PATCH 0747/1664] fixed an issue with fastlink iterators not working right --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40778 --- core/MenuStyle_Valve.cpp | 6 ++---- core/sm_fastlink.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index c507f39f..ed499660 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -189,10 +189,8 @@ void ValveMenuStyle::ProcessWatchList() return; } - FastLink::iterator iter; - unsigned int total = 0; - for (iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter) + for (FastLink::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter) { do_lookup[total++] = (*iter); } @@ -211,7 +209,7 @@ void ValveMenuStyle::ProcessWatchList() } if (curTime > player->menuStartTime + player->menuHoldTime) { - _CancelMenu(i, false); + _CancelMenu(client, false); } } } diff --git a/core/sm_fastlink.h b/core/sm_fastlink.h index 507a9926..bc204558 100644 --- a/core/sm_fastlink.h +++ b/core/sm_fastlink.h @@ -93,11 +93,11 @@ public: public: bool operator ==(const iterator &where) const { - return (link == link && position == position); + return (link == where.link && position == where.position); } bool operator !=(const iterator &where) const { - return (link != link || position != position); + return (link != where.link || position != where.position); } T & operator *() { From 0eae31dd4a87de39ba838502eababc23eabcd3df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 00:19:05 +0000 Subject: [PATCH 0748/1664] fixed this file not having our header --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40779 --- core/MenuManager.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 9a2f4468..7efcf6cd 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -1,3 +1,18 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + + #include #include #include "MenuManager.h" From c07bfbe9bd263a219c8923e8cdfe37aa87c120da Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 00:42:39 +0000 Subject: [PATCH 0749/1664] fixed some re-entrancy bugs removed debug commands --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40780 --- core/MenuStyle_Valve.cpp | 54 +++------------------------------------- core/MenuStyle_Valve.h | 2 +- 2 files changed, 5 insertions(+), 51 deletions(-) diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index ed499660..21f56365 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -51,39 +51,6 @@ bool ValveMenuStyle::OnClientCommand(int client) return true; } - if (strcmp(cmd, "sm_test") == 0) - { - IBaseMenu *menu = g_ValveMenuStyle.CreateMenu(); - menu->AppendItem("test1", ItemDrawInfo("Test #1", 0)); - menu->AppendItem("test2", ItemDrawInfo("Test #2", 0)); - menu->AppendItem("test3", ItemDrawInfo("Test #3", 0)); - menu->AppendItem("test4", ItemDrawInfo("Test #4", 0)); - menu->AppendItem("test5", ItemDrawInfo("Test #5", 0)); - menu->AppendItem("test6", ItemDrawInfo("Test #6", 0)); - menu->AppendItem("test7", ItemDrawInfo("Test #7", 0)); - menu->AppendItem("test8", ItemDrawInfo("Test #8", 0)); - menu->AppendItem("test9", ItemDrawInfo("Test #9", 0)); - menu->AppendItem("test10", ItemDrawInfo("Test #10", 0)); - menu->AppendItem("test11", ItemDrawInfo("Test #11", 0)); - menu->AppendItem("test12", ItemDrawInfo("Test #12", 0)); - menu->AppendItem("test13", ItemDrawInfo("Test #13", 0)); - menu->AppendItem("test14", ItemDrawInfo("Test #14", 0)); - menu->AppendItem("test15", ItemDrawInfo("Test #15", 0)); - menu->AppendItem("test16", ItemDrawInfo("Test #16", 0)); - menu->AppendItem("test17", ItemDrawInfo("Test #17", 0)); - menu->AppendItem("test18", ItemDrawInfo("Test #18", 0)); - menu->AppendItem("test19", ItemDrawInfo("Test #19", 0)); - menu->AppendItem("test20", ItemDrawInfo("Test #20", 0)); - - menu->Display(client, new TestHandler, 20); - return true; - } else if (strcmp(cmd, "gaben") == 0) { - KeyValues *kv = new KeyValues("menu"); - kv->SetString("msg", "hi"); - serverpluginhelpers->CreateMessage(engine->PEntityOfEntIndex(client), DIALOG_MENU, kv, g_pVSPHandle); - kv->deleteThis(); - } - return false; } @@ -109,14 +76,7 @@ void ValveMenuStyle::OnClientDisconnected(int client) return; } - menu_states_t &states = player->states; - states.mh->OnMenuCancel(states.menu, client, MenuCancel_Disconnect); - states.mh->OnMenuEnd(states.menu); - - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } + _CancelMenu(client, true, MenuCancel_Disconnect); player->bInMenu = false; } @@ -214,7 +174,7 @@ void ValveMenuStyle::ProcessWatchList() } } -void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore) +void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore, MenuCancelReason reason) { CValveMenuPlayer *player = &m_players[client]; menu_states_t &states = player->states; @@ -237,7 +197,7 @@ void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore) } /* Fire callbacks */ - mh->OnMenuCancel(menu, client, MenuCancel_Interrupt); + mh->OnMenuCancel(menu, client, reason); mh->OnMenuEnd(menu); if (bAutoIgnore) @@ -447,13 +407,7 @@ bool ValveMenuStyle::DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh menu_states_t &states = player->states; if (player->bInMenu) { - /* We need to cancel the old menu */ - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } - states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); - states.mh->OnMenuEnd(states.menu); + _CancelMenu(client, true); } states.firstItem = 0; diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index 4f45c2fa..cc66826e 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -71,7 +71,7 @@ public: //IMenuStyle private: bool RedoClientMenu(int client, ItemOrder order); void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); - void _CancelMenu(int client, bool bAutoIgnore=false); + void _CancelMenu(int client, bool bAutoIgnore=false, MenuCancelReason reason=MenuCancel_Interrupt); private: CValveMenuPlayer *m_players; FastLink m_WatchList; From 5aabd814066ecb9643a9718563a7017f2023a87a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 03:38:36 +0000 Subject: [PATCH 0750/1664] moved a whole crapload of code into a BaseMenuStyle so I can keep my precious sanity --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40781 --- core/MenuStyle_Base.cpp | 425 ++++++++++++++++++++++++++++++++++++++- core/MenuStyle_Base.h | 53 +++++ core/MenuStyle_Valve.cpp | 406 +++---------------------------------- core/MenuStyle_Valve.h | 35 +--- 4 files changed, 512 insertions(+), 407 deletions(-) diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index e0728dc6..eb139b50 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -15,9 +15,403 @@ #include #include "sm_stringutil.h" #include "MenuStyle_Base.h" +#include "PlayerManager.h" +#include "MenuManager.h" + +BaseMenuStyle::BaseMenuStyle() : m_WatchList(256) +{ +} + +void BaseMenuStyle::AddClientToWatch(int client) +{ + m_WatchList.push_back(client); +} + +void BaseMenuStyle::RemoveClientFromWatch(int client) +{ + m_WatchList.remove(client); +} + +void BaseMenuStyle::_CancelClientMenu(int client, bool bAutoIgnore/* =false */, MenuCancelReason reason/* =MenuCancel_Interrupt */) +{ + CBaseMenuPlayer *player = GetMenuPlayer(client); + menu_states_t &states = player->states; + + bool bOldIgnore = player->bAutoIgnore; + if (bAutoIgnore) + { + player->bAutoIgnore = true; + } + + /* Save states */ + IMenuHandler *mh = states.mh; + IBaseMenu *menu = states.menu; + + /* Clear menu */ + player->bInMenu = false; + if (player->menuHoldTime) + { + RemoveClientFromWatch(client); + } + + /* Fire callbacks */ + mh->OnMenuCancel(menu, client, reason); + mh->OnMenuEnd(menu); + + if (bAutoIgnore) + { + player->bAutoIgnore = bOldIgnore; + } +} + +void BaseMenuStyle::CancelMenu(CBaseMenu *menu) +{ + int maxClients = g_Players.GetMaxClients(); + for (int i=1; i<=maxClients; i++) + { + CBaseMenuPlayer *player = GetMenuPlayer(i); + if (player->bInMenu) + { + menu_states_t &states = player->states; + if (states.menu == menu) + { + _CancelClientMenu(i); + } + } + } +} + +bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore) +{ + if (client < 1 || client > g_Players.MaxClients()) + { + return false; + } + + CBaseMenuPlayer *player = GetMenuPlayer(client); + if (!player->bInMenu) + { + return false; + } + + _CancelClientMenu(client, autoIgnore); + + return true; +} + +MenuSource BaseMenuStyle::GetClientMenu(int client, void **object) +{ + if (client < 1 || client > g_Players.GetMaxClients()) + { + return MenuSource_None; + } + + CBaseMenuPlayer *player = GetMenuPlayer(client); + + if (player->bInMenu) + { + IBaseMenu *menu; + if ((menu=player->states.menu) != NULL) + { + if (object) + { + *object = menu; + } + return MenuSource_BaseMenu; + } + + return MenuSource_Display; + } else { + return GetClientExternMenu(client, object); + } +} + +MenuSource BaseMenuStyle::GetClientExternMenu(int client, void **object) +{ + return MenuSource_None; +} + +void BaseMenuStyle::OnClientDisconnected(int client) +{ + CBaseMenuPlayer *player = GetMenuPlayer(client); + if (!player->bInMenu) + { + return; + } + + _CancelClientMenu(client, true, MenuCancel_Disconnect); + + player->bInMenu = false; +} + +static int do_lookup[256]; +void BaseMenuStyle::ProcessWatchList() +{ + if (!m_WatchList.size()) + { + return; + } + + unsigned int total = 0; + for (FastLink::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter) + { + do_lookup[total++] = (*iter); + } + + int client; + CBaseMenuPlayer *player; + float curTime = gpGlobals->curtime; + for (unsigned int i=0; ibInMenu || !player->menuHoldTime) + { + m_WatchList.remove(i); + continue; + } + if (curTime > player->menuStartTime + player->menuHoldTime) + { + _CancelClientMenu(client, false); + } + } +} + +void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) +{ + CBaseMenuPlayer *player = GetMenuPlayer(client); + + /* First question: Are we in a menu? */ + if (!player->bInMenu) + { + return; + } + + bool cancel = false; + unsigned int item = 0; + MenuCancelReason reason = MenuCancel_Exit; + menu_states_t &states = player->states; + + assert(states.mh != NULL); + + if (states.menu == NULL) + { + item = key_press; + } else if (key_press < 1 || key_press > 8) { + cancel = true; + } else { + ItemSelection type = states.slots[key_press].type; + + /* For navigational items, we're going to redisplay */ + if (type == ItemSel_Back) + { + if (!RedoClientMenu(client, ItemOrder_Descending)) + { + cancel = true; + reason = MenuCancel_NoDisplay; + } else { + return; + } + } else if (type == ItemSel_Next) { + if (!RedoClientMenu(client, ItemOrder_Ascending)) + { + cancel = true; /* I like Saltines. */ + reason = MenuCancel_NoDisplay; + } else { + return; + } + } else if (type == ItemSel_Exit || type == ItemSel_None) { + cancel = true; + } else { + item = states.slots[key_press].item; + } + } + + /* Save variables */ + IMenuHandler *mh = states.mh; + IBaseMenu *menu = states.menu; + + /* Clear states */ + player->bInMenu = false; + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + + if (cancel) + { + mh->OnMenuCancel(menu, client, reason); + } else { + mh->OnMenuSelect(menu, client, item); + } + + mh->OnMenuEnd(menu); +} + +bool BaseMenuStyle::DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) + { + return false; + } + + CBaseMenuPlayer *player = GetMenuPlayer(client); + if (player->bAutoIgnore) + { + return false; + } + + /* For the duration of this, we are going to totally ignore whether + * the player is already in a menu or not (except to cancel the old one). + * Instead, we are simply going to ignore any further menu displays, so + * this display can't be interrupted. + */ + player->bAutoIgnore = true; + + /* Cancel any old menus */ + menu_states_t &states = player->states; + if (player->bInMenu) + { + /* We need to cancel the old menu */ + if (player->menuHoldTime) + { + RemoveClientFromWatch(client); + } + states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); + states.mh->OnMenuEnd(states.menu); + } + + states.firstItem = 0; + states.lastItem = 0; + states.menu = NULL; + states.mh = mh; + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; + player->bInMenu = true; + player->menuStartTime = gpGlobals->curtime; + player->menuHoldTime = time; + + if (time) + { + AddClientToWatch(client); + } + + /* Draw the display */ + SendDisplay(client, menu); + + /* We can be interrupted again! */ + player->bAutoIgnore = false; + + return true; +} + +bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time) +{ + mh->OnMenuStart(menu); + + if (!mh) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + CBaseMenuPlayer *player = GetMenuPlayer(client); + if (player->bAutoIgnore) + { + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + /* For the duration of this, we are going to totally ignore whether + * the player is already in a menu or not (except to cancel the old one). + * Instead, we are simply going to ignore any further menu displays, so + * this display can't be interrupted. + */ + player->bAutoIgnore = true; + + /* Cancel any old menus */ + menu_states_t &states = player->states; + if (player->bInMenu) + { + _CancelClientMenu(client, true); + } + + states.firstItem = 0; + states.lastItem = 0; + states.menu = menu; + states.mh = mh; + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; + + IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending); + if (!display) + { + player->bAutoIgnore = false; + player->bInMenu = false; + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; + } + + /* Finally, set our states */ + player->bInMenu = true; + player->menuStartTime = gpGlobals->curtime; + player->menuHoldTime = time; + + if (time) + { + AddClientToWatch(client); + } + + /* Draw the display */ + SendDisplay(client, display); + + /* Free the display pointer */ + delete display; + + /* We can be interrupted again! */ + player->bAutoIgnore = false; + + return true; +} + +bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) +{ + CBaseMenuPlayer *player = GetMenuPlayer(client); + menu_states_t &states = player->states; + + player->bAutoIgnore = true; + IMenuDisplay *display = g_Menus.RenderMenu(client, states, order); + if (!display) + { + if (player->menuHoldTime) + { + m_WatchList.remove(client); + } + player->bAutoIgnore = false; + return false; + } + + SendDisplay(client, display); + + delete display; + + player->bAutoIgnore = false; + + return true; +} CBaseMenu::CBaseMenu(IMenuStyle *pStyle) : -m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true) +m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), m_bShouldDelete(false), m_bCancelling(false) { } @@ -161,3 +555,32 @@ bool CBaseMenu::SetExitButton(bool set) m_ExitButton = set; return true; } + +void CBaseMenu::Cancel() +{ + if (m_bCancelling) + { + return; + } + + m_bCancelling = true; + Cancel_Finally(); + m_bCancelling = false; + + if (m_bShouldDelete) + { + delete this; + } +} + +void CBaseMenu::Destroy() +{ + if (!m_bCancelling || m_bShouldDelete) + { + Cancel(); + delete this; + } else { + m_bShouldDelete = true; + } +} + diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index fdfa8c29..cff8bd73 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -16,9 +16,11 @@ #define _INCLUDE_MENUSTYLE_BASE_H #include +#include #include #include #include "sm_memtable.h" +#include "sm_fastlink.h" using namespace SourceMod; using namespace SourceHook; @@ -38,6 +40,52 @@ public: unsigned int style; }; +class CBaseMenuPlayer +{ +public: + CBaseMenuPlayer() : bInMenu(false), bAutoIgnore(false) + { + } + menu_states_t states; + bool bInMenu; + bool bAutoIgnore; + float menuStartTime; + unsigned int menuHoldTime; +}; + +class CBaseMenu; + +class BaseMenuStyle : + public IMenuStyle, + public IClientListener +{ +public: + BaseMenuStyle(); +public: //IMenuStyle + bool CancelClientMenu(int client, bool autoIgnore/* =false */); + MenuSource GetClientMenu(int client, void **object); +public: //IClientListener + void OnClientDisconnected(int client); +public: //what derived must implement + virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0; + virtual void SendDisplay(int client, IMenuDisplay *display) =0; +public: //what derived may implement + virtual bool DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time); + virtual bool DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time); + virtual void AddClientToWatch(int client); + virtual void RemoveClientFromWatch(int client); + virtual void ProcessWatchList(); + virtual MenuSource GetClientExternMenu(int client, void **object); +public: //helpers + void CancelMenu(CBaseMenu *menu); + void ClientPressedKey(int client, unsigned int key_press); +protected: + void _CancelClientMenu(int client, bool bAutoIgnore=false, MenuCancelReason reason=MenuCancel_Interrupt); + bool RedoClientMenu(int client, ItemOrder order); +protected: + FastLink m_WatchList; +}; + class CBaseMenu : public IBaseMenu { public: @@ -57,6 +105,9 @@ public: virtual const char *GetDefaultTitle(); virtual bool GetExitButton(); virtual bool SetExitButton(bool set); + virtual void Cancel(); + virtual void Destroy(); + virtual void Cancel_Finally() =0; protected: String m_Title; IMenuStyle *m_pStyle; @@ -64,6 +115,8 @@ protected: CVector m_items; BaseStringTable m_Strings; bool m_ExitButton; + bool m_bCancelling; + bool m_bShouldDelete; }; #endif //_INCLUDE_MENUSTYLE_BASE_H diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index 21f56365..7d8282df 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -36,10 +36,15 @@ public: } }; -ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1]), m_WatchList(256) +ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1]) { } +CBaseMenuPlayer *ValveMenuStyle::GetMenuPlayer(int client) +{ + return &m_players[client]; +} + bool ValveMenuStyle::OnClientCommand(int client) { const char *cmd = engine->Cmd_Argv(0); @@ -68,19 +73,6 @@ void ValveMenuStyle::OnSourceModShutdown() g_Players.RemoveClientListener(this); } -void ValveMenuStyle::OnClientDisconnected(int client) -{ - CValveMenuPlayer *player = &m_players[client]; - if (!player->bInMenu) - { - return; - } - - _CancelMenu(client, true, MenuCancel_Disconnect); - - player->bInMenu = false; -} - void ValveMenuStyle::HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, @@ -112,7 +104,7 @@ void ValveMenuStyle::HookCreateMessage(edict_t *pEdict, * day to avenge its grandfather, killed in the great Menu Interruption * battle. */ - _CancelMenu(client, true); + _CancelClientMenu(client, true); } } @@ -141,360 +133,34 @@ unsigned int ValveMenuStyle::GetMaxPageItems() return 8; } -static int do_lookup[256]; -void ValveMenuStyle::ProcessWatchList() +void ValveMenuStyle::SendDisplay(int client, IMenuDisplay *display) { - if (!m_WatchList.size()) - { - return; - } - - unsigned int total = 0; - for (FastLink::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter) - { - do_lookup[total++] = (*iter); - } - - int client; - CValveMenuPlayer *player; - float curTime = gpGlobals->curtime; - for (unsigned int i=0; ibInMenu || !player->menuHoldTime) - { - m_WatchList.remove(i); - continue; - } - if (curTime > player->menuStartTime + player->menuHoldTime) - { - _CancelMenu(client, false); - } - } -} - -void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore, MenuCancelReason reason) -{ - CValveMenuPlayer *player = &m_players[client]; - menu_states_t &states = player->states; - - bool bOldIgnore = player->bAutoIgnore; - if (bAutoIgnore) - { - player->bAutoIgnore = true; - } - - /* Save states */ - IMenuHandler *mh = states.mh; - IBaseMenu *menu = states.menu; - - /* Clear menu */ - player->bInMenu = false; - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } - - /* Fire callbacks */ - mh->OnMenuCancel(menu, client, reason); - mh->OnMenuEnd(menu); - - if (bAutoIgnore) - { - player->bAutoIgnore = bOldIgnore; - } -} - -void ValveMenuStyle::CancelMenu(CValveMenu *menu) -{ - int maxClients = g_Players.GetMaxClients(); - for (int i=1; i<=maxClients; i++) - { - if (m_players[i].bInMenu) - { - menu_states_t &states = m_players[i].states; - if (states.menu == menu) - { - _CancelMenu(i); - } - } - } -} - -bool ValveMenuStyle::CancelClientMenu(int client, bool autoIgnore) -{ - if (client < 1 || client > 256 || !m_players[client].bInMenu) - { - return false; - } - - _CancelMenu(client, autoIgnore); - - return true; -} - - -void ValveMenuStyle::ClientPressedKey(int client, unsigned int key_press) -{ - CValveMenuPlayer *player = &m_players[client]; - - /* First question: Are we in a menu? */ - if (!player->bInMenu) - { - return; - } - - bool cancel = false; - unsigned int item = 0; - MenuCancelReason reason = MenuCancel_Exit; - menu_states_t &states = player->states; - - assert(states.mh != NULL); - - if (states.menu == NULL) - { - item = key_press; - } else if (key_press < 1 || key_press > 8) { - cancel = true; - } else { - ItemSelection type = states.slots[key_press].type; - - /* For navigational items, we're going to redisplay */ - if (type == ItemSel_Back) - { - if (!RedoClientMenu(client, ItemOrder_Descending)) - { - cancel = true; - reason = MenuCancel_NoDisplay; - } else { - return; - } - } else if (type == ItemSel_Next) { - if (!RedoClientMenu(client, ItemOrder_Ascending)) - { - cancel = true; /* I like Saltines. */ - reason = MenuCancel_NoDisplay; - } else { - return; - } - } else if (type == ItemSel_Exit || type == ItemSel_None) { - cancel = true; - } else { - item = states.slots[key_press].item; - } - } - - /* Save variables */ - IMenuHandler *mh = states.mh; - IBaseMenu *menu = states.menu; - - /* Clear states */ - player->bInMenu = false; - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } - - if (cancel) - { - mh->OnMenuCancel(menu, client, reason); - } else { - mh->OnMenuSelect(menu, client, item); - } - - mh->OnMenuEnd(menu); -} - -bool ValveMenuStyle::DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time) -{ - if (!g_pVSPHandle || !mh) - { - return false; - } - - CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); - if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) - { - return false; - } - - CValveMenuPlayer *player = &m_players[client]; - if (player->bAutoIgnore) - { - return false; - } - - /* For the duration of this, we are going to totally ignore whether - * the player is already in a menu or not (except to cancel the old one). - * Instead, we are simply going to ignore any further menu displays, so - * this display can't be interrupted. - */ - player->bAutoIgnore = true; - - /* Cancel any old menus */ - menu_states_t &states = player->states; - if (player->bInMenu) - { - /* We need to cancel the old menu */ - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } - states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); - states.mh->OnMenuEnd(states.menu); - } - - states.firstItem = 0; - states.lastItem = 0; - states.menu = NULL; - states.mh = mh; - states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; - player->curPrioLevel--; - player->bInMenu = true; - player->menuStartTime = gpGlobals->curtime; - player->menuHoldTime = time; - - if (time) - { - m_WatchList.push_back(client); - } - - /* Draw the display */ - menu->SendRawDisplay(client, player->curPrioLevel, time); - - /* We can be interrupted again! */ - player->bAutoIgnore = false; - - return true; -} - -bool ValveMenuStyle::DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time) -{ - mh->OnMenuStart(menu); - - if (!g_pVSPHandle || !mh) - { - mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); - mh->OnMenuEnd(menu); - return false; - } - - CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); - if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) - { - mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); - mh->OnMenuEnd(menu); - return false; - } - - CValveMenuPlayer *player = &m_players[client]; - if (player->bAutoIgnore) - { - mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); - mh->OnMenuEnd(menu); - return false; - } - - /* For the duration of this, we are going to totally ignore whether - * the player is already in a menu or not (except to cancel the old one). - * Instead, we are simply going to ignore any further menu displays, so - * this display can't be interrupted. - */ - player->bAutoIgnore = true; - - /* Cancel any old menus */ - menu_states_t &states = player->states; - if (player->bInMenu) - { - _CancelMenu(client, true); - } - - states.firstItem = 0; - states.lastItem = 0; - states.menu = menu; - states.mh = mh; - states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; - - IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending); - if (!display) - { - player->bAutoIgnore = false; - player->bInMenu = false; - mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); - mh->OnMenuEnd(menu); - return false; - } - - /* Finally, set our states */ - player->curPrioLevel--; - player->bInMenu = true; - player->menuStartTime = gpGlobals->curtime; - player->menuHoldTime = time; - - if (time) - { - m_WatchList.push_back(client); - } - - /* Draw the display */ + m_players[client].curPrioLevel--; CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display; - vDisplay->SendRawDisplay(client, player->curPrioLevel, time); - - /* Free the display pointer */ - delete display; - - /* We can be interrupted again! */ - player->bAutoIgnore = false; - - return true; + vDisplay->SendRawDisplay(client, m_players[client].curPrioLevel, m_players[client].menuHoldTime); } -bool ValveMenuStyle::RedoClientMenu(int client, ItemOrder order) +bool ValveMenuStyle::DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time) { - CValveMenuPlayer *player = &m_players[client]; - menu_states_t &states = player->states; - - player->bAutoIgnore = true; - IMenuDisplay *display = g_Menus.RenderMenu(client, states, order); - if (!display) + if (!g_pVSPHandle) { - if (player->menuHoldTime) - { - m_WatchList.remove(client); - } - player->bAutoIgnore = false; return false; } - CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display; - vDisplay->SendRawDisplay(client, --player->curPrioLevel, player->menuHoldTime); - - delete display; - - player->bAutoIgnore = false; - - return true; + return BaseMenuStyle::DoClientMenu(client, menu, mh, time); } -MenuSource ValveMenuStyle::GetClientMenu(int client, void **object) +bool ValveMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time) { - if (client < 1 || client > 256 || !m_players[client].bInMenu) + if (!g_pVSPHandle) { - return MenuSource_None; + mh->OnMenuStart(menu); + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); + mh->OnMenuEnd(menu); + return false; } - IBaseMenu *menu; - if ((menu=m_players[client].states.menu) != NULL) - { - if (object) - { - *object = menu; - } - return MenuSource_BaseMenu; - } - - return MenuSource_Display; + return BaseMenuStyle::DoClientMenu(client, menu, mh, time); } CValveMenuDisplay::CValveMenuDisplay() @@ -542,6 +208,9 @@ bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr) int *array = (int *)valuePtr; m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3])); return true; + } else if (option == MenuOption_Priority) { + m_pKv->SetInt("level", *(int *)valuePtr); + return true; } return false; @@ -626,7 +295,7 @@ bool CValveMenuDisplay::DrawRawLine(const char *rawline) void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time) { m_pKv->SetInt("level", priority); - m_pKv->SetInt("time", time); + m_pKv->SetInt("time", time ? time : 200); SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)( engine->PEntityOfEntIndex(client), @@ -641,38 +310,15 @@ bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned } CValveMenu::CValveMenu() : CBaseMenu(&g_ValveMenuStyle), - m_IntroColor(255, 0, 0, 255), m_bShouldDelete(false), m_bCancelling(false) + m_IntroColor(255, 0, 0, 255) { strcpy(m_IntroMsg, "You have a menu, press ESC"); m_Pagination = 5; } -void CValveMenu::Cancel() +void CValveMenu::Cancel_Finally() { - if (m_bCancelling) - { - return; - } - - m_bCancelling = true; g_ValveMenuStyle.CancelMenu(this); - m_bCancelling = false; - - if (m_bShouldDelete) - { - delete this; - } -} - -void CValveMenu::Destroy() -{ - if (!m_bCancelling || m_bShouldDelete) - { - Cancel(); - delete this; - } else { - m_bShouldDelete = true; - } } bool CValveMenu::SetPagination(unsigned int itemsPerPage) diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index cc66826e..78d1a887 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -20,23 +20,17 @@ #include "MenuStyle_Base.h" #include "sourcemm_api.h" #include "KeyValues.h" -#include #include "sm_fastlink.h" using namespace SourceMod; -class CValveMenuPlayer +class CValveMenuPlayer : public CBaseMenuPlayer { public: - CValveMenuPlayer() : bInMenu(false), bAutoIgnore(false), curPrioLevel(1) + CValveMenuPlayer() : curPrioLevel(1) { } - menu_states_t states; - bool bInMenu; - bool bAutoIgnore; int curPrioLevel; - float menuStartTime; - unsigned int menuHoldTime; }; class CValveMenu; @@ -44,37 +38,29 @@ class CValveMenuDisplay; class ValveMenuStyle : public SMGlobalClass, - public IMenuStyle, - public IClientListener + public BaseMenuStyle { public: ValveMenuStyle(); - bool DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time); - bool DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time); - void ClientPressedKey(int client, unsigned int key_press); bool OnClientCommand(int client); - void CancelMenu(CValveMenu *menu); - void ProcessWatchList(); +public: //BaseMenuStyle + CBaseMenuPlayer *GetMenuPlayer(int client); + void SendDisplay(int client, IMenuDisplay *display); + bool DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time); + bool DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); void OnSourceModVSPReceived(IServerPluginCallbacks *iface); -public: //IClientListener - void OnClientDisconnected(int client); public: //IMenuStyle const char *GetStyleName(); IMenuDisplay *CreateDisplay(); IBaseMenu *CreateMenu(); unsigned int GetMaxPageItems(); - MenuSource GetClientMenu(int client, void **object); - bool CancelClientMenu(int client, bool autoIgnore=false); private: - bool RedoClientMenu(int client, ItemOrder order); void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); - void _CancelMenu(int client, bool bAutoIgnore=false, MenuCancelReason reason=MenuCancel_Interrupt); private: CValveMenuPlayer *m_players; - FastLink m_WatchList; }; class CValveMenu; @@ -113,13 +99,10 @@ public: bool SetExitButton(bool set); bool SetPagination(unsigned int itemsPerPage); bool Display(int client, IMenuHandler *handler, unsigned int time); - void Cancel(); - void Destroy(); + void Cancel_Finally(); private: Color m_IntroColor; char m_IntroMsg[128]; - bool m_bCancelling; - bool m_bShouldDelete; }; extern ValveMenuStyle g_ValveMenuStyle; From d9b06e298c3db70c809ca3f874d28858b499ada0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 04:41:10 +0000 Subject: [PATCH 0751/1664] some minor fixups --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40782 --- core/MenuManager.cpp | 10 ++++++++-- core/MenuStyle_Base.cpp | 4 ++-- core/MenuStyle_Valve.cpp | 5 +++++ core/MenuStyle_Valve.h | 4 +++- public/IMenuManager.h | 19 +++++++++---------- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 7efcf6cd..7d9b102e 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -368,7 +368,7 @@ IMenuDisplay *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder o /* There were no items to draw! */ if (!foundItems) { - delete display; + display->DeleteThis(); return NULL; } @@ -520,9 +520,15 @@ skip_search: slots[position].type = ItemSel_None; } } - ItemDrawInfo dr(text, 0); + + /* Put a fake spacer before control stuff, if possible */ + { + ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER); + display->DrawItem(draw); + } /* PREVIOUS */ + ItemDrawInfo dr(text, 0); if (displayPrev || canDrawDisabled) { CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index eb139b50..976d5dd4 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -376,7 +376,7 @@ bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, SendDisplay(client, display); /* Free the display pointer */ - delete display; + display->DeleteThis(); /* We can be interrupted again! */ player->bAutoIgnore = false; @@ -403,7 +403,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) SendDisplay(client, display); - delete display; + display->DeleteThis(); player->bAutoIgnore = false; diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index 7d8282df..fb1e6e04 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -177,6 +177,11 @@ CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu) m_pKv->SetString("title", pMenu->m_IntroMsg); } +void CValveMenuDisplay::DeleteThis() +{ + delete this; +} + CValveMenuDisplay::~CValveMenuDisplay() { m_pKv->deleteThis(); diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index 78d1a887..039bebe3 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -81,6 +81,7 @@ public: bool SetExtOption(MenuOption option, const void *valuePtr); bool CanDrawItem(unsigned int drawFlags); void SendRawDisplay(int client, int priority, unsigned int time); + void DeleteThis(); private: KeyValues *m_pKv; unsigned int m_NextPos; @@ -92,13 +93,14 @@ class CValveMenu : public CBaseMenu friend class CValveMenuDisplay; public: CValveMenu(); -public: +public: //IBaseMenu bool SetExtOption(MenuOption option, const void *valuePtr); IMenuDisplay *CreateDisplay(); bool GetExitButton(); bool SetExitButton(bool set); bool SetPagination(unsigned int itemsPerPage); bool Display(int client, IMenuHandler *handler, unsigned int time); +public: //CBaseMenu void Cancel_Finally(); private: Color m_IntroColor; diff --git a/public/IMenuManager.h b/public/IMenuManager.h index 3f182011..db2a0dd3 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -117,20 +117,18 @@ namespace SourceMod #define MENU_NO_PAGINATION -1 /**< Menu should not be paginated (10 items max) */ #define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ - #define MENU_DETAIL_NOITEMCOLORS (1<<0) /**< Disables extended colors; menus will be white only */ - /** * @brief Extended menu options. */ enum MenuOption { - MenuOption_DetailFlags, /**< INT *: A combination of MENU_DETAIL properties (default=0) */ MenuOption_IntroMessage, /**< CONST CHAR *: Valve menus only; defaults to: "You have a menu, hit ESC" */ MenuOption_IntroColor, /**< INT[4]: Valve menus only; specifies the intro message colour using R,G,B,A (defaults to 255,0,0,255) */ + MenuOption_Priority, /**< INT *: Valve menus only; priority (less is higher) */ }; /** @@ -151,10 +149,6 @@ namespace SourceMod */ class IMenuDisplay { - public: - virtual ~IMenuDisplay() - { - } public: /** * @brief Returns the parent IMenuStyle pointer. @@ -223,6 +217,11 @@ namespace SourceMod * @return True on success, false otherwise. */ virtual bool SendDisplay(int client, IMenuHandler *handler, unsigned int time) =0; + + /** + * @brief Destroys the display object. + */ + virtual void DeleteThis() =0; }; /** @@ -252,7 +251,7 @@ namespace SourceMod /** * @brief Creates an IMenuDisplay object. * - * Note: the object should be freed using delete. + * Note: the object should be freed using ::DeleteThis. * * @return IMenuDisplay object. */ @@ -400,7 +399,7 @@ namespace SourceMod * @brief Creates a new IMenuDisplay object using extended options specific * to the IMenuStyle parent. Titles, items, etc, are not copied. * - * Note: The object should be freed with delete. + * Note: The object should be freed with IMenuDisplay::DeleteThis. * * @return IMenuDisplay pointer. */ @@ -638,7 +637,7 @@ namespace SourceMod * @return IDisplay pointer, or NULL if no items could be * found in the IBaseMenu pointer, or NULL if any * other error occurred. Any valid pointer must - * be freed using delete. + * be freed using IMenuDisplay::DeleteThis. */ virtual IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0; }; From 76b0554f2e2641bb832e2ca2cfd3ad4e066ddbbf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 04:43:37 +0000 Subject: [PATCH 0752/1664] fixed MENU_NO_PAGINATION and a typo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40783 --- public/IMenuManager.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/IMenuManager.h b/public/IMenuManager.h index db2a0dd3..60c4742c 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -83,7 +83,7 @@ namespace SourceMod #define ITEMDRAW_RAWLINE (1<<1) /**< Item should be a raw line, without a slot */ #define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ #define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ - #define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) + #define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) */ /** * @brief Information about item drawing. @@ -99,8 +99,8 @@ namespace SourceMod : display(DISPLAY), style(STYLE) { } - unsigned int style; /**< ITEMDRAW style flags */ const char *display; /**< Display text (NULL for none) */ + unsigned int style; /**< ITEMDRAW style flags */ }; /** @@ -114,7 +114,7 @@ namespace SourceMod MenuCancel_NoDisplay = -4, /** Menu could not be displayed to the client */ }; - #define MENU_NO_PAGINATION -1 /**< Menu should not be paginated (10 items max) */ + #define MENU_NO_PAGINATION 0 /**< Menu should not be paginated (10 items max) */ #define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ /** From 530a5aad80f182f7e8dc3e006f9a0666823d7c41 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 04:43:52 +0000 Subject: [PATCH 0753/1664] fixed various linux compilation problems added menus to the makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40784 --- core/Makefile | 2 +- core/MenuManager.cpp | 1 - core/MenuStyle_Base.cpp | 4 ++-- core/MenuStyle_Base.h | 4 ++-- core/MenuStyle_Valve.cpp | 8 ++++---- core/sm_fastlink.h | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/Makefile b/core/Makefile index fc813335..a25efdd0 100644 --- a/core/Makefile +++ b/core/Makefile @@ -23,7 +23,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ - sourcemm_api.cpp sourcemod.cpp + sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 7d9b102e..70657d59 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -513,7 +513,6 @@ skip_search: if (exitButton || (displayNext || displayPrev)) { /* Add spacers so we can pad to the end */ - unsigned int null_pos = 0; for (unsigned int i=0; iDrawItem(padItem); diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index 976d5dd4..8731b13e 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -421,7 +421,7 @@ CBaseMenu::~CBaseMenu() bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) { - if (m_Pagination == MENU_NO_PAGINATION + if (m_Pagination == (unsigned)MENU_NO_PAGINATION && m_items.size() >= m_pStyle->GetMaxPageItems()) { return false; @@ -444,7 +444,7 @@ bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw) { - if (m_Pagination == MENU_NO_PAGINATION + if (m_Pagination == (unsigned)MENU_NO_PAGINATION && m_items.size() >= m_pStyle->GetMaxPageItems()) { return false; diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index cff8bd73..600333ff 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -111,12 +111,12 @@ public: protected: String m_Title; IMenuStyle *m_pStyle; + BaseStringTable m_Strings; unsigned int m_Pagination; CVector m_items; - BaseStringTable m_Strings; bool m_ExitButton; - bool m_bCancelling; bool m_bShouldDelete; + bool m_bCancelling; }; #endif //_INCLUDE_MENUSTYLE_BASE_H diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index fb1e6e04..2d052234 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -22,8 +22,8 @@ SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *); ValveMenuStyle g_ValveMenuStyle; -const char *g_OptionNumTable[]; -const char *g_OptionCmdTable[]; +extern const char *g_OptionNumTable[]; +extern const char *g_OptionCmdTable[]; IServerPluginCallbacks *g_pVSPHandle = NULL; CallClass *g_pSPHCC = NULL; @@ -378,12 +378,12 @@ bool CValveMenu::SetExitButton(bool set) return false; } -static const char *g_OptionNumTable[11] = +const char *g_OptionNumTable[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; -static const char *g_OptionCmdTable[11] = +const char *g_OptionCmdTable[] = { "sm_vmenuselect 0", /* INVALID! */ "sm_vmenuselect 1", diff --git a/core/sm_fastlink.h b/core/sm_fastlink.h index bc204558..3de9526a 100644 --- a/core/sm_fastlink.h +++ b/core/sm_fastlink.h @@ -183,8 +183,8 @@ public: private: size_t m_Size; unsigned int m_FirstLink; - unsigned int m_LastLink; unsigned int m_FreeNodes; + unsigned int m_LastLink; unsigned int m_MaxSize; FastLinkNode *m_Nodes; }; From 11bd835e55e18d24def91ba95135358aca7ef6d3 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 13 May 2007 05:24:01 +0000 Subject: [PATCH 0754/1664] A pointless commit heading your way. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40785 --- sourcepawn/jit/x86/msvc8/jit-x86.vcproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj index b4e41221..764e5a91 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj @@ -40,7 +40,7 @@ Date: Sun, 13 May 2007 05:51:30 +0000 Subject: [PATCH 0755/1664] initial import of radio message - UNTESTED, DO NOT EVEN TRY LOL added supported mods for radio messages into core gameconf various internal fixes/improvements for menus --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40786 --- configs/gamedata/core.games.txt | 35 ++++ core/MenuManager.cpp | 25 +-- core/MenuManager.h | 1 + core/MenuStyle_Base.cpp | 7 +- core/MenuStyle_Base.h | 4 +- core/MenuStyle_Radio.cpp | 305 ++++++++++++++++++++++++++++++++ core/MenuStyle_Radio.h | 94 ++++++++++ core/PlayerManager.cpp | 37 ++-- core/msvc8/sourcemod_mm.vcproj | 8 + core/sourcemod.cpp | 2 + public/IMenuManager.h | 8 - 11 files changed, 481 insertions(+), 45 deletions(-) create mode 100644 core/MenuStyle_Radio.cpp create mode 100644 core/MenuStyle_Radio.h diff --git a/configs/gamedata/core.games.txt b/configs/gamedata/core.games.txt index 910da115..d558d0be 100644 --- a/configs/gamedata/core.games.txt +++ b/configs/gamedata/core.games.txt @@ -10,5 +10,40 @@ "linux" "14" } } + + } + + "cstrike" + { + "Keys" + { + "HudRadioMenuMsg" "ShowMenu" + } + } + + "dod" + { + "Keys" + { + "HudRadioMenuMsg" "ShowMenu" + } + } + + + "sourceforts" + { + "Keys" + { + "HudRadioMenuMsg" "ShowMenu" + } + } + + + "insurgency" + { + "Keys" + { + "HudRadioMenuMsg" "ShowMenu" + } } } diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 70657d59..5c244b43 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -142,28 +142,12 @@ void VoteHandler::OnBroadcastEnd(IBaseMenu *menu) MenuManager::MenuManager() { - m_ShowMenu = -1; - m_pDefaultStyle = NULL; + m_Styles.push_back(&g_ValveMenuStyle); + SetDefaultStyle(&g_ValveMenuStyle); } void MenuManager::OnSourceModAllInitialized() { - int num = g_SMAPI->GetUserMessageCount(); - if (num >= 1) - { - for (int i=0; iGetUserMessage(i, NULL), "ShowMenu") == 0) - { - m_ShowMenu = i; - break; - } - } - } - - /* :TODO: styles */ - m_Styles.push_back(&g_ValveMenuStyle); - SetDefaultStyle(&g_ValveMenuStyle); } void MenuManager::OnSourceModAllShutdown() @@ -203,6 +187,11 @@ IMenuStyle *MenuManager::GetStyle(unsigned int index) return m_Styles[index]; } +void MenuManager::AddStyle(IMenuStyle *style) +{ + m_Styles.push_back(style); +} + unsigned int MenuManager::GetStyleCount() { return (unsigned int)m_Styles.size(); diff --git a/core/MenuManager.h b/core/MenuManager.h index ebe70320..49fd2da6 100644 --- a/core/MenuManager.h +++ b/core/MenuManager.h @@ -92,6 +92,7 @@ public: unsigned int numClients, unsigned int time); IMenuStyle *GetDefaultStyle(); + void AddStyle(IMenuStyle *style); bool SetDefaultStyle(IMenuStyle *style); IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order); protected: diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index 8731b13e..d0f582b8 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -121,13 +121,10 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object) } return MenuSource_Display; - } else { - return GetClientExternMenu(client, object); + } else if (player->bInExternMenu) { + return MenuSource_External; } -} -MenuSource BaseMenuStyle::GetClientExternMenu(int client, void **object) -{ return MenuSource_None; } diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index 600333ff..64c4b78a 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -43,7 +43,7 @@ public: class CBaseMenuPlayer { public: - CBaseMenuPlayer() : bInMenu(false), bAutoIgnore(false) + CBaseMenuPlayer() : bInMenu(false), bAutoIgnore(false), bInExternMenu(false) { } menu_states_t states; @@ -51,6 +51,7 @@ public: bool bAutoIgnore; float menuStartTime; unsigned int menuHoldTime; + bool bInExternMenu; }; class CBaseMenu; @@ -75,7 +76,6 @@ public: //what derived may implement virtual void AddClientToWatch(int client); virtual void RemoveClientFromWatch(int client); virtual void ProcessWatchList(); - virtual MenuSource GetClientExternMenu(int client, void **object); public: //helpers void CancelMenu(CBaseMenu *menu); void ClientPressedKey(int client, unsigned int key_press); diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp new file mode 100644 index 00000000..1c6d485d --- /dev/null +++ b/core/MenuStyle_Radio.cpp @@ -0,0 +1,305 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "MenuStyle_Radio.h" +#include "sm_stringutil.h" +#include "UserMessages.h" +#include "GameConfigs.h" + +extern const char *g_RadioNumTable[]; +CRadioStyle g_RadioMenuStyle; +int g_ShowMenuId = -1; + +CRadioStyle::CRadioStyle() : m_players(new CBaseMenuPlayer[256+1]) +{ +} + +void CRadioStyle::OnSourceModAllInitialized() +{ + const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg"); + if (!msg || msg[0] == '\0') + { + return; + } + + g_ShowMenuId = g_UserMsgs.GetMessageIndex(msg); + + if (!IsSupported()) + { + return; + } + + g_Menus.AddStyle(this); + g_Menus.SetDefaultStyle(this); + + g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false); +} + +void CRadioStyle::OnSourceModShutdown() +{ + g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false); +} + +bool CRadioStyle::IsSupported() +{ + return (g_ShowMenuId != -1); +} + +bool CRadioStyle::OnClientCommand(int client) +{ + const char *cmd = engine->Cmd_Argv(0); + + if (strcmp(cmd, "menuselect") == 0) + { + if (!m_players[client].bInMenu) + { + return false; + } + int arg = atoi(engine->Cmd_Argv(1)); + ClientPressedKey(client, arg); + } + + return false; +} + +static unsigned int g_last_holdtime = 0; +static unsigned int g_last_client_count = 0; +static int g_last_clients[256]; + +void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +{ + int count = pFilter->GetRecipientCount(); + bf_read br(bf->GetBasePointer(), 2); + + br.ReadWord(); + int c = br.ReadChar(); + + g_last_holdtime = (c == -1) ? 0 : (unsigned)c; + + for (int i=0; iGetRecipientIndex(i); + } +} + +void CRadioStyle::OnUserMessageSent(int msg_id) +{ + for (unsigned int i=0; iSendRawDisplay(client, m_players[client].menuHoldTime); +} + +IMenuDisplay *CRadioStyle::CreateDisplay() +{ + return new CRadioDisplay(); +} + +IBaseMenu *CRadioStyle::CreateMenu() +{ + return new CRadioMenu(); +} + +unsigned int CRadioStyle::GetMaxPageItems() +{ + return 10; +} + +const char *CRadioStyle::GetStyleName() +{ + return "radio"; +} + +CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client) +{ + return &m_players[client]; +} + +CRadioDisplay::CRadioDisplay() +{ + Reset(); +} + +CRadioDisplay::CRadioDisplay(CRadioMenu *menu) +{ + Reset(); +} + +bool CRadioDisplay::DrawRawLine(const char *rawline) +{ + m_BufferText.append(rawline); + m_BufferText.append("\n"); + return true; +} + +void CRadioDisplay::Reset() +{ + m_BufferText.assign(""); + m_Title.assign(""); + m_NextPos = 1; +} + +bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time) +{ + return g_RadioMenuStyle.DoClientMenu(client, this, handler, time); +} + +bool CRadioDisplay::SetExtOption(MenuOption option, const void *valuePtr) +{ + return false; +} + +IMenuStyle *CRadioDisplay::GetParentStyle() +{ + return &g_RadioMenuStyle; +} + +void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */) +{ + if (m_Title.size() != 0 && onlyIfEmpty) + { + return; + } + m_Title.assign(text); +} + +unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item) +{ + if (m_NextPos > 10 || !CanDrawItem(item.style)) + { + return 0; + } + + if (item.style & ITEMDRAW_RAWLINE) + { + if (item.style & ITEMDRAW_SPACER) + { + m_BufferText.append("\n"); + } else { + m_BufferText.append(item.display); + m_BufferText.append("\n"); + } + return 0; + } else if (item.style & ITEMDRAW_SPACER) { + m_BufferText.append("\n"); + return m_NextPos++; + } + + if (item.style & ITEMDRAW_DISABLED) + { + m_BufferText.append(g_RadioNumTable[m_NextPos]); + m_BufferText.append(". "); + m_BufferText.append(item.display); + m_BufferText.append("\n"); + } else { + m_BufferText.append("->. "); + m_BufferText.append(item.display); + m_BufferText.append("\n"); + keys |= (1<<(m_NextPos-1)); + } + + return m_NextPos++; +} + +bool CRadioDisplay::CanDrawItem(unsigned int drawFlags) +{ + if ((drawFlags & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE) + { + return false; + } + + return true; +} + +void CRadioDisplay::SendRawDisplay(int client, unsigned int time) +{ + char buffer[4096]; + size_t len; + + len = UTIL_Format(buffer, sizeof(buffer), "%s\n%s", m_Title.c_str(), m_BufferText.c_str()); + + cell_t players[1] = {client}; + + char *ptr = buffer; + char save = 0; + while (true) + { + if (len > 240) + { + save = ptr[240]; + ptr[240] = '\0'; + } + bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, 0); + buffer->WriteWord(keys); + buffer->WriteChar(time ? time : -1); + buffer->WriteByte( (len > 240) ? 1 : 0 ); + buffer->WriteString(ptr); + g_UserMsgs.EndMessage(); + if (len > 240) + { + ptr[240] = save; + ptr = &ptr[240]; + len -= 240; + } else { + break; + } + } +} + +void CRadioDisplay::DeleteThis() +{ + delete this; +} + +CRadioMenu::CRadioMenu() : CBaseMenu(&g_RadioMenuStyle) +{ +} + +bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr) +{ + return false; +} + +IMenuDisplay *CRadioMenu::CreateDisplay() +{ + return new CRadioDisplay(this); +} + +bool CRadioMenu::Display(int client, IMenuHandler *handler, unsigned int time) +{ + return g_RadioMenuStyle.DoClientMenu(client, this, handler, time); +} + +void CRadioMenu::Cancel_Finally() +{ + g_RadioMenuStyle.CancelMenu(this); +} + +const char *g_RadioNumTable[11] = +{ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" +}; diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h new file mode 100644 index 00000000..dd25e1ea --- /dev/null +++ b/core/MenuStyle_Radio.h @@ -0,0 +1,94 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_MENUSTYLE_RADIO_H +#define _INCLUDE_MENUSTYLE_RADIO_H + +#include "sm_globals.h" +#include "MenuManager.h" +#include "MenuStyle_Base.h" +#include "sourcemm_api.h" +#include +#include +#include "sm_fastlink.h" + +using namespace SourceMod; + +class CRadioStyle : + public BaseMenuStyle, + public SMGlobalClass, + public IUserMessageListener +{ +public: + CRadioStyle(); +public: //SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: //BaseMenuStyle + CBaseMenuPlayer *GetMenuPlayer(int client); + void SendDisplay(int client, IMenuDisplay *display); +public: //IMenuStyle + const char *GetStyleName(); + IMenuDisplay *CreateDisplay(); + IBaseMenu *CreateMenu(); + unsigned int GetMaxPageItems(); +public: //IUserMessageListener + void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); + void OnUserMessageSent(int msg_id); +public: + bool IsSupported(); + bool OnClientCommand(int client); +private: + CBaseMenuPlayer *m_players; +}; + +class CRadioMenu; + +class CRadioDisplay : public IMenuDisplay +{ +public: + CRadioDisplay(); + CRadioDisplay(CRadioMenu *menu); +public: //IMenuDisplay + IMenuStyle *GetParentStyle(); + void Reset(); + void DrawTitle(const char *text, bool onlyIfEmpty=false); + unsigned int DrawItem(const ItemDrawInfo &item); + bool DrawRawLine(const char *rawline); + bool SetExtOption(MenuOption option, const void *valuePtr); + bool CanDrawItem(unsigned int drawFlags); + bool SendDisplay(int client, IMenuHandler *handler, unsigned int time); + void DeleteThis(); + void SendRawDisplay(int client, unsigned int time); +private: + String m_BufferText; + String m_Title; + unsigned int m_NextPos; + int keys; +}; + +class CRadioMenu : public CBaseMenu +{ +public: + CRadioMenu(); +public: + bool SetExtOption(MenuOption option, const void *valuePtr); + IMenuDisplay *CreateDisplay(); + bool Display(int client, IMenuHandler *handler, unsigned int time); + void Cancel_Finally(); +}; + +extern CRadioStyle g_RadioMenuStyle; + +#endif //_INCLUDE_MENUSTYLE_RADIO_H diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 6260285e..15708383 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -18,6 +18,7 @@ #include "AdminCache.h" #include "ConCmdManager.h" #include "MenuStyle_Valve.h" +#include "MenuStyle_Radio.h" PlayerManager g_Players; @@ -385,24 +386,36 @@ void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity) void PlayerManager::OnClientCommand(edict_t *pEntity) { - cell_t res = Pl_Continue; int client = engine->IndexOfEdict(pEntity); - - int args = engine->Cmd_Argc() - 1; - - m_clcommand->PushCell(client); - m_clcommand->PushCell(args); - m_clcommand->Execute(&res, NULL); - - if (res >= Pl_Stop) - { - RETURN_META(MRES_SUPERCEDE); - } + cell_t res = Pl_Continue; bool result = g_ValveMenuStyle.OnClientCommand(client); if (result) { res = Pl_Handled; + } else { + result = g_RadioMenuStyle.OnClientCommand(client); + if (result) + { + res = Pl_Handled; + } + } + + int args = engine->Cmd_Argc() - 1; + + cell_t res2 = Pl_Continue; + m_clcommand->PushCell(client); + m_clcommand->PushCell(args); + m_clcommand->Execute(&res2, NULL); + + if (res2 > res) + { + res = res2; + } + + if (res >= Pl_Stop) + { + RETURN_META(MRES_SUPERCEDE); } res = g_ConCmds.DispatchClientCommand(client, (ResultType)res); diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 09667d5a..bcd11703 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -235,6 +235,10 @@ RelativePath="..\MenuStyle_Base.cpp" > + + @@ -353,6 +357,10 @@ RelativePath="..\MenuStyle_Base.h" > + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 95eaaf8a..42b7e691 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -30,6 +30,7 @@ #include "ForwardSys.h" #include "TimerSys.h" #include "MenuStyle_Valve.h" +#include "MenuStyle_Radio.h" SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -390,6 +391,7 @@ void SourceModBase::GameFrame(bool simulating) if (g_SimTicks.tickcount && (curtime - g_LastMenuTime >= 1.0f)) { g_ValveMenuStyle.ProcessWatchList(); + g_RadioMenuStyle.ProcessWatchList(); g_LastMenuTime = curtime; } diff --git a/public/IMenuManager.h b/public/IMenuManager.h index 60c4742c..b48479a8 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -617,14 +617,6 @@ namespace SourceMod */ virtual IMenuStyle *GetDefaultStyle() =0; - /** - * @brief Sets the default draw style Core uses. - * - * @param style Menu style. - * @return True on success, false on failure. - */ - virtual bool SetDefaultStyle(IMenuStyle *style) =0; - /** * @brief Given a set of menu states, converts it to an IDisplay object. * From 32a472fccf8fe4c96146c95e37e15815897bb6f9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 05:53:36 +0000 Subject: [PATCH 0756/1664] exposed the interface since the API is almost stable --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40787 --- core/MenuManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 5c244b43..2b0aa9df 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -20,6 +20,7 @@ #include "sourcemm_api.h" #include "PlayerManager.h" #include "MenuStyle_Valve.h" +#include "ShareSys.h" MenuManager g_Menus; @@ -148,6 +149,7 @@ MenuManager::MenuManager() void MenuManager::OnSourceModAllInitialized() { + g_ShareSys.AddInterface(NULL, this); } void MenuManager::OnSourceModAllShutdown() From d417dea96836b03ee4507808f2df195b5099d743 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 05:59:06 +0000 Subject: [PATCH 0757/1664] external menus time out now --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40788 --- core/MenuStyle_Base.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index d0f582b8..acc7a111 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -122,6 +122,12 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object) return MenuSource_Display; } else if (player->bInExternMenu) { + if (player->menuHoldTime != 0 + && (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime)) + { + player->bInExternMenu = false; + return MenuSource_None; + } return MenuSource_External; } From f7aa15c06c20cea548c6727bcbbe5a832d0a9bde Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 13 May 2007 06:37:38 +0000 Subject: [PATCH 0758/1664] Added skeleton SDK Tools extension. It's no where near done - DON'T BOTHER USING IT :o --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40789 --- extensions/sdktools/Makefile | 87 ++++++ extensions/sdktools/extension.cpp | 64 +++++ extensions/sdktools/extension.h | 116 ++++++++ extensions/sdktools/msvc8/sdktools.sln | 20 ++ extensions/sdktools/msvc8/sdktools.vcproj | 240 ++++++++++++++++ extensions/sdktools/sdk/smsdk_config.h | 48 ++++ extensions/sdktools/sdk/smsdk_ext.cpp | 334 ++++++++++++++++++++++ extensions/sdktools/sdk/smsdk_ext.h | 213 ++++++++++++++ 8 files changed, 1122 insertions(+) create mode 100644 extensions/sdktools/Makefile create mode 100644 extensions/sdktools/extension.cpp create mode 100644 extensions/sdktools/extension.h create mode 100644 extensions/sdktools/msvc8/sdktools.sln create mode 100644 extensions/sdktools/msvc8/sdktools.vcproj create mode 100644 extensions/sdktools/sdk/smsdk_config.h create mode 100644 extensions/sdktools/sdk/smsdk_ext.cpp create mode 100644 extensions/sdktools/sdk/smsdk_ext.h diff --git a/extensions/sdktools/Makefile b/extensions/sdktools/Makefile new file mode 100644 index 00000000..8c735d7d --- /dev/null +++ b/extensions/sdktools/Makefile @@ -0,0 +1,87 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = sample + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = sdk/smsdk_ext.cpp extension.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/sdk + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/sdk/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/sdk/*.o + rm -rf Debug/$(BINARY) diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp new file mode 100644 index 00000000..4c528358 --- /dev/null +++ b/extensions/sdktools/extension.cpp @@ -0,0 +1,64 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod SDK Tools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + +#include "extension.h" + +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + +SDKTools g_SdkTools; /**< Global singleton for extension's main interface */ +IServerGameEnts *gameents = NULL; +IBinTools *g_pBinTools = NULL; +IPlayerManager *g_pPlayers = NULL; + +SMEXT_LINK(&g_SdkTools); + +bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + SM_GET_IFACE(PLAYERMANAGER, g_pPlayers); + + g_pShareSys->AddDependency(myself, "bintools.ext", true, true); + + return true; +} + +bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + GET_V_IFACE_CURRENT(serverFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS); + + return true; +} + +void SDKTools::SDK_OnAllLoaded() +{ + SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); +} + +bool SDKTools::QueryRunning(char *error, size_t maxlength) +{ + SM_CHECK_IFACE(BINTOOLS, g_pBinTools); + + return true; +} diff --git a/extensions/sdktools/extension.h b/extensions/sdktools/extension.h new file mode 100644 index 00000000..473f9175 --- /dev/null +++ b/extensions/sdktools/extension.h @@ -0,0 +1,116 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod SDK Tools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +/** + * @file extension.h + * @brief SDK Tools extension code header. + */ + +#include "smsdk_ext.h" +#include +#include + +/** + * @brief Implementation of the SDK Tools extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class SDKTools : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + //virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @return True if working, false otherwise. + */ + virtual bool QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlen); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlen); +#endif +}; + +extern IServerGameEnts *gameents; +extern IBinTools *g_pBinTools; +extern IPlayerManager *g_pPlayers; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/sdktools/msvc8/sdktools.sln b/extensions/sdktools/msvc8/sdktools.sln new file mode 100644 index 00000000..1ca7a308 --- /dev/null +++ b/extensions/sdktools/msvc8/sdktools.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdktools", "sdktools.vcproj", "{7A740927-C751-4312-BF9D-6367F8C508F8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7A740927-C751-4312-BF9D-6367F8C508F8}.Debug|Win32.ActiveCfg = Debug|Win32 + {7A740927-C751-4312-BF9D-6367F8C508F8}.Debug|Win32.Build.0 = Debug|Win32 + {7A740927-C751-4312-BF9D-6367F8C508F8}.Release|Win32.ActiveCfg = Release|Win32 + {7A740927-C751-4312-BF9D-6367F8C508F8}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/sdktools/msvc8/sdktools.vcproj b/extensions/sdktools/msvc8/sdktools.vcproj new file mode 100644 index 00000000..2d7defb0 --- /dev/null +++ b/extensions/sdktools/msvc8/sdktools.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/sdktools/sdk/smsdk_config.h b/extensions/sdktools/sdk/smsdk_config.h new file mode 100644 index 00000000..2c6caefd --- /dev/null +++ b/extensions/sdktools/sdk/smsdk_config.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "SDK Tools" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" /* :TODO: Describe this, heh */ +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SDKTOOLS" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +#define SMEXT_CONF_METAMOD + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/sdktools/sdk/smsdk_ext.cpp b/extensions/sdktools/sdk/smsdk_ext.cpp new file mode 100644 index 00000000..d7d3ba02 --- /dev/null +++ b/extensions/sdktools/sdk/smsdk_ext.cpp @@ -0,0 +1,334 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, maxlength, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + + if (SDK_OnLoad(error, maxlength, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif diff --git a/extensions/sdktools/sdk/smsdk_ext.h b/extensions/sdktools/sdk/smsdk_ext.h new file mode 100644 index 00000000..808e9759 --- /dev/null +++ b/extensions/sdktools/sdk/smsdk_ext.h @@ -0,0 +1,213 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif + +public: // IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: // ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error) \ + { \ + snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + return false; \ + } \ + } + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ From 8a9b5b7d415dd7c7f19df67b53da97c5a577de68 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 13 May 2007 07:48:36 +0000 Subject: [PATCH 0759/1664] amb283 - Renamed IsPlayerInGame() to IsClientInGame() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40790 --- core/smn_player.cpp | 17 +++++++++-------- plugins/include/clients.inc | 11 ++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 38e6d34b..fb422ecb 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -111,7 +111,7 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsClientConnected(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) @@ -122,7 +122,7 @@ static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params) return (g_Players.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0; } -static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsClientInGame(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) @@ -133,7 +133,7 @@ static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params) return (g_Players.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0; } -static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsClientAuthorized(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) @@ -144,7 +144,7 @@ static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params) return (g_Players.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0; } -static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params) +static cell_t sm_IsClientFakeClient(IPluginContext *pCtx, const cell_t *params) { int index = params[1]; if ((index < 1) || (index > g_Players.GetMaxClients())) @@ -830,10 +830,11 @@ REGISTER_NATIVES(playernatives) {"GetMaxClients", sm_GetMaxClients}, {"GetUserAdmin", GetUserAdmin}, {"GetUserFlagBits", GetUserFlagBits}, - {"IsClientAuthorized", sm_IsPlayerAuthorized}, - {"IsClientConnected", sm_IsPlayerConnected}, - {"IsFakeClient", sm_IsPlayerFakeClient}, - {"IsPlayerInGame", sm_IsPlayerIngame}, + {"IsClientAuthorized", sm_IsClientAuthorized}, + {"IsClientConnected", sm_IsClientConnected}, + {"IsFakeClient", sm_IsClientFakeClient}, + {"IsPlayerInGame", sm_IsClientInGame}, /* Backwards compat shim */ + {"IsClientInGame", sm_IsClientInGame}, {"RemoveUserFlags", RemoveUserFlags}, {"SetUserAdmin", SetUserAdmin}, {"SetUserFlagBits", SetUserFlagBits}, diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index a01280a6..66e8c298 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -158,7 +158,16 @@ native bool:IsClientConnected(client); * @param client Player index. * @return True if player has entered the game, false otherwise. */ -native bool:IsPlayerInGame(client); +native bool:IsClientInGame(client); + +/** + * Backwards compatibility stock - use IsClientInGame + * @deprecated Renamed to IsClientInGame + */ +stock bool:IsPlayerInGame(client) +{ + return IsClientInGame(client); +} /** * Returns if a certain player has been authenticated. From f76a2b4e07ee7ad72e5f42fa9280b20046624d3f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 17:12:16 +0000 Subject: [PATCH 0760/1664] finished radio menus added a new item flag so radio menus could ignore disabled control items due to a bug where 0 is always white in Valve menus fixed a bug where ClientPressedKey() did not account for the max page items in a style fixed some pagination drawing bugs with control items --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40791 --- core/MenuManager.cpp | 68 ++++++++++++++++++++++++---------------- core/MenuStyle_Base.cpp | 2 +- core/MenuStyle_Radio.cpp | 29 +++++++++++++---- core/MenuStyle_Radio.h | 2 +- core/MenuStyle_Valve.cpp | 9 ------ public/IMenuManager.h | 1 + 6 files changed, 67 insertions(+), 44 deletions(-) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 2b0aa9df..a3e2d794 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -468,7 +468,7 @@ skip_search: /* Now, we need to check if we need to add anything extra */ if (pgn != MENU_NO_PAGINATION) { - bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED); + bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL); bool exitButton = menu->GetExitButton(); char text[50]; @@ -517,34 +517,48 @@ skip_search: display->DrawItem(draw); } - /* PREVIOUS */ ItemDrawInfo dr(text, 0); - if (displayPrev || canDrawDisabled) + /** + * If we have one or the other, we need to have spacers for both. + */ + if (displayPrev || displayNext) { - CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); - dr.style = displayPrev ? 0 : ITEMDRAW_DISABLED; - position = display->DrawItem(dr); - slots[position].type = ItemSel_Back; - } else if ((displayNext || canDrawDisabled) || exitButton) { - /* If we can't display this, - * but there is a "next" or "exit" button, we need to pad! - */ - position = display->DrawItem(padItem); - slots[position].type = ItemSel_None; - } + /* PREVIOUS */ + ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL); + if (displayPrev || canDrawDisabled) + { + CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); + dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; + position = display->DrawItem(dr); + slots[position].type = ItemSel_Back; + } else if (displayNext || exitButton) { + /* If we can't display this, and there is an exit button, + * we need to pad! + */ + position = display->DrawItem(padCtrlItem); + slots[position].type = ItemSel_None; + } - /* NEXT */ - if (displayNext || canDrawDisabled) - { - CorePlayerTranslate(client, text, sizeof(text), "Next", NULL); - dr.style = displayNext ? 0 : ITEMDRAW_DISABLED; - position = display->DrawItem(dr); - slots[position].type = ItemSel_Next; - } else if (exitButton) { - /* If we can't display this, - * but there is an exit button, we need to pad! - */ - position = display->DrawItem(padItem); + /* NEXT */ + if (displayNext || canDrawDisabled) + { + CorePlayerTranslate(client, text, sizeof(text), "Next", NULL); + dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; + position = display->DrawItem(dr); + slots[position].type = ItemSel_Next; + } else if (exitButton) { + /* If we can't display this, + * but there is an "exit" button, we need to pad! + */ + position = display->DrawItem(padCtrlItem); + slots[position].type = ItemSel_None; + } + } else { + /* Otherwise, bump to two slots! */ + ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT); + position = display->DrawItem(numBump); + slots[position].type = ItemSel_None; + position = display->DrawItem(numBump); slots[position].type = ItemSel_None; } @@ -552,7 +566,7 @@ skip_search: if (exitButton) { CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL); - dr.style = 0; + dr.style = ITEMDRAW_CONTROL; position = display->DrawItem(dr); slots[position].type = ItemSel_Exit; } diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index acc7a111..02531725 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -200,7 +200,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) if (states.menu == NULL) { item = key_press; - } else if (key_press < 1 || key_press > 8) { + } else if (key_press < 1 || key_press > GetMaxPageItems()) { cancel = true; } else { ItemSelection type = states.slots[key_press].type; diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp index 1c6d485d..60c386e9 100644 --- a/core/MenuStyle_Radio.cpp +++ b/core/MenuStyle_Radio.cpp @@ -20,13 +20,20 @@ extern const char *g_RadioNumTable[]; CRadioStyle g_RadioMenuStyle; int g_ShowMenuId = -1; +bool g_bRadioInit = false; CRadioStyle::CRadioStyle() : m_players(new CBaseMenuPlayer[256+1]) { } -void CRadioStyle::OnSourceModAllInitialized() +void CRadioStyle::OnSourceModLevelChange(const char *mapName) { + if (g_bRadioInit) + { + return; + } + + g_bRadioInit = true; const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg"); if (!msg || msg[0] == '\0') { @@ -66,8 +73,10 @@ bool CRadioStyle::OnClientCommand(int client) { return false; } + int arg = atoi(engine->Cmd_Argv(1)); ClientPressedKey(client, arg); + return true; } return false; @@ -161,6 +170,7 @@ void CRadioDisplay::Reset() m_BufferText.assign(""); m_Title.assign(""); m_NextPos = 1; + keys = 0; } bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time) @@ -198,25 +208,27 @@ unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item) { if (item.style & ITEMDRAW_SPACER) { - m_BufferText.append("\n"); + m_BufferText.append(" \n"); } else { m_BufferText.append(item.display); m_BufferText.append("\n"); } return 0; } else if (item.style & ITEMDRAW_SPACER) { - m_BufferText.append("\n"); + m_BufferText.append(" \n"); + return m_NextPos++; + } else if (item.style & ITEMDRAW_NOTEXT) { return m_NextPos++; } if (item.style & ITEMDRAW_DISABLED) { m_BufferText.append(g_RadioNumTable[m_NextPos]); - m_BufferText.append(". "); m_BufferText.append(item.display); m_BufferText.append("\n"); } else { - m_BufferText.append("->. "); + m_BufferText.append("->"); + m_BufferText.append(g_RadioNumTable[m_NextPos]); m_BufferText.append(item.display); m_BufferText.append("\n"); keys |= (1<<(m_NextPos-1)); @@ -232,6 +244,11 @@ bool CRadioDisplay::CanDrawItem(unsigned int drawFlags) return false; } + if ((drawFlags & ITEMDRAW_DISABLED) && (drawFlags & ITEMDRAW_CONTROL)) + { + return false; + } + return true; } @@ -301,5 +318,5 @@ void CRadioMenu::Cancel_Finally() const char *g_RadioNumTable[11] = { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" + "0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. " }; diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h index dd25e1ea..da6bd5e2 100644 --- a/core/MenuStyle_Radio.h +++ b/core/MenuStyle_Radio.h @@ -33,7 +33,7 @@ class CRadioStyle : public: CRadioStyle(); public: //SMGlobalClass - void OnSourceModAllInitialized(); + void OnSourceModLevelChange(const char *mapName); void OnSourceModShutdown(); public: //BaseMenuStyle CBaseMenuPlayer *GetMenuPlayer(int client); diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index 2d052234..74d4e4d3 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -27,15 +27,6 @@ extern const char *g_OptionCmdTable[]; IServerPluginCallbacks *g_pVSPHandle = NULL; CallClass *g_pSPHCC = NULL; -class TestHandler : public IMenuHandler -{ -public: - virtual void OnMenuEnd(IBaseMenu *menu) - { - menu->Destroy(); - } -}; - ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1]) { } diff --git a/public/IMenuManager.h b/public/IMenuManager.h index b48479a8..3819d644 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -84,6 +84,7 @@ namespace SourceMod #define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ #define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ #define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) */ + #define ITEMDRAW_CONTROL (1<<4) /**< Item is control text (back/next/exit) */ /** * @brief Information about item drawing. From ae8b06194f8b8f98c9981b97ada3c109623fd080 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 13 May 2007 17:23:42 +0000 Subject: [PATCH 0761/1664] fixed bug in amb275 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40792 --- core/sourcemod.cpp | 5 ++++- core/sourcemod.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 42b7e691..53bb6772 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -73,6 +73,7 @@ SourceModBase::SourceModBase() { m_IsMapLoading = false; m_ExecPluginReload = false; + m_ExecOnMapEnd = false; m_GotBasePath = false; } @@ -266,6 +267,7 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch m_IsMapLoading = true; m_ExecPluginReload = true; + m_ExecOnMapEnd = true; g_LastTime = 0.0f; g_LastMenuTime = 0.0f; g_LastAuthCheck = 0.0f; @@ -403,9 +405,10 @@ void SourceModBase::GameFrame(bool simulating) void SourceModBase::LevelShutdown() { - if (g_pOnMapEnd) + if (g_pOnMapEnd && m_ExecOnMapEnd) { g_pOnMapEnd->Execute(NULL); + m_ExecOnMapEnd = false; } if (m_ExecPluginReload) diff --git a/core/sourcemod.h b/core/sourcemod.h index c675d22d..0a27b3c9 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -114,6 +114,7 @@ private: char m_ModDir[32]; bool m_IsMapLoading; bool m_ExecPluginReload; + bool m_ExecOnMapEnd; unsigned int m_target; bool m_CheckingAuth; bool m_GotBasePath; From 0b45984017758e102e672e3a59ee8c6cfa82d227 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 18:55:59 +0000 Subject: [PATCH 0762/1664] changed IMenuDisplay/CreateDisplay to IMenuPanel/CreatePanel --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40793 --- core/MenuManager.cpp | 8 ++++---- core/MenuManager.h | 4 ++-- core/MenuStyle_Base.cpp | 6 +++--- core/MenuStyle_Base.h | 4 ++-- core/MenuStyle_Radio.cpp | 6 +++--- core/MenuStyle_Radio.h | 10 +++++----- core/MenuStyle_Valve.cpp | 8 ++++---- core/MenuStyle_Valve.h | 10 +++++----- public/IMenuManager.h | 36 ++++++++++++++++++------------------ 9 files changed, 46 insertions(+), 46 deletions(-) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index a3e2d794..53d1d03f 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -44,7 +44,7 @@ void BroadcastHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReaso m_pHandler->OnMenuCancel(menu, client, reason); } -void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display) +void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display) { numClients++; m_pHandler->OnMenuDisplay(menu, client, display); @@ -214,7 +214,7 @@ IMenuStyle *MenuManager::FindStyleByName(const char *name) return NULL; } -inline bool IsSlotItem(IMenuDisplay *display, +inline bool IsSlotItem(IMenuPanel *display, unsigned int style) { if (!display->CanDrawItem(style)) @@ -233,7 +233,7 @@ inline bool IsSlotItem(IMenuDisplay *display, return true; } -IMenuDisplay *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order) +IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order) { IBaseMenu *menu = md.menu; @@ -290,7 +290,7 @@ IMenuDisplay *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder o } /* Get our Display pointer and initialize some crap */ - IMenuDisplay *display = menu->CreateDisplay(); + IMenuPanel *display = menu->CreatePanel(); IMenuHandler *mh = md.mh; bool foundExtra = false; unsigned int extraItem = 0; diff --git a/core/MenuManager.h b/core/MenuManager.h index 49fd2da6..f610fae0 100644 --- a/core/MenuManager.h +++ b/core/MenuManager.h @@ -30,7 +30,7 @@ class BroadcastHandler : public IMenuHandler public: BroadcastHandler(IMenuHandler *handler); public: //IMenuHandler - void OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display); + void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display); void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); void OnMenuEnd(IBaseMenu *menu); void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason); @@ -94,7 +94,7 @@ public: IMenuStyle *GetDefaultStyle(); void AddStyle(IMenuStyle *style); bool SetDefaultStyle(IMenuStyle *style); - IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order); + IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order); protected: void FreeBroadcastHandler(BroadcastHandler *bh); void FreeVoteHandler(VoteHandler *vh); diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index 02531725..40a90684 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -251,7 +251,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) mh->OnMenuEnd(menu); } -bool BaseMenuStyle::DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time) +bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time) { CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) @@ -355,7 +355,7 @@ bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, states.mh = mh; states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; - IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending); + IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending); if (!display) { player->bAutoIgnore = false; @@ -393,7 +393,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) menu_states_t &states = player->states; player->bAutoIgnore = true; - IMenuDisplay *display = g_Menus.RenderMenu(client, states, order); + IMenuPanel *display = g_Menus.RenderMenu(client, states, order); if (!display) { if (player->menuHoldTime) diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index 64c4b78a..8a166d58 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -69,10 +69,10 @@ public: //IClientListener void OnClientDisconnected(int client); public: //what derived must implement virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0; - virtual void SendDisplay(int client, IMenuDisplay *display) =0; + virtual void SendDisplay(int client, IMenuPanel *display) =0; public: //what derived may implement virtual bool DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time); - virtual bool DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time); + virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time); virtual void AddClientToWatch(int client); virtual void RemoveClientFromWatch(int client); virtual void ProcessWatchList(); diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp index 60c386e9..a885fa27 100644 --- a/core/MenuStyle_Radio.cpp +++ b/core/MenuStyle_Radio.cpp @@ -117,13 +117,13 @@ void CRadioStyle::OnUserMessageSent(int msg_id) g_last_client_count = 0; } -void CRadioStyle::SendDisplay(int client, IMenuDisplay *display) +void CRadioStyle::SendDisplay(int client, IMenuPanel *display) { CRadioDisplay *rDisplay = (CRadioDisplay *)display; rDisplay->SendRawDisplay(client, m_players[client].menuHoldTime); } -IMenuDisplay *CRadioStyle::CreateDisplay() +IMenuPanel *CRadioStyle::CreatePanel() { return new CRadioDisplay(); } @@ -301,7 +301,7 @@ bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr) return false; } -IMenuDisplay *CRadioMenu::CreateDisplay() +IMenuPanel *CRadioMenu::CreatePanel() { return new CRadioDisplay(this); } diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h index da6bd5e2..59eb8282 100644 --- a/core/MenuStyle_Radio.h +++ b/core/MenuStyle_Radio.h @@ -37,10 +37,10 @@ public: //SMGlobalClass void OnSourceModShutdown(); public: //BaseMenuStyle CBaseMenuPlayer *GetMenuPlayer(int client); - void SendDisplay(int client, IMenuDisplay *display); + void SendDisplay(int client, IMenuPanel *display); public: //IMenuStyle const char *GetStyleName(); - IMenuDisplay *CreateDisplay(); + IMenuPanel *CreatePanel(); IBaseMenu *CreateMenu(); unsigned int GetMaxPageItems(); public: //IUserMessageListener @@ -55,12 +55,12 @@ private: class CRadioMenu; -class CRadioDisplay : public IMenuDisplay +class CRadioDisplay : public IMenuPanel { public: CRadioDisplay(); CRadioDisplay(CRadioMenu *menu); -public: //IMenuDisplay +public: //IMenuPanel IMenuStyle *GetParentStyle(); void Reset(); void DrawTitle(const char *text, bool onlyIfEmpty=false); @@ -84,7 +84,7 @@ public: CRadioMenu(); public: bool SetExtOption(MenuOption option, const void *valuePtr); - IMenuDisplay *CreateDisplay(); + IMenuPanel *CreatePanel(); bool Display(int client, IMenuHandler *handler, unsigned int time); void Cancel_Finally(); }; diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index 74d4e4d3..68b7365e 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -104,7 +104,7 @@ void ValveMenuStyle::OnSourceModVSPReceived(IServerPluginCallbacks *iface) g_pVSPHandle = iface; } -IMenuDisplay *ValveMenuStyle::CreateDisplay() +IMenuPanel *ValveMenuStyle::CreatePanel() { return new CValveMenuDisplay(); } @@ -124,14 +124,14 @@ unsigned int ValveMenuStyle::GetMaxPageItems() return 8; } -void ValveMenuStyle::SendDisplay(int client, IMenuDisplay *display) +void ValveMenuStyle::SendDisplay(int client, IMenuPanel *display) { m_players[client].curPrioLevel--; CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display; vDisplay->SendRawDisplay(client, m_players[client].curPrioLevel, m_players[client].menuHoldTime); } -bool ValveMenuStyle::DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time) +bool ValveMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time) { if (!g_pVSPHandle) { @@ -354,7 +354,7 @@ bool CValveMenu::Display(int client, IMenuHandler *handler, unsigned int time) return g_ValveMenuStyle.DoClientMenu(client, this, handler, time); } -IMenuDisplay *CValveMenu::CreateDisplay() +IMenuPanel *CValveMenu::CreatePanel() { return new CValveMenuDisplay(this); } diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index 039bebe3..ab6e5d17 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -45,16 +45,16 @@ public: bool OnClientCommand(int client); public: //BaseMenuStyle CBaseMenuPlayer *GetMenuPlayer(int client); - void SendDisplay(int client, IMenuDisplay *display); + void SendDisplay(int client, IMenuPanel *display); bool DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time); - bool DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time); + bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); void OnSourceModVSPReceived(IServerPluginCallbacks *iface); public: //IMenuStyle const char *GetStyleName(); - IMenuDisplay *CreateDisplay(); + IMenuPanel *CreatePanel(); IBaseMenu *CreateMenu(); unsigned int GetMaxPageItems(); private: @@ -65,7 +65,7 @@ private: class CValveMenu; -class CValveMenuDisplay : public IMenuDisplay +class CValveMenuDisplay : public IMenuPanel { public: CValveMenuDisplay(); @@ -95,7 +95,7 @@ public: CValveMenu(); public: //IBaseMenu bool SetExtOption(MenuOption option, const void *valuePtr); - IMenuDisplay *CreateDisplay(); + IMenuPanel *CreatePanel(); bool GetExitButton(); bool SetExitButton(bool set); bool SetPagination(unsigned int itemsPerPage); diff --git a/public/IMenuManager.h b/public/IMenuManager.h index 3819d644..2daf5970 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -62,7 +62,7 @@ namespace SourceMod }; class IBaseMenu; - class IMenuDisplay; + class IMenuPanel; class IMenuHandler; /** @@ -109,10 +109,10 @@ namespace SourceMod */ enum MenuCancelReason { - MenuCancel_Disconnect = -1, /** Client dropped from the server */ - MenuCancel_Interrupt = -2, /** Client was interrupted with another menu */ - MenuCancel_Exit = -3, /** Client selected "exit" on a paginated menu */ - MenuCancel_NoDisplay = -4, /** Menu could not be displayed to the client */ + MenuCancel_Disconnect = -1, /**< Client dropped from the server */ + MenuCancel_Interrupt = -2, /**< Client was interrupted with another menu */ + MenuCancel_Exit = -3, /**< Client selected "exit" on a paginated menu */ + MenuCancel_NoDisplay = -4, /**< Menu could not be displayed to the client */ }; #define MENU_NO_PAGINATION 0 /**< Menu should not be paginated (10 items max) */ @@ -140,7 +140,7 @@ namespace SourceMod MenuSource_None = 0, /**< No menu is being displayed */ MenuSource_External = 1, /**< External menu, no pointer */ MenuSource_BaseMenu = 2, /**< An IBaseMenu pointer. */ - MenuSource_Display = 3, /**< IMenuDisplay source, no pointer */ + MenuSource_Display = 3, /**< IMenuPanel source, no pointer */ }; class IMenuStyle; @@ -148,7 +148,7 @@ namespace SourceMod /** * @brief Sets how a raw menu should be drawn. */ - class IMenuDisplay + class IMenuPanel { public: /** @@ -250,13 +250,13 @@ namespace SourceMod virtual const char *GetStyleName() =0; /** - * @brief Creates an IMenuDisplay object. + * @brief Creates an IMenuPanel object. * * Note: the object should be freed using ::DeleteThis. * - * @return IMenuDisplay object. + * @return IMenuPanel object. */ - virtual IMenuDisplay *CreateDisplay() =0; + virtual IMenuPanel *CreatePanel() =0; /** * @brief Creates an IBaseMenu object of this style. @@ -397,14 +397,14 @@ namespace SourceMod virtual bool SetExtOption(MenuOption option, const void *valuePtr) =0; /** - * @brief Creates a new IMenuDisplay object using extended options specific + * @brief Creates a new IMenuPanel object using extended options specific * to the IMenuStyle parent. Titles, items, etc, are not copied. * - * Note: The object should be freed with IMenuDisplay::DeleteThis. + * Note: The object should be freed with IMenuPanel::DeleteThis. * - * @return IMenuDisplay pointer. + * @return IMenuPanel pointer. */ - virtual IMenuDisplay *CreateDisplay() =0; + virtual IMenuPanel *CreatePanel() =0; /** * @brief Returns whether or not the menu should have an "Exit" button for @@ -479,9 +479,9 @@ namespace SourceMod * * @param menu Menu pointer. * @param client Client index. - * @param display IMenuDisplay pointer. + * @param display IMenuPanel pointer. */ - virtual void OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display) + virtual void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display) { } @@ -630,9 +630,9 @@ namespace SourceMod * @return IDisplay pointer, or NULL if no items could be * found in the IBaseMenu pointer, or NULL if any * other error occurred. Any valid pointer must - * be freed using IMenuDisplay::DeleteThis. + * be freed using IMenuPanel::DeleteThis. */ - virtual IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0; + virtual IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0; }; } From b0a32b39c2b69ba54c2d690ff42bae7eb277e628 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 13 May 2007 21:45:40 +0000 Subject: [PATCH 0763/1664] fixed bug in amb284 --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40794 --- sourcepawn/jit/x86/jit_x86.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index d151e597..76822968 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1462,6 +1462,9 @@ inline void WriteOp_Switch(JitWriter *jit) } else { IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); } + } else { + //mov ecx, eax + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); } cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val); //cmp ecx, From d1dea716a60fce4f6c2db2094f0db1ff7c6bf082 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 13 May 2007 22:36:22 +0000 Subject: [PATCH 0764/1664] Added a re-entrancy check to Handles so the destructor won't fire twice in certain cases --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40795 --- core/systems/HandleSys.cpp | 11 +++++++++++ core/systems/HandleSys.h | 1 + 2 files changed, 12 insertions(+) diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index dea38e9b..d6a7e934 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -285,6 +285,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, pHandle->owner = owner; pHandle->ch_next = 0; pHandle->access_special = false; + pHandle->is_destroying = false; /* Create the hash value */ Handle_t hash = pHandle->serial; @@ -601,6 +602,7 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) { /* Type should be the same but do this anyway... */ pType = &m_Types[pMaster->type]; + pMaster->is_destroying = true; pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); ReleasePrimHandle(master); } @@ -613,6 +615,7 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) /* Decrement, free if necessary */ if (--pHandle->refcount == 0) { + pHandle->is_destroying = true; pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); ReleasePrimHandle(index); } else { @@ -646,6 +649,14 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec return HandleError_Access; } + if (pHandle->is_destroying) + { + /* Someone tried to free this recursively. + * We'll just ignore this safely. + */ + return HandleError_None; + } + return FreeHandle(pHandle, index); } diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 826c88b7..1837f5cb 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -65,6 +65,7 @@ struct QHandle unsigned int clone; /* If non-zero, this is our cloned parent index */ HandleSet set; /* Information about the handle's state */ bool access_special; /* Whether or not access rules are special or type-derived */ + bool is_destroying; /* Whether or not the handle is being destroyed */ HandleAccess sec; /* Security rules */ /* The following variables are unrelated to the Handle array, and used * as an inlined chain of information */ From 49369d07bc7c6c0e5eebb8c68e8e5ef6a4321313 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 14 May 2007 04:46:06 +0000 Subject: [PATCH 0765/1664] redid API yet again - IMenuHandler is now bound to an IBaseMenu instance implemented MOST natives removed broadcasting/voting handlers for the time being fixed a crash bug in basecontext when i didn't obey the api moved radio displays to a caching stack --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40796 --- core/MenuManager.cpp | 75 +++ core/MenuManager.h | 14 +- core/MenuStyle_Base.cpp | 90 +++- core/MenuStyle_Base.h | 14 +- core/MenuStyle_Radio.cpp | 40 +- core/MenuStyle_Radio.h | 17 +- core/MenuStyle_Valve.cpp | 11 +- core/MenuStyle_Valve.h | 6 +- core/msvc8/sourcemod_mm.vcproj | 4 + core/smn_menus.cpp | 890 +++++++++++++++++++++++++++++++++ core/vm/sp_vm_basecontext.cpp | 7 + plugins/include/menus.inc | 500 ++++++++++++++++++ public/IMenuManager.h | 45 +- 13 files changed, 1669 insertions(+), 44 deletions(-) create mode 100644 core/smn_menus.cpp create mode 100644 plugins/include/menus.inc diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 53d1d03f..c7a5bdd5 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -21,6 +21,7 @@ #include "PlayerManager.h" #include "MenuStyle_Valve.h" #include "ShareSys.h" +#include "HandleSys.h" MenuManager g_Menus; @@ -150,10 +151,24 @@ MenuManager::MenuManager() void MenuManager::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); + + HandleAccess access; + g_HandleSys.InitAccessDefaults(NULL, &access); + + /* Deny cloning to menus */ + access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; + m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL); + + /* Also deny deletion to styles */ + access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; + m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL); } void MenuManager::OnSourceModAllShutdown() { + g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent); + g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent); + while (!m_BroadcastHandlers.empty()) { delete m_BroadcastHandlers.front(); @@ -167,6 +182,57 @@ void MenuManager::OnSourceModAllShutdown() } } +void MenuManager::OnHandleDestroy(HandleType_t type, void *object) +{ + if (type == m_MenuType) + { + IBaseMenu *menu = (IBaseMenu *)object; + menu->Destroy(false); + } else if (type == m_StyleType) { + /* Do nothing */ + } +} + +Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner) +{ + if (m_MenuType == NO_HANDLE_TYPE) + { + return BAD_HANDLE; + } + + return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL); +} + +Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style) +{ + if (m_StyleType == NO_HANDLE_TYPE) + { + return BAD_HANDLE; + } + + return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL); +} + +HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu) +{ + HandleSecurity sec; + + sec.pIdentity = g_pCoreIdent; + sec.pOwner = NULL; + + return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu); +} + +HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style) +{ + HandleSecurity sec; + + sec.pIdentity = g_pCoreIdent; + sec.pOwner = g_pCoreIdent; + + return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style); +} + bool MenuManager::SetDefaultStyle(IMenuStyle *style) { if (!style) @@ -503,6 +569,13 @@ skip_search: ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER); if (exitButton || (displayNext || displayPrev)) { + /* If there are no control options, + * Instead just pad with invisible slots. + */ + if (!displayPrev && !displayPrev) + { + padItem.style = ITEMDRAW_NOTEXT; + } /* Add spacers so we can pad to the end */ for (unsigned int i=0; i m_BroadcastHandlers; CStack m_VoteHandlers; CVector m_Styles; + HandleType_t m_StyleType; + HandleType_t m_MenuType; }; extern MenuManager g_Menus; diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index 40a90684..f372c92f 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -17,11 +17,23 @@ #include "MenuStyle_Base.h" #include "PlayerManager.h" #include "MenuManager.h" +#include "HandleSys.h" -BaseMenuStyle::BaseMenuStyle() : m_WatchList(256) +BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE) { } +Handle_t BaseMenuStyle::GetHandle() +{ + /* Don't create the handle until we need it */ + if (m_hHandle == BAD_HANDLE) + { + m_hHandle = g_Menus.CreateStyleHandle(this); + } + + return m_hHandle; +} + void BaseMenuStyle::AddClientToWatch(int client) { m_WatchList.push_back(client); @@ -56,7 +68,12 @@ void BaseMenuStyle::_CancelClientMenu(int client, bool bAutoIgnore/* =false */, /* Fire callbacks */ mh->OnMenuCancel(menu, client, reason); - mh->OnMenuEnd(menu); + + /* Only fire end if there's a valid menu */ + if (menu) + { + mh->OnMenuEnd(menu); + } if (bAutoIgnore) { @@ -145,6 +162,7 @@ void BaseMenuStyle::OnClientDisconnected(int client) _CancelClientMenu(client, true, MenuCancel_Disconnect); player->bInMenu = false; + player->bInExternMenu = false; } static int do_lookup[256]; @@ -248,7 +266,11 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) mh->OnMenuSelect(menu, client, item); } - mh->OnMenuEnd(menu); + /* Only fire end for valid menus */ + if (menu) + { + mh->OnMenuEnd(menu); + } } bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time) @@ -276,13 +298,7 @@ bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, menu_states_t &states = player->states; if (player->bInMenu) { - /* We need to cancel the old menu */ - if (player->menuHoldTime) - { - RemoveClientFromWatch(client); - } - states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt); - states.mh->OnMenuEnd(states.menu); + _CancelClientMenu(client, true); } states.firstItem = 0; @@ -291,6 +307,7 @@ bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, states.mh = mh; states.apiVers = SMINTERFACE_MENUMANAGER_VERSION; player->bInMenu = true; + player->bInExternMenu = false; player->menuStartTime = gpGlobals->curtime; player->menuHoldTime = time; @@ -367,6 +384,7 @@ bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, /* Finally, set our states */ player->bInMenu = true; + player->bInExternMenu = false; player->menuStartTime = gpGlobals->curtime; player->menuHoldTime = time; @@ -413,8 +431,10 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) return true; } -CBaseMenu::CBaseMenu(IMenuStyle *pStyle) : -m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), m_bShouldDelete(false), m_bCancelling(false) +CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) : +m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), +m_bShouldDelete(false), m_bCancelling(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent), +m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler) { } @@ -422,6 +442,16 @@ CBaseMenu::~CBaseMenu() { } +Handle_t CBaseMenu::GetHandle() +{ + if (!m_hHandle) + { + m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner); + } + + return m_hHandle; +} + bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) { if (m_Pagination == (unsigned)MENU_NO_PAGINATION @@ -572,18 +602,48 @@ void CBaseMenu::Cancel() if (m_bShouldDelete) { - delete this; + InternalDelete(); } } -void CBaseMenu::Destroy() +void CBaseMenu::Destroy(bool releaseHandle) { + /* Check if we shouldn't be here */ + if (m_bDeleting) + { + return; + } + + /* Save the destruction hint about our handle */ + m_bWillFreeHandle = releaseHandle; + + /* Now actually do stuff */ if (!m_bCancelling || m_bShouldDelete) { Cancel(); - delete this; + InternalDelete(); } else { m_bShouldDelete = true; } } +void CBaseMenu::InternalDelete() +{ + if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE) + { + Handle_t hndl = m_hHandle; + HandleSecurity sec; + + sec.pOwner = m_pOwner; + sec.pIdentity = g_pCoreIdent; + + m_hHandle = BAD_HANDLE; + m_bDeleting = true; + g_HandleSys.FreeHandle(hndl, &sec); + } + + m_pHandler->OnMenuDestroy(this); + + delete this; +} + diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index 8a166d58..49707ebd 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -65,6 +65,7 @@ public: public: //IMenuStyle bool CancelClientMenu(int client, bool autoIgnore/* =false */); MenuSource GetClientMenu(int client, void **object); + Handle_t GetHandle(); public: //IClientListener void OnClientDisconnected(int client); public: //what derived must implement @@ -84,12 +85,13 @@ protected: bool RedoClientMenu(int client, ItemOrder order); protected: FastLink m_WatchList; + Handle_t m_hHandle; }; class CBaseMenu : public IBaseMenu { public: - CBaseMenu(IMenuStyle *pStyle); + CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner); virtual ~CBaseMenu(); public: virtual bool AppendItem(const char *info, const ItemDrawInfo &draw); @@ -106,8 +108,11 @@ public: virtual bool GetExitButton(); virtual bool SetExitButton(bool set); virtual void Cancel(); - virtual void Destroy(); + virtual void Destroy(bool releaseHandle); virtual void Cancel_Finally() =0; + virtual Handle_t GetHandle(); +private: + void InternalDelete(); protected: String m_Title; IMenuStyle *m_pStyle; @@ -117,6 +122,11 @@ protected: bool m_ExitButton; bool m_bShouldDelete; bool m_bCancelling; + bool m_bDeleting; + bool m_bWillFreeHandle; + IdentityToken_t *m_pOwner; + Handle_t m_hHandle; + IMenuHandler *m_pHandler; }; #endif //_INCLUDE_MENUSTYLE_BASE_H diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp index a885fa27..2f78409b 100644 --- a/core/MenuStyle_Radio.cpp +++ b/core/MenuStyle_Radio.cpp @@ -56,6 +56,12 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName) void CRadioStyle::OnSourceModShutdown() { g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false); + + while (!m_FreeDisplays.empty()) + { + delete m_FreeDisplays.front(); + m_FreeDisplays.pop(); + } } bool CRadioStyle::IsSupported() @@ -125,12 +131,12 @@ void CRadioStyle::SendDisplay(int client, IMenuPanel *display) IMenuPanel *CRadioStyle::CreatePanel() { - return new CRadioDisplay(); + return g_RadioMenuStyle.MakeRadioDisplay(); } -IBaseMenu *CRadioStyle::CreateMenu() +IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) { - return new CRadioMenu(); + return new CRadioMenu(pHandler, pOwner); } unsigned int CRadioStyle::GetMaxPageItems() @@ -148,6 +154,25 @@ CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client) return &m_players[client]; } +CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu) +{ + CRadioDisplay *display; + if (m_FreeDisplays.empty()) + { + display = new CRadioDisplay(); + } else { + display = m_FreeDisplays.front(); + m_FreeDisplays.pop(); + display->Reset(); + } + return display; +} + +void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display) +{ + m_FreeDisplays.push(display); +} + CRadioDisplay::CRadioDisplay() { Reset(); @@ -292,7 +317,8 @@ void CRadioDisplay::DeleteThis() delete this; } -CRadioMenu::CRadioMenu() : CBaseMenu(&g_RadioMenuStyle) +CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : +CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner) { } @@ -303,12 +329,12 @@ bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr) IMenuPanel *CRadioMenu::CreatePanel() { - return new CRadioDisplay(this); + return g_RadioMenuStyle.MakeRadioDisplay(this); } -bool CRadioMenu::Display(int client, IMenuHandler *handler, unsigned int time) +bool CRadioMenu::Display(int client, unsigned int time) { - return g_RadioMenuStyle.DoClientMenu(client, this, handler, time); + return g_RadioMenuStyle.DoClientMenu(client, this, m_pHandler, time); } void CRadioMenu::Cancel_Finally() diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h index 59eb8282..eac5cb4d 100644 --- a/core/MenuStyle_Radio.h +++ b/core/MenuStyle_Radio.h @@ -22,9 +22,13 @@ #include #include #include "sm_fastlink.h" +#include using namespace SourceMod; +class CRadioDisplay; +class CRadioMenu; + class CRadioStyle : public BaseMenuStyle, public SMGlobalClass, @@ -41,7 +45,7 @@ public: //BaseMenuStyle public: //IMenuStyle const char *GetStyleName(); IMenuPanel *CreatePanel(); - IBaseMenu *CreateMenu(); + IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); unsigned int GetMaxPageItems(); public: //IUserMessageListener void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); @@ -49,14 +53,17 @@ public: //IUserMessageListener public: bool IsSupported(); bool OnClientCommand(int client); +public: + CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL); + void FreeRadioDisplay(CRadioDisplay *display); private: CBaseMenuPlayer *m_players; + CStack m_FreeDisplays; }; -class CRadioMenu; - class CRadioDisplay : public IMenuPanel { + friend class CRadioStyle; public: CRadioDisplay(); CRadioDisplay(CRadioMenu *menu); @@ -81,11 +88,11 @@ private: class CRadioMenu : public CBaseMenu { public: - CRadioMenu(); + CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); public: bool SetExtOption(MenuOption option, const void *valuePtr); IMenuPanel *CreatePanel(); - bool Display(int client, IMenuHandler *handler, unsigned int time); + bool Display(int client, unsigned int time); void Cancel_Finally(); }; diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index 68b7365e..de9f2dd9 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -109,9 +109,9 @@ IMenuPanel *ValveMenuStyle::CreatePanel() return new CValveMenuDisplay(); } -IBaseMenu *ValveMenuStyle::CreateMenu() +IBaseMenu *ValveMenuStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) { - return new CValveMenu(); + return new CValveMenu(pHandler, pOwner); } const char *ValveMenuStyle::GetStyleName() @@ -305,7 +305,8 @@ bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned return g_ValveMenuStyle.DoClientMenu(client, this, handler, time); } -CValveMenu::CValveMenu() : CBaseMenu(&g_ValveMenuStyle), +CValveMenu::CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : +CBaseMenu(pHandler, &g_ValveMenuStyle, pOwner), m_IntroColor(255, 0, 0, 255) { strcpy(m_IntroMsg, "You have a menu, press ESC"); @@ -344,14 +345,14 @@ bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr) return false; } -bool CValveMenu::Display(int client, IMenuHandler *handler, unsigned int time) +bool CValveMenu::Display(int client, unsigned int time) { if (m_bCancelling) { return false; } - return g_ValveMenuStyle.DoClientMenu(client, this, handler, time); + return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time); } IMenuPanel *CValveMenu::CreatePanel() diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index ab6e5d17..a4c48df7 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -55,7 +55,7 @@ public: //SMGlobalClass public: //IMenuStyle const char *GetStyleName(); IMenuPanel *CreatePanel(); - IBaseMenu *CreateMenu(); + IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); unsigned int GetMaxPageItems(); private: void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); @@ -92,14 +92,14 @@ class CValveMenu : public CBaseMenu { friend class CValveMenuDisplay; public: - CValveMenu(); + CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); public: //IBaseMenu bool SetExtOption(MenuOption option, const void *valuePtr); IMenuPanel *CreatePanel(); bool GetExitButton(); bool SetExitButton(bool set); bool SetPagination(unsigned int itemsPerPage); - bool Display(int client, IMenuHandler *handler, unsigned int time); + bool Display(int client, unsigned int time); public: //CBaseMenu void Cancel_Finally(); private: diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index bcd11703..e7cd8617 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -842,6 +842,10 @@ RelativePath="..\smn_lang.cpp" > + + diff --git a/core/smn_menus.cpp b/core/smn_menus.cpp new file mode 100644 index 00000000..b0c6b17b --- /dev/null +++ b/core/smn_menus.cpp @@ -0,0 +1,890 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sm_globals.h" +#include +#include "MenuManager.h" +#include "MenuStyle_Valve.h" +#include "MenuStyle_Radio.h" +#include "HandleSys.h" +#include "PluginSys.h" + +#if defined CreateMenu +#undef CreateMenu +#endif + +/** + * And God said, "let there be menus," and behold, there were menus. + * God saw the menus and they were good. And the evening and the morning + * were the third day. + */ + +enum MenuAction +{ + MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */ + MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */ + MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ + MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=item) */ + MenuAction_End = (1<<4), /**< A menu's display/selection cycle is complete (nothing passed). */ + MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */ +}; + +class CPanelHandler : public IMenuHandler +{ + friend class MenuNativeHelpers; +public: + CPanelHandler() + { + } + void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason); + void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); +private: + IPluginFunction *m_pFunc; + IPlugin *m_pPlugin; +}; + +class CMenuHandler : public IMenuHandler +{ + friend class MenuNativeHelpers; +public: + CMenuHandler(IPluginFunction *pBasic, int flags); +public: + void OnMenuStart(IBaseMenu *menu); + void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display); + void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); + void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason); + void OnMenuEnd(IBaseMenu *menu); + void OnMenuDestroy(IBaseMenu *menu); +#if 0 + void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style); + void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display); +#endif +private: + IPluginFunction *m_pBasic; + int m_Flags; +}; + +/** + * GLOBAL CLASS FOR HELPERS + */ + +class MenuNativeHelpers : + public SMGlobalClass, + public IHandleTypeDispatch, + public IPluginsListener +{ +public: + virtual void OnSourceModAllInitialized() + { + m_PanelType = g_HandleSys.CreateType("IMenuPanel", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_PluginSys.AddPluginsListener(this); + } + + virtual void OnSourceModShutdown() + { + g_HandleSys.RemoveType(m_PanelType, g_pCoreIdent); + + while (!m_FreePanelHandlers.empty()) + { + delete m_FreePanelHandlers.front(); + m_FreePanelHandlers.pop(); + } + + while (!m_FreeMenuHandlers.empty()) + { + delete m_FreeMenuHandlers.front(); + m_FreeMenuHandlers.pop(); + } + } + + virtual void OnHandleDestroy(HandleType_t type, void *object) + { + IMenuPanel *panel = (IMenuPanel *)object; + panel->DeleteThis(); + } + + /** + * It is extremely important that unloaded plugins don't crash. + * Thus, if a plugin unloads, we run through every handler we have. + * This means we do almost no runtime work for keeping track of + * our panel handlers (we don't have to store a list of the running + * ones), but when push comes to shove, we have to scan them all + * in case any of them are active. + */ + virtual void OnPluginUnloaded(IPlugin *plugin) + { + IPluginContext *pContext = plugin->GetBaseContext(); + for (size_t i = 0; i < m_PanelHandlers.size(); i++) + { + if (m_PanelHandlers[i]->m_pPlugin == plugin) + { + m_PanelHandlers[i]->m_pPlugin = NULL; + m_PanelHandlers[i]->m_pFunc = NULL; + } + } + } + + inline HandleType_t GetPanelType() + { + return m_PanelType; + } + + CPanelHandler *GetPanelHandler(IPluginFunction *pFunction) + { + CPanelHandler *handler; + if (m_FreePanelHandlers.empty()) + { + handler = new CPanelHandler; + m_PanelHandlers.push_back(handler); + } else { + handler = m_FreePanelHandlers.front(); + m_FreePanelHandlers.pop(); + } + handler->m_pFunc = pFunction; + handler->m_pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + return handler; + } + + void FreePanelHandler(CPanelHandler *handler) + { + handler->m_pFunc = NULL; + handler->m_pPlugin = NULL; + m_FreePanelHandlers.push(handler); + } + + CMenuHandler *GetMenuHandler(IPluginFunction *pFunction, int flags) + { + CMenuHandler *handler; + if (m_FreeMenuHandlers.empty()) + { + handler = new CMenuHandler(pFunction, flags); + } else { + handler = m_FreeMenuHandlers.front(); + m_FreeMenuHandlers.pop(); + handler->m_pBasic = pFunction; + handler->m_Flags = flags; + } + return handler; + } + + void FreeMenuHandler(CMenuHandler *handler) + { + m_FreeMenuHandlers.push(handler); + } + +private: + HandleType_t m_PanelType; + CStack m_FreePanelHandlers; + CStack m_FreeMenuHandlers; + CVector m_PanelHandlers; +} g_MenuHelpers; + +/** + * BASIC PANEL HANDLER WRAPPER + */ + +void CPanelHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason) +{ + if (m_pFunc) + { + m_pFunc->PushCell(BAD_HANDLE); + m_pFunc->PushCell(MenuAction_Cancel); + m_pFunc->PushCell(client); + m_pFunc->PushCell(reason); + m_pFunc->Execute(NULL); + } + g_MenuHelpers.FreePanelHandler(this); +} + +void CPanelHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) +{ + if (m_pFunc) + { + m_pFunc->PushCell(BAD_HANDLE); + m_pFunc->PushCell(MenuAction_Select); + m_pFunc->PushCell(client); + m_pFunc->PushCell(item); + m_pFunc->Execute(NULL); + } + g_MenuHelpers.FreePanelHandler(this); +} + +/** + * MENU HANDLER WRAPPER + */ +CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) : + m_pBasic(pBasic), m_Flags(flags) +{ + /* :TODO: We can probably cache the handle ahead of time */ +} + +void CMenuHandler::OnMenuStart(IBaseMenu *menu) +{ + if ((m_Flags & (int)MenuAction_Start) == (int)MenuAction_Start) + { + m_pBasic->PushCell(menu->GetHandle()); + m_pBasic->PushCell(MenuAction_Start); + m_pBasic->PushCell(0); + m_pBasic->PushCell(0); + m_pBasic->Execute(NULL); + } +} + +void CMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *panel) +{ + if ((m_Flags & (int)MenuAction_Display) == (int)MenuAction_Display) + { + HandleSecurity sec; + sec.pIdentity = m_pBasic->GetParentContext()->GetIdentity(); + sec.pOwner = g_pCoreIdent; + + HandleAccess access; + g_HandleSys.InitAccessDefaults(NULL, &access); + access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; + + Handle_t hndl = g_HandleSys.CreateHandleEx(g_MenuHelpers.GetPanelType(), panel, &sec, &access, NULL); + + m_pBasic->PushCell(menu->GetHandle()); + m_pBasic->PushCell(MenuAction_Display); + m_pBasic->PushCell(client); + m_pBasic->PushCell(hndl); + m_pBasic->Execute(NULL); + + g_HandleSys.FreeHandle(hndl, &sec); + } +} + +void CMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) +{ + m_pBasic->PushCell(menu->GetHandle()); + m_pBasic->PushCell(MenuAction_Select); + m_pBasic->PushCell(client); + m_pBasic->PushCell(item); + m_pBasic->Execute(NULL); +} + +void CMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason) +{ + m_pBasic->PushCell(menu->GetHandle()); + m_pBasic->PushCell(MenuAction_Cancel); + m_pBasic->PushCell(client); + m_pBasic->PushCell(reason); + m_pBasic->Execute(NULL); +} + +void CMenuHandler::OnMenuEnd(IBaseMenu *menu) +{ + m_pBasic->PushCell(menu->GetHandle()); + m_pBasic->PushCell(MenuAction_End); + m_pBasic->PushCell(0); + m_pBasic->PushCell(0); + m_pBasic->Execute(NULL); +} + +void CMenuHandler::OnMenuDestroy(IBaseMenu *menu) +{ + g_MenuHelpers.FreeMenuHandler(this); +} + +/** + * INLINE FUNCTIONS FOR NATIVES + */ + +inline Handle_t MakePanelHandle(IMenuPanel *panel, IPluginContext *pContext) +{ + return g_HandleSys.CreateHandle(g_MenuHelpers.GetPanelType(), panel, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +inline HandleError ReadPanelHandle(Handle_t hndl, IMenuPanel **panel) +{ + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = NULL; + return g_HandleSys.ReadHandle(hndl, g_MenuHelpers.GetPanelType(), &sec, (void **)panel); +} + +inline IMenuStyle *GetStyleFromCell(cell_t cell) +{ + enum MenuStyle + { + MenuStyle_Default = 0, /**< The "default" menu style for the mod */ + MenuStyle_Valve = 1, /**< The Valve provided menu style (Used on HL2DM) */ + MenuStyle_Radio = 2, /**< The simpler menu style commonly used on CS:S */ + }; + + if (cell == MenuStyle_Valve) + { + return &g_ValveMenuStyle; + } else if (cell == MenuStyle_Radio + && g_RadioMenuStyle.IsSupported()) + { + return &g_RadioMenuStyle; + } + + return g_Menus.GetDefaultStyle(); +} + +/*********************************** + **** NATIVE DEFINITIONS *********** + ***********************************/ + +static cell_t CreateMenu(IPluginContext *pContext, const cell_t *params) +{ + IMenuStyle *style = g_Menus.GetDefaultStyle(); + IPluginFunction *pFunction; + + if ((pFunction=pContext->GetFunctionById(params[1])) == NULL) + { + return pContext->ThrowNativeError("Function id %x is invalid", params[1]); + } + + CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[2]); + IBaseMenu *menu = style->CreateMenu(handler, pContext->GetIdentity()); + + Handle_t hndl = menu->GetHandle(); + if (!hndl) + { + menu->Destroy(); + return BAD_HANDLE; + } + + return hndl; +} + +static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->Display(params[2], params[3]) ? 1 : 0; +} + +static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + char *info; + ItemDrawInfo dr; + + pContext->LocalToString(params[2], &info); + pContext->LocalToString(params[3], (char **)&dr.display); + dr.style = params[4]; + + return menu->AppendItem(info, dr) ? 1 : 0; +} + +static cell_t InsertMenuItem(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + char *info; + ItemDrawInfo dr; + + pContext->LocalToString(params[3], &info); + pContext->LocalToString(params[4], (char **)&dr.display); + dr.style = params[5]; + + return menu->InsertItem(params[2], info, dr) ? 1 : 0; +} + +static cell_t RemoveMenuItem(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->RemoveItem(params[2]) ? 1 : 0; +} + +static cell_t RemoveAllMenuItems(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + menu->RemoveAllItems(); + + return 1; +} + +static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + ItemDrawInfo dr; + const char *info; + + if ((info=menu->GetItemInfo(params[2], &dr)) == NULL) + { + return 0; + } + + pContext->StringToLocalUTF8(params[3], params[4], info, NULL); + pContext->StringToLocalUTF8(params[6], params[7], dr.display ? dr.display : "", NULL); + + cell_t *addr; + pContext->LocalToPhysAddr(params[5], &addr); + *addr = dr.style; + + return 1; +} + +static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->SetPagination(params[2]) ? 1 : 0; +} + +static cell_t GetMenuPagination(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->GetPagination(); +} + +static cell_t GetMenuItemCount(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->GetItemCount(); +} + +static cell_t SetMenuTitle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + char buffer[1024]; + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); + + menu->SetDefaultTitle(buffer); + + return 1; +} + +static cell_t CreatePanelFromMenu(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + IMenuPanel *panel = menu->CreatePanel(); + hndl = MakePanelHandle(panel, pContext); + if (!hndl) + { + panel->DeleteThis(); + } + + return hndl; +} + +static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->GetExitButton() ? 1 : 0; +} + +static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->SetExitButton(params[2] ? true : false) ? 1 : 0; +} + +static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + menu->Cancel(); + + return 1; +} + +static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IBaseMenu *menu; + + if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return menu->GetDrawStyle()->GetHandle(); +} + +static cell_t GetMenuStyleHandle(IPluginContext *pContext, const cell_t *params) +{ + IMenuStyle *style = GetStyleFromCell(params[1]); + if (!style) + { + return BAD_HANDLE; + } + + return style->GetHandle(); +} + +static cell_t CreatePanel(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuStyle *style; + + if (hndl != 0) + { + if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None) + { + return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err); + } + } else { + style = g_Menus.GetDefaultStyle(); + } + + IMenuPanel *panel = style->CreatePanel(); + + hndl = MakePanelHandle(panel, pContext); + if (!hndl) + { + panel->DeleteThis(); + return BAD_HANDLE; + } + + return hndl; +} + +static cell_t CreateMenuEx(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuStyle *style; + + if (hndl != 0) + { + if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None) + { + return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err); + } + } else { + style = g_Menus.GetDefaultStyle(); + } + + IPluginFunction *pFunction; + if ((pFunction=pContext->GetFunctionById(params[2])) == NULL) + { + return pContext->ThrowNativeError("Function id %x is invalid", params[2]); + } + + CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[3]); + + IBaseMenu *pMenu = style->CreateMenu(handler, pContext->GetIdentity()); + hndl = pMenu->GetHandle(); + if (!hndl) + { + pMenu->Destroy(); + return BAD_HANDLE; + } + + return hndl; +} + +static cell_t GetClientMenu(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[2]; + HandleError err; + IMenuStyle *style; + + if (hndl != 0) + { + if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None) + { + return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err); + } + } else { + style = g_Menus.GetDefaultStyle(); + } + + return style->GetClientMenu(params[1], NULL); +} + +static cell_t CancelClientMenu(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[3]; + HandleError err; + IMenuStyle *style; + + if (hndl != 0) + { + if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None) + { + return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err); + } + } else { + style = g_Menus.GetDefaultStyle(); + } + + return style->CancelClientMenu(params[1], params[2] ? true : false) ? 1 : 0; +} + +static cell_t GetMaxPageItems(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuStyle *style; + + if (hndl != 0) + { + if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None) + { + return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err); + } + } else { + style = g_Menus.GetDefaultStyle(); + } + + return style->GetMaxPageItems(); +} + +static cell_t GetPanelStyle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return panel->GetParentStyle()->GetHandle(); +} + +static cell_t SetPanelTitle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + char *text; + pContext->LocalToString(params[2], &text); + + panel->DrawTitle(text, params[3] ? true : false); + + return 1; +} + +static cell_t DrawPanelItem(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + ItemDrawInfo dr; + pContext->LocalToString(params[2], (char **)&dr.display); + dr.style = params[3]; + + return panel->DrawItem(dr); +} + +static cell_t DrawPanelText(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + char *text; + pContext->LocalToString(params[2], &text); + + return panel->DrawRawLine(text) ? 1 : 0; +} + +static cell_t CanPanelDrawFlags(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + return panel->CanDrawItem(params[2]); +} + +static cell_t SendPanelToClient(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMenuPanel *panel; + + if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None) + { + return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); + } + + IPluginFunction *pFunction; + if ((pFunction=pContext->GetFunctionById(params[3])) == NULL) + { + return pContext->ThrowNativeError("Function id %x is invalid", params[3]); + } + + CPanelHandler *handler = g_MenuHelpers.GetPanelHandler(pFunction); + if (!panel->SendDisplay(params[2], handler, params[4])) + { + g_MenuHelpers.FreePanelHandler(handler); + } + + return 1; +} + +REGISTER_NATIVES(menuNatives) +{ + {"AddMenuItem", AddMenuItem}, + {"CanPanelDrawFlags", CanPanelDrawFlags}, + {"CancelClientMenu", CancelClientMenu}, + {"CancelMenu", CancelMenu}, + {"CreateMenu", CreateMenu}, + {"CreateMenuEx", CreateMenuEx}, + {"CreatePanel", CreatePanel}, + {"CreatePanelFromMenu", CreatePanelFromMenu},\ + {"DisplayMenu", DisplayMenu}, + {"DrawPanelItem", DrawPanelItem}, + {"DrawPanelText", DrawPanelText}, + {"GetClientMenu", GetClientMenu}, + {"GetMaxPageItems", GetMaxPageItems}, + {"GetMenuExitButton", GetMenuExitButton}, + {"GetMenuItem", GetMenuItem}, + {"GetMenuItemCount", GetMenuItemCount}, + {"GetMenuPagination", GetMenuPagination}, + {"GetMenuStyle", GetMenuStyle}, + {"GetMenuStyleHandle", GetMenuStyleHandle}, + {"GetPanelStyle", GetPanelStyle}, + {"InsertMenuItem", InsertMenuItem}, + {"RemoveAllMenuItems", RemoveAllMenuItems}, + {"RemoveMenuItem", RemoveMenuItem}, + {"SendPanelToClient", SendPanelToClient}, + {"SetMenuExitButton", SetMenuExitButton}, + {"SetMenuPagination", SetMenuPagination}, + {"SetMenuTitle", SetMenuTitle}, + {"SetPanelTitle", SetPanelTitle}, + {NULL, NULL}, +}; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 6475241e..dbd4f07a 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -194,6 +194,13 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) return SP_ERROR_NOT_RUNNABLE; } + /* tada, prevent a crash */ + cell_t _ignore_result; + if (!result) + { + result = &_ignore_result; + } + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; uint32_t pushcount = ctx->pushcount; diff --git a/plugins/include/menus.inc b/plugins/include/menus.inc new file mode 100644 index 00000000..82ad88bf --- /dev/null +++ b/plugins/include/menus.inc @@ -0,0 +1,500 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _menus_included + #endinput +#endif +#define _menus_included + +/** + * Low-level drawing style of the menu. + */ +enum MenuStyle +{ + MenuStyle_Default = 0, /**< The "default" menu style for the mod */ + MenuStyle_Valve = 1, /**< The Valve provided menu style (Used on HL2DM) */ + MenuStyle_Radio = 2, /**< The simpler menu style commonly used on CS:S */ +}; + +/** + * Different actions for the menu "pump" callback + */ +enum MenuAction +{ + MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */ + MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */ + MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ + MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=item) */ + MenuAction_End = (1<<4), /**< A menu's display/selection cycle is complete (nothing passed). */ + MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */ +}; + +/** Default menu actions */ +#define MENU_ACTIONS_DEFAULT MenuAction_Select|MenuAction_Cancel|MenuAction_End +/** All menu actions */ +#define MENU_ACTIONS_ALL -1 + +#define MENU_NO_PAGINATION 0 /**< Menu should not be paginated (10 items max) */ +#define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ + +#define ITEMDRAW_DEFAULT (0) /**< Item should be drawn normally */ +#define ITEMDRAW_DISABLED (1<<0) /**< Item is drawn but not selectable */ +#define ITEMDRAW_RAWLINE (1<<1) /**< Item should be a raw line, without a slot */ +#define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ +#define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ +#define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) */ +#define ITEMDRAW_CONTROL (1<<4) /**< Item is control text (back/next/exit) */ + +/** + * Reasons a menu can be cancelled. + */ +enum +{ + MenuCancel_Disconnect = -1, /**< Client dropped from the server */ + MenuCancel_Interrupt = -2, /**< Client was interrupted with another menu */ + MenuCancel_Exit = -3, /**< Client selected "exit" on a paginated menu */ + MenuCancel_NoDisplay = -4, /**< Menu could not be displayed to the client */ +}; + +/** + * Describes a menu's source + */ +enum MenuSource +{ + MenuSource_None = 0, /**< No menu is being displayed */ + MenuSource_External = 1, /**< External menu */ + MenuSource_Normal = 2, /**< A basic menu is being displayed */ + MenuSource_RawPanel = 3, /**< A display is active, but it is not tied to a menu */ +}; + +/** + * Called when a menu action is completed. + * + * @param menu The menu being acted upon. + * @param action The action of the menu. + * @param param1 First action parameter (usually the client). + * @param param2 Second action parameter (usually the item). + * @noreturn + */ +functag MenuHandler public(Handle:menu, MenuAction:action, param1, param2); + +/** + * Creates a new, empty menu using the default style. + * + * @param handler Function which will receive menu actions. + * @param actions Optionally set which actions to receive. Select, + * Cancel, and End will always be received regardless + * of whether they are set or not. They are also + * the only default actions. + * @return A new menu Handle. + */ +native Handle:CreateMenu(MenuHandler:handler, MenuAction:actions=MENU_ACTIONS_DEFAULT); + +/** + * Displays a menu to a client. + * + * @param menu Menu Handle. + * @param client Client index. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false on failure. + * @error Invalid Handle or client not in game. + */ +native bool:DisplayMenu(Handle:menu, client, time); + +/** + * Appends a new item to the end of a menu. + * + * @param menu Menu Handle. + * @param info Item information string. + * @param display Default item display string. + * @param style Drawing style flags. + * @return True on success, false on failure. + * @error Invalid Handle or item limit reached. + */ +native AddMenuItem(Handle:menu, + const String:info[], + const String:display[], + style=ITEMDRAW_DEFAULT); + +/** + * Inserts an item into the menu before a certain position; the new item will + * be at the given position and all next items pushed forward. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @param info Item information string. + * @param display Default item display string. + * @param style Drawing style flags. + * @return True on success, false on failure. + * @error Invalid Handle or menu position. + */ +native bool:InsertMenuItem(Handle:menu, + position, + const String:info[], + const String:display[], + style=ITEMDRAW_DEFAULT); + +/** + * Removes an item from the menu. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @return True on success, false on failure. + * @error Invalid Handle or menu position. + */ +native bool:RemoveMenuItem(Handle:menu, position); + +/** + * Removes all items from a menu. + * + * @param menu Menu Handle. + * @noreturn + * @error Invalid Handle or menu position. + */ +native RemoveAllMenuItems(Handle:menu); + +/** + * Retrieves information about a menu item. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @param infoBuf Info buffer. + * @param infoBufLen Maximum length of the info buffer. + * @param style By-reference variable to store drawing flags. + * @param dispBuf Display buffer. + * @param dispBufLen Maximum length of the display buffer. + * @return True on success, false if position is invalid. + * @error Invalid Handle. + */ +native bool:GetMenuItem(Handle:menu, position, String:infoBuf[], infoBufLen, &style=0, String:dispBuf[]="", dispBufLen=0); + +/** + * Returns the number of items in a menu. + * + * @param menu Menu Handle. + * @return Number of items in the menu. + * @error Invalid Handle. + */ +native GetMenuItemCount(Handle:menu); + +/** + * Sets whether the menu should be paginated or not. + * + * @param menu Handle to the menu. + * @param itemsPerPage Number of items per page, or MENU_NO_PAGINATION. + * @return True on success, false if pagination is too high or low. + * @error Invalid Handle. + */ +native bool:SetMenuPagination(Handle:menu, itemsPerPage); + +/** + * Returns a menu's pagination setting. + * + * @param menu Handle to the menu. + * @return Pagination setting. + * @error Invalid Handle. + */ +native GetMenuPagination(Handle:menu); + +/** + * Returns a menu's MenuStyle Handle. The Handle + * is global and cannot be freed. + * + * @param menu Handle to the menu. + * @return Handle to the menu's draw style. + * @error Invalid Handle. + */ +native Handle:GetMenuStyle(Handle:menu); + +/** + * Sets the menu's default title/instruction message. + * + * @param menu Menu Handle. + * @param fmt Message string format + * @param ... Message string arguments. + * @noreturn + * @error Invalid Handle. + */ +native SetMenuTitle(Handle:menu, const String:fmt[], any:...); + +/** + * Creates a raw MenuPanel based off the menu's style. + * The Handle must be freed with CloseHandle(). + * + * @return A new MenuPanel Handle. + * @error Invalid Handle. + */ +native Handle:CreatePanelFromMenu(Handle:menu); + +/** + * Returns whether or not the menu has an exit button. + * By default, menus have an exit button. + * + * @param menu Menu Handle. + * @return True if the menu has an exit button; false otherwise. + * @error Invalid Handle. + */ +native bool:GetMenuExitButton(Handle:menu); + +/** + * Sets whether or not the menu has an exit button. + * By default, menus have an exit button. + * + * @param menu Menu Handle. + * @param button True to enable the button, false to remove it. + * @return True if allowed; false on failure. + * @error Invalid Handle. + */ +native bool:SetMenuExitButton(Handle:menu, bool:button); + +/** + * Cancels a menu from displaying on all clients. While the + * cancellation is in progress, this menu cannot be re-displayed + * to any clients. + * + * The menu may still exist on the client's screen after this command. + * This simply verifies that the menu is not being used anywhere. + * + * @param menu Menu Handle. + * @noreturn + * @error Invalid Handle. + */ +native CancelMenu(Handle:menu); + +#if 0 +/** + * Broadcasts a menu to a list of clients. + * + * @param menu Menu Handle. + * @param handler MenuHandler callback to receive actions. + * @param players Array of players to broadcast to. + * @param numPlayers Number of players in the array. + * @param time Maximum time to leave menu on the screen. + * @return Number of clients that broadcast will wait upon. + * @error Invalid Handle. + */ +native BroadcastMenu(Handle:menu, MenuHandler:handler, players[], numPlayers, time); + +/** + * Broadcasts a menu to a list of clients. The most selected + * item will be returned through MenuAction_End. On a tie, a random + * item will be returned. + * + * @param menu Menu Handle. + * @param handler MenuHandler callback to receive actions. + * @param players Array of players to broadcast to. + * @param numPlayers Number of players in the array. + * @param time Maximum time to leave menu on the screen. + * @return Number of clients that vote will wait upon. + * @error Invalid Handle. + */ +native VoteMenu(Handle:menu, MenuHandler:handler, players[], numPlayers, time); + +/** + * Broadcasts a menu to all clients. + * + * @param menu Menu Handle. + * @param handler MenuHandler callback to receive actions. + * @param time Maximum time to leave menu on the screen. + * @return Number of clients that broadcast will wait upon. + * @error Invalid Handle. + */ +stock BroadcastMenuToAll(Handle:menu, MenuHandler:handler, time) +{ + new num = GetMaxClients(); + new total; + decl players[num]; + + for (new i=1; i<=num; i++) + { + if (!IsClientConnected(i)) + { + continue; + } + players[total++] = i; + } + + return BroadcastMenu(menu, handler, players, total, time); +} + +/** + * Broadcasts a menu to all clients. The most selected item will + * be returned through MenuAction_End. On a tie, a random item + * will be returned. + * + * @param menu Menu Handle. + * @param handler MenuHandler callback to receive actions. + * @param time Maximum time to leave menu on the screen. + * @return Number of clients that the vote will wait upon. + * @error Invalid Handle. + */ +native VoteMenuToAll(Handle:menu, MenuHandler:handler, time) +{ + new num = GetMaxClients(); + new total; + decl players[num]; + + for (new i=1; i<=num; i++) + { + if (!IsClientConnected(i)) + { + continue; + } + players[total++] = i; + } + + return VoteMenu(menu, handler, players, total, time); +} +#endif + +/** + * Returns a style's global Handle. + * + * @param style Menu Style. + * @return A Handle, or INVALID_HANDLE if not found or unusable. + */ +native Handle:GetMenuStyleHandle(MenuStyle:style); + +/** + * Creates a MenuPanel from a MenuStyle. Panels are used for drawing raw + * menus without any extra helper functions. The Handle must be closed + * with CloseHandle(). + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return A new MenuPanel Handle. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native Handle:CreatePanel(Handle:hStyle=INVALID_HANDLE); + +/** + * Creates a Menu from a MenuStyle. The Handle must be closed with + * CloseHandle(). + * + * @parma hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @param handler Function which will receive menu actions. + * @param actions Optionally set which actions to receive. Select, + * Cancel, and End will always be received regardless + * of whether they are set or not. They are also + * the only default actions. + * @return A new menu Handle. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native Handle:CreateMenuEx(Handle:hStyle=INVALID_HANDLE, MenuHandler:handler, MenuAction:actions=MENU_ACTIONS_DEFAULT); + +/** + * Returns whether a client is viewing a menu. If the menu source + * is MenuSource_Normal, a menu Handle will also be returned. + * + * @param client Client index. + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return A MenuSource value. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native MenuSource:GetClientMenu(client, Handle:hStyle=INVALID_HANDLE); + +/** + * Cancels a menu on a client. This will only affect non-external menus. + * + * @param hstyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @param client Client index. + * @param autoIgnore If true, no menus can be re-drawn on the client during + * the cancellation process. + * @return True if a menu was cancelled, false otherwise. + */ +native bool:CancelClientMenu(client, bool:autoIgnore=false, Handle:hStyle=INVALID_HANDLE); + +/** + * Returns a style's maximum items per page. + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return Maximum items per page. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native GetMaxPageItems(Handle:hStyle=INVALID_HANDLE); + +/** + * Returns a MenuPanel's parent style. + * + * @param panel A MenuPanel Handle. + * @return The MenuStyle Handle that created the panel. + * @error Invalid Handle. + */ +native Handle:GetPanelStyle(Handle:panel); + +/** + * Sets the panel's title. + * + * @param panel A MenuPanel Handle. + * @param title Text to set as the title. + * @param onlyIfEmpty If true, the title will only be set if no title is set. + * @noreturn + * @error Invalid Handle. + */ +native Handle:SetPanelTitle(Handle:panel, const String:text[], bool:onlyIfEmpty=false); + +/** + * Draws an item on a panel. If the item takes up a slot, the position + * is returned. + * + * @param panel A MenuPanel Handle. + * @param text Display text to use. If not a raw line, + * the style may automatically add color markup. + * No numbering or newlines are needed. + * @param style ITEMDRAW style flags. + * @return A slot position, or 0 if item was a rawline or could not be drawn. + * @error Invalid Handle. + */ +native DrawPanelItem(Handle:panel, const String:text[], style=ITEMDRAW_DEFAULT); + +/** + * Draws a raw line of text on a panel, without any markup other than a newline. + * + * @param panel A MenuPanel Handle. + * @param text Display text to use. + * @return True on success, false if raw lines are not supported. + * @error Invalid Handle. + */ +native DrawPanelText(Handle:panel, const String:text[]); + +/** + * Returns whether or not the given drawing flags are supported by + * the menu style. + * + * @param panel A MenuPanel Handle. + * @param style ITEMDRAW style flags. + * @return True if item is drawable, false otherwise. + * @error Invalid Handle. + */ +native CanPanelDrawFlags(Handle:panel, style); + +/** + * Sends a panel to a client. Unlike full menus, the handler + * function will only receive the following actions, both of + * which will have INVALID_HANDLE for a menu, and the client + * as param1. + * + * MenuAction_Select (param2 will be the key pressed) + * MenuAction_Cancel (param2 will be the reason) + * + * Also, if the menu fails to display, no callbacks will be called. + * + * @param panel A MenuPanel Handle. + * @param client A client to draw to. + * @param handler The MenuHandler function to catch actions with. + * @param time Time to hold the menu for. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool:SendPanelToClient(Handle:panel, client, MenuHandler:handler, time); diff --git a/public/IMenuManager.h b/public/IMenuManager.h index 2daf5970..77a05389 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -20,6 +20,7 @@ #define _INCLUDE_SOURCEMOD_MENU_SYSTEM_H_ #include +#include #define SMINTERFACE_MENUMANAGER_NAME "IMenuManager" #define SMINTERFACE_MENUMANAGER_VERSION 1 @@ -263,9 +264,12 @@ namespace SourceMod * * Note: the object should be freed using IBaseMenu::Destroy. * + * @param handler IMenuHandler pointer. + * @param pOwner Optional IdentityToken_t owner for handle + * creation. * @return An IBaseMenu pointer. */ - virtual IBaseMenu *CreateMenu() =0; + virtual IBaseMenu *CreateMenu(IMenuHandler *handler, IdentityToken_t *pOwner=NULL) =0; /** * @brief Returns the maximum number of items per page. @@ -293,6 +297,13 @@ namespace SourceMod * @return True if a menu was cancelled, false otherwise. */ virtual bool CancelClientMenu(int client, bool autoIgnore=false) =0; + + /** + * @brief Returns a Handle the IMenuStyle object. + * + * @return Handle_t pointing to this object. + */ + virtual Handle_t GetHandle() =0; }; /** @@ -428,16 +439,20 @@ namespace SourceMod * @brief Sends the menu to a client. * * @param client Client index to display to. - * @param handler Menu handler to use. * @param time Time to hold menu for. * @return True on success, false otherwise. */ - virtual bool Display(int client, IMenuHandler *handler, unsigned int time) =0; + virtual bool Display(int client, unsigned int time) =0; /** - * @brief Destroys the menu and frees all associated resources.1 + * @brief Destroys the menu and frees all associated resources. + * + * @param releaseHandle If true, the Handle will be released + * in the destructor. This should be set + * to true except for IHandleTypeDispatch + * destructors. */ - virtual void Destroy() =0; + virtual void Destroy(bool releaseHandle=true) =0; /** * @brief Cancels the menu on all client's displays. While the menu is @@ -446,6 +461,14 @@ namespace SourceMod * @return Number of menus cancelled. */ virtual void Cancel() =0; + + /** + * @brief Returns the menu's Handle. The Handle is automatically + * removed when the menu is destroyed. + * + * @return Handle_t handle value. + */ + virtual Handle_t GetHandle() =0; }; /** @@ -516,6 +539,15 @@ namespace SourceMod { } + /** + * @brief Called when the menu object is destroyed. + * + * @param menu Menu pointer. + */ + virtual void OnMenuDestroy(IBaseMenu *menu) + { + } + /** * @brief Called when requesting how to render an item. * @@ -579,11 +611,11 @@ namespace SourceMod */ virtual IMenuStyle *FindStyleByName(const char *name) =0; +#if 0 /** * @brief Broadcasts a menu to a number of clients. * * @param menu Menu pointer. - * @param handler IMenuHandler pointer. * @param clients Array of client indexes. * @param numClients Number of clients in the array. * @param time Time to hold the menu. @@ -610,6 +642,7 @@ namespace SourceMod int clients[], unsigned int numClients, unsigned int time) =0; +#endif /** * @brief Returns the default draw style Core is using. From 2af178229dae4a7f91d424b47ddeaf3730314288 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 14 May 2007 04:48:03 +0000 Subject: [PATCH 0766/1664] fixed linux build for menu natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40797 --- core/Makefile | 2 +- core/MenuStyle_Base.h | 2 +- core/smn_menus.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/Makefile b/core/Makefile index a25efdd0..fc8ed470 100644 --- a/core/Makefile +++ b/core/Makefile @@ -28,7 +28,7 @@ OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \ - smn_usermsgs.cpp + smn_usermsgs.cpp smn_menus.cpp OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index 49707ebd..fe5f7b11 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -122,9 +122,9 @@ protected: bool m_ExitButton; bool m_bShouldDelete; bool m_bCancelling; + IdentityToken_t *m_pOwner; bool m_bDeleting; bool m_bWillFreeHandle; - IdentityToken_t *m_pOwner; Handle_t m_hHandle; IMenuHandler *m_pHandler; }; diff --git a/core/smn_menus.cpp b/core/smn_menus.cpp index b0c6b17b..5f174d56 100644 --- a/core/smn_menus.cpp +++ b/core/smn_menus.cpp @@ -124,7 +124,6 @@ public: */ virtual void OnPluginUnloaded(IPlugin *plugin) { - IPluginContext *pContext = plugin->GetBaseContext(); for (size_t i = 0; i < m_PanelHandlers.size(); i++) { if (m_PanelHandlers[i]->m_pPlugin == plugin) From 663906c60eb2f8da303f351da3913172d1def0c3 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 14 May 2007 06:45:27 +0000 Subject: [PATCH 0767/1664] Fixed amb289 - Crash on SourceMod shutdown when hooking events as post in Linux. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40798 --- core/EventManager.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/EventManager.cpp b/core/EventManager.cpp index b0c08460..9678f474 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -345,7 +345,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) if (pForward) { - EventInfo info = {pEvent, false}; + EventInfo info = { pEvent, NULL }; Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); pForward->PushCell(hndl); @@ -389,11 +389,10 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) if (pForward) { + EventInfo info = { pHook->pEventCopy, NULL }; + if (pHook->postCopy) { - pEventCopy = pHook->pEventCopy; - - EventInfo info = {pEventCopy, false}; hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); pForward->PushCell(hndl); From a0486eea8c4e18c7dc0278cd2bc72e892944cac4 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 14 May 2007 19:32:38 +0000 Subject: [PATCH 0768/1664] Fixed amb290 - Some incorrect reporting of tag mismatches with the 'any' tag --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40799 --- sourcepawn/compiler/sc3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index d4e780c5..9a64175d 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -322,12 +322,12 @@ SC_FUNC int matchtag_string(int ident, int tag) SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) { - if (formaltag!=actualtag) { + if (formaltag != actualtag) { /* if the formal tag is zero and the actual tag is not "fixed", the actual * tag is "coerced" to zero */ if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) { - if (formaltag == pc_anytag) + if (formaltag == pc_anytag || actualtag == pc_anytag) { return TRUE; } From 515be43896f56085b06c11dce7622fccc6f8a7b0 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Mon, 14 May 2007 21:29:17 +0000 Subject: [PATCH 0769/1664] Implemented amb286 - .smx extension no longer required with "sm plugins load" --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40800 --- core/systems/LibrarySys.cpp | 20 ++++++++++++++++++++ core/systems/LibrarySys.h | 1 + core/systems/PluginSys.cpp | 13 +++++++++---- public/ILibrarySys.h | 10 +++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 76e2f2df..af956f23 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -322,3 +322,23 @@ size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) return mylen; } + +const char *LibrarySystem::GetFileExtension(const char *filename) +{ + size_t len = strlen(filename); + + for (size_t i = len - 1; i >= 0; i--) + { + if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR) + { + return NULL; + } + + if (filename[i] == '.' && i != len - 1) + { + return &filename[++i]; + } + } + + return NULL; +} diff --git a/core/systems/LibrarySys.h b/core/systems/LibrarySys.h index 7b15e062..ff6223fa 100644 --- a/core/systems/LibrarySys.h +++ b/core/systems/LibrarySys.h @@ -74,6 +74,7 @@ public: bool IsPathDirectory(const char *path); void GetPlatformError(char *error, size_t maxlength); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); + const char *GetFileExtension(const char *filename); }; extern LibrarySystem g_LibSys; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 9fc1615a..c501f7fb 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1661,19 +1661,24 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc char error[128]; bool wasloaded; const char *filename = g_RootMenu.GetArgument(3); - IPlugin *pl = LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded); + + char pluginfile[256]; + const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx"; + UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext); + + IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded); if (wasloaded) { - g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", filename); + g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile); return; } if (pl) { - g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", filename); + g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile); } else { - g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", filename, error); + g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error); } return; diff --git a/public/ILibrarySys.h b/public/ILibrarySys.h index 2af2d162..d8e2c407 100644 --- a/public/ILibrarySys.h +++ b/public/ILibrarySys.h @@ -29,7 +29,7 @@ namespace SourceMod { #define SMINTERFACE_LIBRARYSYS_NAME "ILibrarySys" - #define SMINTERFACE_LIBRARYSYS_VERSION 1 + #define SMINTERFACE_LIBRARYSYS_VERSION 2 class ILibrary { @@ -173,6 +173,14 @@ namespace SourceMod * @param ... Format string arguments. */ virtual size_t PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0; + + /** + * @brief Returns a pointer to the extension in a filename. + * + * @param filename Name of file from which the extension should be extracted. + * @return Pointer to file extension. + */ + virtual const char *GetFileExtension(const char *filename) =0; }; } From a03caa91200abf0ad0ad939ac45e2637f31ecd20 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 14 May 2007 22:10:18 +0000 Subject: [PATCH 0770/1664] fixed makefile for radio menus being excluded --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40801 --- core/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/Makefile b/core/Makefile index fc8ed470..e12a20de 100644 --- a/core/Makefile +++ b/core/Makefile @@ -23,7 +23,8 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ - sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp + sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \ + MenuStyle_Radio.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \ From be9c5e8675fde4f6334951d855b4533f895d7745 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 May 2007 02:13:07 +0000 Subject: [PATCH 0771/1664] fixed a comment typo --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40802 --- plugins/include/menus.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/menus.inc b/plugins/include/menus.inc index 82ad88bf..72ff2b9f 100644 --- a/plugins/include/menus.inc +++ b/plugins/include/menus.inc @@ -36,7 +36,7 @@ enum MenuAction MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */ MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */ MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ - MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=item) */ + MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=reason) */ MenuAction_End = (1<<4), /**< A menu's display/selection cycle is complete (nothing passed). */ MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */ }; From 82e07a9bf08a136bc4ac9126cb557070b743d09f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 May 2007 02:23:12 +0000 Subject: [PATCH 0772/1664] fixed a visual spacer being added to radio menus when no control options existed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40803 --- core/MenuManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index c7a5bdd5..d7e50d5f 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -585,6 +585,7 @@ skip_search: } /* Put a fake spacer before control stuff, if possible */ + if ((displayPrev || displayNext) || exitButton) { ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER); display->DrawItem(draw); From c9bc46e770f3dec4e88087be159fbc4e7d9634c9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 May 2007 04:59:24 +0000 Subject: [PATCH 0773/1664] core will now ignore missing natives starting with '@' the compiler will now resolve aliased natives to single references and export '@' natives for each redundant entry --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40804 --- core/systems/PluginSys.cpp | 3 ++- sourcepawn/compiler/sc4.c | 9 +++++++++ sourcepawn/compiler/sc6.c | 27 ++++++++++++++------------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index c501f7fb..2404df7c 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1037,7 +1037,8 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng { break; } - if (native->status == SP_NATIVE_UNBOUND) + if (native->status == SP_NATIVE_UNBOUND + && native->name[0] != '@') { if (error) { diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index b3e7fb86..a18267e3 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -738,6 +738,7 @@ SC_FUNC void ffcase(cell value,char *labelname,int newtable) SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) { char symname[2*sNAMEMAX+16]; + char aliasname[sNAMEMAX+1]; assert(sym!=NULL); assert(sym->ident==iFUNCTN); @@ -749,6 +750,14 @@ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) sym->addr=ntv_funcid++; stgwrite("\tsysreq.c "); + /* Look for an alias */ + if (lookup_alias(aliasname, sym->name)) { + symbol *asym = findglb(aliasname, sGLOBAL); + if (asym && asym->ident==iFUNCTN && ((sym->usage & uNATIVE) != 0)) { + sym = asym; + } + } + assert(sym->addr != 0x1d); outval(sym->addr,FALSE); if (sc_asmfile) { stgwrite("\t; "); diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index ea090bb2..a19b62cd 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -676,6 +676,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) constvalue *constptr; cell mainaddr; char nullchar; + char testalias[sNAMEMAX+1]; /* if compression failed, restart the assembly with compaction switched off */ if (setjmp(compact_err)!=0) { @@ -706,8 +707,9 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) for (sym=glbtab.next; sym!=NULL; sym=sym->next) { int match=0; if (sym->ident==iFUNCTN) { - if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) + if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) { match=++numnatives; + } if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) match=++numpublics; if (strcmp(sym->name,uMAINFUNC)==0) { @@ -719,13 +721,12 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) match=++numpubvars; } /* if */ if (match) { - char alias[sNAMEMAX+1]; + const char *aliasptr = sym->name; assert(sym!=NULL); - if ((sym->usage & uNATIVE)==0 || !lookup_alias(alias,sym->name)) { - assert(strlen(sym->name)<=sNAMEMAX); - strcpy(alias,sym->name); + if (((sym->usage & uNATIVE)!=0) && lookup_alias(testalias,sym->name)) { + aliasptr = "@"; } /* if */ - nametablesize+=strlen(alias)+1; + nametablesize+=strlen(aliasptr)+1; } /* if */ } /* for */ assert(numnatives==ntv_funcid); @@ -843,13 +844,13 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) } /* for */ count=0; for (i=0; iname)) { - assert(strlen(sym->name)<=sNAMEMAX); - strcpy(alias,sym->name); - } /* if */ + aliasptr = sym->name; + if (lookup_alias(testalias,sym->name)) { + aliasptr = "@"; + } assert(sym->vclass==sGLOBAL); func.address=0; func.nameofs=nameofs; @@ -860,8 +861,8 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); - pc_writebin(fout,alias,strlen(alias)+1); - nameofs+=strlen(alias)+1; + pc_writebin(fout,(void *)aliasptr,strlen(aliasptr)+1); + nameofs+=strlen(aliasptr)+1; count++; } /* for */ free(nativelist); From 98bf124013821d85fa2fd1058f3ebbd3833358bd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 May 2007 04:59:48 +0000 Subject: [PATCH 0774/1664] compiler now gets its own versioning, finally --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40805 --- modules.versions | 5 +++++ sourcepawn/compiler/libpawnc.rc | 13 +++++------- sourcepawn/compiler/msvc8/spcomp.vcproj | 4 ++++ sourcepawn/compiler/sc1.c | 4 ++-- sourcepawn/compiler/svn_version.h | 28 ++++++++++++++++++------- sourcepawn/compiler/svn_version.tpl | 25 ++++++++++++++++++++++ 6 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 sourcepawn/compiler/svn_version.tpl diff --git a/modules.versions b/modules.versions index d1197ce5..d6fc94e8 100644 --- a/modules.versions +++ b/modules.versions @@ -27,3 +27,8 @@ out = svn_version.h folder = extensions/threader in = svn_version.tpl out = svn_version.h + +[compiler] +folder = sourcepawn/compiler +in = svn_version.tpl +out = svn_version.h diff --git a/sourcepawn/compiler/libpawnc.rc b/sourcepawn/compiler/libpawnc.rc index d486738d..f84f9c93 100644 --- a/sourcepawn/compiler/libpawnc.rc +++ b/sourcepawn/compiler/libpawnc.rc @@ -13,17 +13,14 @@ AppIcon ICON "pawn.ico" * All strings MUST have an explicit \0. See the Windows SDK documentation * for details on version information and the VERSIONINFO structure. */ -#define VERSION 1 -#define REVISION 0 -#define BUILD SVN_REVISION -#define VERSIONSTR SVN_REVISION_STRING + #define VERSIONNAME "smcomp.exe\0" #define VERSIONDESCRIPTION "SourcePawn Compiler\0" #define VERSIONPRODUCTNAME "smcomp\0" VS_VERSION_INFO VERSIONINFO -FILEVERSION VERSION, REVISION, BUILD, 0 -PRODUCTVERSION VERSION, REVISION, BUILD, 0 +FILEVERSION SVN_FILE_VERSION +PRODUCTVERSION SVN_FILE_VERSION FILEFLAGSMASK 0x0000003FL FILEFLAGS 0 #if defined(WIN32) @@ -39,12 +36,12 @@ BEGIN BEGIN VALUE "CompanyName", "(C)1998-2006 ITB CompuPhase, AlliedModders LLC\0" VALUE "FileDescription", VERSIONDESCRIPTION - VALUE "FileVersion", VERSIONSTR + VALUE "FileVersion", SVN_FULL_VERSION VALUE "InternalName", VERSIONNAME VALUE "LegalCopyright", "(C)1998-2006 ITB CompuPhase, AlliedModders LLC\0" VALUE "OriginalFilename", VERSIONNAME VALUE "ProductName", VERSIONPRODUCTNAME - VALUE "ProductVersion", VERSIONSTR + VALUE "ProductVersion", SVN_FULL_VERSION END END diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index 8d1fa240..84416348 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -330,6 +330,10 @@ RelativePath="..\sc7.scp" > + + Date: Wed, 16 May 2007 01:17:14 +0000 Subject: [PATCH 0775/1664] fixed a bug where the JIT initiated the optimized stack top boundary check with a doubly relocated address, causing a rare bug with stack operations --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40806 --- sourcepawn/jit/x86/opcode_helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 00fc3dd7..65d1d554 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -80,7 +80,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) //mov ecx, [eax+] - copy memsize to temp var //add ecx, ebp - relocate //mov [esi+x], ecx - store relocated - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, mem_size)); IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); From 4ed2d6e51576dd5e770be1e28964f88fc2677a15 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 16 May 2007 04:09:31 +0000 Subject: [PATCH 0776/1664] Implemented amb296 - Added HookEventEx() which does not generate a runtime error if the event does not exist and returns false instead. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40807 --- core/smn_events.cpp | 21 +++++++++++++++++++++ plugins/include/events.inc | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 679c4efe..2948dda6 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -38,6 +38,26 @@ static cell_t sm_HookEvent(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_HookEventEx(IPluginContext *pContext, const cell_t *params) +{ + char *name; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + if (g_EventManager.HookEvent(name, pFunction, static_cast(params[3])) == EventHookErr_InvalidEvent) + { + return 0; + } + + return 1; +} + static cell_t sm_UnhookEvent(IPluginContext *pContext, const cell_t *params) { char *name; @@ -313,6 +333,7 @@ static cell_t sm_SetEventString(IPluginContext *pContext, const cell_t *params) REGISTER_NATIVES(gameEventNatives) { {"HookEvent", sm_HookEvent}, + {"HookEventEx", sm_HookEventEx}, {"UnhookEvent", sm_UnhookEvent}, {"CreateEvent", sm_CreateEvent}, {"FireEvent", sm_FireEvent}, diff --git a/plugins/include/events.inc b/plugins/include/events.inc index d1fd81d9..ede8c3e4 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -66,6 +66,17 @@ funcenum EventHook */ native HookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); +/** + * Creates a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @return True if event exists and was hooked successfully, false otherwise. + * @error Invalid callback function. + */ +native bool:HookEventEx(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); + /** * Removes a hook for when a game event is fired. * From 727e15b5a3359134fe1a3f15945efcf259c9f0e9 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 16 May 2007 05:04:28 +0000 Subject: [PATCH 0777/1664] Yikes, fixed HookEventEx() --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40808 --- core/smn_events.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/smn_events.cpp b/core/smn_events.cpp index 2948dda6..85bb8585 100644 --- a/core/smn_events.cpp +++ b/core/smn_events.cpp @@ -44,6 +44,7 @@ static cell_t sm_HookEventEx(IPluginContext *pContext, const cell_t *params) IPluginFunction *pFunction; pContext->LocalToString(params[1], &name); + pFunction = pContext->GetFunctionById(params[2]); if (!pFunction) { From f3b3ca6b2246cc6bbd0d35f37f0a684dcce59c6d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 16 May 2007 18:30:43 +0000 Subject: [PATCH 0778/1664] jit errors will now get passed upwards --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40809 --- core/systems/PluginSys.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2404df7c..122af7a1 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -204,7 +204,7 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) memset(&m_ctx, 0, sizeof(m_ctx)); if (error) { - snprintf(error, maxlength, "Failed to compile (error %d)", err); + snprintf(error, maxlength, "JIT failed to compile (error %d)", err); } return false; } @@ -820,7 +820,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de /* Do the actual compiling */ if (co) { - pPlugin->FinishMyCompile(NULL, 0); + pPlugin->FinishMyCompile(error, maxlength); co = NULL; } From f17a61e709f07748a8efeb0fa0859d425f5c95c1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 16 May 2007 19:52:24 +0000 Subject: [PATCH 0779/1664] fixed a compiler bug where the native table indexes were not exported correctly for aliases. thus pure float operators would be bound to the wrong natives removed a debug assert --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40810 --- sourcepawn/compiler/sc4.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index a18267e3..91887f5c 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -739,6 +739,7 @@ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) { char symname[2*sNAMEMAX+16]; char aliasname[sNAMEMAX+1]; + int wasAlias = 0; assert(sym!=NULL); assert(sym->ident==iFUNCTN); @@ -747,17 +748,20 @@ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) if ((sym->usage & uNATIVE)!=0) { /* reserve a SYSREQ id if called for the first time */ assert(label==NULL); + stgwrite("\tsysreq.c "); if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) sym->addr=ntv_funcid++; - stgwrite("\tsysreq.c "); /* Look for an alias */ if (lookup_alias(aliasname, sym->name)) { symbol *asym = findglb(aliasname, sGLOBAL); if (asym && asym->ident==iFUNCTN && ((sym->usage & uNATIVE) != 0)) { sym = asym; + if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) { + sym->addr=ntv_funcid++; + markusage(sym, uREAD); + } } } - assert(sym->addr != 0x1d); outval(sym->addr,FALSE); if (sc_asmfile) { stgwrite("\t; "); From 63284450435d1761e9599322a0a9a750f54c287a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 16 May 2007 21:53:47 +0000 Subject: [PATCH 0780/1664] vm errors from dynamic natives will now be explained more clearly to the calling plugin --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40811 --- core/smn_fakenatives.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 8df20220..ec248837 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -70,11 +70,12 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD cell_t result = 0; native->call->PushCell(pCaller->GetMyHandle()); native->call->PushCell(params[0]); - if (native->call->Execute(&result) != SP_ERROR_NONE) + int error; + if ((error=native->call->Execute(&result)) != SP_ERROR_NONE) { if (pContext->GetContext()->n_err == SP_ERROR_NONE) { - pContext->ThrowNativeError("Error encountered while processing a dynamic native"); + pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native"); } } From ca5242682541db575db725f65a506ab1f3aff728 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 16 May 2007 23:32:22 +0000 Subject: [PATCH 0781/1664] compressor step is now optional --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40812 --- tools/builder/ABuilder.cs | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tools/builder/ABuilder.cs b/tools/builder/ABuilder.cs index 0d198ca1..22d83830 100644 --- a/tools/builder/ABuilder.cs +++ b/tools/builder/ABuilder.cs @@ -173,25 +173,28 @@ namespace builder } string pkg_file = null; - if ((pkg_file=CompressPackage(pkg)) == null) + if (cfg.Compressor != null) { - throw new System.Exception("Failed to compress package: " + pkg.GetPackageName()); + if ((pkg_file=CompressPackage(pkg)) == null) + { + throw new System.Exception("Failed to compress package: " + pkg.GetPackageName()); + } + + string lpath = null, ltarget = null; + pkg.GetCompressBases(ref lpath, ref ltarget); + lpath = Config.PathFormat("{0}/{1}/{2}", + cfg.OutputBase, + lpath, + pkg_file); + ltarget = Config.PathFormat("{0}/{1}", cfg.OutputBase, pkg_file); + + if (File.Exists(ltarget)) + { + File.Delete(ltarget); + } + + File.Move(lpath, ltarget); } - - string lpath = null, ltarget = null; - pkg.GetCompressBases(ref lpath, ref ltarget); - lpath = Config.PathFormat("{0}/{1}/{2}", - cfg.OutputBase, - lpath, - pkg_file); - ltarget = Config.PathFormat("{0}/{1}", cfg.OutputBase, pkg_file); - - if (File.Exists(ltarget)) - { - File.Delete(ltarget); - } - - File.Move(lpath, ltarget); } } } From 02b645a3f9fc36f4ae4d24f1af0895f45df169a7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 May 2007 00:27:09 +0000 Subject: [PATCH 0782/1664] added more scripting exports --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40813 --- tools/builder/PkgCore.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 9e6d0b4c..6e4dce37 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -29,7 +29,7 @@ namespace builder */ public override string [] GetFolders() { - string [] folders = new string[8]; + string [] folders = new string[10]; folders[0] = "bin"; folders[1] = "plugins/disabled"; @@ -39,6 +39,8 @@ namespace builder folders[5] = "extensions"; folders[6] = "scripting/include"; folders[7] = "data"; + folders[8] = "scripting/admin-flatfile"; + folders[9] = "scripting/testsuite"; return folders; } @@ -68,6 +70,8 @@ namespace builder builder.CopyFolder(this, "plugins/include", "scripting/include", include_omits); builder.CopyFolder(this, "translations", "translations", null); builder.CopyFolder(this, "public/licenses", null, null); + builder.CopyFolder(this, "plugins/admin-flatfile", "scripting/admin-flatfile"); + builder.CopyFolder(this, "plugins/testsuite", "scripting/testsuite"); } /** From 1f7a250efd74a5804b0d28bd30618f68058cb377 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 May 2007 00:28:01 +0000 Subject: [PATCH 0783/1664] whoops, fixed build tool --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40814 --- tools/builder/PkgCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index 6e4dce37..1ef0fb75 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -70,8 +70,8 @@ namespace builder builder.CopyFolder(this, "plugins/include", "scripting/include", include_omits); builder.CopyFolder(this, "translations", "translations", null); builder.CopyFolder(this, "public/licenses", null, null); - builder.CopyFolder(this, "plugins/admin-flatfile", "scripting/admin-flatfile"); - builder.CopyFolder(this, "plugins/testsuite", "scripting/testsuite"); + builder.CopyFolder(this, "plugins/admin-flatfile", "scripting/admin-flatfile", null); + builder.CopyFolder(this, "plugins/testsuite", "scripting/testsuite", null); } /** From f1ee53f6b5706fedef7ba878a3f5cd1d5be6fb65 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 May 2007 03:33:22 +0000 Subject: [PATCH 0784/1664] this is a pointless commit to trigger a sync from the new build system --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40815 --- NOTICE.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/NOTICE.txt b/NOTICE.txt index 35815e51..a5bf529e 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -20,3 +20,4 @@ Under [auto-props], add these lines: *.sp = svn:keywords=Id *.inc = svn:keywords=Id +This is a pointless commit. \ No newline at end of file From 1a54f82eb127275e3e97c40d7aed906f611943ee Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 May 2007 16:41:04 +0000 Subject: [PATCH 0785/1664] another build sync trigger --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40816 --- NOTICE.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index a5bf529e..09e18fe7 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -19,5 +19,3 @@ Under [auto-props], add these lines: *.h = svn:keywords=Id *.sp = svn:keywords=Id *.inc = svn:keywords=Id - -This is a pointless commit. \ No newline at end of file From 5d4693c6f94d363d312b655ee448b0a2cb58bf1f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 May 2007 17:17:14 +0000 Subject: [PATCH 0786/1664] added to sourcemod.inc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40817 --- plugins/include/sourcemod.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 6a7e4eda..170d0b52 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -462,3 +462,4 @@ native bool:GameConfGetKeyValue(Handle:gc, const String:key[], String:buffer[], #include #include +#include \ No newline at end of file From 0fb64f891d193a95c7e54d03407d4c415294b0cf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 18 May 2007 18:00:35 +0000 Subject: [PATCH 0787/1664] removed @brief syntax from early includes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40818 --- plugins/include/admin.inc | 4 ++-- plugins/include/files.inc | 30 +++++++++++++++--------------- plugins/include/handles.inc | 6 +++--- plugins/include/lang.inc | 2 +- plugins/include/usermessages.inc | 8 ++++---- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 0fbea006..4ea66eaf 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -136,7 +136,7 @@ enum AdmAccessMode }; /** - * @brief Represents the various cache regions. + * Represents the various cache regions. */ enum AdminCachePart { @@ -200,7 +200,7 @@ native UnsetCommandOverride(const String:cmd[], OverrideType:type); native GroupId:CreateAdmGroup(const String:group_name[]); /** - * @brief Finds a group by name. + * Finds a group by name. * * @param group_name String containing the group name. * @return A group id, or INVALID_GROUP_ID if not found. diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 87574dbc..86501a68 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -45,7 +45,7 @@ enum PathType }; /** - * @brief Builds a path relative to the SourceMod folder. + * Builds a path relative to the SourceMod folder. * * @param type Type of path to build as the base. * @param buffer Buffer to store the path. @@ -57,7 +57,7 @@ enum PathType native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], any:...); /** - * @brief Opens a directory/folder for contents enumeration. + * Opens a directory/folder for contents enumeration. * @note Directories are closed with CloseHandle(). * @note Directories Handles can be cloned. * @@ -67,7 +67,7 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], native Handle:OpenDirectory(const String:path[]); /** - * @brief Reads the current directory entry as a local filename, then moves to the next file. + * Reads the current directory entry as a local filename, then moves to the next file. * @note Contents of buffers are undefined when returning false. * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. * @@ -81,7 +81,7 @@ native Handle:OpenDirectory(const String:path[]); native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=FileType_Unknown); /** - * @brief Opens a file. + * Opens a file. * @note Files are closed with CloseHandle(). * @note File Handles can be cloned. * @@ -92,7 +92,7 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type= native Handle:OpenFile(const String:file[], const String:mode[]); /** - * @brief Deletes a file. + * Deletes a file. * * @param path Path of the file to delete. * @return True on success, false otherwise. @@ -100,7 +100,7 @@ native Handle:OpenFile(const String:file[], const String:mode[]); native bool:DeleteFile(const String:path[]); /** - * @brief Reads a line from a text file. + * Reads a line from a text file. * * @param hndl Handle to the file. * @param buffer String buffer to hold the line. @@ -110,7 +110,7 @@ native bool:DeleteFile(const String:path[]); native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength); /** - * @brief Tests if the end of file has been reached. + * Tests if the end of file has been reached. * * @param file Handle to the file. * @return True if end of file has been reached, false otherwise. @@ -118,7 +118,7 @@ native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength); native bool:IsEndOfFile(Handle:file); /** - * @brief Sets the file position indicator. + * Sets the file position indicator. * * @param file Handle to the file. * @param position Position relative to what is specified in whence. @@ -128,7 +128,7 @@ native bool:IsEndOfFile(Handle:file); native bool:FileSeek(Handle:file, position, whence); /** - * @brief Get current position in the file. + * Get current position in the file. * * @param file Handle to the file. * @return Value for the file position indicator. @@ -136,7 +136,7 @@ native bool:FileSeek(Handle:file, position, whence); native FilePosition(Handle:file); /** - * @brief Checks if a file exists. + * Checks if a file exists. * * @param path Path to the file. * @return True if the file exists, false otherwise. @@ -144,7 +144,7 @@ native FilePosition(Handle:file); native bool:FileExists(const String:path[]); /** - * @brief Renames a file. + * Renames a file. * * @param newpath New path to the file. * @param oldpath Path to the existing file. @@ -153,7 +153,7 @@ native bool:FileExists(const String:path[]); native bool:RenameFile(const String:newpath[], const String:oldpath[]); /** - * @brief Checks if a directory exists. + * Checks if a directory exists. * * @param path Path to the directory. * @return True if the directory exists, false otherwise. @@ -161,7 +161,7 @@ native bool:RenameFile(const String:newpath[], const String:oldpath[]); native bool:DirExists(const String:path[]); /** - * @brief Get the file size in bytes. + * Get the file size in bytes. * * @param path Path to the file. * @return File size in bytes, -1 if file not found. @@ -169,7 +169,7 @@ native bool:DirExists(const String:path[]); native FileSize(const String:path[]); /** - * @brief Removes a directory. + * Removes a directory. * @note On most Operating Systems you cannot remove a directory which has files inside it. * * @param path Path to the directory. @@ -178,7 +178,7 @@ native FileSize(const String:path[]); native bool:RemoveDir(const String:path[]); /** - * @brief Writes a line of text in a file. + * Writes a line of text in a file. * @note This native will append the newline character. * * @param hndl Handle to the file. diff --git a/plugins/include/handles.inc b/plugins/include/handles.inc index 724c883a..2d15125d 100644 --- a/plugins/include/handles.inc +++ b/plugins/include/handles.inc @@ -27,7 +27,7 @@ enum Handle }; /** - * @brief Returns if a handle is valid or not. + * Returns if a handle is valid or not. * @note It is not a good idea to call this on every Handle. If you code properly, * all of your Handles will either be valid or will expose important bugs to fix. * This is provided for situations only where testing for handle validity is needed. @@ -38,7 +38,7 @@ enum Handle native bool:IsValidHandle(Handle:hndl); /** - * @brief Closes a Handle. If the handle has multiple copies open, + * Closes a Handle. If the handle has multiple copies open, * it is not destroyed unless all copies are closed. * * @note Closing a Handle has a different meaning for each Handle type. Make @@ -51,7 +51,7 @@ native bool:IsValidHandle(Handle:hndl); native bool:CloseHandle(Handle:hndl); /** - * @brief Clones a Handle. When passing handles in between plugins, caching handles + * Clones a Handle. When passing handles in between plugins, caching handles * can result in accidental invalidation when one plugin releases the Handle, or is its owner * is unloaded from memory. To prevent this, the Handle may be "cloned" with a new owner. * diff --git a/plugins/include/lang.inc b/plugins/include/lang.inc index 42c9b01b..1b45612e 100644 --- a/plugins/include/lang.inc +++ b/plugins/include/lang.inc @@ -21,7 +21,7 @@ #define LANG_SERVER 0 /**< Translate using the server's language */ /** - * @brief Loads a translation file for the plugin calling this native. + * Loads a translation file for the plugin calling this native. * * @param path Translation file. * @noreturn diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index c7677115..e6804b4f 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -90,7 +90,7 @@ native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags=0); native EndMessage(); /** - * @brief Called when a message is hooked + * Called when a message is hooked * * @param msg_id Message index. * @param bf Handle to the input bit buffer of the message. @@ -104,14 +104,14 @@ native EndMessage(); functag MsgHook Action:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); /** - * @brief Called when a message is finished sending. + * Called when a message is finished sending. * * @param msg_id Message index. */ functag MsgSentNotify public(UserMsg:msg_id); /** - * @brief Hooks a user message. + * Hooks a user message. * * @param msg_id Message index. * @param hook Function to use as a hook. @@ -125,7 +125,7 @@ functag MsgSentNotify public(UserMsg:msg_id); native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgSentNotify:notify=MsgSentNotify:-1); /** - * @brief Removes one usermessage hook. + * Removes one usermessage hook. * * @param msg_id Message index. * @param hook Function used for the hook. From e1fd0b694095cdcf48b2bd789501af6198e3dabe Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 18 May 2007 18:05:11 +0000 Subject: [PATCH 0788/1664] updated admin.inc's commenting style --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40819 --- plugins/include/admin.inc | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index 4ea66eaf..bf70ab9f 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -50,7 +50,7 @@ enum AdminFlag #define AdminFlags_TOTAL 21 /**< Total number of admin flags */ /** - * @section These define bitwise values for bitstrings (numbers containing bitwise flags). + * @section Bitwise values definitions for admin flags. */ #define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ #define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ @@ -81,25 +81,25 @@ enum AdminFlag /** * @section Hardcoded authentication methods */ -#define AUTHMETHOD_STEAM "steam" -#define AUTHMETHOD_IP "ip" -#define AUTHMETHOD_NAME "name" +#define AUTHMETHOD_STEAM "steam" /**< SteamID based authentication */ +#define AUTHMETHOD_IP "ip" /**< IP based authentication */ +#define AUTHMETHOD_NAME "name" /**< Name based authentication */ /** * @endsection */ /** - * Override types. + * Access override types. */ enum OverrideType { - Override_Command = 1, /* Command */ - Override_CommandGroup, /* Command group */ + Override_Command = 1, /**< Command */ + Override_CommandGroup, /**< Command group */ }; /** - * Override rules. + * Access override rules. */ enum OverrideRule { @@ -112,23 +112,29 @@ enum OverrideRule */ enum ImmunityType { - Immunity_Default = 1, /* Immune from everyone with no immunity */ - Immunity_Global, /* Immune from everyone (except root admins) */ + Immunity_Default = 1, /**< Immune from everyone with no immunity */ + Immunity_Global, /**< Immune from everyone (except root admins) */ }; -/** Identifies a unique entry in the group permissions cache. These are not Handles. */ +/** + * Identifies a unique entry in the group permissions cache. These are not Handles. + */ enum GroupId { - INVALID_GROUP_ID = -1, + INVALID_GROUP_ID = -1, /**< An invalid/nonexistant group */ }; -/** Identifies a unique entry in the admin permissions cache. These are not Handles. */ +/** + * Identifies a unique entry in the admin permissions cache. These are not Handles. + */ enum AdminId { - INVALID_ADMIN_ID = -1, + INVALID_ADMIN_ID = -1, /**< An invalid/nonexistant admin */ }; -/** Defines user access modes. */ +/** + * Methods of computing access permissions. + */ enum AdmAccessMode { Access_Real, /**< Access the user has inherently */ @@ -323,6 +329,7 @@ native AdminId:CreateAdmin(const String:name[]=""); /** * Retrieves an admin's user name as made with CreateAdmin(). + * * @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. * * @param id AdminId of the admin. @@ -435,6 +442,7 @@ native AdminId:FindAdminByIdentity(const String:auth[], const String:identity[]) /** * Removes an admin entry from the cache. + * * @note This will remove any bindings to a specific user. * * @param id AdminId index to remove/invalidate. @@ -528,3 +536,4 @@ stock bool:BitToFlag(bit, &AdminFlag:flag) return false; } + From 86344c06af85ec7f4a8d6631eea1a9a017834461 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 19 May 2007 17:28:19 +0000 Subject: [PATCH 0789/1664] invalid tokens removed from admin.inc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40820 --- plugins/include/admin.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/include/admin.inc b/plugins/include/admin.inc index bf70ab9f..0d1b9b87 100644 --- a/plugins/include/admin.inc +++ b/plugins/include/admin.inc @@ -409,7 +409,7 @@ native GetAdminGroupCount(AdminId:id); * @return A GroupId index and a name pointer, or * INVALID_GROUP_ID and NULL if an error occurred. */ -native GroupId:GetAdminGroup(AdminId:id, index, const String:name[], maxlength) =0; +native GroupId:GetAdminGroup(AdminId:id, index, const String:name[], maxlength); /** * Sets a password on an admin. @@ -476,7 +476,7 @@ native FlagBitArrayToBits(const bool:array[], maxSize); * @param numFlags Number of flags in the array. * @return A bit string composed of the array flags. */ -native FlagArrayToBits(const AdminFlag:array[], numFlags) =0; +native FlagArrayToBits(const AdminFlag:array[], numFlags); /** * Converts a bit string to an array of flags. @@ -486,7 +486,7 @@ native FlagArrayToBits(const AdminFlag:array[], numFlags) =0; * @param maxSize Maximum size of the flag array. * @return Number of flags written. */ -native FlagBitsToArray(bits, AdminFlag:array[], maxSize) =0; +native FlagBitsToArray(bits, AdminFlag:array[], maxSize); /** * Tests whether one admin can target another. From a55400b0acf5fab730ad856865c4d1ffe74f7267 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 19 May 2007 21:21:55 +0000 Subject: [PATCH 0790/1664] include file cleanup added semicolons where needed replaced taglists with 'any' tag added braces to one-line stocks --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40821 --- plugins/include/console.inc | 2 +- plugins/include/core.inc | 2 +- plugins/include/float.inc | 52 +++++++++++++++++++++++++++++++++++ plugins/include/functions.inc | 14 +++++----- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 120a42eb..8b07d6fb 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -33,7 +33,7 @@ enum ConVarBounds enum QueryCookie { QUERYCOOKIE_FAILED = 0, -} +}; /** * Console variable query result values. diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 6cc01675..5fd5634a 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -43,7 +43,7 @@ enum Action Plugin_Continue = 0, /**< Continue with the original action */ Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */ Plugin_Stop = 4, /**< Immediately stop the hook chain and handle the original */ -} +}; public PlVers:__version = { diff --git a/plugins/include/float.inc b/plugins/include/float.inc index 4b302a37..9914220f 100644 --- a/plugins/include/float.inc +++ b/plugins/include/float.inc @@ -212,83 +212,135 @@ native Float:operator+(Float:oper1, Float:oper2) = FloatAdd; native Float:operator-(Float:oper1, Float:oper2) = FloatSub; stock Float:operator++(Float:oper) +{ return oper+1.0; +} stock Float:operator--(Float:oper) +{ return oper-1.0; +} stock Float:operator-(Float:oper) +{ return oper^Float:((-1)^((-1)/2)); /* IEEE values are sign/magnitude */ +} stock Float:operator*(Float:oper1, oper2) +{ return FloatMul(oper1, float(oper2)); /* "*" is commutative */ +} stock Float:operator/(Float:oper1, oper2) +{ return FloatDiv(oper1, float(oper2)); +} stock Float:operator/(oper1, Float:oper2) +{ return FloatDiv(float(oper1), oper2); +} stock Float:operator+(Float:oper1, oper2) +{ return FloatAdd(oper1, float(oper2)); /* "+" is commutative */ +} stock Float:operator-(Float:oper1, oper2) +{ return FloatSub(oper1, float(oper2)); +} stock Float:operator-(oper1, Float:oper2) +{ return FloatSub(float(oper1), oper2); +} stock bool:operator==(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) == 0; +} stock bool:operator==(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) == 0; /* "==" is commutative */ +} stock bool:operator!=(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) != 0; +} stock bool:operator!=(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) != 0; /* "==" is commutative */ +} stock bool:operator>(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) > 0; +} stock bool:operator>(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) > 0; +} stock bool:operator>(oper1, Float:oper2) +{ return FloatCompare(float(oper1), oper2) > 0; +} stock bool:operator>=(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) >= 0; +} stock bool:operator>=(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) >= 0; +} stock bool:operator>=(oper1, Float:oper2) +{ return FloatCompare(float(oper1), oper2) >= 0; +} stock bool:operator<(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) < 0; +} stock bool:operator<(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) < 0; +} stock bool:operator<(oper1, Float:oper2) +{ return FloatCompare(float(oper1), oper2) < 0; +} stock bool:operator<=(Float:oper1, Float:oper2) +{ return FloatCompare(oper1, oper2) <= 0; +} stock bool:operator<=(Float:oper1, oper2) +{ return FloatCompare(oper1, float(oper2)) <= 0; +} stock bool:operator<=(oper1, Float:oper2) +{ return FloatCompare(float(oper1), oper2) <= 0; +} stock bool:operator!(Float:oper) +{ return (_:oper & ((-1)/2)) == 0; /* -1 = all bits to 1; /2 = remove most significant bit (sign) works on both 32bit and 64bit systems; no constant required */ +} /** * Forbidden operators. diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index aa42c3c8..d7b6eeab 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -211,7 +211,7 @@ native Call_StartFunction(Handle:plugin, Function:func); * @noreturn * @error Called before a call has been started. */ -native Call_PushCell({Handle,Function,_}:value); +native Call_PushCell(any:value); /** * Pushes a cell by reference onto the current call. @@ -222,7 +222,7 @@ native Call_PushCell({Handle,Function,_}:value); * @noreturn * @error Called before a call has been started. */ -native Call_PushCellRef(&{Handle,Function,_}:value); +native Call_PushCellRef(&any:value); /** @@ -258,7 +258,7 @@ native Call_PushFloatRef(&Float:value); * @noreturn * @error Called before a call has been started. */ -native Call_PushArray(const {Handle,Float,Function,_}:value[], size); +native Call_PushArray(const any:value[], size); /** * Pushes an array onto the current call. @@ -272,7 +272,7 @@ native Call_PushArray(const {Handle,Float,Function,_}:value[], size); * @noreturn * @error Called before a call has been started. */ -native Call_PushArrayEx({Handle,Float,Function,_}:value[], size, cpflags); +native Call_PushArrayEx(any:value[], size, cpflags); /** * Pushes a string onto the current call. @@ -420,7 +420,7 @@ native GetNativeCellRef(param); * @noreturn * @error Invalid parameter number or calling from a non-native function. */ -native SetNativeCellRef(param, {Float,Function,Handle,_}:value); +native SetNativeCellRef(param, any:value); /** * Gets an array from a native parameter (always by reference). @@ -431,7 +431,7 @@ native SetNativeCellRef(param, {Float,Function,Handle,_}:value); * @return SP_ERROR_NONE on success, anything else on failure. * @error Invalid parameter number or calling from a non-native function. */ -native GetNativeArray(param, {Float,Function,Handle,_}:local[], size); +native GetNativeArray(param, any:local[], size); /** * Copies a local array into a native parameter array (always by reference). @@ -442,7 +442,7 @@ native GetNativeArray(param, {Float,Function,Handle,_}:local[], size); * @return SP_ERROR_NONE on success, anything else on failure. * @error Invalid parameter number or calling from a non-native function. */ -native SetNativeArray(param, const {Float,Function,Handle,_}:local[], size); +native SetNativeArray(param, const any:local[], size); /** * Formats a string using parameters from a native. From 2cad3c34241c91edf78b39e7fb1f282b98955d1c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 19 May 2007 21:36:14 +0000 Subject: [PATCH 0791/1664] fixed capitalization on uint64 keyvalues natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40822 --- core/smn_keyvalues.cpp | 8 ++++---- plugins/include/keyvalues.inc | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 95073117..80912cb3 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -124,7 +124,7 @@ static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t smn_KvSetUint64(IPluginContext *pCtx, const cell_t *params) +static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError herr; @@ -312,7 +312,7 @@ static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t smn_KvGetUint64(IPluginContext *pCtx, const cell_t *params) +static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError herr; @@ -820,14 +820,14 @@ REGISTER_NATIVES(keyvaluenatives) { {"KvSetString", smn_KvSetString}, {"KvSetNum", smn_KvSetNum}, - {"KvSetUint64", smn_KvSetUint64}, + {"KvSetUInt64", smn_KvSetUInt64}, {"KvSetFloat", smn_KvSetFloat}, {"KvSetColor", smn_KvSetColor}, {"KvGetString", smn_KvGetString}, {"KvGetNum", smn_KvGetNum}, {"KvGetFloat", smn_KvGetFloat}, {"KvGetColor", smn_KvGetColor}, - {"KvGetUint64", smn_KvGetUint64}, + {"KvGetUInt64", smn_KvGetUInt64}, {"CreateKeyValues", smn_CreateKeyValues}, {"KvJumpToKey", smn_KvJumpToKey}, {"KvGotoNextKey", smn_KvGotoNextKey}, diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index 6c816319..bfead33c 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -76,7 +76,7 @@ native KvSetNum(Handle:kv, const String:key[], value); * @noreturn * @error Invalid Handle. */ -native KvSetUint64(Handle:kv, const String:key[], const value[2]); +native KvSetUInt64(Handle:kv, const String:key[], const value[2]); /** * Sets a floating point value of a KeyValues key. @@ -162,7 +162,7 @@ native KvGetColor(Handle:kv, const String:key[], &r, &g, &b, &a); * @noreturn * @error Invalid Handle. */ -native KvGetUint64(Handle:kv, const String:key[], value[2], defvalue[2]={0,0}); +native KvGetUInt64(Handle:kv, const String:key[], value[2], defvalue[2]={0,0}); /** * Sets the current position in the KeyValues tree to the given key. From bee6b715b9f9055c783d062bbf2487275af86d35 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 19 May 2007 22:19:27 +0000 Subject: [PATCH 0792/1664] fixed a typo in an unusable stock (so our include parser won't choke) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40823 --- plugins/include/menus.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/include/menus.inc b/plugins/include/menus.inc index 72ff2b9f..c18b1623 100644 --- a/plugins/include/menus.inc +++ b/plugins/include/menus.inc @@ -340,7 +340,7 @@ stock BroadcastMenuToAll(Handle:menu, MenuHandler:handler, time) * @return Number of clients that the vote will wait upon. * @error Invalid Handle. */ -native VoteMenuToAll(Handle:menu, MenuHandler:handler, time) +stock VoteMenuToAll(Handle:menu, MenuHandler:handler, time) { new num = GetMaxClients(); new total; From 98374f2ce6df382a16ed3dccf7ba2843a251523d Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sun, 20 May 2007 04:16:27 +0000 Subject: [PATCH 0793/1664] Fixed amb306 - GeoIP.dat wasn't packaged --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40824 --- configs/geoip/GeoIP.dat | Bin 0 -> 994672 bytes extensions/geoip/GeoIP.dat | Bin 682474 -> 0 bytes tools/builder/PkgCore.cs | 16 +++++++++------- 3 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 configs/geoip/GeoIP.dat delete mode 100644 extensions/geoip/GeoIP.dat diff --git a/configs/geoip/GeoIP.dat b/configs/geoip/GeoIP.dat new file mode 100644 index 0000000000000000000000000000000000000000..0531b57c7053393b6e2b742ec585f4239268eb6a GIT binary patch literal 994672 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

c34;3qCj2R{d}OFDlE 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