diff --git a/compiler/amxxpc/amx.cpp b/compiler/amxxpc/amx.cpp new file mode 100755 index 00000000..912a12fa --- /dev/null +++ b/compiler/amxxpc/amx.cpp @@ -0,0 +1,3984 @@ +/* Pawn Abstract Machine (for the Pawn language) + * + * Copyright (c) ITB CompuPhase, 1997-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$ + */ + +#if BUILD_PLATFORM == WINDOWS && BUILD_TYPE == RELEASE && BUILD_COMPILER == MSVC && PAWN_CELL_SIZE == 64 + /* bad bad workaround but we have to prevent a compiler crash :/ */ + #pragma optimize("g",off) +#endif + +#define WIN32_LEAN_AND_MEAN +#if defined _UNICODE || defined __UNICODE__ || defined UNICODE +# if !defined UNICODE /* for Windows API */ +# define UNICODE +# endif +# if !defined _UNICODE /* for C library */ +# define _UNICODE +# endif +#endif + +#include +#include +#include +#include /* for wchar_t */ +#include +#include "osdefs.h" +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + #include + #if !defined AMX_NODYNALOAD + #include + #endif + #if defined JIT + #include + #include + #endif +#endif +#if defined __LCC__ + #include /* for wcslen() */ +#endif +#include "amx.h" +#if (defined _Windows && !defined AMX_NODYNALOAD) || (defined JIT && __WIN32__) + #include +#endif + + +/* When one or more of the AMX_funcname macris are defined, we want + * to compile only those functions. However, when none of these macros + * is present, we want to compile everything. + */ +#if defined AMX_ALIGN || defined AMX_ALLOT || defined AMX_CLEANUP + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_CLONE || defined AMX_EXEC || defined AMX_FLAGS + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_GETADDR || defined AMX_INIT || defined AMX_MEMINFO + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_NAMELENGTH || defined AMX_NATIVEINFO || defined AMX_RAISEERROR + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_REGISTER || defined AMX_SETCALLBACK || defined AMX_SETDEBUGHOOK + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXNATIVES || defined AMX_XXXPUBLICS || defined AMX_XXXPUBVARS + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXSTRING || defined AMX_XXXTAGS || defined AMX_XXXUSERDATA + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_UTF8XXX + #define AMX_EXPLIT_FUNCTIONS +#endif +#if !defined AMX_EXPLIT_FUNCTIONS + /* no constant set, set them all */ + #define AMX_ALIGN /* amx_Align16(), amx_Align32() and amx_Align64() */ + #define AMX_ALLOT /* amx_Allot() and amx_Release() */ + #define AMX_CLEANUP /* amx_Cleanup() */ + #define AMX_CLONE /* amx_Clone() */ + #define AMX_EXEC /* amx_Exec() plus amx_Push(), amx_PushArray() and amx_PushString() */ + #define AMX_FLAGS /* amx_Flags() */ + #define AMX_GETADDR /* amx_GetAddr() */ + #define AMX_INIT /* amx_Init() and amx_InitJIT() */ + #define AMX_MEMINFO /* amx_MemInfo() */ + #define AMX_NAMELENGTH /* amx_NameLength() */ + #define AMX_NATIVEINFO /* amx_NativeInfo() */ + #define AMX_RAISEERROR /* amx_RaiseError() */ + #define AMX_REGISTER /* amx_Register() */ + #define AMX_SETCALLBACK /* amx_SetCallback() */ + #define AMX_SETDEBUGHOOK /* amx_SetDebugHook() */ + #define AMX_XXXNATIVES /* amx_NumNatives(), amx_GetNative() and amx_FindNative() */ + #define AMX_XXXPUBLICS /* amx_NumPublics(), amx_GetPublic() and amx_FindPublic() */ + #define AMX_XXXPUBVARS /* amx_NumPubVars(), amx_GetPubVar() and amx_FindPubVar() */ + #define AMX_XXXSTRING /* amx_StrLen(), amx_GetString() and amx_SetString() */ + #define AMX_XXXTAGS /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */ + #define AMX_XXXUSERDATA /* amx_GetUserData() and amx_SetUserData() */ + #define AMX_UTF8XXX /* amx_UTF8Get(), amx_UTF8Put(), amx_UTF8Check() */ +#endif +#undef AMX_EXPLIT_FUNCTIONS +#if defined AMX_ANSIONLY + #undef AMX_UTF8XXX /* no UTF-8 support in ANSI/ASCII-only version */ +#endif + +typedef enum { + OP_NONE, /* invalid opcode */ + OP_LOAD_PRI, + OP_LOAD_ALT, + OP_LOAD_S_PRI, + OP_LOAD_S_ALT, + OP_LREF_PRI, + OP_LREF_ALT, + OP_LREF_S_PRI, + OP_LREF_S_ALT, + OP_LOAD_I, + OP_LODB_I, + OP_CONST_PRI, + OP_CONST_ALT, + OP_ADDR_PRI, + OP_ADDR_ALT, + OP_STOR_PRI, + OP_STOR_ALT, + OP_STOR_S_PRI, + OP_STOR_S_ALT, + OP_SREF_PRI, + OP_SREF_ALT, + OP_SREF_S_PRI, + OP_SREF_S_ALT, + OP_STOR_I, + OP_STRB_I, + OP_LIDX, + OP_LIDX_B, + OP_IDXADDR, + OP_IDXADDR_B, + OP_ALIGN_PRI, + OP_ALIGN_ALT, + OP_LCTRL, + OP_SCTRL, + OP_MOVE_PRI, + OP_MOVE_ALT, + OP_XCHG, + OP_PUSH_PRI, + OP_PUSH_ALT, + OP_PUSH_R, + OP_PUSH_C, + OP_PUSH, + OP_PUSH_S, + OP_POP_PRI, + OP_POP_ALT, + OP_STACK, + OP_HEAP, + OP_PROC, + OP_RET, + OP_RETN, + OP_CALL, + OP_CALL_PRI, + 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, + OP_SHR, + OP_SSHR, + OP_SHL_C_PRI, + OP_SHL_C_ALT, + OP_SHR_C_PRI, + OP_SHR_C_ALT, + OP_SMUL, + OP_SDIV, + OP_SDIV_ALT, + OP_UMUL, + OP_UDIV, + OP_UDIV_ALT, + OP_ADD, + OP_SUB, + OP_SUB_ALT, + OP_AND, + OP_OR, + OP_XOR, + OP_NOT, + OP_NEG, + OP_INVERT, + OP_ADD_C, + OP_SMUL_C, + OP_ZERO_PRI, + OP_ZERO_ALT, + OP_ZERO, + OP_ZERO_S, + OP_SIGN_PRI, + OP_SIGN_ALT, + OP_EQ, + OP_NEQ, + OP_LESS, + OP_LEQ, + OP_GRTR, + OP_GEQ, + OP_SLESS, + OP_SLEQ, + OP_SGRTR, + OP_SGEQ, + OP_EQ_C_PRI, + OP_EQ_C_ALT, + OP_INC_PRI, + OP_INC_ALT, + OP_INC, + OP_INC_S, + OP_INC_I, + OP_DEC_PRI, + OP_DEC_ALT, + OP_DEC, + OP_DEC_S, + OP_DEC_I, + OP_MOVS, + OP_CMPS, + OP_FILL, + OP_HALT, + OP_BOUNDS, + OP_SYSREQ_PRI, + OP_SYSREQ_C, + OP_FILE, /* obsolete */ + OP_LINE, /* obsolete */ + OP_SYMBOL, /* obsolete */ + OP_SRANGE, /* obsolete */ + OP_JUMP_PRI, + OP_SWITCH, + OP_CASETBL, + OP_SWAP_PRI, + OP_SWAP_ALT, + OP_PUSHADDR, + OP_NOP, + OP_SYSREQ_D, + OP_SYMTAG, /* obsolete */ + OP_BREAK, + /* ----- */ + OP_NUM_OPCODES +} OPCODE; + +#define USENAMETABLE(hdr) \ + ((hdr)->defsize==sizeof(AMX_FUNCSTUBNT)) +#define NUMENTRIES(hdr,field,nextfield) \ + (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) +#define GETENTRY(hdr,table,index) \ + (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize) +#define GETENTRYNAME(hdr,entry) \ + ( USENAMETABLE(hdr) \ + ? (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUBNT*)(entry))->nameofs) \ + : ((AMX_FUNCSTUB*)(entry))->name ) + +#if !defined NDEBUG + static int check_endian(void) + { + uint16_t val=0x00ff; + unsigned char *ptr=(unsigned char *)&val; + /* "ptr" points to the starting address of "val". If that address + * holds the byte "0xff", the computer stored the low byte of "val" + * at the lower address, and so the memory lay out is Little Endian. + */ + assert(*ptr==0xff || *ptr==0x00); + #if BYTE_ORDER==BIG_ENDIAN + return *ptr==0x00; /* return "true" if big endian */ + #else + return *ptr==0xff; /* return "true" if little endian */ + #endif + } +#endif + +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==16 + static void swap16(uint16_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==2); + /* swap two bytes */ + t=s[0]; + s[0]=s[1]; + s[1]=t; + } +#endif + +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==32 + static void swap32(uint32_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==4); + /* swap outer two bytes */ + t=s[0]; + s[0]=s[3]; + s[3]=t; + /* swap inner two bytes */ + t=s[1]; + s[1]=s[2]; + s[2]=t; + } +#endif + +#if (BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==64) && (defined _I64_MAX || defined HAVE_I64) + static void swap64(uint64_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==8); + + t=s[0]; + s[0]=s[7]; + s[7]=t; + + t=s[1]; + s[1]=s[6]; + s[6]=t; + + t=s[2]; + s[2]=s[5]; + s[5]=t; + + t=s[3]; + s[3]=s[4]; + s[4]=t; + } +#endif + +#if defined AMX_ALIGN || defined AMX_INIT +uint16_t * AMXAPI amx_Align16(uint16_t *v) +{ + assert(sizeof(*v)==2); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + swap16(v); + #endif + return v; +} + +uint32_t * AMXAPI amx_Align32(uint32_t *v) +{ + assert(sizeof(*v)==4); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + swap32(v); + #endif + return v; +} + +#if defined _I64_MAX || defined HAVE_I64 +uint64_t * AMXAPI amx_Align64(uint64_t *v) +{ + assert(sizeof(*v)==8); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + swap64(v); + #endif + return v; +} +#endif /* _I64_MAX || HAVE_I64 */ +#endif /* AMX_ALIGN || AMX_INIT */ + +#if PAWN_CELL_SIZE==16 + #define swapcell swap16 +#elif PAWN_CELL_SIZE==32 + #define swapcell swap32 +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) + #define swapcell swap64 +#else + #error Unsupported cell size +#endif + +#if defined AMX_FLAGS +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) +{ + AMX_HEADER *hdr; + + *flags=0; + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionflags; + return AMX_ERR_NONE; +} +#endif /* AMX_FLAGS */ + +#if defined AMX_INIT +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + AMX_NATIVE f; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); +#if defined AMX_NATIVETABLE + if (index=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); + func=GETENTRY(hdr,natives,index); + f=(AMX_NATIVE)func->address; +#if defined AMX_NATIVETABLE + } /* if */ +#endif + assert(f!=NULL); + + /* Now that we have found the function, patch the program so that any + * subsequent call will call the function directly (bypassing this + * callback). + * This trick cannot work in the JIT, because the program would need to + * be re-JIT-compiled after patching a P-code instruction. + */ + #if defined JIT && !defined NDEBUG + if ((amx->flags & AMX_FLAG_JITC)!=0) + assert(amx->sysreq_d==0); + #endif + if (amx->sysreq_d!=0) { + /* at the point of the call, the CIP pseudo-register points directly + * behind the SYSREQ instruction and its parameter. + */ + unsigned char *code=amx->base+(int)hdr->cod+(int)amx->cip-4; + assert(amx->cip >= 4 && amx->cip < (hdr->dat - hdr->cod)); + assert(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */ +#if defined __GNUC__ || defined ASM32 + if (*(cell*)code==index) { +#else + if (*(cell*)code!=OP_SYSREQ_PRI) { + assert(*(cell*)(code-sizeof(cell))==OP_SYSREQ_C); + assert(*(cell*)code==index); +#endif + *(cell*)(code-sizeof(cell))=amx->sysreq_d; + *(cell*)code=(cell)f; + } /* if */ + } /* if */ + + /* Note: + * params[0] == number of bytes for the additional parameters passed to the native function + * params[1] == first argument + * etc. + */ + + amx->error=AMX_ERR_NONE; + *result = f(amx,params); + return amx->error; +} +#endif /* defined AMX_INIT */ + + +#if defined JIT + extern int AMXAPI getMaxCodeSize(void); + extern int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase); +#endif + +#if PAWN_CELL_SIZE==16 + #define JUMPABS(base,ip) ((cell *)((base) + *(ip))) + #define RELOC_ABS(base, off) + #define RELOC_VALUE(base, v) +#else + #define JUMPABS(base, ip) ((cell *)*(ip)) + #define RELOC_ABS(base, off) (*(ucell *)((base)+(int)(off)) += (ucell)(base)) + #define RELOC_VALUE(base, v) ((v)+((ucell)(base))) +#endif + +#define DBGPARAM(v) ( (v)=*(cell *)(code+(int)cip), cip+=sizeof(cell) ) + +#if defined AMX_INIT + +static int amx_BrowseRelocate(AMX *amx) +{ + AMX_HEADER *hdr; + unsigned char *code; + cell cip; + long codesize; + OPCODE op; + #if defined __GNUC__ || defined ASM32 || defined JIT + cell *opcode_list; + #endif + #if defined JIT + int opcode_count = 0; + int reloc_count = 0; + #endif + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + code=amx->base+(int)hdr->cod; + codesize=hdr->dat - hdr->cod; + amx->flags=AMX_FLAG_BROWSE; + + /* sanity checks */ + assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + + amx->sysreq_d=0; /* preset */ + #if (defined __GNUC__ || defined ASM32 || defined JIT) && !defined __64BIT__ + amx_Exec(amx, (cell*)(void*)&opcode_list, 0); + /* to use direct system requests, a function pointer must fit in a cell; + * because the native function's address will be stored as the parameter + * of SYSREQ.D + */ + if ((amx->flags & AMX_FLAG_JITC)==0 && sizeof(AMX_NATIVE)<=sizeof(cell)) + amx->sysreq_d=opcode_list[OP_SYSREQ_D]; + #else + /* ANSI C + * to use direct system requests, a function pointer must fit in a cell; + * see the comment above + */ + if (sizeof(AMX_NATIVE)<=sizeof(cell)) + amx->sysreq_d=OP_SYSREQ_D; + #endif + + /* start browsing code */ + for (cip=0; cip0 && op=256) { + amx->flags &= ~AMX_FLAG_BROWSE; + return AMX_ERR_INVINSTR; + } /* if */ + #if defined __GNUC__ || defined ASM32 || defined JIT + /* relocate opcode (only works if the size of an opcode is at least + * as big as the size of a pointer (jump address); so basically we + * rely on the opcode and a pointer being 32-bit + */ + *(cell *)(code+(int)cip) = opcode_list[op]; + #endif + #if defined JIT + opcode_count++; + #endif + cip+=sizeof(cell); + switch (op) { + 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_SYSREQ_C: + case OP_PUSHADDR: + case OP_SYSREQ_D: + cip+=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_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: + #if defined JIT + reloc_count++; + #endif + RELOC_ABS(code, cip); + cip+=sizeof(cell); + break; + + case OP_FILE: + case OP_SYMBOL: { + cell num; + DBGPARAM(num); + cip+=num; + break; + } /* case */ + case OP_LINE: + case OP_SRANGE: + cip+=2*sizeof(cell); + break; + case OP_SYMTAG: + cip+=sizeof(cell); + break; + case OP_CASETBL: { + cell num; + int i; + DBGPARAM(num); /* number of records follows the opcode */ + for (i=0; i<=num; i++) { + RELOC_ABS(code, cip+2*i*sizeof(cell)); + #if defined JIT + reloc_count++; + #endif + } /* for */ + cip+=(2*num + 1)*sizeof(cell); + break; + } /* case */ + default: + amx->flags &= ~AMX_FLAG_BROWSE; + return AMX_ERR_INVINSTR; + } /* switch */ + } /* for */ + + #if defined JIT + amx->code_size = getMaxCodeSize()*opcode_count + hdr->cod + + (hdr->stp - hdr->dat); + amx->reloc_size = 2*sizeof(cell)*reloc_count; + #endif + + amx->flags &= ~AMX_FLAG_BROWSE; + amx->flags |= AMX_FLAG_RELOC; + return AMX_ERR_NONE; +} + +#if AMX_COMPACTMARGIN > 2 +static void expand(unsigned char *code, long codesize, long memsize) +{ + ucell c; + struct { + long memloc; + ucell c; + } spare[AMX_COMPACTMARGIN]; + int sh=0,st=0,sc=0; + int shift; + + /* for in-place expansion, move from the end backward */ + assert(memsize % sizeof(cell) == 0); + while (codesize>0) { + c=0; + shift=0; + do { + codesize--; + /* no input byte should be shifted out completely */ + assert(shift<8*sizeof(cell)); + /* we work from the end of a sequence backwards; the final code in + * a sequence may not have the continuation bit set */ + assert(shift>0 || (code[(size_t)codesize] & 0x80)==0); + c|=(ucell)(code[(size_t)codesize] & 0x7f) << shift; + shift+=7; + } while (codesize>0 && (code[(size_t)codesize-1] & 0x80)!=0); + /* sign expand */ + if ((code[(size_t)codesize] & 0x40)!=0) { + while (shift < (int)(8*sizeof(cell))) { + c|=(ucell)0xff << shift; + shift+=8; + } /* while */ + } /* if */ + /* store */ + while (sc && (spare[sh].memloc>codesize)) { + *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c; + sh=(sh+1)%AMX_COMPACTMARGIN; + sc--; + } /* while */ + memsize -= sizeof(cell); + assert(memsize>=0); + if ((memsize>codesize)||((memsize==codesize)&&(memsize==0))) { + *(ucell *)(code+(size_t)memsize)=c; + } else { + assert(scflags & AMX_FLAG_RELOC)!=0) + return AMX_ERR_INIT; /* already initialized (may not do so twice) */ + + hdr=(AMX_HEADER *)program; + /* the header is in Little Endian, on a Big Endian machine, swap all + * multi-byte words + */ + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + amx_Align32((uint32_t*)&hdr->size); + amx_Align16(&hdr->magic); + amx_Align16((uint16_t*)&hdr->flags); + amx_Align16((uint16_t*)&hdr->defsize); + amx_Align32((uint32_t*)&hdr->cod); + amx_Align32((uint32_t*)&hdr->dat); + amx_Align32((uint32_t*)&hdr->hea); + amx_Align32((uint32_t*)&hdr->stp); + amx_Align32((uint32_t*)&hdr->cip); + amx_Align32((uint32_t*)&hdr->publics); + amx_Align32((uint32_t*)&hdr->natives); + amx_Align32((uint32_t*)&hdr->libraries); + amx_Align32((uint32_t*)&hdr->pubvars); + amx_Align32((uint32_t*)&hdr->tags); + #endif + + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_versionamx_version>CUR_FILE_VERSION) + return AMX_ERR_VERSION; + if (hdr->defsize!=sizeof(AMX_FUNCSTUB) && hdr->defsize!=sizeof(AMX_FUNCSTUBNT)) + return AMX_ERR_FORMAT; + if (USENAMETABLE(hdr)) { + uint16_t *namelength; + /* when there is a separate name table, check the maximum name length + * in that table + */ + amx_Align32((uint32_t*)&hdr->nametable); + namelength=(uint16_t*)((unsigned char*)program + (unsigned)hdr->nametable); + amx_Align16(namelength); + if (*namelength>sNAMEMAX) + return AMX_ERR_FORMAT; + } /* if */ + if (hdr->stp<=0) + return AMX_ERR_FORMAT; + #if BYTE_ORDER==BIG_ENDIAN + if ((hdr->flags & AMX_FLAG_COMPACT)==0) { + ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod); + while (code<(ucell *)((unsigned char *)program+(int)hdr->hea)) + swapcell(code++); + } /* if */ + #endif + assert((hdr->flags & AMX_FLAG_COMPACT)!=0 || hdr->hea == hdr->size); + if ((hdr->flags & AMX_FLAG_COMPACT)!=0) { + #if AMX_COMPACTMARGIN > 2 + expand((unsigned char *)program+(int)hdr->cod, + hdr->size - hdr->cod, hdr->hea - hdr->cod); + #else + return AMX_ERR_FORMAT; + #endif + } /* if */ + + amx->base=(unsigned char *)program; + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amx->base+(int)hdr->stp-sizeof(cell)) = 0; + + /* set initial values */ + amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amx->stp=hdr->stp - hdr->dat - sizeof(cell); + amx->hea=amx->hlw; + amx->stk=amx->stp; + if (amx->callback==NULL) + amx->callback=amx_Callback; + amx->data=NULL; + + /* also align all addresses in the public function, public variable, + * public tag and native function tables --offsets into the name table + * (if present) must also be swapped. + */ + #if BYTE_ORDER==BIG_ENDIAN + { /* local */ + AMX_FUNCSTUB *fs; + int i,num; + + fs=GETENTRY(hdr,natives,0); + num=NUMENTRIES(hdr,natives,libraries); + for (i=0; iaddress); /* redundant, because it should be zero */ + if (USENAMETABLE(hdr)) + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,publics,0); + assert(hdr->publics<=hdr->natives); + num=NUMENTRIES(hdr,publics,natives); + for (i=0; iaddress); + if (USENAMETABLE(hdr)) + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,pubvars,0); + assert(hdr->pubvars<=hdr->tags); + num=NUMENTRIES(hdr,pubvars,tags); + for (i=0; iaddress); + if (USENAMETABLE(hdr)) + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,tags,0); + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + num=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + num=NUMENTRIES(hdr,tags,nametable); + } /* if */ + for (i=0; iaddress); + if (USENAMETABLE(hdr)) + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + } /* local */ + #endif + + /* relocate call and jump instructions */ + amx_BrowseRelocate(amx); + + /* load any extension modules that the AMX refers to */ + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD + hdr=(AMX_HEADER *)amx->base; + numlibraries=NUMENTRIES(hdr,libraries,pubvars); + for (i=0; iaddress=(ucell)hlib; + } /* for */ + #endif + + return AMX_ERR_NONE; +} + +#if defined JIT + + #define CODESIZE_JIT 8192 /* approximate size of the code for the JIT */ + + #if defined __WIN32__ /* this also applies to Win32 "console" applications */ + + #define PROT_READ 0x1 /* page can be read */ + #define PROT_WRITE 0x2 /* page can be written */ + #define PROT_EXEC 0x4 /* page can be executed */ + #define PROT_NONE 0x0 /* page can not be accessed */ + + static int mprotect(void *addr, size_t len, int prot) + { + DWORD prev, p = 0; + if ((prot & PROT_WRITE)!=0) + p = PAGE_EXECUTE_READWRITE; + else + p |= PAGE_EXECUTE_READ; + return !VirtualProtect(addr, len, p, &prev); + } + + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + + /* Linux already has mprotect() */ + + #else + + // TODO: Add cases for Linux, Unix, OS/2, ... + + /* DOS32 has no imposed limits on its segments */ + #define mprotect(addr, len, prot) (0) + + #endif /* #if defined __WIN32 __ */ + +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) +{ + int res; + AMX_HEADER *hdr; + + if ((amx->flags & AMX_FLAG_JITC)==0) + return AMX_ERR_INIT_JIT; /* flag not set, this AMX is not prepared for JIT */ + + /* Patching SYSREQ opcodes to SYSREQ_D cannot work in the JIT, because the + * program would need to be re-JIT-compiled after patching a P-code + * instruction. If this field is not zero, something went wrong with the + * amx_BrowseRelocate(). + */ + assert(amx->sysreq_d==0); + + if (mprotect(asm_runJIT, CODESIZE_JIT, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return AMX_ERR_INIT_JIT; + + /* copy the prefix */ + memcpy(native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod); + hdr = native_code; + + /* JIT rulz! (TM) */ + /* MP: added check for correct compilation */ + if ((res = asm_runJIT(amx->base, reloc_table, native_code)) != 0) { + /* update the required memory size (the previous value was a + * conservative estimate, now we know the exact size) + */ + amx->code_size = (hdr->dat + hdr->stp + 3) & ~3; + /* The compiled code is relocatable, since only relative jumps are + * used for destinations within the generated code and absoulute + * addresses for jumps into the runtime, which is fixed in memory. + */ + amx->base = (unsigned char*) native_code; + amx->cip = hdr->cip; + amx->hea = hdr->hea; + amx->stp = hdr->stp - sizeof(cell); + /* also put a sentinel for strings at the top the stack */ + *(cell *)((char*)native_code + hdr->dat + hdr->stp - sizeof(cell)) = 0; + amx->stk = amx->stp; + } /* if */ + + return (res == 0) ? AMX_ERR_NONE : AMX_ERR_INIT_JIT; +} + +#else /* #if defined JIT */ + +int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table) +{ + (void)amx; + (void)compiled_program; + (void)reloc_table; + return AMX_ERR_INIT_JIT; +} + +#endif /* #if defined JIT */ + +#endif /* AMX_INIT */ + +#if defined AMX_CLEANUP +int AMXAPI amx_Cleanup(AMX *amx) +{ + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD + #if defined _Windows + typedef int (FAR WINAPI *AMX_ENTRY)(AMX FAR *amx); + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + typedef int (*AMX_ENTRY)(AMX *amx); + #endif + AMX_HEADER *hdr; + int numlibraries,i; + AMX_FUNCSTUB *lib; + AMX_ENTRY libcleanup; + #endif + + /* unload all extension modules */ + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD + hdr=(AMX_HEADER *)amx->base; + assert(hdr->magic==AMX_MAGIC); + numlibraries=NUMENTRIES(hdr,libraries,pubvars); + for (i=0; iaddress!=0) { + char funcname[sNAMEMAX+12]; /* +1 for '\0', +4 for 'amx_', +7 for 'Cleanup' */ + strcpy(funcname,"amx_"); + strcat(funcname,GETENTRYNAME(hdr,lib)); + strcat(funcname,"Cleanup"); + #if defined _Windows + libcleanup=(AMX_ENTRY)GetProcAddress((HINSTANCE)lib->address,funcname); + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + libcleanup=(AMX_ENTRY)dlsym((void*)lib->address,funcname); + #endif + if (libcleanup!=NULL) + libcleanup(amx); + #if defined _Windows + FreeLibrary((HINSTANCE)lib->address); + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + dlclose((void*)lib->address); + #endif + } /* if */ + } /* for */ + #else + (void)amx; + #endif + return AMX_ERR_NONE; +} +#endif /* AMX_CLEANUP */ + +#if defined AMX_CLONE +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) +{ + AMX_HEADER *hdr; + unsigned char _FAR *dataSource; + + if (amxSource==NULL) + return AMX_ERR_FORMAT; + if (amxClone==NULL) + return AMX_ERR_PARAMS; + if ((amxSource->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + hdr=(AMX_HEADER *)amxSource->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionbase=amxSource->base; + amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); + amxClone->hea=amxClone->hlw; + amxClone->stk=amxClone->stp; + if (amxClone->callback==NULL) + amxClone->callback=amxSource->callback; + if (amxClone->debug==NULL) + amxClone->debug=amxSource->debug; + amxClone->flags=amxSource->flags; + + /* copy the data segment; the stack and the heap can be left uninitialized */ + assert(data!=NULL); + amxClone->data=(unsigned char _FAR *)data; + dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; + memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amxClone->data+(int)amxClone->stp) = 0; + + return AMX_ERR_NONE; +} +#endif /* AMX_CLONE */ + +#if defined AMX_MEMINFO +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) +{ + AMX_HEADER *hdr; + + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versiondat - hdr->cod; + if (datasize!=NULL) + *datasize=hdr->hea - hdr->dat; + if (stackheap!=NULL) + *stackheap=hdr->stp - hdr->hea; + + return AMX_ERR_NONE; +} +#endif /* AMX_MEMINFO */ + +#if defined AMX_NAMELENGTH +int AMXAPI amx_NameLength(AMX *amx, int *length) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + if (USENAMETABLE(hdr)) { + uint16_t *namelength=(uint16_t*)(amx->base + (unsigned)hdr->nametable); + *length=*namelength; + assert(hdr->file_version>=7); /* name table exists only for file version 7+ */ + } else { + *length=hdr->defsize - sizeof(ucell); + } /* if */ + return AMX_ERR_NONE; +} +#endif /* AMX_NAMELENGTH */ + +#if defined AMX_XXXNATIVES +int AMXAPI amx_NumNatives(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + *number=NUMENTRIES(hdr,natives,libraries); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + if (index>=(cell)NUMENTRIES(hdr,natives,libraries)) + return AMX_ERR_INDEX; + + func=GETENTRY(hdr,natives,index); + strcpy(funcname,GETENTRYNAME(hdr,func)); + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index) +{ + int first,last,mid,result; + char pname[sNAMEMAX+1]; + + amx_NumNatives(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetNative(amx, mid, pname); + result=strcmp(pname,name); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *index=mid; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found, set to an invalid index, so amx_Exec() will fail */ + *index=INT_MAX; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXNATIVES */ + +#if defined AMX_XXXPUBLICS +int AMXAPI amx_NumPublics(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->publics<=hdr->natives); + *number=NUMENTRIES(hdr,publics,natives); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->publics<=hdr->natives); + if (index>=(cell)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + + func=GETENTRY(hdr,publics,index); + strcpy(funcname,GETENTRYNAME(hdr,func)); + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index) +{ + int first,last,mid,result; + char pname[sNAMEMAX+1]; + + amx_NumPublics(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetPublic(amx, mid, pname); + result=strcmp(pname,name); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *index=mid; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found, set to an invalid index, so amx_Exec() will fail */ + *index=INT_MAX; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXPUBLICS */ + +#if defined AMX_XXXPUBVARS +int AMXAPI amx_NumPubVars(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->pubvars<=hdr->tags); + *number=NUMENTRIES(hdr,pubvars,tags); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *var; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->pubvars<=hdr->tags); + if (index>=(cell)NUMENTRIES(hdr,pubvars,tags)) + return AMX_ERR_INDEX; + + var=GETENTRY(hdr,pubvars,index); + strcpy(varname,GETENTRYNAME(hdr,var)); + *amx_addr=var->address; + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr) +{ + int first,last,mid,result; + char pname[sNAMEMAX+1]; + cell paddr; + + amx_NumPubVars(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetPubVar(amx, mid, pname, &paddr); + result=strcmp(pname,varname); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *amx_addr=paddr; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found */ + *amx_addr=0; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXPUBVARS */ + +#if defined AMX_XXXTAGS +int AMXAPI amx_NumTags(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *number=0; + return AMX_ERR_VERSION; + } /* if */ + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + *number=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + *number=NUMENTRIES(hdr,tags,nametable); + } /* if */ + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *tag; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *tagname='\0'; + *tag_id=0; + return AMX_ERR_VERSION; + } /* if */ + + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + if (index>=(cell)NUMENTRIES(hdr,tags,cod)) + return AMX_ERR_INDEX; + } else { + assert(hdr->tags<=hdr->nametable); + if (index>=(cell)NUMENTRIES(hdr,tags,nametable)) + return AMX_ERR_INDEX; + } /* if */ + + tag=GETENTRY(hdr,tags,index); + strcpy(tagname,GETENTRYNAME(hdr,tag)); + *tag_id=tag->address; + + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) +{ + int first,last,mid; + cell mid_id; + + #if !defined NDEBUG + /* verify that the tagname table is sorted on the tag_id */ + amx_NumTags(amx, &last); + if (last>0) { + cell cur_id; + amx_GetTag(amx,0,tagname,&cur_id); + for (first=1; firsttag_id) + last=mid-1; + else if (mid_idusertags[index]!=tag; index++) + /* nothing */; + if (index>=AMX_USERNUM) + return AMX_ERR_USERDATA; + *ptr=amx->userdata[index]; + return AMX_ERR_NONE; +} + +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) +{ + int index; + + assert(amx!=NULL); + assert(tag!=0); + /* try to find existing tag */ + for (index=0; indexusertags[index]!=tag; index++) + /* nothing */; + /* if not found, try to find empty tag */ + if (index>=AMX_USERNUM) + for (index=0; indexusertags[index]!=0; index++) + /* nothing */; + /* if still not found, quit with error */ + if (index>=AMX_USERNUM) + return AMX_ERR_INDEX; + /* set the tag and the value */ + amx->usertags[index]=tag; + amx->userdata[index]=ptr; + return AMX_ERR_NONE; +} +#endif /* AMX_XXXUSERDATA */ + +#if defined AMX_REGISTER || defined AMX_EXEC || defined AMX_INIT +static AMX_NATIVE findfunction(const char *name, const AMX_NATIVE_INFO *list, int number) +{ + int i; + + assert(list!=NULL); + for (i=0; list[i].name!=NULL && (ibase; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + numnatives=NUMENTRIES(hdr,natives,libraries); + + err=AMX_ERR_NONE; + func=GETENTRY(hdr,natives,0); + for (i=0; iaddress==0) { + /* this function is not yet located */ + funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL; + if (funcptr!=NULL) + func->address=(ucell)funcptr; + else + err=AMX_ERR_NOTFOUND; + } /* if */ + func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); + } /* for */ + if (err==AMX_ERR_NONE) + amx->flags|=AMX_FLAG_NTVREG; + return err; +} +#endif /* AMX_REGISTER || AMX_EXEC || AMX_INIT */ + +#if defined AMX_NATIVEINFO +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func) +{ + static AMX_NATIVE_INFO n; + n.name=name; + n.func=func; + return &n; +} +#endif /* AMX_NATIVEINFO */ + +#if defined AMX_EXEC || defined AMX_INIT + +#define STKMARGIN ((cell)(16*sizeof(cell))) + +int AMXAPI amx_Push(AMX *amx, cell value) +{ + AMX_HEADER *hdr; + unsigned char *data; + + if (amx->hea+STKMARGIN>amx->stk) + return AMX_ERR_STACKERR; + hdr=(AMX_HEADER *)amx->base; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + amx->stk-=sizeof(cell); + amx->paramcount+=1; + *(cell *)(data+(int)amx->stk)=value; + return AMX_ERR_NONE; +} + +int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells) +{ + cell *paddr; + int err; + + assert(amx!=NULL); + assert(amx_addr!=NULL); + assert(array!=NULL); + + err=amx_Allot(amx,numcells,amx_addr,&paddr); + if (err==AMX_ERR_NONE) { + if (phys_addr!=NULL) + *phys_addr=paddr; + memcpy(paddr,array,numcells*sizeof(cell)); + err=amx_Push(amx,*amx_addr); + } /* if */ + return err; +} + +int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar) +{ + cell *paddr; + int numcells,err; + + assert(amx!=NULL); + assert(amx_addr!=NULL); + assert(string!=NULL); + + #if defined AMX_ANSIONLY + numcells=strlen(string) + 1; + #else + numcells= (use_wchar ? wcslen((const wchar_t*)string) : strlen(string)) + 1; + #endif + if (pack) + numcells=(numcells+sizeof(cell)-1)/sizeof(cell); + err=amx_Allot(amx,numcells,amx_addr,&paddr); + if (err==AMX_ERR_NONE) { + if (phys_addr!=NULL) + *phys_addr=paddr; + amx_SetString(paddr,string,pack,use_wchar,UNLIMITED); + err=amx_Push(amx,*amx_addr); + } /* if */ + return err; +} + +#define GETPARAM(v) ( v=*(cell *)cip++ ) +#define SKIPPARAM(n) ( cip=(cell *)cip+(n) ) +#define PUSH(v) ( stk-=sizeof(cell), *(cell *)(data+(int)stk)=v ) +#define POP(v) ( v=*(cell *)(data+(int)stk), stk+=sizeof(cell) ) +#define ABORT(amx,v) { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; } + +#define CHKMARGIN() if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR +#define CHKSTACK() if (stk>amx->stp) return AMX_ERR_STACKLOW +#define CHKHEAP() if (heahlw) return AMX_ERR_HEAPLOW + +#if defined __GNUC__ && !(defined ASM32 || defined JIT) + /* GNU C version uses the "labels as values" extension to create + * fast "indirect threaded" interpreter. + */ + +#define NEXT(cip) goto **cip++ + +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) +{ +static const void * const amx_opcodelist[] = { + &&op_none, &&op_load_pri, &&op_load_alt, &&op_load_s_pri, + &&op_load_s_alt,&&op_lref_pri, &&op_lref_alt, &&op_lref_s_pri, + &&op_lref_s_alt,&&op_load_i, &&op_lodb_i, &&op_const_pri, + &&op_const_alt, &&op_addr_pri, &&op_addr_alt, &&op_stor_pri, + &&op_stor_alt, &&op_stor_s_pri,&&op_stor_s_alt,&&op_sref_pri, + &&op_sref_alt, &&op_sref_s_pri,&&op_sref_s_alt,&&op_stor_i, + &&op_strb_i, &&op_lidx, &&op_lidx_b, &&op_idxaddr, + &&op_idxaddr_b, &&op_align_pri, &&op_align_alt, &&op_lctrl, + &&op_sctrl, &&op_move_pri, &&op_move_alt, &&op_xchg, + &&op_push_pri, &&op_push_alt, &&op_push_r, &&op_push_c, + &&op_push, &&op_push_s, &&op_pop_pri, &&op_pop_alt, + &&op_stack, &&op_heap, &&op_proc, &&op_ret, + &&op_retn, &&op_call, &&op_call_pri, &&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, &&op_shr, &&op_sshr, + &&op_shl_c_pri, &&op_shl_c_alt, &&op_shr_c_pri, &&op_shr_c_alt, + &&op_smul, &&op_sdiv, &&op_sdiv_alt, &&op_umul, + &&op_udiv, &&op_udiv_alt, &&op_add, &&op_sub, + &&op_sub_alt, &&op_and, &&op_or, &&op_xor, + &&op_not, &&op_neg, &&op_invert, &&op_add_c, + &&op_smul_c, &&op_zero_pri, &&op_zero_alt, &&op_zero, + &&op_zero_s, &&op_sign_pri, &&op_sign_alt, &&op_eq, + &&op_neq, &&op_less, &&op_leq, &&op_grtr, + &&op_geq, &&op_sless, &&op_sleq, &&op_sgrtr, + &&op_sgeq, &&op_eq_c_pri, &&op_eq_c_alt, &&op_inc_pri, + &&op_inc_alt, &&op_inc, &&op_inc_s, &&op_inc_i, + &&op_dec_pri, &&op_dec_alt, &&op_dec, &&op_dec_s, + &&op_dec_i, &&op_movs, &&op_cmps, &&op_fill, + &&op_halt, &&op_bounds, &&op_sysreq_pri,&&op_sysreq_c, + &&op_file, &&op_line, &&op_symbol, &&op_srange, + &&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri, + &&op_swap_alt, &&op_pushaddr, &&op_nop, &&op_sysreq_d, + &&op_symtag, &&op_break }; + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + unsigned char *code, *data; + cell pri,alt,stk,frm,hea; + cell reset_stk, reset_hea, *cip; + cell offs; + ucell codesize; + int num,i; + + /* HACK: return label table (for amx_BrowseRelocate) if amx structure + * has the AMX_FLAG_BROWSE flag set. + */ + assert(amx!=NULL); + if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { + assert(sizeof(cell)==sizeof(void *)); + assert(retval!=NULL); + *retval=(cell)amx_opcodelist; + return 0; + } /* if */ + + if (amx->callback==NULL) + return AMX_ERR_CALLBACK; + if ((amx->flags & AMX_FLAG_NTVREG)==0) + return AMX_ERR_NOTFOUND; + if ((amx->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + assert((amx->flags & AMX_FLAG_BROWSE)==0); + + /* set up the registers */ + hdr=(AMX_HEADER *)amx->base; + assert(hdr->magic==AMX_MAGIC); + codesize=(ucell)(hdr->dat-hdr->cod); + code=amx->base+(int)hdr->cod; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + hea=amx->hea; + stk=amx->stk; + reset_stk=stk; + reset_hea=hea; + alt=frm=0; /* just to avoid compiler warnings */ + num=0; /* just to avoid compiler warnings */ + + /* get the start address */ + if (index==AMX_EXEC_MAIN) { + if (hdr->cip<0) + return AMX_ERR_INDEX; + cip=(cell *)(code + (int)hdr->cip); + } else if (index==AMX_EXEC_CONT) { + /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ + frm=amx->frm; + stk=amx->stk; + hea=amx->hea; + pri=amx->pri; + alt=amx->alt; + reset_stk=amx->reset_stk; + reset_hea=amx->reset_hea; + cip=(cell *)(code + (int)amx->cip); + } else if (index<0) { + return AMX_ERR_INDEX; + } else { + if (index>=(int)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,publics,index); + cip=(cell *)(code + (int)func->address); + } /* if */ + /* check values just copied */ + CHKSTACK(); + CHKHEAP(); + assert(check_endian()); + + /* sanity checks */ + assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + #if PAWN_CELL_SIZE==16 + assert(sizeof(cell)==2); + #elif PAWN_CELL_SIZE==32 + assert(sizeof(cell)==4); + #elif PAWN_CELL_SIZE==64 + assert(sizeof(cell)==8); + #else + #error Unsupported cell size + #endif + + if (index!=AMX_EXEC_CONT) { + reset_stk+=amx->paramcount*sizeof(cell); + PUSH(amx->paramcount*sizeof(cell)); + amx->paramcount=0; /* push the parameter count to the stack & reset */ + PUSH(0); /* zero return address */ + } /* if */ + /* check stack/heap before starting to run */ + CHKMARGIN(); + + /* start running */ + NEXT(cip); + + op_none: + ABORT(amx,AMX_ERR_INVINSTR); + op_load_pri: + GETPARAM(offs); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_load_alt: + GETPARAM(offs); + alt= * (cell *)(data+(int)offs); + NEXT(cip); + op_load_s_pri: + GETPARAM(offs); + pri= * (cell *)(data+(int)frm+(int)offs); + NEXT(cip); + op_load_s_alt: + GETPARAM(offs); + alt= * (cell *)(data+(int)frm+(int)offs); + NEXT(cip); + op_lref_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_lref_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + alt= * (cell *)(data+(int)offs); + NEXT(cip); + op_lref_s_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_lref_s_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + alt= * (cell *)(data+(int)offs); + NEXT(cip); + op_load_i: + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)pri); + NEXT(cip); + op_lodb_i: + GETPARAM(offs); + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + pri= * (data+(int)pri); + break; + case 2: + pri= * (uint16_t *)(data+(int)pri); + break; + case 4: + pri= * (uint32_t *)(data+(int)pri); + break; + } /* switch */ + NEXT(cip); + op_const_pri: + GETPARAM(pri); + NEXT(cip); + op_const_alt: + GETPARAM(alt); + NEXT(cip); + op_addr_pri: + GETPARAM(pri); + pri+=frm; + NEXT(cip); + op_addr_alt: + GETPARAM(alt); + alt+=frm; + NEXT(cip); + op_stor_pri: + GETPARAM(offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_stor_alt: + GETPARAM(offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_stor_s_pri: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=pri; + NEXT(cip); + op_stor_s_alt: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=alt; + NEXT(cip); + op_sref_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_sref_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_sref_s_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_sref_s_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_stor_i: + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + *(cell *)(data+(int)alt)=pri; + NEXT(cip); + op_strb_i: + GETPARAM(offs); + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + *(data+(int)alt)=(unsigned char)pri; + break; + case 2: + *(uint16_t *)(data+(int)alt)=(uint16_t)pri; + break; + case 4: + *(uint32_t *)(data+(int)alt)=(uint32_t)pri; + break; + } /* switch */ + NEXT(cip); + op_lidx: + offs=pri*sizeof(cell)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_lidx_b: + GETPARAM(offs); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_idxaddr: + pri=pri*sizeof(cell)+alt; + NEXT(cip); + op_idxaddr_b: + GETPARAM(offs); + pri=(pri << (int)offs)+alt; + NEXT(cip); + op_align_pri: + GETPARAM(offs); + #if BYTE_ORDER==LITTLE_ENDIAN + if (offs<(int)sizeof(cell)) + pri ^= sizeof(cell)-offs; + #endif + NEXT(cip); + op_align_alt: + GETPARAM(offs); + #if BYTE_ORDER==LITTLE_ENDIAN + if (offs<(int)sizeof(cell)) + alt ^= sizeof(cell)-offs; + #endif + NEXT(cip); + op_lctrl: + GETPARAM(offs); + switch (offs) { + case 0: + pri=hdr->cod; + break; + case 1: + pri=hdr->dat; + break; + case 2: + pri=hea; + break; + case 3: + pri=amx->stp; + break; + case 4: + pri=stk; + break; + case 5: + pri=frm; + break; + case 6: + pri=(cell)((unsigned char *)cip - code); + break; + } /* switch */ + NEXT(cip); + op_sctrl: + GETPARAM(offs); + switch (offs) { + case 0: + case 1: + case 3: + /* cannot change these parameters */ + break; + case 2: + hea=pri; + break; + case 4: + stk=pri; + break; + case 5: + frm=pri; + break; + case 6: + cip=(cell *)(code + (int)pri); + break; + } /* switch */ + NEXT(cip); + op_move_pri: + pri=alt; + NEXT(cip); + op_move_alt: + alt=pri; + NEXT(cip); + op_xchg: + offs=pri; /* offs is a temporary variable */ + pri=alt; + alt=offs; + NEXT(cip); + op_push_pri: + PUSH(pri); + NEXT(cip); + op_push_alt: + PUSH(alt); + NEXT(cip); + op_push_c: + GETPARAM(offs); + PUSH(offs); + NEXT(cip); + op_push_r: + GETPARAM(offs); + while (offs--) + PUSH(pri); + NEXT(cip); + op_push: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)offs)); + NEXT(cip); + op_push_s: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)frm+(int)offs)); + NEXT(cip); + op_pop_pri: + POP(pri); + NEXT(cip); + op_pop_alt: + POP(alt); + NEXT(cip); + op_stack: + GETPARAM(offs); + alt=stk; + stk+=offs; + CHKMARGIN(); + CHKSTACK(); + NEXT(cip); + op_heap: + GETPARAM(offs); + alt=hea; + hea+=offs; + CHKMARGIN(); + CHKHEAP(); + NEXT(cip); + op_proc: + PUSH(frm); + frm=stk; + CHKMARGIN(); + NEXT(cip); + op_ret: + POP(frm); + POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(code+(int)offs); + NEXT(cip); + op_retn: + POP(frm); + POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(code+(int)offs); + stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ + NEXT(cip); + op_call: + PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */ + cip=JUMPABS(code, cip); /* jump to the address */ + NEXT(cip); + op_call_pri: + PUSH((unsigned char *)cip-code); + cip=(cell *)(code+(int)pri); + NEXT(cip); + op_jump: + /* since the GETPARAM() macro modifies cip, you cannot + * do GETPARAM(cip) directly */ + cip=JUMPABS(code, cip); + NEXT(cip); + op_jrel: + offs=*cip; + cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell)); + NEXT(cip); + op_jzer: + if (pri==0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jnz: + if (pri!=0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jeq: + if (pri==alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jneq: + if (pri!=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jless: + if ((ucell)pri < (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jleq: + if ((ucell)pri <= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jgrtr: + if ((ucell)pri > (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jgeq: + if ((ucell)pri >= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jsless: + if (prialt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_jsgeq: + if (pri>=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + NEXT(cip); + op_shl: + pri<<=alt; + NEXT(cip); + op_shr: + pri=(ucell)pri >> (ucell)alt; + NEXT(cip); + op_sshr: + pri>>=alt; + NEXT(cip); + op_shl_c_pri: + GETPARAM(offs); + pri<<=offs; + NEXT(cip); + op_shl_c_alt: + GETPARAM(offs); + alt<<=offs; + NEXT(cip); + op_shr_c_pri: + GETPARAM(offs); + pri=(ucell)pri >> (ucell)offs; + NEXT(cip); + op_shr_c_alt: + GETPARAM(offs); + alt=(ucell)alt >> (ucell)offs; + NEXT(cip); + op_smul: + pri*=alt; + NEXT(cip); + op_sdiv: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(pri % alt + alt) % alt; /* true modulus */ + pri=(pri - offs) / alt; /* division result */ + alt=offs; + NEXT(cip); + op_sdiv_alt: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(alt % pri + pri) % pri; /* true modulus */ + pri=(alt - offs) / pri; /* division result */ + alt=offs; + NEXT(cip); + op_umul: + pri=(ucell)pri * (ucell)alt; + NEXT(cip); + op_udiv: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)pri % (ucell)alt; /* temporary storage */ + pri=(ucell)pri / (ucell)alt; + alt=offs; + NEXT(cip); + op_udiv_alt: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)alt % (ucell)pri; /* temporary storage */ + pri=(ucell)alt / (ucell)pri; + alt=offs; + NEXT(cip); + op_add: + pri+=alt; + NEXT(cip); + op_sub: + pri-=alt; + NEXT(cip); + op_sub_alt: + pri=alt-pri; + NEXT(cip); + op_and: + pri&=alt; + NEXT(cip); + op_or: + pri|=alt; + NEXT(cip); + op_xor: + pri^=alt; + NEXT(cip); + op_not: + pri=!pri; + NEXT(cip); + op_neg: + pri=-pri; + NEXT(cip); + op_invert: + pri=~pri; + NEXT(cip); + op_add_c: + GETPARAM(offs); + pri+=offs; + NEXT(cip); + op_smul_c: + GETPARAM(offs); + pri*=offs; + NEXT(cip); + op_zero_pri: + pri=0; + NEXT(cip); + op_zero_alt: + alt=0; + NEXT(cip); + op_zero: + GETPARAM(offs); + *(cell *)(data+(int)offs)=0; + NEXT(cip); + op_zero_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=0; + NEXT(cip); + op_sign_pri: + if ((pri & 0xff)>=0x80) + pri|= ~ (ucell)0xff; + NEXT(cip); + op_sign_alt: + if ((alt & 0xff)>=0x80) + alt|= ~ (ucell)0xff; + NEXT(cip); + op_eq: + pri= pri==alt ? 1 : 0; + NEXT(cip); + op_neq: + pri= pri!=alt ? 1 : 0; + NEXT(cip); + op_less: + pri= (ucell)pri < (ucell)alt ? 1 : 0; + NEXT(cip); + op_leq: + pri= (ucell)pri <= (ucell)alt ? 1 : 0; + NEXT(cip); + op_grtr: + pri= (ucell)pri > (ucell)alt ? 1 : 0; + NEXT(cip); + op_geq: + pri= (ucell)pri >= (ucell)alt ? 1 : 0; + NEXT(cip); + op_sless: + pri= prialt ? 1 : 0; + NEXT(cip); + op_sgeq: + pri= pri>=alt ? 1 : 0; + NEXT(cip); + op_eq_c_pri: + GETPARAM(offs); + pri= pri==offs ? 1 : 0; + NEXT(cip); + op_eq_c_alt: + GETPARAM(offs); + pri= alt==offs ? 1 : 0; + NEXT(cip); + op_inc_pri: + pri++; + NEXT(cip); + op_inc_alt: + alt++; + NEXT(cip); + op_inc: + GETPARAM(offs); + *(cell *)(data+(int)offs) += 1; + NEXT(cip); + op_inc_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) += 1; + NEXT(cip); + op_inc_i: + *(cell *)(data+(int)pri) += 1; + NEXT(cip); + op_dec_pri: + pri--; + NEXT(cip); + op_dec_alt: + alt--; + NEXT(cip); + op_dec: + GETPARAM(offs); + *(cell *)(data+(int)offs) -= 1; + NEXT(cip); + op_dec_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) -= 1; + NEXT(cip); + op_dec_i: + *(cell *)(data+(int)pri) -= 1; + NEXT(cip); + op_movs: + GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + memcpy(data+(int)alt, data+(int)pri, (int)offs); + NEXT(cip); + op_cmps: + GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); + NEXT(cip); + op_fill: + GETPARAM(offs); + /* verify top & bottom memory addresses */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + for (i=(int)alt; offs>=(int)sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + *(cell *)(data+i) = pri; + NEXT(cip); + op_halt: + GETPARAM(offs); + if (retval!=NULL) + *retval=pri; + /* store complete status (stk and hea are already set in the ABORT macro) */ + amx->frm=frm; + amx->pri=pri; + amx->alt=alt; + amx->cip=(cell)((unsigned char*)cip-code); + if (offs==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,(int)offs); + op_bounds: + GETPARAM(offs); + if ((ucell)pri>(ucell)offs) + ABORT(amx,AMX_ERR_BOUNDS); + NEXT(cip); + op_sysreq_pri: + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + NEXT(cip); + op_sysreq_c: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + NEXT(cip); + op_sysreq_d: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + NEXT(cip); + op_file: + GETPARAM(offs); + cip=(cell *)((unsigned char *)cip + (int)offs); + assert(0); /* this code should not occur during execution */ + NEXT(cip); + op_line: + SKIPPARAM(2); + NEXT(cip); + op_symbol: + GETPARAM(offs); + cip=(cell *)((unsigned char *)cip + (int)offs); + NEXT(cip); + op_srange: + SKIPPARAM(2); + NEXT(cip); + op_symtag: + SKIPPARAM(1); + NEXT(cip); + op_jump_pri: + cip=(cell *)(code+(int)pri); + NEXT(cip); + op_switch: { + cell *cptr; + cptr=JUMPABS(code,cip)+1; /* +1, to skip the "casetbl" opcode */ + cip=JUMPABS(code,cptr+1); /* preset to "none-matched" case */ + num=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) + /* nothing */; + if (num>0) + cip=JUMPABS(code,cptr+1); /* case found */ + NEXT(cip); + } + op_casetbl: + assert(0); /* this should not occur during execution */ + NEXT(cip); + op_swap_pri: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=pri; + pri=offs; + NEXT(cip); + op_swap_alt: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=alt; + alt=offs; + NEXT(cip); + op_pushaddr: + GETPARAM(offs); + PUSH(frm+offs); + NEXT(cip); + op_nop: + NEXT(cip); + op_break: + if (amx->debug!=NULL) { + /* store status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->cip=(cell)((unsigned char*)cip-code); + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + } /* if */ + NEXT(cip); +} + +#else + /* ANSI C & assembler versions */ + +#if defined ASM32 || defined JIT + /* For Watcom C/C++ use register calling convention (faster); for + * Microsoft C/C++ (and most other C compilers) use "cdecl". + * The important point is that you assemble AMXEXEC.ASM with the matching + * calling convention, or the right JIT, respectively. + * AMXJITR.ASM is for Watcom's register calling convention, AMXJITS.ASM and + * AMXJITSN.ASM are for "cdecl". + */ + #if defined __WATCOMC__ + #if !defined STACKARGS /* for AMX32.DLL */ + extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + /* The following pragma tells the compiler into which registers + * the parameters have to go. */ + #pragma aux amx_exec_asm parm [eax] [edx] [ebx] [ecx]; + extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); + #pragma aux amx_exec_jit parm [eax] [edx] [ebx] [ecx]; + #else + extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + extern cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); + #endif + #elif defined __GNUC__ + /* force "cdecl" by adding an "attribute" to the declaration */ + extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl)); + extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl)); + #else + /* force "cdecl" by specifying it as a "function class" with the "__cdecl" keyword */ + extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + extern cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); + #endif +#endif + +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + unsigned char *code, *data; + cell pri,alt,stk,frm,hea; + cell reset_stk, reset_hea, *cip; + ucell codesize; + int i; + #if defined ASM32 || defined JIT + cell parms[9]; /* registers and parameters for assembler AMX */ + #else + OPCODE op; + cell offs; + int num; + #endif + #if defined ASM32 + extern void const *amx_opcodelist[]; + #ifdef __WATCOMC__ + #pragma aux amx_opcodelist "_*" + #endif + #endif + #if defined JIT + extern void const *amx_opcodelist_jit[]; + #ifdef __WATCOMC__ + #pragma aux amx_opcodelist_jit "_*" + #endif + #endif + + assert(amx!=NULL); + #if defined ASM32 || defined JIT + /* HACK: return label table (for amx_BrowseRelocate) if amx structure + * is not passed. + */ + if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { + assert(sizeof(cell)==sizeof(void *)); + assert(retval!=NULL); + #if defined ASM32 && defined JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + *retval=(cell)amx_opcodelist_jit; + else + *retval=(cell)amx_opcodelist; + #elif defined ASM32 + *retval=(cell)amx_opcodelist; + #else + *retval=(cell)amx_opcodelist_jit; + #endif + return 0; + } /* if */ + #endif + + if (amx->callback==NULL) + return AMX_ERR_CALLBACK; + if ((amx->flags & AMX_FLAG_NTVREG)==0) + return AMX_ERR_NOTFOUND; + if ((amx->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + assert((amx->flags & AMX_FLAG_BROWSE)==0); + + /* set up the registers */ + hdr=(AMX_HEADER *)amx->base; + assert(hdr->magic==AMX_MAGIC); + codesize=(ucell)(hdr->dat-hdr->cod); + code=amx->base+(int)hdr->cod; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + hea=amx->hea; + stk=amx->stk; + reset_stk=stk; + reset_hea=hea; + frm=alt=pri=0; /* silence up compiler */ + + /* get the start address */ + if (index==AMX_EXEC_MAIN) { + if (hdr->cip<0) + return AMX_ERR_INDEX; + cip=(cell *)(code + (int)hdr->cip); + } else if (index==AMX_EXEC_CONT) { + /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ + frm=amx->frm; + stk=amx->stk; + hea=amx->hea; + pri=amx->pri; + alt=amx->alt; + reset_stk=amx->reset_stk; + reset_hea=amx->reset_hea; + cip=(cell *)(code + (int)amx->cip); + } else if (index<0) { + return AMX_ERR_INDEX; + } else { + if (index>=(cell)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,publics,index); + cip=(cell *)(code + (int)func->address); + } /* if */ + /* check values just copied */ + CHKSTACK(); + CHKHEAP(); + assert(check_endian()); + + /* sanity checks */ + assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + #if PAWN_CELL_SIZE==16 + assert(sizeof(cell)==2); + #elif PAWN_CELL_SIZE==32 + assert(sizeof(cell)==4); + #elif PAWN_CELL_SIZE==64 + assert(sizeof(cell)==8); + #else + #error Unsupported cell size + #endif + + if (index!=AMX_EXEC_CONT) { + reset_stk+=amx->paramcount*sizeof(cell); + PUSH(amx->paramcount*sizeof(cell)); + amx->paramcount=0; /* push the parameter count to the stack & reset */ + #if defined ASM32 || defined JIT + PUSH(RELOC_VALUE(code,0));/* relocated zero return address */ + #else + PUSH(0); /* zero return address */ + #endif + } /* if */ + /* check stack/heap before starting to run */ + CHKMARGIN(); + + /* start running */ +#if defined ASM32 || defined JIT + /* either the assembler abstract machine or the JIT; both by Marc Peter */ + + parms[0] = pri; + parms[1] = alt; + parms[2] = (cell)cip; + parms[3] = (cell)data; + parms[4] = stk; + parms[5] = frm; + parms[6] = (cell)amx; + parms[7] = (cell)code; + parms[8] = (cell)codesize; + + #if defined ASM32 && defined JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + i = amx_exec_jit(parms,retval,amx->stp,hea); + else + i = amx_exec_asm(parms,retval,amx->stp,hea); + #elif defined ASM32 + i = amx_exec_asm(parms,retval,amx->stp,hea); + #else + i = amx_exec_jit(parms,retval,amx->stp,hea); + #endif + if (i == AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + } else { + /* remove parameters from the stack; do this the "hard" way, because + * the assembler version has no internal knowledge of the local + * variables, so any "clean" way would be a kludge anyway. + */ + amx->stk=reset_stk; + amx->hea=reset_hea; + } /* if */ + return i; + +#else + + for ( ;; ) { + op=(OPCODE) *cip++; + switch (op) { + case OP_LOAD_PRI: + GETPARAM(offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LOAD_ALT: + GETPARAM(offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LOAD_S_PRI: + GETPARAM(offs); + pri= * (cell *)(data+(int)frm+(int)offs); + break; + case OP_LOAD_S_ALT: + GETPARAM(offs); + alt= * (cell *)(data+(int)frm+(int)offs); + break; + case OP_LREF_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LREF_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LREF_S_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LREF_S_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LOAD_I: + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)pri); + break; + case OP_LODB_I: + GETPARAM(offs); + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + pri= * (data+(int)pri); + break; + case 2: + pri= * (uint16_t *)(data+(int)pri); + break; + case 4: + pri= * (uint32_t *)(data+(int)pri); + break; + } /* switch */ + break; + case OP_CONST_PRI: + GETPARAM(pri); + break; + case OP_CONST_ALT: + GETPARAM(alt); + break; + case OP_ADDR_PRI: + GETPARAM(pri); + pri+=frm; + break; + case OP_ADDR_ALT: + GETPARAM(alt); + alt+=frm; + break; + case OP_STOR_PRI: + GETPARAM(offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_STOR_ALT: + GETPARAM(offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_STOR_S_PRI: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=pri; + break; + case OP_STOR_S_ALT: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=alt; + break; + case OP_SREF_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_SREF_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_SREF_S_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_SREF_S_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_STOR_I: + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + *(cell *)(data+(int)alt)=pri; + break; + case OP_STRB_I: + GETPARAM(offs); + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + *(data+(int)alt)=(unsigned char)pri; + break; + case 2: + *(uint16_t *)(data+(int)alt)=(uint16_t)pri; + break; + case 4: + *(uint32_t *)(data+(int)alt)=(uint32_t)pri; + break; + } /* switch */ + break; + case OP_LIDX: + offs=pri*sizeof(cell)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + break; + case OP_LIDX_B: + GETPARAM(offs); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + break; + case OP_IDXADDR: + pri=pri*sizeof(cell)+alt; + break; + case OP_IDXADDR_B: + GETPARAM(offs); + pri=(pri << (int)offs)+alt; + break; + case OP_ALIGN_PRI: + GETPARAM(offs); + #if BYTE_ORDER==LITTLE_ENDIAN + if ((size_t)offscod; + break; + case 1: + pri=hdr->dat; + break; + case 2: + pri=hea; + break; + case 3: + pri=amx->stp; + break; + case 4: + pri=stk; + break; + case 5: + pri=frm; + break; + case 6: + pri=(cell)((unsigned char *)cip - code); + break; + } /* switch */ + break; + case OP_SCTRL: + GETPARAM(offs); + switch (offs) { + case 0: + case 1: + case 3: + /* cannot change these parameters */ + break; + case 2: + hea=pri; + break; + case 4: + stk=pri; + break; + case 5: + frm=pri; + break; + case 6: + cip=(cell *)(code + (int)pri); + break; + } /* switch */ + break; + case OP_MOVE_PRI: + pri=alt; + break; + case OP_MOVE_ALT: + alt=pri; + break; + case OP_XCHG: + offs=pri; /* offs is a temporary variable */ + pri=alt; + alt=offs; + break; + case OP_PUSH_PRI: + PUSH(pri); + break; + case OP_PUSH_ALT: + PUSH(alt); + break; + case OP_PUSH_C: + GETPARAM(offs); + PUSH(offs); + break; + case OP_PUSH_R: + GETPARAM(offs); + while (offs--) + PUSH(pri); + break; + case OP_PUSH: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)offs)); + break; + case OP_PUSH_S: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)frm+(int)offs)); + break; + case OP_POP_PRI: + POP(pri); + break; + case OP_POP_ALT: + POP(alt); + break; + case OP_STACK: + GETPARAM(offs); + alt=stk; + stk+=offs; + CHKMARGIN(); + CHKSTACK(); + break; + case OP_HEAP: + GETPARAM(offs); + alt=hea; + hea+=offs; + CHKMARGIN(); + CHKHEAP(); + break; + case OP_PROC: + PUSH(frm); + frm=stk; + CHKMARGIN(); + break; + case OP_RET: + POP(frm); + POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(code+(int)offs); + break; + case OP_RETN: + POP(frm); + POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(code+(int)offs); + stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ + amx->stk=stk; + break; + case OP_CALL: + PUSH(((unsigned char *)cip-code)+sizeof(cell));/* skip address */ + cip=JUMPABS(code, cip); /* jump to the address */ + break; + case OP_CALL_PRI: + PUSH((unsigned char *)cip-code); + cip=(cell *)(code+(int)pri); + break; + case OP_JUMP: + /* since the GETPARAM() macro modifies cip, you cannot + * do GETPARAM(cip) directly */ + cip=JUMPABS(code, cip); + break; + case OP_JREL: + offs=*cip; + cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell)); + break; + case OP_JZER: + if (pri==0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JNZ: + if (pri!=0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JEQ: + if (pri==alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JNEQ: + if (pri!=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JLESS: + if ((ucell)pri < (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JLEQ: + if ((ucell)pri <= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JGRTR: + if ((ucell)pri > (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JGEQ: + if ((ucell)pri >= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JSLESS: + if (prialt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_JSGEQ: + if (pri>=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((unsigned char *)cip+sizeof(cell)); + break; + case OP_SHL: + pri<<=alt; + break; + case OP_SHR: + pri=(ucell)pri >> (int)alt; + break; + case OP_SSHR: + pri>>=alt; + break; + case OP_SHL_C_PRI: + GETPARAM(offs); + pri<<=offs; + break; + case OP_SHL_C_ALT: + GETPARAM(offs); + alt<<=offs; + break; + case OP_SHR_C_PRI: + GETPARAM(offs); + pri=(ucell)pri >> (int)offs; + break; + case OP_SHR_C_ALT: + GETPARAM(offs); + alt=(ucell)alt >> (int)offs; + break; + case OP_SMUL: + pri*=alt; + break; + case OP_SDIV: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(pri % alt + alt) % alt; /* true modulus */ + pri=(pri - offs) / alt; /* division result */ + alt=offs; + break; + case OP_SDIV_ALT: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(alt % pri + pri) % pri; /* true modulus */ + pri=(alt - offs) / pri; /* division result */ + alt=offs; + break; + case OP_UMUL: + pri=(ucell)pri * (ucell)alt; + break; + case OP_UDIV: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)pri % (ucell)alt; /* temporary storage */ + pri=(ucell)pri / (ucell)alt; + alt=offs; + break; + case OP_UDIV_ALT: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)alt % (ucell)pri; /* temporary storage */ + pri=(ucell)alt / (ucell)pri; + alt=offs; + break; + case OP_ADD: + pri+=alt; + break; + case OP_SUB: + pri-=alt; + break; + case OP_SUB_ALT: + pri=alt-pri; + break; + case OP_AND: + pri&=alt; + break; + case OP_OR: + pri|=alt; + break; + case OP_XOR: + pri^=alt; + break; + case OP_NOT: + pri=!pri; + break; + case OP_NEG: + pri=-pri; + break; + case OP_INVERT: + pri=~pri; + break; + case OP_ADD_C: + GETPARAM(offs); + pri+=offs; + break; + case OP_SMUL_C: + GETPARAM(offs); + pri*=offs; + break; + case OP_ZERO_PRI: + pri=0; + break; + case OP_ZERO_ALT: + alt=0; + break; + case OP_ZERO: + GETPARAM(offs); + *(cell *)(data+(int)offs)=0; + break; + case OP_ZERO_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=0; + break; + case OP_SIGN_PRI: + if ((pri & 0xff)>=0x80) + pri|= ~ (ucell)0xff; + break; + case OP_SIGN_ALT: + if ((alt & 0xff)>=0x80) + alt|= ~ (ucell)0xff; + break; + case OP_EQ: + pri= pri==alt ? 1 : 0; + break; + case OP_NEQ: + pri= pri!=alt ? 1 : 0; + break; + case OP_LESS: + pri= (ucell)pri < (ucell)alt ? 1 : 0; + break; + case OP_LEQ: + pri= (ucell)pri <= (ucell)alt ? 1 : 0; + break; + case OP_GRTR: + pri= (ucell)pri > (ucell)alt ? 1 : 0; + break; + case OP_GEQ: + pri= (ucell)pri >= (ucell)alt ? 1 : 0; + break; + case OP_SLESS: + pri= prialt ? 1 : 0; + break; + case OP_SGEQ: + pri= pri>=alt ? 1 : 0; + break; + case OP_EQ_C_PRI: + GETPARAM(offs); + pri= pri==offs ? 1 : 0; + break; + case OP_EQ_C_ALT: + GETPARAM(offs); + pri= alt==offs ? 1 : 0; + break; + case OP_INC_PRI: + pri++; + break; + case OP_INC_ALT: + alt++; + break; + case OP_INC: + GETPARAM(offs); + *(cell *)(data+(int)offs) += 1; + break; + case OP_INC_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) += 1; + break; + case OP_INC_I: + *(cell *)(data+(int)pri) += 1; + break; + case OP_DEC_PRI: + pri--; + break; + case OP_DEC_ALT: + alt--; + break; + case OP_DEC: + GETPARAM(offs); + *(cell *)(data+(int)offs) -= 1; + break; + case OP_DEC_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) -= 1; + break; + case OP_DEC_I: + *(cell *)(data+(int)pri) -= 1; + break; + case OP_MOVS: + GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + memcpy(data+(int)alt, data+(int)pri, (int)offs); + break; + case OP_CMPS: + GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); + break; + case OP_FILL: + GETPARAM(offs); + /* verify top & bottom memory addresses (destination only) */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + *(cell *)(data+i) = pri; + break; + case OP_HALT: + GETPARAM(offs); + if (retval!=NULL) + *retval=pri; + /* store complete status (stk and hea are already set in the ABORT macro) */ + amx->frm=frm; + amx->pri=pri; + amx->alt=alt; + amx->cip=(cell)((unsigned char*)cip-code); + if (offs==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,(int)offs); + case OP_BOUNDS: + GETPARAM(offs); + if ((ucell)pri>(ucell)offs) + ABORT(amx,AMX_ERR_BOUNDS); + break; + case OP_SYSREQ_PRI: + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + break; + case OP_SYSREQ_C: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + break; + case OP_SYSREQ_D: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + break; + case OP_LINE: + SKIPPARAM(2); + break; + case OP_SYMBOL: + GETPARAM(offs); + cip=(cell *)((unsigned char *)cip + (int)offs); + break; + case OP_SRANGE: + SKIPPARAM(2); + break; + case OP_SYMTAG: + SKIPPARAM(1); + break; + case OP_JUMP_PRI: + cip=(cell *)(code+(int)pri); + break; + case OP_SWITCH: { + cell *cptr; + + cptr=JUMPABS(code,cip)+1; /* +1, to skip the "casetbl" opcode */ + cip=JUMPABS(code,cptr+1); /* preset to "none-matched" case */ + num=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) + /* nothing */; + if (num>0) + cip=JUMPABS(code,cptr+1); /* case found */ + break; + } /* case */ + case OP_SWAP_PRI: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=pri; + pri=offs; + break; + case OP_SWAP_ALT: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=alt; + alt=offs; + break; + case OP_PUSHADDR: + GETPARAM(offs); + PUSH(frm+offs); + break; + case OP_NOP: + break; + case OP_BREAK: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + if (amx->debug!=NULL) { + /* store status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->cip=(cell)((unsigned char*)cip-code); + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + } /* if */ + break; + default: + /* case OP_FILE: should not occur during execution + * case OP_CASETBL: should not occur during execution + */ + assert(0); + ABORT(amx,AMX_ERR_INVINSTR); + } /* switch */ + } /* for */ +#endif +} + +#endif /* __GNUC__ */ + +#endif /* AMX_EXEC || AMX_INIT */ + +#if defined AMX_SETCALLBACK +int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) +{ + assert(amx!=NULL); + assert(callback!=NULL); + amx->callback=callback; + return AMX_ERR_NONE; +} +#endif /* AMX_SETCALLBACK */ + +#if defined AMX_SETDEBUGHOOK +int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) +{ + assert(amx!=NULL); + amx->debug=debug; + return AMX_ERR_NONE; +} +#endif /* AMX_SETDEBUGHOOK */ + +#if defined AMX_RAISEERROR +int AMXAPI amx_RaiseError(AMX *amx, int error) +{ + assert(error>0); + amx->error=error; + return AMX_ERR_NONE; +} +#endif /* AMX_RAISEERROR */ + +#if defined AMX_GETADDR +int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) +{ + AMX_HEADER *hdr; + unsigned char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + assert(phys_addr!=NULL); + if (amx_addr>=amx->hea && amx_addrstk || amx_addr<0 || amx_addr>=amx->stp) { + *phys_addr=NULL; + return AMX_ERR_MEMACCESS; + } /* if */ + + *phys_addr=(cell *)(data + (int)amx_addr); + return AMX_ERR_NONE; +} +#endif /* AMX_GETADDR */ + +#if defined AMX_ALLOT || defined AMX_EXEC +int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr) +{ + AMX_HEADER *hdr; + unsigned char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN) + return AMX_ERR_MEMORY; + assert(amx_addr!=NULL); + assert(phys_addr!=NULL); + *amx_addr=amx->hea; + *phys_addr=(cell *)(data + (int)amx->hea); + amx->hea += cells*sizeof(cell); + return AMX_ERR_NONE; +} + +int AMXAPI amx_Release(AMX *amx,cell amx_addr) +{ + if (amx->hea > amx_addr) + amx->hea=amx_addr; + return AMX_ERR_NONE; +} +#endif /* AMX_ALLOT */ + +#if defined AMX_XXXSTRING || defined AMX_UTF8XXX + +#define CHARBITS (8*sizeof(char)) +#if PAWN_CELL_SIZE==16 + #define CHARMASK (0xffffu << 8*(2-sizeof(char))) +#elif PAWN_CELL_SIZE==32 + #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) +#elif PAWN_CELL_SIZE==64 + #define CHARMASK (0xffffffffffffffffuLL << 8*(8-sizeof(char))) +#else + #error Unsupported cell size +#endif + +int AMXAPI amx_StrLen(const cell *cstr, int *length) +{ + int len; + #if BYTE_ORDER==LITTLE_ENDIAN + cell c; + #endif + + assert(length!=NULL); + if (cstr==NULL) { + *length=0; + return AMX_ERR_PARAMS; + } /* if */ + + if ((ucell)*cstr>UNPACKEDMAX) { + /* packed string */ + assert(sizeof(char)==1); + len=strlen((char *)cstr); /* find '\0' */ + assert(check_endian()); + #if BYTE_ORDER==LITTLE_ENDIAN + /* on Little Endian machines, toggle the last bytes */ + c=cstr[len/sizeof(cell)]; /* get last cell */ + len=len - len % sizeof(cell); /* len = multiple of "cell" bytes */ + while ((c & CHARMASK)!=0) { + len++; + c <<= 8*sizeof(char); + } /* if */ + #endif + } else { + for (len=0; cstr[len]!=0; len++) + /* nothing */; + } /* if */ + *length = len; + return AMX_ERR_NONE; +} +#endif + +#if defined AMX_XXXSTRING || defined AMX_EXEC +int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar,size_t size) +{ /* the memory blocks should not overlap */ + int len, i; + + assert(UNLIMITED>0); + #if defined AMX_ANSIONLY + (void)use_wchar; + len=strlen(source); + #else + len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); + #endif + if (pack) { + /* create a packed string */ + if (size=size*sizeof(cell)) + len=size*sizeof(cell)-1; + dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ + #if defined AMX_ANSIONLY + memcpy(dest,source,len); + #else + if (use_wchar) { + for (i=0; i=0) + swapcell((ucell *)&dest[len--]); + #endif + + } else { + /* create an unpacked string */ + if (size=size) + len=size-1; + #if defined AMX_ANSIONLY + for (i=0; iUNPACKEDMAX) { + /* source string is packed */ + cell c = 0; /* to avoid a compiler warning */ + int i=sizeof(cell)-1; + while ((size_t)len> i*CHARBITS); + #else + if (use_wchar) + ((wchar_t*)dest)[len++]=(char)(c >> i*CHARBITS); + else + dest[len++]=(char)(c >> i*CHARBITS); + #endif + if (dest[len-1]=='\0') + break; /* terminating zero character found */ + i=(i+sizeof(cell)-1) % sizeof(cell); + } /* for */ + } else { + /* source string is unpacked */ + #if defined AMX_ANSIONLY + while (*source!=0 && (size_t)len=size) + len=size-1; + if (len>=0) + dest[len]='\0'; /* store terminator */ + return AMX_ERR_NONE; +} +#endif /* AMX_XXXSTRING */ + +#if defined AMX_UTF8XXX + #if defined __BORLANDC__ + #pragma warn -amb -8000 /* ambiguous operators need parentheses */ + #endif +/* amx_UTF8Get() + * Extract a single UTF-8 encoded character from a string and return a pointer + * to the character just behind that UTF-8 character. The parameters "endptr" + * and "value" may be NULL. + * If the code is not valid UTF-8, "endptr" has the value of the input + * parameter "string" and "value" is zero. + */ +int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value) +{ +static const char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 }; +static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x4000000L }; + unsigned char c; + cell result; + int followup; + + assert(string!=NULL); + if (value!=NULL) /* preset, in case of an error */ + *value=0; + if (endptr!=NULL) + *endptr=string; + + c = *(const unsigned char*)string++; + if (c<0x80) { + /* ASCII */ + result=c; + } else { + if (c<0xc0 || c>=0xfe) + return AMX_ERR_PARAMS; /* invalid or "follower" code, quit with error */ + /* At this point we know that the two top bits of c are ones. The two + * bottom bits are always part of the code. We only need to consider + * the 4 remaining bits; i.e., a 16-byte table. This is "utf8_count[]". + * (Actually the utf8_count[] table records the number of follow-up + * bytes minus 1. This is just for convenience.) + */ + assert((c & 0xc0)==0xc0); + followup=(int)utf8_count[(c >> 2) & 0x0f]; + /* The mask depends on the code length; this is just a very simple + * relation. + */ + #define utf8_mask (0x1f >> followup) + result= c & utf8_mask; + /* Collect the follow-up codes using a drop-through switch statement; + * this avoids a loop. In each case, verify the two leading bits. + */ + assert(followup>=0 && followup<=4); + switch (followup) { + case 4: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 3: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 2: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 1: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 0: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + } /* switch */ + /* Do additional checks: shortest encoding & reserved positions. The + * lowmark limits also depends on the code length; it can be read from + * a table with 5 elements. This is "utf8_lowmark[]". + */ + if (result=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff) + goto error; + } /* if */ + + if (value!=NULL) + *value=result; + if (endptr!=NULL) + *endptr=string; + + return AMX_ERR_NONE; + +error: + return AMX_ERR_PARAMS; +} + +/* amx_UTF8Put() + * Encode a single character into a byte string. The character may result in + * a string of up to 6 bytes. The function returns an error code if "maxchars" + * is lower than the required number of characters; in this case nothing is + * stored. + * The function does not zero-terminate the string. + */ +int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value) +{ + assert(string!=NULL); + if (endptr!=NULL) /* preset, in case of an error */ + *endptr=string; + + if (value<0x80) { + /* 0xxxxxxx */ + if (maxchars < 1) goto error; + *string++ = (char)value; + } else if (value<0x800) { + /* 110xxxxx 10xxxxxx */ + if (maxchars < 2) goto error; + *string++ = (char)((value>>6) & 0x1f | 0xc0); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x10000) { + /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */ + if (maxchars < 3) goto error; + if (value>=0xd800 && value<=0xdfff || value==0xfffe || value==0xffff) + goto error; /* surrogate pairs and invalid characters */ + *string++ = (char)((value>>12) & 0x0f | 0xe0); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x200000) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (maxchars < 4) goto error; + *string++ = (char)((value>>18) & 0x07 | 0xf0); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x4000000) { + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (maxchars < 5) goto error; + *string++ = (char)((value>>24) & 0x03 | 0xf8); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else { + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */ + if (maxchars < 6) goto error; + *string++ = (char)((value>>30) & 0x01 | 0xfc); + *string++ = (char)((value>>24) & 0x3f | 0x80); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } /* if */ + + if (endptr!=NULL) + *endptr=string; + return AMX_ERR_NONE; + +error: + return AMX_ERR_PARAMS; +} + +/* amx_UTF8Check() + * Run through a zero-terminated string and check the validity of the UTF-8 + * encoding. The function returns an error code, it is AMX_ERR_NONE if the + * string is valid UTF-8 (or valid ASCII for that matter). + */ +int AMXAPI amx_UTF8Check(const char *string, int *length) +{ + int err=AMX_ERR_NONE; + int len=0; + while (err==AMX_ERR_NONE && *string!='\0') { + err=amx_UTF8Get(string,&string,NULL); + len++; + } /* while */ + if (length!=NULL) + *length=len; + return err; +} + +/* amx_UTF8Len() + * Run through a wide string and return how many 8-bit characters are needed to + * store the string in UTF-8 format. The returned cound excludes the terminating + * zero byte. The function returns an error code. + */ +int AMXAPI amx_UTF8Len(const cell *cstr, int *length) +{ + int err; + + assert(length!=NULL); + err=amx_StrLen(cstr, length); + if (err==AMX_ERR_NONE && (ucell)*cstr<=UNPACKEDMAX) { + char buffer[10]; /* maximum UTF-8 code is 6 characters */ + char *endptr; + int len=*length, count=0; + while (len-->0) { + amx_UTF8Put(buffer, &endptr, sizeof buffer, *cstr++); + count+=(int)(endptr-buffer); + } /* while */ + *length=count; + } /* while */ + return err; +} +#endif /* AMX_UTF8XXX */ diff --git a/compiler/amxxpc/amx.h b/compiler/amxxpc/amx.h new file mode 100755 index 00000000..cf194750 --- /dev/null +++ b/compiler/amxxpc/amx.h @@ -0,0 +1,439 @@ +/* Pawn Abstract Machine (for the Pawn language) + * + * Copyright (c) ITB CompuPhase, 1997-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$ + */ + +#if defined FREEBSD && !defined __FreeBSD__ + #define __FreeBSD__ +#endif +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ + #include +#endif + +#ifndef AMX_H_INCLUDED +#define AMX_H_INCLUDED + +#if defined HAVE_STDINT_H + #include +#else + #if defined __LCC__ || defined __DMC__ || defined LINUX + #if defined HAVE_INTTYPES_H + #include + #else + #include + #endif + #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L + /* The ISO C99 defines the int16_t and int_32t types. If the compiler got + * here, these types are probably undefined. + */ + #if defined __MACH__ + #include + typedef unsigned short int uint16_t; + typedef unsigned long int uint32_t; + #elif defined __FreeBSD__ + #include + #else + typedef short int int16_t; + typedef unsigned short int uint16_t; + #if defined SN_TARGET_PS2 + typedef int int32_t; + typedef unsigned int uint32_t; + #else + typedef long int int32_t; + typedef unsigned long int uint32_t; + #endif + #if defined __WIN32__ || defined _WIN32 || defined WIN32 + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + #define HAVE_I64 + #elif defined __GNUC__ + typedef long long int64_t; + typedef unsigned long long uint64_t; + #define HAVE_I64 + #endif + #endif + #endif + #define HAVE_STDINT_H +#endif +#if defined _LP64 || defined WIN64 || defined _WIN64 + #if !defined __64BIT__ + #define __64BIT__ + #endif +#endif + +#if HAVE_ALLOCA_H + #include +#endif +#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */ + #if !defined alloca + #define alloca(n) _alloca(n) + #endif +#endif + +#if !defined arraysize + #define arraysize(array) (sizeof(array) / sizeof((array)[0])) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined PAWN_DLL + #if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL __stdcall + #endif + #if !defined AMXAPI + #define AMXAPI __stdcall + #endif +#endif + +/* calling convention for native functions */ +#if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL +#endif +/* calling convention for all interface functions and callback functions */ +#if !defined AMXAPI + #if defined STDECL + #define AMXAPI __stdcall + #elif defined CDECL + #define AMXAPI __cdecl + #elif defined GCC_HASCLASSVISIBILITY + #define AMXAPI __attribute__ ((visibility("default"))) + #else + #define AMXAPI + #endif +#endif +#if !defined AMXEXPORT + #define AMXEXPORT +#endif + +/* File format version Required AMX version + * 0 (original version) 0 + * 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1 + * 2 (compressed files) 2 + * 3 (public variables) 2 + * 4 (opcodes SWAP.pri/alt and PUSHADDR) 4 + * 5 (tagnames table) 4 + * 6 (reformatted header) 6 + * 7 (name table, opcodes SYMTAG & SYSREQ.D) 7 + * 8 (opcode STMT, renewed debug interface) 8 + */ +#define CUR_FILE_VERSION 8 /* current file version; also the current AMX version */ +#define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */ +#define MIN_AMX_VERSION 8 /* minimum AMX version needed to support the current file format */ + +#if !defined PAWN_CELL_SIZE + #define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */ +#endif +#if PAWN_CELL_SIZE==16 + typedef uint16_t ucell; + typedef int16_t cell; +#elif PAWN_CELL_SIZE==32 + typedef uint32_t ucell; + typedef int32_t cell; +#elif PAWN_CELL_SIZE==64 + typedef uint64_t ucell; + typedef int64_t cell; +#else + #error Unsupported cell size (PAWN_CELL_SIZE) +#endif + +#define UNPACKEDMAX ((1L << (sizeof(cell)-1)*8) - 1) +#define UNLIMITED (~1u >> 1) + +struct tagAMX; +typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params); +typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index, + cell *result, cell *params); +typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); +#if !defined _FAR + #define _FAR +#endif + +#if defined _MSC_VER + #pragma warning(disable:4103) /* disable warning message 4103 that complains + * about pragma pack in a header file */ + #pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */ +#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__) && !defined AMX_NO_ALIGN + #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_NATIVE_INFO { + const char _FAR *name PACKED; + AMX_NATIVE func PACKED; +} PACKED AMX_NATIVE_INFO; + +#define AMX_USERNUM 4 +#define sEXPMAX 19 /* maximum name length for file version <= 6 */ +#define sNAMEMAX 31 /* maximum name length of symbol name */ + +typedef struct tagAMX_FUNCSTUB { + ucell address PACKED; + char name[sEXPMAX+1] PACKED; +} PACKED AMX_FUNCSTUB; + +typedef struct tagFUNCSTUBNT { + ucell address PACKED; + uint32_t nameofs PACKED; +} PACKED 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 */ + /* 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() */ + /* user data */ + long usertags[AMX_USERNUM] PACKED; + void _FAR *userdata[AMX_USERNUM] PACKED; + /* native functions can raise an error */ + int error PACKED; + /* 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 */ + #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 */ + #endif +} PACKED AMX; + +/* The AMX_HEADER structure is both the memory format as the file format. The + * 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 */ +} PACKED AMX_HEADER; + +#if PAWN_CELL_SIZE==16 + #define AMX_MAGIC 0xf1e2 +#elif PAWN_CELL_SIZE==32 + #define AMX_MAGIC 0xf1e0 +#elif PAWN_CELL_SIZE==64 + #define AMX_MAGIC 0xf1e1 +#endif + +enum { + AMX_ERR_NONE, + /* reserve the first 15 error codes for exit codes of the abstract machine */ + AMX_ERR_EXIT, /* forced exit */ + AMX_ERR_ASSERT, /* assertion failed */ + AMX_ERR_STACKERR, /* stack/heap collision */ + AMX_ERR_BOUNDS, /* index out of bounds */ + AMX_ERR_MEMACCESS, /* invalid memory access */ + AMX_ERR_INVINSTR, /* invalid instruction */ + AMX_ERR_STACKLOW, /* stack underflow */ + AMX_ERR_HEAPLOW, /* heap underflow */ + AMX_ERR_CALLBACK, /* no callback, or invalid callback */ + AMX_ERR_NATIVE, /* native function failed */ + AMX_ERR_DIVIDE, /* divide by zero */ + AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ + AMX_ERR_INVSTATE, /* invalid state for this access */ + + AMX_ERR_MEMORY = 16, /* out of memory */ + AMX_ERR_FORMAT, /* invalid file format */ + AMX_ERR_VERSION, /* file is for a newer version of the AMX */ + AMX_ERR_NOTFOUND, /* function not found */ + AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */ + AMX_ERR_DEBUG, /* debugger cannot run */ + AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */ + AMX_ERR_USERDATA, /* unable to set user data field (table full) */ + AMX_ERR_INIT_JIT, /* cannot initialize the JIT */ + AMX_ERR_PARAMS, /* parameter error */ + AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */ + AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */ +}; + +/* AMX_FLAG_CHAR16 0x01 no longer used */ +#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */ +#define AMX_FLAG_COMPACT 0x04 /* compact encoding */ +#define AMX_FLAG_BYTEOPC 0x08 /* opcode is a byte (not a cell) */ +#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no STMT 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 */ +#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */ + +#define AMX_EXEC_MAIN -1 /* start at program entry point */ +#define AMX_EXEC_CONT -2 /* continue from last address */ + +#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) + +#if !defined AMX_COMPACTMARGIN + #define AMX_COMPACTMARGIN 64 +#endif + +/* for native functions that use floating point parameters, the following + * two macros are convenient for casting a "cell" into a "float" type _without_ + * changing the bit pattern + */ +#if PAWN_CELL_SIZE==32 + #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ + #define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */ +#elif PAWN_CELL_SIZE==64 + #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ + #define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */ +#else + #error Unsupported cell size +#endif + +#define amx_StrParam(amx,param,result) \ + do { \ + cell *amx_cstr_; int amx_length_; \ + amx_GetAddr((amx), (param), &amx_cstr_); \ + amx_StrLen(amx_cstr_, &amx_length_); \ + if (amx_length_ > 0 && \ + ((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \ + amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_); \ + else (result) = NULL; \ + } while (0) + +uint16_t * AMXAPI amx_Align16(uint16_t *v); +uint32_t * AMXAPI amx_Align32(uint32_t *v); +#if defined _I64_MAX || defined HAVE_I64 + uint64_t * AMXAPI amx_Align64(uint64_t *v); +#endif +int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params); +int AMXAPI amx_Cleanup(AMX *amx); +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index); +int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index); +int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index); +int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr); +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname); +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags); +int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr); +int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname); +int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname); +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr); +int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size); +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id); +int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr); +int AMXAPI amx_Init(AMX *amx, void *program); +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code); +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap); +int AMXAPI amx_NameLength(AMX *amx, int *length); +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func); +int AMXAPI amx_NumNatives(AMX *amx, int *number); +int AMXAPI amx_NumPublics(AMX *amx, int *number); +int AMXAPI amx_NumPubVars(AMX *amx, int *number); +int AMXAPI amx_NumTags(AMX *amx, int *number); +int AMXAPI amx_Push(AMX *amx, cell value); +int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells); +int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar); +int AMXAPI amx_RaiseError(AMX *amx, int error); +int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); +int AMXAPI amx_Release(AMX *amx, cell amx_addr); +int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); +int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); +int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size); +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); +int AMXAPI amx_StrLen(const cell *cstring, int *length); +int AMXAPI amx_UTF8Check(const char *string, int *length); +int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value); +int AMXAPI amx_UTF8Len(const cell *cstr, int *length); +int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value); + +#if PAWN_CELL_SIZE==16 + #define amx_AlignCell(v) amx_Align16(v) +#elif PAWN_CELL_SIZE==32 + #define amx_AlignCell(v) amx_Align32(v) +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) + #define amx_AlignCell(v) amx_Align64(v) +#else + #error Unsupported cell size +#endif + +#define amx_RegisterFunc(amx, name, func) \ + amx_Register((amx), amx_NativeInfo((name),(func)), 1); + +#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 /* AMX_H_INCLUDED */ diff --git a/compiler/amxxpc/amxxpc.cpp b/compiler/amxxpc/amxxpc.cpp new file mode 100755 index 00000000..28a8a3f4 --- /dev/null +++ b/compiler/amxxpc/amxxpc.cpp @@ -0,0 +1,326 @@ +#include +#ifdef __linux__ +#include +#else +#include +#include +#endif +#include "zlib.h" +#include "amx.h" +#include "amxxpc.h" + +int main(int argc, char **argv) +{ + struct abl pl32; + struct abl pl64; + +#ifdef _DEBUG + printf("debug clamp\n"); + getchar(); +#endif + +#ifdef __linux__ + HINSTANCE lib = dlmount("./amxxpc32.so"); +#else + HINSTANCE lib = dlmount("amxxpc32.dll"); +#endif + if (!lib) + { +#ifdef __linux__ + printf("32bit compiler failed to instantiate: %s\n", dlerror()); +#else + printf("32bit compiler failed to instantiate: %d\n", GetLastError()); +#endif + exit(0); + } + + COMPILER sc32 = (COMPILER)dlsym(lib, "Compile32"); + + if (!sc32) + { +#ifdef __linux__ + printf("32bit compiler failed to link: %p|%p.\n",sc32, sc_printf); +#else + printf("32bit compiler failed to link: %d.\n", GetLastError()); +#endif + exit(0); + } + + AMX_HEADER hdr; + + printf("Welcome to the AMX Mod X %s Compiler.\n", VERSION_STRING); + printf("Copyright (c) 1997-2005 ITB CompuPhase, AMX Mod X Team\n\n"); + + if (argc < 2) + { + printf("Usage: [options]\n"); + printf("Use -? or --help to see full options\n\n"); + getchar(); + exit(0); + } + + if (!strcmp(argv[1], "-?") || !strcmp(argv[1], "--help")) + { + show_help(); + printf("Press any key to continue.\n"); + getchar(); + exit(0); + } + + sc32(argc, argv); + + char *file = FindFileName(argc, argv); + + if (file == NULL) + { + printf("Could not locate the output file.\n"); + exit(0); + } else if (strstr(file, ".asm")) { + printf("Assembler output succeeded.\n"); + exit(0); + } else { + FILE *fp = fopen(file, "rb"); + if (fp == NULL) + { + printf("Could not locate output file %s (compile failed).\n", file); + exit(0); + } + fread(&hdr, sizeof(hdr), 1, fp); + amx_Align32((uint32_t *)&hdr.stp); + amx_Align32((uint32_t *)&hdr.size); + pl32.stp = hdr.stp; + pl32.cellsize = 4; + int size = sizeof(hdr) + hdr.size; + pl32.size = size; + pl32.data = new char[size]; + rewind(fp); + fread(pl32.data, 1, size, fp); + fclose(fp); + } + + unlink(file); + + HINSTANCE lib64 = 0; +#ifdef __linux__ + lib64 = dlmount("./amxxpc64.so"); +#else + lib64 = dlmount("amxxpc64.dll"); +#endif + if (!lib64) + { + printf("64bit compiler failed to instantiate.\n"); + exit(0); + } + + COMPILER sc64 = (COMPILER)dlsym(lib64, "Compile64"); + + if (!sc64) + { +#ifdef __linux__ + sc_printf("64bit compiler failed to link: %s.\n", dlerror()); +#else + printf("64bit compiler failed to link: %d.\n", GetLastError()); +#endif + exit(0); + } + + sc64(argc, argv); + + dlclose(lib64); + + if (file == NULL) + { + printf("Could not locate the output file on second pass.\n"); + exit(0); + } else { + FILE *fp = fopen(file, "rb"); + if (fp == NULL) + { + printf("Could not locate output file on second pass (compile failed).\n"); + exit(0); + } + fread(&hdr, sizeof(hdr), 1, fp); + amx_Align32((uint32_t *)&hdr.stp); + amx_Align32((uint32_t *)&hdr.size); + pl64.stp = hdr.stp; + pl64.cellsize = 8; + int size = sizeof(hdr) + hdr.size; + pl64.size = sizeof(hdr) + hdr.size; + pl64.data = new char[size]; + rewind(fp); + fread(pl64.data, 1, size, fp); + fclose(fp); + } + + ///////////// + // COMPRSSION + ///////////// + + int err; + + pl32.cmpsize = compressBound(pl32.size); + pl32.cmp = new char[pl32.cmpsize]; + err = compress((Bytef *)pl32.cmp, (uLongf *)&(pl32.cmpsize), (const Bytef*)pl32.data, pl32.size); + + if (err != Z_OK) + { + printf("internal error - compression failed on first pass: %d\n", err); + exit(0); + } + + pl64.cmpsize = compressBound(pl64.size); + pl64.cmp = new char[pl64.cmpsize]; + err = compress((Bytef *)pl64.cmp, (uLongf *)&(pl64.cmpsize), (const Bytef*)pl64.data, pl64.size); + + if (err != Z_OK) + { + printf("internal error - compression failed on second pass: %d\n", err); + exit(0); + } + + char *newfile = new char[strlen(file)+3]; + strcpy(newfile, file); + if (!strstr(file, ".amxx") && !strstr(file, ".AMXX")) + strcat(newfile, "x"); + + FILE *fp = fopen(newfile, "wb"); + if (!fp) + { + printf("Error trying to write file %s.\n", newfile); + exit(0); + } + + //magic + archn + int hdrsize = sizeof(long) + sizeof(char); + int entry = sizeof(long) + sizeof(long) + sizeof(char); + int offset1 = hdrsize + (entry * 2); + int offset2 = offset1 + pl32.cmpsize; + + int magic = MAGIC_HEADER; + fwrite((void *)&magic, sizeof(int), 1, fp); + char n = 2; + fwrite((void *)&n, sizeof(char), 1, fp); + + fwrite((void *)&(pl32.cellsize), sizeof(char), 1, fp); + fwrite((void *)&(pl32.stp), sizeof(long), 1, fp); + fwrite((void *)&(offset1), sizeof(long), 1, fp); + fwrite((void *)&(pl64.cellsize), sizeof(char), 1, fp); + fwrite((void *)&(pl64.stp), sizeof(long), 1, fp); + fwrite((void *)&(offset2), sizeof(long), 1, fp); + fwrite(pl32.cmp, sizeof(char), pl32.cmpsize, fp); + fwrite(pl64.cmp, sizeof(char), pl64.cmpsize, fp); + + fclose(fp); + + unlink(file); + + printf("Done.\n"); + + dlclose(lib); + + exit(0); +} + +//we get the full name of the file here +//our job is to a] switch the .sma extension to .amx +// and to b] strip everything but the trailing name +char *swiext(const char *file, const char *ext, int isO) +{ + int i = 0, pos = -1, j = 0; + int fileLen = strlen(file); + int extLen = strlen(ext); + int max = 0, odirFlag = -1; + + for (i=fileLen-1; i>=0; i--) + { + if (file[i] == '.' && pos == -1) + { + pos = i+1; + } + if ((file[i] == '/' || file[i] == '\\') && !isO) + { + odirFlag = i+1; + //realign pos - we've just stripped fileLen-i chars + pos -= i + 1; + break; + } + } + + char *newbuffer = new char[fileLen+strlen(ext)+2]; + fileLen += strlen(ext); + if (odirFlag == -1) + { + strcpy(newbuffer, file); + } else { + strcpy(newbuffer, &(file[odirFlag])); + } + + if (pos > -1) + { + for (i=pos; i0) + { + return swiext(argv[save], "amx", 0); + } + + return NULL; +} + +void show_help() +{ + printf("Options:\n"); + printf("\t-A alignment in bytes of the data segment and the stack\n"); + printf("\t-a output assembler code\n"); + printf("\t-C[+/-] compact encoding for output file (default=-)\n"); + printf("\t-c codepage name or number; e.g. 1252 for Windows Latin-1\n"); + printf("\t-Dpath active directory path\n"); + printf("\t-d0 no symbolic information, no run-time checks\n"); + printf("\t-d1 [default] run-time checks, no symbolic information\n"); + printf("\t-d2 full debug information and dynamic checking\n"); + printf("\t-d3 full debug information, dynamic checking, no optimization\n"); + printf("\t-e set name of error file (quiet compile)\n"); + printf("\t-H window handle to send a notification message on finish\n"); + printf("\t-i path for include files\n"); + printf("\t-l create list file (preprocess only)\n"); + printf("\t-o set base name of output file\n"); + printf("\t-p set name of \"prefix\" file\n"); + printf("\t-r[name] write cross reference report to console or to specified file\n"); +} diff --git a/compiler/amxxpc/amxxpc.h b/compiler/amxxpc/amxxpc.h new file mode 100755 index 00000000..cec83117 --- /dev/null +++ b/compiler/amxxpc/amxxpc.h @@ -0,0 +1,51 @@ +#ifndef _AMXXSC_INCLUDE_H +#define _AMXXSC_INCLUDE_H + +#define VERSION_STRING "1.50-300" +#define VERSION 03000 +#define MAGIC_HEADER 0x414D5842 + +#ifdef __linux__ +# include +#else +# include +#endif + +#include + +#ifdef __linux__ +# define dlmount(x) dlopen(x, RTLD_NOW) + typedef void* HINSTANCE; +#else +# define dlsym(x, s) GetProcAddress(x, s) +# define dlmount(x) LoadLibrary(x) +# define dlclose(x) FreeLibrary(x) +#endif + +#include "zlib.h" + +typedef int (*COMPILER)(int argc, char **argv); +typedef int (*PRINTF)(const char *message, ...); + +char *FindFileName(int argc, char **argv); +char *swiext(const char *file, const char *ext); +void show_help(); + + +struct ablhdr +{ + int magic; + char size; +}; + +struct abl +{ + long stp; + char cellsize; + int size; + long cmpsize; + char *data; + char *cmp; +}; + +#endif //_AMXXSC_INCLUDE_H diff --git a/compiler/amxxpc/amxxpc.sln b/compiler/amxxpc/amxxpc.sln new file mode 100755 index 00000000..a397c2e0 --- /dev/null +++ b/compiler/amxxpc/amxxpc.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "amxxpc", "amxxpc.vcproj", "{39412290-D01C-472F-A439-AB5592A04C08}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {39412290-D01C-472F-A439-AB5592A04C08}.Debug.ActiveCfg = Debug|Win32 + {39412290-D01C-472F-A439-AB5592A04C08}.Debug.Build.0 = Debug|Win32 + {39412290-D01C-472F-A439-AB5592A04C08}.Release.ActiveCfg = Release|Win32 + {39412290-D01C-472F-A439-AB5592A04C08}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/compiler/amxxpc/amxxpc.vcproj b/compiler/amxxpc/amxxpc.vcproj new file mode 100755 index 00000000..a16966d0 --- /dev/null +++ b/compiler/amxxpc/amxxpc.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compiler/amxxpc/amxxpc1.rc b/compiler/amxxpc/amxxpc1.rc new file mode 100755 index 00000000..0fd6c894 --- /dev/null +++ b/compiler/amxxpc/amxxpc1.rc @@ -0,0 +1,72 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +1 ICON "favicon.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/compiler/amxxpc/favicon.ico b/compiler/amxxpc/favicon.ico new file mode 100755 index 00000000..4e340661 Binary files /dev/null and b/compiler/amxxpc/favicon.ico differ diff --git a/compiler/amxxpc/osdefs.h b/compiler/amxxpc/osdefs.h new file mode 100755 index 00000000..60d61e68 --- /dev/null +++ b/compiler/amxxpc/osdefs.h @@ -0,0 +1,60 @@ +/* __MSDOS__ set when compiling for DOS (not Windows) + * _Windows set when compiling for any version of Microsoft Windows + * __WIN32__ set when compiling for Windows95 or WindowsNT (32 bit mode) + * __32BIT__ set when compiling in 32-bit "flat" mode (DOS or Windows) + * + * Copyright 1998-2002, ITB CompuPhase, The Netherlands. + * info@compuphase.com. + */ + +#ifndef _OSDEFS_H +#define _OSDEFS_H + +/* Every compiler uses different "default" macros to indicate the mode + * it is in. Throughout the source, we use the Borland C++ macros, so + * the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to + * those of Borland C++. + */ +#if defined(__WATCOMC__) +# if defined(__WINDOWS__) || defined(__NT__) +# define _Windows 1 +# endif +# ifdef __386__ +# define __32BIT__ 1 +# endif +# if defined(_Windows) && defined(__32BIT__) +# define __WIN32__ 1 +# endif +#elif defined(_MSC_VER) +# if defined(_WINDOWS) || defined(_WIN32) +# define _Windows 1 +# endif +# ifdef _WIN32 +# define __WIN32__ 1 +# define __32BIT__ 1 +# endif +#endif + +#if defined __linux__ + #include +#endif + +/* Linux NOW has these */ +#if !defined BIG_ENDIAN + #define BIG_ENDIAN 4321 +#endif +#if !defined LITTLE_ENDIAN + #define LITTLE_ENDIAN 1234 +#endif + +/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */ +#if !defined BYTE_ORDER + #if defined UCLINUX + #define BYTE_ORDER BIG_ENDIAN + #else + #define BYTE_ORDER LITTLE_ENDIAN + #endif +#endif + +#endif /* _OSDEFS_H */ + diff --git a/compiler/amxxpc/resource.h b/compiler/amxxpc/resource.h new file mode 100755 index 00000000..c5a4bded --- /dev/null +++ b/compiler/amxxpc/resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by amxxsc.rc +// +#define ICON 5 +#define IDI_ICON1 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/compiler/amxxpc/resource1.h b/compiler/amxxpc/resource1.h new file mode 100755 index 00000000..c32213f3 --- /dev/null +++ b/compiler/amxxpc/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by amxxsc1.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/compiler/amxxpc/sclinux.h b/compiler/amxxpc/sclinux.h new file mode 100755 index 00000000..f22497a8 --- /dev/null +++ b/compiler/amxxpc/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 */ diff --git a/compiler/amxxpc/testmini.c b/compiler/amxxpc/testmini.c new file mode 100755 index 00000000..2e5e13f5 --- /dev/null +++ b/compiler/amxxpc/testmini.c @@ -0,0 +1,155 @@ +/* testmini.c -- very simple test program for the miniLZO library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + + +#include +#include + + +/************************************************************************* +// This program shows the basic usage of the LZO library. +// We will compress a block of data and decompress again. +// +// For more information, documentation, example programs and other support +// files (like Makefiles and build scripts) please download the full LZO +// package from +// http://www.oberhumer.com/opensource/lzo/ +**************************************************************************/ + +/* First let's include "minizo.h". */ + +#include "minilzo.h" + + +/* We want to compress the data block at `in' with length `IN_LEN' to + * the block at `out'. Because the input block may be incompressible, + * we must provide a little more output space in case that compression + * is not possible. + */ + +#if defined(__LZO_STRICT_16BIT) +#define IN_LEN (8*1024) +#else +#define IN_LEN (128*1024L) +#endif +#define OUT_LEN (IN_LEN + IN_LEN / 64 + 16 + 3) + +static lzo_byte in [ IN_LEN ]; +static lzo_byte out [ OUT_LEN ]; + + +/* Work-memory needed for compression. Allocate memory in units + * of `lzo_align_t' (instead of `char') to make sure it is properly aligned. + */ + +#define HEAP_ALLOC(var,size) \ + lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] + +static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS); + + +/************************************************************************* +// +**************************************************************************/ + +int main(int argc, char *argv[]) +{ + int r; + lzo_uint in_len; + lzo_uint out_len; + lzo_uint new_len; + +#if defined(__EMX__) + _response(&argc,&argv); + _wildcard(&argc,&argv); +#endif + + if (argc < 0 && argv == NULL) /* avoid warning about unused args */ + return 0; + + printf("\nLZO real-time data compression library (v%s, %s).\n", + lzo_version_string(), lzo_version_date()); + printf("Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer\n\n"); + + +/* + * Step 1: initialize the LZO library + */ + if (lzo_init() != LZO_E_OK) + { + printf("lzo_init() failed !!!\n"); + return 3; + } + +/* + * Step 2: prepare the input block that will get compressed. + * We just fill it with zeros in this example program, + * but you would use your real-world data here. + */ + in_len = IN_LEN; + lzo_memset(in,0,in_len); + +/* + * Step 3: compress from `in' to `out' with LZO1X-1 + */ + r = lzo1x_1_compress(in,in_len,out,&out_len,wrkmem); + if (r == LZO_E_OK) + printf("compressed %lu bytes into %lu bytes\n", + (long) in_len, (long) out_len); + else + { + /* this should NEVER happen */ + printf("internal error - compression failed: %d\n", r); + return 2; + } + /* check for an incompressible block */ + if (out_len >= in_len) + { + printf("This block contains incompressible data.\n"); + return 0; + } + +/* + * Step 4: decompress again, now going from `out' to `in' + */ + r = lzo1x_decompress(out,out_len,in,&new_len,NULL); + if (r == LZO_E_OK && new_len == in_len) + printf("decompressed %lu bytes back into %lu bytes\n", + (long) out_len, (long) in_len); + else + { + /* this should NEVER happen */ + printf("internal error - decompression failed: %d\n", r); + return 1; + } + + printf("\nminiLZO simple compression test passed.\n"); + return 0; +} + +/* +vi:ts=4 +*/ + diff --git a/compiler/amxxpc/zconf.h b/compiler/amxxpc/zconf.h new file mode 100755 index 00000000..3cea897e --- /dev/null +++ b/compiler/amxxpc/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#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__)) && !defined(WIN32) +# define WIN32 +#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/compiler/amxxpc/zlib.h b/compiler/amxxpc/zlib.h new file mode 100755 index 00000000..92edf96f --- /dev/null +++ b/compiler/amxxpc/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 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.1" +#define ZLIB_VERNUM 0x1210 + +/* + 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 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. + + 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. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + 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: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + 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_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#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. + + 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 + the 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 data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). 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 get 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). + + 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. + + 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. + + 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 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 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). + + 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 negative + memLevel). 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 this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + 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 inflateBackInit OF((z_stream FAR *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_stream FAR *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_stream FAR *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 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 crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + 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(); +*/ + + + /* 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_stream FAR *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 err)); +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/compiler/amxxpc/zlib.lib b/compiler/amxxpc/zlib.lib new file mode 100755 index 00000000..d5348407 Binary files /dev/null and b/compiler/amxxpc/zlib.lib differ diff --git a/compiler/libpc300/amx.h b/compiler/libpc300/amx.h index cf194750..b0443801 100755 --- a/compiler/libpc300/amx.h +++ b/compiler/libpc300/amx.h @@ -249,11 +249,9 @@ typedef struct tagAMX { cell reset_stk PACKED; cell reset_hea PACKED; cell sysreq_d PACKED; /* 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 */ - #endif + /* 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 */ } PACKED AMX; /* The AMX_HEADER structure is both the memory format as the file format. The @@ -279,13 +277,8 @@ typedef struct tagAMX_HEADER { int32_t nametable PACKED; /* name table */ } PACKED AMX_HEADER; -#if PAWN_CELL_SIZE==16 - #define AMX_MAGIC 0xf1e2 -#elif PAWN_CELL_SIZE==32 - #define AMX_MAGIC 0xf1e0 -#elif PAWN_CELL_SIZE==64 - #define AMX_MAGIC 0xf1e1 -#endif +//This is always the same for us +#define AMX_MAGIC 0xf1e0 enum { AMX_ERR_NONE, diff --git a/compiler/libpc300/libpawnc.c b/compiler/libpc300/libpawnc.c index 13fcc8e8..39b42ab0 100755 --- a/compiler/libpc300/libpawnc.c +++ b/compiler/libpc300/libpawnc.c @@ -56,48 +56,13 @@ # if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __NT__ __declspec (dllexport) - void EXCOMPILER(HWND hwnd, HINSTANCE hinst, LPSTR lpCommandLine, int nCmdShow) + void EXCOMPILER(int argc, char **argv) # else - void extern EXCOMPILER(HWND hwnd, HINSTANCE hinst, LPSTR lpCommandLine, int nCmdShow) + void extern EXCOMPILER(int argc, char **argv) # endif { - char RootPath[_MAX_PATH]; - LPSTR ptr; - - /* RUNDLL32 may have passed us a HWND and a HINSTANCE, but we can hardly - * trust these. They may not contain values that we can use. - */ - - /* the root path in argv[0] */ - GetModuleFileName(hinstDLL, RootPath, sizeof RootPath); - argv[argc++]=RootPath; - - /* all other options */ - assert(lpCommandLine!=NULL); - ptr=dll_skipwhite(lpCommandLine); - while (*ptr!='\0') { - if (*ptr=='"') { - argv[argc++]=ptr+1; - while (*ptr!='"' && *ptr!='\0') - ptr++; - } else { - argv[argc++]=ptr; - while (*ptr>' ') - ptr++; - } /* if */ - if (*ptr!='\0') - *ptr++='\0'; - ptr=dll_skipwhite(ptr); - } /* while */ - pc_compile(argc,argv); - UNUSED_PARAM(hwnd); - UNUSED_PARAM(hinst); - UNUSED_PARAM(nCmdShow); + pc_compile(argc, argv); } - -#else /* PAWNC_DLL */ - - #endif /* PAWNC_DLL */ diff --git a/compiler/libpc300/libpc300.vcproj b/compiler/libpc300/libpc300.vcproj index 87880631..cf897b05 100755 --- a/compiler/libpc300/libpc300.vcproj +++ b/compiler/libpc300/libpc300.vcproj @@ -258,6 +258,9 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + + diff --git a/compiler/libpc300/sclist.c b/compiler/libpc300/sclist.c index ab96a9e7..7d24e142 100755 --- a/compiler/libpc300/sclist.c +++ b/compiler/libpc300/sclist.c @@ -409,16 +409,18 @@ SC_FUNC stringlist *insert_dbgline(int linenr) char string[40]; if (linenr>0) linenr--; /* line numbers are zero-based in the debug information */ -#if PAWN_CELL_SIZE==32 sprintf(string,"L:%08lx %04x",(long)code_idx,linenr); -#elif PAWN_CELL_SIZE==64 - sprintf(string,"L:%08Lx %04x",(long)code_idx,linenr); -#endif return insert_string(&dbgstrings,string); } /* if */ return NULL; } +#ifdef WIN32 +#define LONGCAST long +#else +#define LONGCAST cell +#endif + SC_FUNC stringlist *insert_dbgsymbol(symbol *sym) { if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) { @@ -440,10 +442,10 @@ SC_FUNC stringlist *insert_dbgsymbol(symbol *sym) symname,sym->codeaddr,code_idx,sym->ident,sym->vclass); #elif PAWN_CELL_SIZE==64 if (sym->ident==iFUNCTN) - sprintf(string,"S:%08Lx %x:%s %08Lx %08Lx %x %x",sym->addr,sym->tag, + sprintf(string,"S:%08Lx %x:%s %08Lx %08Lx %x %x",(LONGCAST)sym->addr,sym->tag, symname,sym->addr,sym->codeaddr,sym->ident,sym->vclass); else - sprintf(string,"S:%08Lx %x:%s %08Lx %08Lx %x %x",sym->addr,sym->tag, + sprintf(string,"S:%08Lx %x:%s %08Lx %08Lx %x %x",(LONGCAST)sym->addr,sym->tag, symname,sym->codeaddr,code_idx,sym->ident,sym->vclass); #endif if (sym->ident==iARRAY || sym->ident==iREFARRAY) {