This is the open source Pawn interpreter ported to mbed. See here: http://www.compuphase.com/pawn/pawn.htm and here: http://code.google.com/p/pawnscript/
amx.c
00001 /* Pawn Abstract Machine (for the Pawn language) 00002 * 00003 * Copyright (c) ITB CompuPhase, 1997-2012 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 00006 * use this file except in compliance with the License. You may obtain a copy 00007 * of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 00014 * License for the specific language governing permissions and limitations 00015 * under the License. 00016 * 00017 * Version: $Id: amx.c 4708 2012-05-18 12:52:49Z thiadmer $ 00018 */ 00019 00020 #define WIN32_LEAN_AND_MEAN 00021 #if defined _UNICODE || defined __UNICODE__ || defined UNICODE 00022 # if !defined UNICODE /* for Windows API */ 00023 # define UNICODE 00024 # endif 00025 # if !defined _UNICODE /* for C library */ 00026 # define _UNICODE 00027 # endif 00028 #endif 00029 00030 #include <assert.h> 00031 #include <stdarg.h> 00032 #include <stddef.h> /* for wchar_t */ 00033 #include <stdlib.h> /* for getenv() */ 00034 #include <string.h> 00035 #include "osdefs.h" 00036 #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 00037 #include <sclinux.h> 00038 #if !defined AMX_NODYNALOAD 00039 #include <dlfcn.h> 00040 #endif 00041 #if defined AMX_JIT 00042 #include <sys/types.h> 00043 #include <sys/mman.h> 00044 #endif 00045 #endif 00046 #if defined __LCC__ || defined __LINUX__ 00047 #include <wchar.h> /* for wcslen() */ 00048 #endif 00049 00050 #if defined __ECOS__ 00051 /* eCos puts include files in cyg/package_name */ 00052 #include <cyg/pawn/amx.h> 00053 #else 00054 #include "amx.h" 00055 #endif 00056 00057 #if (defined _Windows && !defined AMX_NODYNALOAD) || (defined AMX_JIT && __WIN32__) 00058 #include <windows.h> 00059 #endif 00060 00061 00062 /* When one or more of the AMX_funcname macros are defined, we want 00063 * to compile only those functions. However, when none of these macros 00064 * is present, we want to compile everything. 00065 */ 00066 #if defined AMX_ALIGN || defined AMX_ALLOT || defined AMX_CLEANUP 00067 #define AMX_EXPLIT_FUNCTIONS 00068 #endif 00069 #if defined AMX_CLONE || defined AMX_DEFCALLBACK || defined AMX_EXEC 00070 #define AMX_EXPLIT_FUNCTIONS 00071 #endif 00072 #if defined AMX_FLAGS || defined AMX_INIT || defined AMX_MEMINFO 00073 #define AMX_EXPLIT_FUNCTIONS 00074 #endif 00075 #if defined AMX_NAMELENGTH || defined AMX_NATIVEINFO || defined AMX_PUSHXXX 00076 #define AMX_EXPLIT_FUNCTIONS 00077 #endif 00078 #if defined AMX_RAISEERROR || defined AMX_REGISTER || defined AMX_SETCALLBACK 00079 #define AMX_EXPLIT_FUNCTIONS 00080 #endif 00081 #if defined AMX_SETDEBUGHOOK || defined AMX_UTF8XXX || defined AMX_XXXNATIVES 00082 #define AMX_EXPLIT_FUNCTIONS 00083 #endif 00084 #if defined AMX_XXXPUBLICS || defined AMX_XXXPUBVARS || defined AMX_XXXSTRING 00085 #define AMX_EXPLIT_FUNCTIONS 00086 #endif 00087 #if defined AMX_XXXTAGS || defined AMX_XXXUSERDATA 00088 #define AMX_EXPLIT_FUNCTIONS 00089 #endif 00090 #if !defined AMX_EXPLIT_FUNCTIONS 00091 /* no constant set, set them all */ 00092 #define AMX_ALIGN /* amx_Align16(), amx_Align32() and amx_Align64() */ 00093 #define AMX_ALLOT /* amx_Allot() and amx_Release() */ 00094 #define AMX_DEFCALLBACK /* amx_Callback() */ 00095 #define AMX_CLEANUP /* amx_Cleanup() */ 00096 #define AMX_CLONE /* amx_Clone() */ 00097 #define AMX_EXEC /* amx_Exec() */ 00098 #define AMX_FLAGS /* amx_Flags() */ 00099 #define AMX_INIT /* amx_Init() and amx_InitJIT() */ 00100 #define AMX_MEMINFO /* amx_MemInfo() */ 00101 #define AMX_NAMELENGTH /* amx_NameLength() */ 00102 #define AMX_NATIVEINFO /* amx_NativeInfo() */ 00103 #define AMX_PUSHXXX /* amx_Push(), amx_PushAddress(), amx_PushArray() and amx_PushString() */ 00104 #define AMX_RAISEERROR /* amx_RaiseError() */ 00105 #define AMX_REGISTER /* amx_Register() */ 00106 #define AMX_SETCALLBACK /* amx_SetCallback() */ 00107 #define AMX_SETDEBUGHOOK /* amx_SetDebugHook() */ 00108 #define AMX_UTF8XXX /* amx_UTF8Check(), amx_UTF8Get(), amx_UTF8Len() and amx_UTF8Put() */ 00109 #define AMX_XXXNATIVES /* amx_NumNatives(), amx_GetNative() and amx_FindNative() */ 00110 #define AMX_XXXPUBLICS /* amx_NumPublics(), amx_GetPublic() and amx_FindPublic() */ 00111 #define AMX_XXXPUBVARS /* amx_NumPubVars(), amx_GetPubVar() and amx_FindPubVar() */ 00112 #define AMX_XXXSTRING /* amx_StrLen(), amx_GetString() and amx_SetString() */ 00113 #define AMX_XXXTAGS /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */ 00114 #define AMX_XXXUSERDATA /* amx_GetUserData() and amx_SetUserData() */ 00115 #endif 00116 #undef AMX_EXPLIT_FUNCTIONS 00117 #if defined AMX_ANSIONLY 00118 #undef AMX_UTF8XXX /* no UTF-8 support in ANSI/ASCII-only version */ 00119 #endif 00120 #if defined AMX_NO_NATIVEINFO 00121 #undef AMX_NATIVEINFO 00122 #endif 00123 #if AMX_USERNUM <= 0 00124 #undef AMX_XXXUSERDATA 00125 #endif 00126 #if defined AMX_JIT 00127 /* JIT is incompatible with macro instructions, packed opcodes and overlays */ 00128 #if !defined AMX_NO_MACRO_INSTR 00129 #define AMX_NO_MACRO_INSTR 00130 #endif 00131 #if !defined AMX_NO_PACKED_OPC 00132 #define AMX_NO_PACKED_OPC 00133 #endif 00134 #if !defined AMX_NO_OVERLAY 00135 #define AMX_NO_OVERLAY 00136 #endif 00137 #endif 00138 #if (defined AMX_ASM || defined AMX_JIT) && !defined AMX_ALTCORE 00139 /* do not use the standard ANSI-C amx_Exec() function */ 00140 #define AMX_ALTCORE 00141 #endif 00142 #if !defined AMX_NO_PACKED_OPC && !defined AMX_TOKENTHREADING 00143 #define AMX_TOKENTHREADING /* packed opcodes require token threading */ 00144 #endif 00145 00146 #if defined AMX_ALTCORE 00147 #if defined __WIN32__ 00148 /* For Watcom C/C++ use register calling convention (faster); for 00149 * Microsoft C/C++ (and most other C compilers) use "cdecl". 00150 * The important point is that you assemble AMXEXEC.ASM with the matching 00151 * calling convention, or the right JIT, respectively. 00152 * AMXJITR.ASM is for Watcom's register calling convention, AMXJITS.ASM and 00153 * AMXJITSN.ASM are for "cdecl". 00154 */ 00155 #if defined __WATCOMC__ && !defined STACKARGS 00156 /* register calling convention; the #pragma tells the compiler into which 00157 * registers the parameters should go 00158 */ 00159 extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data); 00160 #pragma aux amx_exec_run parm [eax] [edx] [ebx]; 00161 extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00162 #pragma aux amx_exec_run parm [eax] [edx] [ebx]; 00163 extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode); 00164 #pragma aux amx_exec_run parm [eax] [edx] [ebx]; 00165 extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data); 00166 #pragma aux amx_jit_run parm [eax] [edx] [ebx]; 00167 extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00168 #pragma aux amx_exec_run parm [eax] [edx] [ebx]; 00169 #elif defined __GNUC__ 00170 /* force "cdecl" by adding an "attribute" to the declaration */ 00171 extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data) __attribute__((cdecl)); 00172 extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes) __attribute__((cdecl)); 00173 extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode) __attribute__((cdecl)); 00174 extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data) __attribute__((cdecl)); 00175 extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes) __attribute__((cdecl)); 00176 #else 00177 /* force "cdecl" by specifying it as a "function class" with the "__cdecl" keyword */ 00178 extern cell __cdecl amx_exec_run(AMX *amx,cell *retval,unsigned char *data); 00179 extern int __cdecl amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00180 extern cell __cdecl amx_jit_compile(void *pcode, void *jumparray, void *nativecode); 00181 extern cell __cdecl amx_jit_run(AMX *amx,cell *retval,unsigned char *data); 00182 extern int __cdecl amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00183 #endif 00184 #else /* __WIN32__ */ 00185 /* assume no specific calling conventions for other platforms than Windows */ 00186 extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data); 00187 extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00188 extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode); 00189 extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data); 00190 extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); 00191 #endif /* __WIN32__ */ 00192 #else 00193 int amx_exec_list(AMX *amx,const cell **opcodelist,int *numopcodes); 00194 #endif /* AMX_ALTCORE */ 00195 00196 typedef enum { 00197 OP_NOP, 00198 OP_LOAD_PRI, 00199 OP_LOAD_ALT, 00200 OP_LOAD_S_PRI, 00201 OP_LOAD_S_ALT, 00202 OP_LREF_S_PRI, 00203 OP_LREF_S_ALT, 00204 OP_LOAD_I, 00205 OP_LODB_I, 00206 OP_CONST_PRI, 00207 OP_CONST_ALT, 00208 OP_ADDR_PRI, 00209 OP_ADDR_ALT, 00210 OP_STOR, 00211 OP_STOR_S, 00212 OP_SREF_S, 00213 OP_STOR_I, 00214 OP_STRB_I, 00215 OP_ALIGN_PRI, 00216 OP_LCTRL, 00217 OP_SCTRL, 00218 OP_XCHG, 00219 OP_PUSH_PRI, 00220 OP_PUSH_ALT, 00221 OP_PUSHR_PRI, 00222 OP_POP_PRI, 00223 OP_POP_ALT, 00224 OP_PICK, 00225 OP_STACK, 00226 OP_HEAP, 00227 OP_PROC, 00228 OP_RET, 00229 OP_RETN, 00230 OP_CALL, 00231 OP_JUMP, 00232 OP_JZER, 00233 OP_JNZ, 00234 OP_SHL, 00235 OP_SHR, 00236 OP_SSHR, 00237 OP_SHL_C_PRI, 00238 OP_SHL_C_ALT, 00239 OP_SMUL, 00240 OP_SDIV, 00241 OP_ADD, 00242 OP_SUB, 00243 OP_AND, 00244 OP_OR, 00245 OP_XOR, 00246 OP_NOT, 00247 OP_NEG, 00248 OP_INVERT, 00249 OP_EQ, 00250 OP_NEQ, 00251 OP_SLESS, 00252 OP_SLEQ, 00253 OP_SGRTR, 00254 OP_SGEQ, 00255 OP_INC_PRI, 00256 OP_INC_ALT, 00257 OP_INC_I, 00258 OP_DEC_PRI, 00259 OP_DEC_ALT, 00260 OP_DEC_I, 00261 OP_MOVS, 00262 OP_CMPS, 00263 OP_FILL, 00264 OP_HALT, 00265 OP_BOUNDS, 00266 OP_SYSREQ, 00267 OP_SWITCH, 00268 OP_SWAP_PRI, 00269 OP_SWAP_ALT, 00270 OP_BREAK, 00271 OP_CASETBL, 00272 /* patched instructions */ 00273 OP_SYSREQ_D, 00274 OP_SYSREQ_ND, 00275 /* overlay instructions */ 00276 OP_CALL_OVL, 00277 OP_RETN_OVL, 00278 OP_SWITCH_OVL, 00279 OP_CASETBL_OVL, 00280 #if !defined AMX_NO_MACRO_INSTR 00281 /* supplemental & macro instructions */ 00282 OP_LIDX, 00283 OP_LIDX_B, 00284 OP_IDXADDR, 00285 OP_IDXADDR_B, 00286 OP_PUSH_C, 00287 OP_PUSH, 00288 OP_PUSH_S, 00289 OP_PUSH_ADR, 00290 OP_PUSHR_C, 00291 OP_PUSHR_S, 00292 OP_PUSHR_ADR, 00293 OP_JEQ, 00294 OP_JNEQ, 00295 OP_JSLESS, 00296 OP_JSLEQ, 00297 OP_JSGRTR, 00298 OP_JSGEQ, 00299 OP_SDIV_INV, 00300 OP_SUB_INV, 00301 OP_ADD_C, 00302 OP_SMUL_C, 00303 OP_ZERO_PRI, 00304 OP_ZERO_ALT, 00305 OP_ZERO, 00306 OP_ZERO_S, 00307 OP_EQ_C_PRI, 00308 OP_EQ_C_ALT, 00309 OP_INC, 00310 OP_INC_S, 00311 OP_DEC, 00312 OP_DEC_S, 00313 /* macro instructions */ 00314 OP_SYSREQ_N, 00315 OP_PUSHM_C, 00316 OP_PUSHM, 00317 OP_PUSHM_S, 00318 OP_PUSHM_ADR, 00319 OP_PUSHRM_C, 00320 OP_PUSHRM_S, 00321 OP_PUSHRM_ADR, 00322 OP_LOAD2, 00323 OP_LOAD2_S, 00324 OP_CONST, 00325 OP_CONST_S, 00326 #endif 00327 #if !defined AMX_NO_PACKED_OPC 00328 /* packed instructions */ 00329 OP_LOAD_P_PRI, 00330 OP_LOAD_P_ALT, 00331 OP_LOAD_P_S_PRI, 00332 OP_LOAD_P_S_ALT, 00333 OP_LREF_P_S_PRI, 00334 OP_LREF_P_S_ALT, 00335 OP_LODB_P_I, 00336 OP_CONST_P_PRI, 00337 OP_CONST_P_ALT, 00338 OP_ADDR_P_PRI, 00339 OP_ADDR_P_ALT, 00340 OP_STOR_P, 00341 OP_STOR_P_S, 00342 OP_SREF_P_S, 00343 OP_STRB_P_I, 00344 OP_LIDX_P_B, 00345 OP_IDXADDR_P_B, 00346 OP_ALIGN_P_PRI, 00347 OP_PUSH_P_C, 00348 OP_PUSH_P, 00349 OP_PUSH_P_S, 00350 OP_PUSH_P_ADR, 00351 OP_PUSHR_P_C, 00352 OP_PUSHR_P_S, 00353 OP_PUSHR_P_ADR, 00354 OP_PUSHM_P_C, 00355 OP_PUSHM_P, 00356 OP_PUSHM_P_S, 00357 OP_PUSHM_P_ADR, 00358 OP_PUSHRM_P_C, 00359 OP_PUSHRM_P_S, 00360 OP_PUSHRM_P_ADR, 00361 OP_STACK_P, 00362 OP_HEAP_P, 00363 OP_SHL_P_C_PRI, 00364 OP_SHL_P_C_ALT, 00365 OP_ADD_P_C, 00366 OP_SMUL_P_C, 00367 OP_ZERO_P, 00368 OP_ZERO_P_S, 00369 OP_EQ_P_C_PRI, 00370 OP_EQ_P_C_ALT, 00371 OP_INC_P, 00372 OP_INC_P_S, 00373 OP_DEC_P, 00374 OP_DEC_P_S, 00375 OP_MOVS_P, 00376 OP_CMPS_P, 00377 OP_FILL_P, 00378 OP_HALT_P, 00379 OP_BOUNDS_P, 00380 #endif 00381 /* ----- */ 00382 OP_NUM_OPCODES 00383 } OPCODE; 00384 00385 #define NUMENTRIES(hdr,field,nextfield) \ 00386 (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) 00387 #define GETENTRY(hdr,table,index) \ 00388 (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize) 00389 #define GETENTRYNAME(hdr,entry) \ 00390 (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUB*)(entry))->nameofs) 00391 00392 #if !defined NDEBUG 00393 static int check_endian(void) 00394 { 00395 uint16_t val=0x00ff; 00396 unsigned char *ptr=(unsigned char *)&val; 00397 /* "ptr" points to the starting address of "val". If that address 00398 * holds the byte "0xff", the computer stored the low byte of "val" 00399 * at the lower address, and so the memory lay out is Little Endian. 00400 */ 00401 assert(*ptr==0xff || *ptr==0x00); 00402 #if BYTE_ORDER==BIG_ENDIAN 00403 return *ptr==0x00; /* return "true" if big endian */ 00404 #else 00405 return *ptr==0xff; /* return "true" if little endian */ 00406 #endif 00407 } 00408 #endif 00409 00410 #if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==16 00411 static void swap16(uint16_t *v) 00412 { 00413 unsigned char *s = (unsigned char *)v; 00414 unsigned char t; 00415 00416 assert_static(sizeof(*v)==2); 00417 /* swap two bytes */ 00418 t=s[0]; 00419 s[0]=s[1]; 00420 s[1]=t; 00421 } 00422 #endif 00423 00424 #if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==32 00425 static void swap32(uint32_t *v) 00426 { 00427 unsigned char *s = (unsigned char *)v; 00428 unsigned char t; 00429 00430 assert_static(sizeof(*v)==4); 00431 /* swap outer two bytes */ 00432 t=s[0]; 00433 s[0]=s[3]; 00434 s[3]=t; 00435 /* swap inner two bytes */ 00436 t=s[1]; 00437 s[1]=s[2]; 00438 s[2]=t; 00439 } 00440 #endif 00441 00442 #if (BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==64) && (defined _I64_MAX || defined HAVE_I64) 00443 static void swap64(uint64_t *v) 00444 { 00445 unsigned char *s = (unsigned char *)v; 00446 unsigned char t; 00447 00448 assert(sizeof(*v)==8); 00449 00450 t=s[0]; 00451 s[0]=s[7]; 00452 s[7]=t; 00453 00454 t=s[1]; 00455 s[1]=s[6]; 00456 s[6]=t; 00457 00458 t=s[2]; 00459 s[2]=s[5]; 00460 s[5]=t; 00461 00462 t=s[3]; 00463 s[3]=s[4]; 00464 s[4]=t; 00465 } 00466 #endif 00467 00468 #if defined AMX_ALIGN || defined AMX_INIT 00469 uint16_t * AMXAPI amx_Align16(uint16_t *v) 00470 { 00471 assert_static(sizeof(*v)==2); 00472 assert(check_endian()); 00473 #if BYTE_ORDER==BIG_ENDIAN 00474 swap16(v); 00475 #endif 00476 return v; 00477 } 00478 00479 uint32_t * AMXAPI amx_Align32(uint32_t *v) 00480 { 00481 assert_static(sizeof(*v)==4); 00482 assert(check_endian()); 00483 #if BYTE_ORDER==BIG_ENDIAN 00484 swap32(v); 00485 #endif 00486 return v; 00487 } 00488 00489 #if defined _I64_MAX || defined HAVE_I64 00490 uint64_t * AMXAPI amx_Align64(uint64_t *v) 00491 { 00492 assert(sizeof(*v)==8); 00493 assert(check_endian()); 00494 #if BYTE_ORDER==BIG_ENDIAN 00495 swap64(v); 00496 #endif 00497 return v; 00498 } 00499 #endif /* _I64_MAX || HAVE_I64 */ 00500 #endif /* AMX_ALIGN || AMX_INIT */ 00501 00502 #if PAWN_CELL_SIZE==16 00503 #define swapcell swap16 00504 #elif PAWN_CELL_SIZE==32 00505 #define swapcell swap32 00506 #elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) 00507 #define swapcell swap64 00508 #else 00509 #error Unsupported cell size 00510 #endif 00511 00512 #if defined AMX_FLAGS 00513 int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) 00514 { 00515 AMX_HEADER *hdr; 00516 00517 *flags=0; 00518 if (amx==NULL) 00519 return AMX_ERR_FORMAT; 00520 hdr=(AMX_HEADER *)amx->base; 00521 if (hdr->magic!=AMX_MAGIC) 00522 return AMX_ERR_FORMAT; 00523 if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION) 00524 return AMX_ERR_VERSION; 00525 *flags=hdr->flags; 00526 return AMX_ERR_NONE; 00527 } 00528 #endif /* AMX_FLAGS */ 00529 00530 #if defined AMX_DEFCALLBACK 00531 int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params) 00532 { 00533 #if defined AMX_NATIVETABLE 00534 extern AMX_NATIVE const AMX_NATIVETABLE[]; 00535 #endif 00536 AMX_HEADER *hdr; 00537 AMX_FUNCSTUB *func; 00538 AMX_NATIVE f; 00539 00540 assert(amx!=NULL); 00541 hdr=(AMX_HEADER *)amx->base; 00542 assert(hdr!=NULL); 00543 assert(hdr->magic==AMX_MAGIC); 00544 assert(hdr->natives<=hdr->libraries); 00545 #if defined AMX_NATIVETABLE 00546 if (index<0) { 00547 /* size of AMX_NATIVETABLE is unknown here, so we cannot verify index */ 00548 f=(AMX_NATIVETABLE)[-(index+1)]; 00549 } else { 00550 #endif 00551 assert(index>=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); 00552 func=GETENTRY(hdr,natives,index); 00553 f=(AMX_NATIVE)func->address; 00554 #if defined AMX_NATIVETABLE 00555 } /* if */ 00556 #endif 00557 assert(f!=NULL); 00558 00559 /* Now that we have found the function, patch the program so that any 00560 * subsequent call will call the function directly (bypassing this 00561 * callback). 00562 * This trick cannot work in the JIT, because the program would need to 00563 * be re-JIT-compiled after patching a P-code instruction. 00564 */ 00565 assert((amx->flags & AMX_FLAG_JITC)==0 || amx->sysreq_d==0); 00566 if (amx->sysreq_d!=0) { 00567 /* at the point of the call, the CIP pseudo-register points directly 00568 * behind the SYSREQ(.N) instruction and its parameter(s) 00569 */ 00570 unsigned char *code=amx->code+(int)amx->cip-sizeof(cell); 00571 if (amx->flags & AMX_FLAG_SYSREQN) /* SYSREQ.N has 2 parameters */ 00572 code-=sizeof(cell); 00573 assert(amx->code!=NULL); 00574 assert(amx->cip>=4 && amx->cip<(hdr->dat - hdr->cod)); 00575 assert_static(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */ 00576 assert(*(cell*)code==index); 00577 #if defined AMX_TOKENTHREADING || !(defined __GNUC__ || defined __ICC || defined AMX_ASM || defined AMX_JIT) 00578 assert(!(amx->flags & AMX_FLAG_SYSREQN) && *(cell*)(code-sizeof(cell))==OP_SYSREQ 00579 || (amx->flags & AMX_FLAG_SYSREQN) && *(cell*)(code-sizeof(cell))==OP_SYSREQ_N); 00580 #endif 00581 *(cell*)(code-sizeof(cell))=amx->sysreq_d; 00582 *(cell*)code=(cell)f; 00583 } /* if */ 00584 00585 /* Note: 00586 * params[0] == number of bytes for the additional parameters passed to the native function 00587 * params[1] == first argument 00588 * etc. 00589 */ 00590 00591 amx->error=AMX_ERR_NONE; 00592 *result = f(amx,params); 00593 return amx->error; 00594 } 00595 #endif /* defined AMX_DEFCALLBACK */ 00596 00597 00598 #if defined AMX_JIT 00599 /* convert from relative addresses to absolute physical addresses */ 00600 #define RELOC_ABS(base,off) (*(ucell *)((base)+(int)(off)) += (ucell)(base)+(int)(off)-sizeof(cell)) 00601 #else 00602 #define JUMPREL(ip) ((cell*)((intptr_t)(ip)+*(cell*)(ip)-sizeof(cell))) 00603 #endif 00604 #if defined AMX_ASM || defined AMX_JIT 00605 #define RELOCATE_ADDR(base,v) ((v)+((ucell)(base))) 00606 #else 00607 #define RELOCATE_ADDR(base,v) (v) 00608 #endif 00609 00610 #define DBGPARAM(v) ( (v)=*(cell *)(amx->code+(int)cip), cip+=sizeof(cell) ) 00611 00612 #if !defined GETOPCODE 00613 #if defined AMX_NO_PACKED_OPC 00614 #define GETOPCODE(c) (OPCODE)(c) 00615 #else 00616 #define GETOPCODE(c) (OPCODE)((c) & ((1 << sizeof(cell)*4)-1)) 00617 #endif 00618 #endif 00619 #if !defined GETPARAM_P 00620 #define GETPARAM_P(v,o) ( v=((cell)(o) >> (int)(sizeof(cell)*4)) ) 00621 #endif 00622 00623 #if defined AMX_INIT 00624 00625 static int VerifyPcode(AMX *amx) 00626 { 00627 AMX_HEADER *hdr; 00628 cell op,cip,tgt,opmask; 00629 int sysreq_flg,max_opcode; 00630 int datasize,stacksize; 00631 const cell *opcode_list; 00632 #if defined AMX_JIT 00633 int opcode_count=0; 00634 int reloc_count=0; 00635 int jit_codesize=0; 00636 #endif 00637 00638 assert(amx!=NULL); 00639 hdr=(AMX_HEADER *)amx->base; 00640 assert(hdr!=NULL); 00641 assert(hdr->magic==AMX_MAGIC); 00642 amx->flags|=AMX_FLAG_VERIFY; 00643 datasize=hdr->hea-hdr->dat; 00644 stacksize=hdr->stp-hdr->hea; 00645 00646 #if defined AMX_ASM && defined AMX_JIT 00647 if ((amx->flags & AMX_FLAG_JITC)!=0) 00648 jit_codesize=amx_jit_list(amx,&opcode_list,&max_opcode); 00649 else 00650 amx_exec_list(amx,&opcode_list,&max_opcode); 00651 #elif defined AMX_JIT 00652 jit_codesize=amx_jit_list(amx,&opcode_list,&max_opcode); 00653 #else 00654 amx_exec_list(amx,&opcode_list,&max_opcode); 00655 #endif 00656 #if defined AMX_TOKENTHREADING 00657 opcode_list=NULL; /* avoid token translation if token threading is in effect */ 00658 #endif 00659 #if defined AMX_NO_PACKED_OPC 00660 opmask= ~0; 00661 #else 00662 opmask=(1 << sizeof(cell)*4)-1; 00663 #endif 00664 00665 /* sanity checks */ 00666 assert_static(OP_XCHG==21); 00667 assert_static(OP_SMUL==42); 00668 assert_static(OP_MOVS==64); 00669 #if !defined AMX_NO_MACRO_INSTR 00670 assert_static(OP_LIDX==81); 00671 assert_static(OP_ZERO_PRI==102); 00672 assert_static(OP_LOAD2==120); 00673 #endif 00674 #if !defined AMX_NO_PACKED_OPC 00675 assert_static(OP_LOAD_P_PRI==124); 00676 assert_static(OP_ALIGN_P_PRI==141); 00677 assert_static(OP_BOUNDS_P==174); 00678 #endif 00679 00680 sysreq_flg=0; 00681 if (opcode_list!=NULL) { 00682 if (amx->sysreq_d==opcode_list[OP_SYSREQ_D]) 00683 sysreq_flg=0x01; 00684 else if (amx->sysreq_d==opcode_list[OP_SYSREQ_ND]) 00685 sysreq_flg=0x02; 00686 } else { 00687 if (amx->sysreq_d==OP_SYSREQ_D) 00688 sysreq_flg=0x01; 00689 else if (amx->sysreq_d==OP_SYSREQ_ND) 00690 sysreq_flg=0x02; 00691 } /* if */ 00692 amx->sysreq_d=0; /* preset */ 00693 00694 /* start browsing code */ 00695 assert(amx->code!=NULL); /* should already have been set in amx_Init() */ 00696 for (cip=0; cip<amx->codesize; ) { 00697 op=*(cell *)(amx->code+(int)cip); 00698 if ((op & opmask)>=max_opcode) { 00699 amx->flags &= ~AMX_FLAG_VERIFY; 00700 return AMX_ERR_INVINSTR; 00701 } /* if */ 00702 /* relocate opcode (only works if the size of an opcode is at least 00703 * as big as the size of a pointer (jump address); so basically we 00704 * rely on the opcode and a pointer being 32-bit 00705 */ 00706 if (opcode_list!=NULL) { 00707 /* verify that opcode_list[op]!=NULL, if it is, this instruction 00708 * is unsupported 00709 */ 00710 if (opcode_list[op & opmask]==0) { 00711 amx->flags &= ~AMX_FLAG_VERIFY; 00712 return AMX_ERR_INVINSTR; 00713 } /* if */ 00714 *(cell *)(amx->code+(int)cip)=opcode_list[op & opmask]; 00715 } /* if */ 00716 #if defined AMX_JIT 00717 opcode_count++; 00718 #endif 00719 cip+=sizeof(cell); 00720 switch (op & opmask) { 00721 #if !defined AMX_NO_MACRO_INSTR 00722 case OP_PUSHM_C: /* instructions with variable number of parameters */ 00723 case OP_PUSHM: 00724 case OP_PUSHM_S: 00725 case OP_PUSHM_ADR: 00726 case OP_PUSHRM_C: 00727 case OP_PUSHRM_S: 00728 case OP_PUSHRM_ADR: 00729 tgt=*(cell*)(amx->code+(int)cip); /* get count */ 00730 cip+=sizeof(cell)*(tgt+1); 00731 break; 00732 00733 case OP_LOAD2: 00734 tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ 00735 if (tgt<0 || tgt>=datasize) { 00736 amx->flags &= ~AMX_FLAG_VERIFY; 00737 return AMX_ERR_BOUNDS; 00738 } /* if */ 00739 tgt=*(cell*)(amx->code+(int)cip+(int)sizeof(cell)); 00740 if (tgt<0 || tgt>=datasize) { 00741 amx->flags &= ~AMX_FLAG_VERIFY; 00742 return AMX_ERR_BOUNDS; 00743 } /* if */ 00744 cip+=sizeof(cell)*2; 00745 break; 00746 00747 case OP_LOAD2_S: 00748 tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ 00749 if (tgt<-stacksize || tgt>stacksize) { 00750 amx->flags &= ~AMX_FLAG_VERIFY; 00751 return AMX_ERR_BOUNDS; 00752 } /* if */ 00753 tgt=*(cell*)(amx->code+(int)cip+(int)sizeof(cell)); 00754 if (tgt<-stacksize || tgt>stacksize) { 00755 amx->flags &= ~AMX_FLAG_VERIFY; 00756 return AMX_ERR_BOUNDS; 00757 } /* if */ 00758 cip+=sizeof(cell)*2; 00759 break; 00760 00761 case OP_CONST: 00762 tgt=*(cell*)(amx->code+(int)cip); /* verify address */ 00763 if (tgt<0 || tgt>=datasize) { 00764 amx->flags &= ~AMX_FLAG_VERIFY; 00765 return AMX_ERR_BOUNDS; 00766 } /* if */ 00767 cip+=sizeof(cell)*2; 00768 break; 00769 00770 case OP_CONST_S: 00771 tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ 00772 if (tgt<-stacksize || tgt>stacksize) { 00773 amx->flags &= ~AMX_FLAG_VERIFY; 00774 return AMX_ERR_BOUNDS; 00775 } /* if */ 00776 cip+=sizeof(cell)*2; 00777 break; 00778 #endif /* !defined AMX_NO_MACRO_INSTR */ 00779 00780 #if !defined AMX_NO_PACKED_OPC 00781 case OP_LODB_P_I: /* instructions with 1 parameter packed inside the same cell */ 00782 case OP_CONST_P_PRI: 00783 case OP_CONST_P_ALT: 00784 case OP_ADDR_P_PRI: 00785 case OP_ADDR_P_ALT: 00786 case OP_STRB_P_I: 00787 case OP_LIDX_P_B: 00788 case OP_IDXADDR_P_B: 00789 case OP_ALIGN_P_PRI: 00790 case OP_PUSH_P_C: 00791 case OP_PUSH_P: 00792 case OP_PUSH_P_S: 00793 case OP_PUSH_P_ADR: 00794 case OP_PUSHR_P_C: 00795 case OP_PUSHR_P_S: 00796 case OP_PUSHR_P_ADR: 00797 case OP_STACK_P: 00798 case OP_HEAP_P: 00799 case OP_SHL_P_C_PRI: 00800 case OP_SHL_P_C_ALT: 00801 case OP_ADD_P_C: 00802 case OP_SMUL_P_C: 00803 case OP_ZERO_P: 00804 case OP_ZERO_P_S: 00805 case OP_EQ_P_C_PRI: 00806 case OP_EQ_P_C_ALT: 00807 case OP_MOVS_P: 00808 case OP_CMPS_P: 00809 case OP_FILL_P: 00810 case OP_HALT_P: 00811 case OP_BOUNDS_P: 00812 break; 00813 00814 case OP_LOAD_P_PRI: /* data instructions with 1 parameter packed inside the same cell */ 00815 case OP_LOAD_P_ALT: 00816 case OP_STOR_P: 00817 case OP_INC_P: 00818 case OP_DEC_P: 00819 GETPARAM_P(tgt,op); /* verify address */ 00820 if (tgt<0 || tgt>=datasize) { 00821 amx->flags &= ~AMX_FLAG_VERIFY; 00822 return AMX_ERR_BOUNDS; 00823 } /* if */ 00824 break; 00825 00826 case OP_LOAD_P_S_PRI: /* stack instructions with 1 parameter packed inside the same cell */ 00827 case OP_LOAD_P_S_ALT: 00828 case OP_LREF_P_S_PRI: 00829 case OP_LREF_P_S_ALT: 00830 case OP_STOR_P_S: 00831 case OP_SREF_P_S: 00832 case OP_INC_P_S: 00833 case OP_DEC_P_S: 00834 GETPARAM_P(tgt,op); /* verify address */ 00835 if (tgt<-stacksize || tgt>stacksize) { 00836 amx->flags &= ~AMX_FLAG_VERIFY; 00837 return AMX_ERR_BOUNDS; 00838 } /* if */ 00839 break; 00840 00841 case OP_PUSHM_P_C: /* instructions with variable number of parameters */ 00842 case OP_PUSHM_P: 00843 case OP_PUSHM_P_S: 00844 case OP_PUSHM_P_ADR: 00845 case OP_PUSHRM_P_C: 00846 case OP_PUSHRM_P_S: 00847 case OP_PUSHRM_P_ADR: 00848 GETPARAM_P(tgt,op); /* verify address */ 00849 cip+=sizeof(cell)*tgt; 00850 break; 00851 #endif /* !defined AMX_NO_PACKED_OPC */ 00852 00853 case OP_LODB_I: /* instructions with 1 parameter (not packed) */ 00854 case OP_CONST_PRI: 00855 case OP_CONST_ALT: 00856 case OP_ADDR_PRI: 00857 case OP_ADDR_ALT: 00858 case OP_STRB_I: 00859 case OP_ALIGN_PRI: 00860 case OP_LCTRL: 00861 case OP_SCTRL: 00862 case OP_PICK: 00863 case OP_STACK: 00864 case OP_HEAP: 00865 case OP_SHL_C_PRI: 00866 case OP_SHL_C_ALT: 00867 case OP_MOVS: 00868 case OP_CMPS: 00869 case OP_FILL: 00870 case OP_HALT: 00871 case OP_BOUNDS: 00872 #if !defined AMX_NO_MACRO_INSTR 00873 case OP_LIDX_B: 00874 case OP_IDXADDR_B: 00875 case OP_PUSH_C: 00876 case OP_PUSH_ADR: 00877 case OP_PUSHR_C: 00878 case OP_PUSHR_ADR: 00879 case OP_ADD_C: 00880 case OP_SMUL_C: 00881 case OP_ZERO: 00882 case OP_ZERO_S: 00883 case OP_EQ_C_PRI: 00884 case OP_EQ_C_ALT: 00885 #endif 00886 cip+=sizeof(cell); 00887 break; 00888 00889 case OP_LOAD_PRI: 00890 case OP_LOAD_ALT: 00891 case OP_STOR: 00892 #if !defined AMX_NO_MACRO_INSTR 00893 case OP_PUSH: 00894 case OP_INC: 00895 case OP_DEC: 00896 #endif 00897 tgt=*(cell*)(amx->code+(int)cip); /* verify address */ 00898 if (tgt<0 || tgt>=datasize) { 00899 amx->flags &= ~AMX_FLAG_VERIFY; 00900 return AMX_ERR_BOUNDS; 00901 } /* if */ 00902 cip+=sizeof(cell); 00903 break; 00904 00905 case OP_LOAD_S_PRI: 00906 case OP_LOAD_S_ALT: 00907 case OP_LREF_S_PRI: 00908 case OP_LREF_S_ALT: 00909 case OP_STOR_S: 00910 case OP_SREF_S: 00911 #if !defined AMX_NO_MACRO_INSTR 00912 case OP_PUSH_S: 00913 case OP_PUSHR_S: 00914 case OP_INC_S: 00915 case OP_DEC_S: 00916 #endif 00917 tgt=*(cell*)(amx->code+(int)cip); /* verify address */ 00918 if (tgt<-stacksize || tgt>stacksize) { 00919 amx->flags &= ~AMX_FLAG_VERIFY; 00920 return AMX_ERR_BOUNDS; 00921 } /* if */ 00922 cip+=sizeof(cell); 00923 break; 00924 00925 case OP_NOP: /* instructions without parameters */ 00926 case OP_LOAD_I: 00927 case OP_STOR_I: 00928 case OP_XCHG: 00929 case OP_PUSH_PRI: 00930 case OP_PUSH_ALT: 00931 case OP_PUSHR_PRI: 00932 case OP_POP_PRI: 00933 case OP_POP_ALT: 00934 case OP_PROC: 00935 case OP_RET: 00936 case OP_RETN: 00937 case OP_SHL: 00938 case OP_SHR: 00939 case OP_SSHR: 00940 case OP_SMUL: 00941 case OP_SDIV: 00942 case OP_ADD: 00943 case OP_SUB: 00944 case OP_AND: 00945 case OP_OR: 00946 case OP_XOR: 00947 case OP_NOT: 00948 case OP_NEG: 00949 case OP_INVERT: 00950 case OP_EQ: 00951 case OP_NEQ: 00952 case OP_SLESS: 00953 case OP_SLEQ: 00954 case OP_SGRTR: 00955 case OP_SGEQ: 00956 case OP_INC_PRI: 00957 case OP_INC_ALT: 00958 case OP_INC_I: 00959 case OP_DEC_PRI: 00960 case OP_DEC_ALT: 00961 case OP_DEC_I: 00962 case OP_SWAP_PRI: 00963 case OP_SWAP_ALT: 00964 case OP_BREAK: 00965 #if !defined AMX_NO_MACRO_INSTR 00966 case OP_LIDX: 00967 case OP_IDXADDR: 00968 case OP_SDIV_INV: 00969 case OP_SUB_INV: 00970 case OP_ZERO_PRI: 00971 case OP_ZERO_ALT: 00972 #endif 00973 break; 00974 00975 case OP_CALL: /* opcodes that need relocation (JIT only), or conversion to position-independent code */ 00976 case OP_JUMP: 00977 case OP_JZER: 00978 case OP_JNZ: 00979 case OP_SWITCH: 00980 #if !defined AMX_NO_MACRO_INSTR 00981 case OP_JEQ: 00982 case OP_JNEQ: 00983 case OP_JSLESS: 00984 case OP_JSLEQ: 00985 case OP_JSGRTR: 00986 case OP_JSGEQ: 00987 #endif 00988 tgt=*(cell*)(amx->code+(int)cip)+cip-sizeof(cell); 00989 if (tgt<0 || tgt>amx->codesize) { 00990 amx->flags &= ~AMX_FLAG_VERIFY; 00991 return AMX_ERR_BOUNDS; 00992 } /* if */ 00993 #if defined AMX_JIT 00994 reloc_count++; 00995 RELOC_ABS(amx->code, cip); /* change to absolute physical address */ 00996 #endif 00997 cip+=sizeof(cell); 00998 break; 00999 01000 #if !defined AMX_NO_OVERLAY 01001 /* overlay opcodes (overlays must be enabled) */ 01002 case OP_SWITCH_OVL: 01003 assert(hdr->file_version>=10); 01004 tgt=*(cell*)(amx->code+(int)cip)+cip-sizeof(cell); 01005 if (tgt<0 || tgt>amx->codesize) { 01006 amx->flags &= ~AMX_FLAG_VERIFY; 01007 return AMX_ERR_BOUNDS; 01008 } /* if */ 01009 /* drop through */ 01010 case OP_CALL_OVL: 01011 cip+=sizeof(cell); 01012 /* drop through */ 01013 case OP_RETN_OVL: 01014 assert(hdr->overlays!=0 && hdr->overlays!=hdr->nametable); 01015 #if defined AMX_JIT 01016 if ((amx->flags & AMX_FLAG_JITC)!=0) 01017 return AMX_ERR_OVERLAY; /* JIT does not support overlays */ 01018 #endif 01019 if (amx->overlay==NULL) 01020 return AMX_ERR_OVERLAY; /* no overlay callback */ 01021 break; 01022 case OP_CASETBL_OVL: { 01023 cell num; 01024 DBGPARAM(num); /* number of records follows the opcode */ 01025 cip+=(2*num + 1)*sizeof(cell); 01026 if (amx->overlay==NULL) 01027 return AMX_ERR_OVERLAY; /* no overlay callback */ 01028 break; 01029 } /* case */ 01030 #endif 01031 01032 case OP_SYSREQ: 01033 cip+=sizeof(cell); 01034 sysreq_flg|=0x01; /* mark SYSREQ found */ 01035 break; 01036 #if !defined AMX_NO_MACRO_INSTR 01037 case OP_SYSREQ_N: 01038 cip+=sizeof(cell)*2; 01039 sysreq_flg|=0x02; /* mark SYSREQ.N found */ 01040 break; 01041 #endif 01042 01043 case OP_CASETBL: { 01044 cell num,offs; 01045 int i; 01046 DBGPARAM(num); /* number of records follows the opcode */ 01047 for (i=0; i<=num; i++) { 01048 offs=cip+2*i*sizeof(cell); 01049 tgt=*(cell*)(amx->code+(int)offs)+offs-sizeof(cell); 01050 if (tgt<0 || tgt>amx->codesize) { 01051 amx->flags &= ~AMX_FLAG_VERIFY; 01052 return AMX_ERR_BOUNDS; 01053 } /* if */ 01054 #if defined AMX_JIT 01055 RELOC_ABS(amx->code, cip+2*i*sizeof(cell)); 01056 reloc_count++; 01057 #endif 01058 } /* for */ 01059 cip+=(2*num + 1)*sizeof(cell); 01060 break; 01061 } /* case */ 01062 01063 default: 01064 amx->flags &= ~AMX_FLAG_VERIFY; 01065 return AMX_ERR_INVINSTR; 01066 } /* switch */ 01067 } /* for */ 01068 01069 #if !defined AMX_DONT_RELOCATE 01070 /* only either type of system request opcode should be found (otherwise, 01071 * we probably have a non-conforming compiler 01072 */ 01073 if ((sysreq_flg==0x01 || sysreq_flg==0x02) && (amx->flags & AMX_FLAG_JITC)==0) { 01074 /* to use direct system requests, a function pointer must fit in a cell; 01075 * because the native function's address will be stored as the parameter 01076 * of SYSREQ.(N)D 01077 */ 01078 if (sizeof(AMX_NATIVE)<=sizeof(cell)) { 01079 if (opcode_list!=NULL) 01080 amx->sysreq_d=(sysreq_flg==0x01) ? opcode_list[OP_SYSREQ_D] : opcode_list[OP_SYSREQ_ND]; 01081 else 01082 amx->sysreq_d=(sysreq_flg==0x01) ? OP_SYSREQ_D : OP_SYSREQ_ND; 01083 } /* if */ 01084 } /* if */ 01085 #endif 01086 01087 #if defined AMX_JIT 01088 /* adjust the code size to mean: estimated code size of the native code 01089 * (instead of the size of the P-code) 01090 */ 01091 amx->codesize=jit_codesize*opcode_count + hdr->cod + (hdr->stp - hdr->dat); 01092 amx->reloc_size=2*sizeof(cell)*reloc_count; 01093 #endif 01094 01095 amx->flags &= ~AMX_FLAG_VERIFY; 01096 amx->flags |= AMX_FLAG_INIT; 01097 if (sysreq_flg & 0x02) 01098 amx->flags |= AMX_FLAG_SYSREQN; 01099 01100 return AMX_ERR_NONE; 01101 } 01102 01103 /* definitions used for amx_Init() and amx_Cleanup() */ 01104 #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD 01105 typedef int AMXEXPORT (AMXAPI _FAR *AMX_ENTRY)(AMX _FAR *amx); 01106 #endif 01107 01108 int AMXAPI amx_Init(AMX *amx,void *program) 01109 { 01110 AMX_HEADER *hdr; 01111 int err; 01112 uint16_t *namelength; 01113 unsigned char *data; 01114 #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD 01115 #if defined _Windows 01116 char libname[sNAMEMAX+8]; /* +1 for '\0', +3 for 'amx' prefix, +4 for extension */ 01117 HINSTANCE hlib; 01118 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01119 char libname[_MAX_PATH]; 01120 char *root; 01121 void *hlib; 01122 #if !defined AMX_LIBPATH 01123 #define AMX_LIBPATH "AMXLIB" 01124 #endif 01125 #endif 01126 int numlibraries; 01127 AMX_FUNCSTUB *lib; 01128 AMX_ENTRY libinit; 01129 #endif 01130 01131 if ((amx->flags & AMX_FLAG_INIT)!=0) 01132 return AMX_ERR_INIT; /* already initialized (may not do so twice) */ 01133 01134 hdr=(AMX_HEADER *)program; 01135 /* the header is in Little Endian, on a Big Endian machine, swap all 01136 * multi-byte words 01137 */ 01138 assert(check_endian()); 01139 #if BYTE_ORDER==BIG_ENDIAN 01140 amx_Align32((uint32_t*)&hdr->size); 01141 amx_Align16(&hdr->magic); 01142 amx_Align16((uint16_t*)&hdr->flags); 01143 amx_Align16((uint16_t*)&hdr->defsize); 01144 amx_Align32((uint32_t*)&hdr->cod); 01145 amx_Align32((uint32_t*)&hdr->dat); 01146 amx_Align32((uint32_t*)&hdr->hea); 01147 amx_Align32((uint32_t*)&hdr->stp); 01148 amx_Align32((uint32_t*)&hdr->cip); 01149 amx_Align32((uint32_t*)&hdr->publics); 01150 amx_Align32((uint32_t*)&hdr->natives); 01151 amx_Align32((uint32_t*)&hdr->libraries); 01152 amx_Align32((uint32_t*)&hdr->pubvars); 01153 amx_Align32((uint32_t*)&hdr->tags); 01154 if (hdr->file_version>=10) 01155 amx_Align32((uint32_t*)&hdr->overlays); 01156 #endif 01157 01158 if (hdr->magic!=AMX_MAGIC) 01159 return AMX_ERR_FORMAT; 01160 if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION) 01161 return AMX_ERR_VERSION; 01162 if (hdr->defsize!=sizeof(AMX_FUNCSTUB)) 01163 return AMX_ERR_FORMAT; 01164 /* check the maximum name length in the separate name table */ 01165 amx_Align32((uint32_t*)&hdr->nametable); 01166 namelength=(uint16_t*)((unsigned char*)program + (unsigned)hdr->nametable); 01167 amx_Align16(namelength); 01168 if (*namelength>sNAMEMAX) 01169 return AMX_ERR_FORMAT; 01170 if (hdr->stp<=0) 01171 return AMX_ERR_FORMAT; 01172 assert(hdr->hea == hdr->size); 01173 #if BYTE_ORDER==BIG_ENDIAN 01174 if ((hdr->flags & AMX_FLAG_COMPACT)==0) { 01175 ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod); 01176 while (code<(ucell *)((unsigned char *)program+(int)hdr->hea)) 01177 swapcell(code++); 01178 } /* if */ 01179 #endif 01180 01181 amx->base=(unsigned char *)program; 01182 01183 /* set initial values */ 01184 amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ 01185 amx->stp=hdr->stp - hdr->dat - sizeof(cell); 01186 amx->hea=amx->hlw; 01187 amx->stk=amx->stp; 01188 #if defined AMX_DEFCALLBACK 01189 if (amx->callback==NULL) 01190 amx->callback=amx_Callback; 01191 #endif 01192 01193 /* when running P-code from ROM (with the header with the native function 01194 * table in RAM), the "code" field must be set to a non-NULL value on 01195 * initialization, before calling amx_Init(); in an overlay scheme, the 01196 * code field is modified dynamically by the overlay callback 01197 */ 01198 if (amx->code==NULL) 01199 amx->code=amx->base+(int)hdr->cod; 01200 if (amx->codesize==0) 01201 amx->codesize=hdr->dat-hdr->cod; 01202 01203 /* to split the data segment off the code segment, the "data" field must 01204 * be set to a non-NULL value on initialization, before calling amx_Init(); 01205 * you may also need to explicitly initialize the data section with the 01206 * contents read from the AMX file 01207 */ 01208 if (amx->data!=NULL) { 01209 data=amx->data; 01210 if ((amx->flags & AMX_FLAG_DSEG_INIT)==0 && amx->overlay==NULL) 01211 memcpy(data,amx->base+(int)hdr->dat,(size_t)(hdr->hea-hdr->dat)); 01212 } else { 01213 data=amx->base+(int)hdr->dat; 01214 } /* if */ 01215 01216 /* Set a zero cell at the top of the stack, which functions 01217 * as a sentinel for strings. 01218 */ 01219 * (cell *)(data+(int)(hdr->stp-hdr->dat-sizeof(cell)))=0; 01220 01221 /* also align all addresses in the public function, public variable, 01222 * public tag and native function tables --offsets into the name table 01223 * (if present) must also be swapped. 01224 */ 01225 #if BYTE_ORDER==BIG_ENDIAN 01226 { /* local */ 01227 AMX_FUNCSTUB *fs; 01228 int i,num; 01229 01230 fs=GETENTRY(hdr,natives,0); 01231 num=NUMENTRIES(hdr,natives,libraries); 01232 for (i=0; i<num; i++) { 01233 amx_Align32(&fs->address); /* redundant, because it should be zero */ 01234 amx_Align32(&fs->nameofs); 01235 fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); 01236 } /* for */ 01237 01238 fs=GETENTRY(hdr,publics,0); 01239 assert(hdr->publics<=hdr->natives); 01240 num=NUMENTRIES(hdr,publics,natives); 01241 for (i=0; i<num; i++) { 01242 amx_Align32(&fs->address); 01243 amx_Align32(&fs->nameofs); 01244 fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); 01245 } /* for */ 01246 01247 fs=GETENTRY(hdr,pubvars,0); 01248 assert(hdr->pubvars<=hdr->tags); 01249 num=NUMENTRIES(hdr,pubvars,tags); 01250 for (i=0; i<num; i++) { 01251 amx_Align32(&fs->address); 01252 amx_Align32(&fs->nameofs); 01253 fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); 01254 } /* for */ 01255 01256 fs=GETENTRY(hdr,tags,0); 01257 if (hdr->file_version<7) { /* file version 7 introduced the name table */ 01258 assert(hdr->tags<=hdr->cod); 01259 num=NUMENTRIES(hdr,tags,cod); 01260 } else { 01261 assert(hdr->tags<=hdr->nametable); 01262 num=NUMENTRIES(hdr,tags,nametable); 01263 } /* if */ 01264 for (i=0; i<num; i++) { 01265 amx_Align32(&fs->address); 01266 amx_Align32(&fs->nameofs); 01267 fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); 01268 } /* for */ 01269 } /* local */ 01270 #endif 01271 01272 /* verify P-code and relocate address in the case of the JIT */ 01273 if ((hdr->flags & AMX_FLAG_OVERLAY)==0) { 01274 err=VerifyPcode(amx); 01275 } else { 01276 int i; 01277 err=(amx->overlay==NULL) ? AMX_ERR_OVERLAY : AMX_ERR_NONE; 01278 /* load every overlay on initialization and verify explicitly; we must 01279 * do this to know whether to use new or old system requests 01280 */ 01281 for (i=0; err==AMX_ERR_NONE && i<(int)((hdr->nametable - hdr->overlays)/sizeof(AMX_OVERLAYINFO)); i++) { 01282 err=amx->overlay(amx, i); 01283 if (err==AMX_ERR_NONE) 01284 err=VerifyPcode(amx); 01285 } /* for */ 01286 } /* if */ 01287 if (err!=AMX_ERR_NONE) 01288 return err; 01289 01290 /* load any extension modules that the AMX refers to */ 01291 #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD 01292 { /* local */ 01293 int i; 01294 #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01295 root=getenv("AMXLIB"); 01296 #endif 01297 hdr=(AMX_HEADER *)amx->base; 01298 numlibraries=NUMENTRIES(hdr,libraries,pubvars); 01299 for (i=0; i<numlibraries; i++) { 01300 lib=GETENTRY(hdr,libraries,i); 01301 libname[0]='\0'; 01302 #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01303 if (root!=NULL && *root!='\0') { 01304 strcpy(libname,root); 01305 if (libname[strlen(libname)-1]!='/') 01306 strcat(libname,"/"); 01307 } /* if */ 01308 #endif 01309 strcat(libname,"amx"); 01310 strcat(libname,GETENTRYNAME(hdr,lib)); 01311 #if defined _Windows 01312 strcat(libname,".dll"); 01313 #if defined __WIN32__ 01314 hlib=LoadLibraryA(libname); 01315 #else 01316 hlib=LoadLibrary(libname); 01317 if (hlib<=HINSTANCE_ERROR) 01318 hlib=NULL; 01319 #endif 01320 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01321 strcat(libname,".so"); 01322 hlib=dlopen(libname,RTLD_NOW); 01323 #endif 01324 if (hlib!=NULL) { 01325 /* a library that cannot be loaded or that does not have the required 01326 * initialization function is simply ignored 01327 */ 01328 char funcname[sNAMEMAX+9]; /* +1 for '\0', +4 for 'amx_', +4 for 'Init' */ 01329 strcpy(funcname,"amx_"); 01330 strcat(funcname,GETENTRYNAME(hdr,lib)); 01331 strcat(funcname,"Init"); 01332 #if defined _Windows 01333 libinit=(AMX_ENTRY)GetProcAddress(hlib,funcname); 01334 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01335 libinit=(AMX_ENTRY)dlsym(hlib,funcname); 01336 #endif 01337 if (libinit!=NULL) 01338 libinit(amx); 01339 } /* if */ 01340 lib->address=(ucell)hlib; 01341 } /* for */ 01342 } /* local */ 01343 #endif 01344 01345 return AMX_ERR_NONE; 01346 } 01347 01348 #if defined AMX_JIT 01349 01350 #define CODESIZE_JIT 8192 /* approximate size of the code for the JIT */ 01351 01352 #if defined __WIN32__ /* this also applies to Win32 "console" applications */ 01353 01354 #define ALIGN(addr) (addr) 01355 01356 #define PROT_READ 0x1 /* page can be read */ 01357 #define PROT_WRITE 0x2 /* page can be written */ 01358 #define PROT_EXEC 0x4 /* page can be executed */ 01359 #define PROT_NONE 0x0 /* page can not be accessed */ 01360 01361 static int mprotect(void *addr, size_t len, int prot) 01362 { 01363 DWORD prev, p = 0; 01364 if ((prot & PROT_WRITE)!=0) 01365 p = PAGE_EXECUTE_READWRITE; 01366 else 01367 p |= PAGE_EXECUTE_READ; 01368 return !VirtualProtect(addr, len, p, &prev); 01369 } 01370 01371 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01372 01373 /* Linux already has mprotect() */ 01374 #define ALIGN(addr) (char *)(((long)addr + sysconf(_SC_PAGESIZE)-1) & ~(sysconf(_SC_PAGESIZE)-1)) 01375 01376 #else 01377 01378 // TODO: Add cases for Mac OS/X and other operating systems 01379 01380 /* DOS32 has no imposed limits on its segments */ 01381 #define ALIGN(addr) (addr) 01382 #define mprotect(addr, len, prot) (0) 01383 01384 #endif /* #if defined __WIN32 __ */ 01385 01386 int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) 01387 { 01388 int res; 01389 AMX_HEADER *hdr; 01390 01391 if ((amx->flags & AMX_FLAG_JITC)==0) 01392 return AMX_ERR_INIT_JIT; /* flag not set, this AMX is not prepared for JIT */ 01393 if (hdr->file_version>MAX_FILE_VER_JIT) 01394 return AMX_ERR_VERSION; /* JIT may not support the newest file version(s) */ 01395 /* the JIT does not support overlays, but this is already checked in VerifyPcode() 01396 * the same goes for macro instructions: not supported in the JIT, but already 01397 * checked in VerifyPcode() 01398 */ 01399 01400 /* Patching SYSREQ(.N) opcodes to SYSREQ.(N)D cannot work in the JIT, because 01401 * the program would need to be re-JIT-compiled after patching a P-code 01402 * instruction. If this field is not zero, something went wrong in 01403 * VerifyPcode(). 01404 */ 01405 assert(amx->sysreq_d==0); 01406 01407 if (mprotect(ALIGN(amx_jit_compile), CODESIZE_JIT, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) 01408 return AMX_ERR_INIT_JIT; 01409 01410 /* copy the prefix */ 01411 memcpy(native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod); 01412 hdr = native_code; 01413 01414 /* MP: added check for correct compilation */ 01415 if ((res = amx_jit_compile(amx->base, reloc_table, native_code)) == 0) { 01416 /* update the required memory size (the previous value was a 01417 * conservative estimate, now we know the exact size) 01418 */ 01419 amx->codesize = (hdr->dat + hdr->stp + sizeof(cell)) & ~(sizeof(cell)-1); 01420 /* The compiled code is relocatable, since only relative jumps are 01421 * used for destinations within the generated code, and absolute 01422 * addresses are only for jumps into the runtime, which is fixed 01423 * in memory. 01424 */ 01425 /* set the new pointers */ 01426 amx->base = (unsigned char*)native_code; 01427 amx->code = amx->base + (int)hdr->cod; 01428 amx->cip = hdr->cip; 01429 } /* if */ 01430 01431 return (res == 0) ? AMX_ERR_NONE : AMX_ERR_INIT_JIT; 01432 } 01433 01434 #else /* #if defined AMX_JIT */ 01435 01436 int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table) 01437 { 01438 (void)amx; 01439 (void)compiled_program; 01440 (void)reloc_table; 01441 return AMX_ERR_INIT_JIT; 01442 } 01443 01444 #endif /* #if defined AMX_JIT */ 01445 01446 #endif /* AMX_INIT */ 01447 01448 #if defined AMX_CLEANUP 01449 int AMXAPI amx_Cleanup(AMX *amx) 01450 { 01451 #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD 01452 AMX_HEADER *hdr; 01453 int numlibraries,i; 01454 AMX_FUNCSTUB *lib; 01455 AMX_ENTRY libcleanup; 01456 #endif 01457 01458 /* unload all extension modules */ 01459 #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD 01460 hdr=(AMX_HEADER *)amx->base; 01461 assert(hdr->magic==AMX_MAGIC); 01462 numlibraries=NUMENTRIES(hdr,libraries,pubvars); 01463 for (i=0; i<numlibraries; i++) { 01464 lib=GETENTRY(hdr,libraries,i); 01465 if (lib->address!=0) { 01466 char funcname[sNAMEMAX+12]; /* +1 for '\0', +4 for 'amx_', +7 for 'Cleanup' */ 01467 strcpy(funcname,"amx_"); 01468 strcat(funcname,GETENTRYNAME(hdr,lib)); 01469 strcat(funcname,"Cleanup"); 01470 #if defined _Windows 01471 libcleanup=(AMX_ENTRY)GetProcAddress((HINSTANCE)lib->address,funcname); 01472 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01473 libcleanup=(AMX_ENTRY)dlsym((void*)lib->address,funcname); 01474 #endif 01475 if (libcleanup!=NULL) 01476 libcleanup(amx); 01477 #if defined _Windows 01478 FreeLibrary((HINSTANCE)lib->address); 01479 #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ 01480 dlclose((void*)lib->address); 01481 #endif 01482 } /* if */ 01483 } /* for */ 01484 #else 01485 (void)amx; 01486 #endif 01487 return AMX_ERR_NONE; 01488 } 01489 #endif /* AMX_CLEANUP */ 01490 01491 #if defined AMX_CLONE 01492 int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) 01493 { 01494 AMX_HEADER *hdr; 01495 unsigned char _FAR *dataSource; 01496 01497 if (amxSource==NULL) 01498 return AMX_ERR_FORMAT; 01499 if (amxClone==NULL) 01500 return AMX_ERR_PARAMS; 01501 if ((amxSource->flags & AMX_FLAG_INIT)==0) 01502 return AMX_ERR_INIT; 01503 hdr=(AMX_HEADER *)amxSource->base; 01504 if (hdr->magic!=AMX_MAGIC) 01505 return AMX_ERR_FORMAT; 01506 if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION) 01507 return AMX_ERR_VERSION; 01508 01509 /* set initial values */ 01510 amxClone->base=amxSource->base; 01511 amxClone->code=amxSource->code; 01512 amxClone->codesize=amxSource->codesize; 01513 amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ 01514 amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); 01515 amxClone->hea=amxClone->hlw; 01516 amxClone->stk=amxClone->stp; 01517 if (amxClone->callback==NULL) 01518 amxClone->callback=amxSource->callback; 01519 if (amxClone->debug==NULL) 01520 amxClone->debug=amxSource->debug; 01521 amxClone->flags=amxSource->flags; 01522 01523 /* copy the data segment; the stack and the heap can be left uninitialized */ 01524 assert(data!=NULL); 01525 amxClone->data=(unsigned char _FAR *)data; 01526 dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; 01527 memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); 01528 01529 /* Set a zero cell at the top of the stack, which functions 01530 * as a sentinel for strings. 01531 */ 01532 * (cell *)(amxClone->data+(int)amxClone->stp) = 0; 01533 01534 return AMX_ERR_NONE; 01535 } 01536 #endif /* AMX_CLONE */ 01537 01538 #if defined AMX_MEMINFO 01539 int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) 01540 { 01541 AMX_HEADER *hdr; 01542 01543 if (amx==NULL) 01544 return AMX_ERR_FORMAT; 01545 hdr=(AMX_HEADER *)amx->base; 01546 if (hdr->magic!=AMX_MAGIC) 01547 return AMX_ERR_FORMAT; 01548 if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION) 01549 return AMX_ERR_VERSION; 01550 01551 if (codesize!=NULL) 01552 *codesize=amx->codesize; 01553 if (datasize!=NULL) 01554 *datasize=hdr->hea - hdr->dat; 01555 if (stackheap!=NULL) 01556 *stackheap=hdr->stp - hdr->hea; 01557 01558 return AMX_ERR_NONE; 01559 } 01560 #endif /* AMX_MEMINFO */ 01561 01562 #if defined AMX_NAMELENGTH 01563 int AMXAPI amx_NameLength(AMX *amx, int *length) 01564 { 01565 AMX_HEADER *hdr; 01566 uint16_t *namelength; 01567 01568 assert(amx!=NULL); 01569 hdr=(AMX_HEADER *)amx->base; 01570 assert(hdr!=NULL); 01571 assert(hdr->magic==AMX_MAGIC); 01572 namelength=(uint16_t*)(amx->base + (unsigned)hdr->nametable); 01573 *length=*namelength; 01574 return AMX_ERR_NONE; 01575 } 01576 #endif /* AMX_NAMELENGTH */ 01577 01578 #if defined AMX_XXXNATIVES 01579 int AMXAPI amx_NumNatives(AMX *amx, int *number) 01580 { 01581 AMX_HEADER *hdr=(AMX_HEADER *)amx->base; 01582 assert(hdr!=NULL); 01583 assert(hdr->magic==AMX_MAGIC); 01584 assert(hdr->natives<=hdr->libraries); 01585 *number=NUMENTRIES(hdr,natives,libraries); 01586 return AMX_ERR_NONE; 01587 } 01588 01589 int AMXAPI amx_GetNative(AMX *amx, int index, char *name) 01590 { 01591 AMX_HEADER *hdr; 01592 AMX_FUNCSTUB *func; 01593 01594 hdr=(AMX_HEADER *)amx->base; 01595 assert(hdr!=NULL); 01596 assert(hdr->magic==AMX_MAGIC); 01597 assert(hdr->natives<=hdr->libraries); 01598 if (index>=(cell)NUMENTRIES(hdr,natives,libraries)) 01599 return AMX_ERR_INDEX; 01600 01601 func=GETENTRY(hdr,natives,index); 01602 strcpy(name,GETENTRYNAME(hdr,func)); 01603 return AMX_ERR_NONE; 01604 } 01605 01606 int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index) 01607 { 01608 int idx,last; 01609 char pname[sNAMEMAX+1]; 01610 01611 amx_NumNatives(amx, &last); 01612 /* linear search, the natives table is not sorted alphabetically */ 01613 for (idx=0; idx<last; idx++) { 01614 amx_GetNative(amx,idx,pname); 01615 if (strcmp(pname,name)==0) { 01616 *index=idx; 01617 return AMX_ERR_NONE; 01618 } /* if */ 01619 } /* for */ 01620 *index=INT_MAX; 01621 return AMX_ERR_NOTFOUND; 01622 } 01623 #endif /* AMX_XXXNATIVES */ 01624 01625 #if defined AMX_XXXPUBLICS 01626 int AMXAPI amx_NumPublics(AMX *amx, int *number) 01627 { 01628 AMX_HEADER *hdr=(AMX_HEADER *)amx->base; 01629 assert(hdr!=NULL); 01630 assert(hdr->magic==AMX_MAGIC); 01631 assert(hdr->publics<=hdr->natives); 01632 *number=NUMENTRIES(hdr,publics,natives); 01633 return AMX_ERR_NONE; 01634 } 01635 01636 int AMXAPI amx_GetPublic(AMX *amx, int index, char *name, ucell *address) 01637 { 01638 AMX_HEADER *hdr; 01639 AMX_FUNCSTUB *func; 01640 01641 hdr=(AMX_HEADER *)amx->base; 01642 assert(hdr!=NULL); 01643 assert(hdr->magic==AMX_MAGIC); 01644 assert(hdr->publics<=hdr->natives); 01645 if (index>=(cell)NUMENTRIES(hdr,publics,natives)) 01646 return AMX_ERR_INDEX; 01647 01648 func=GETENTRY(hdr,publics,index); 01649 if (name!=NULL) 01650 strcpy(name,GETENTRYNAME(hdr,func)); 01651 if (address!=NULL) 01652 *address=func->address; 01653 return AMX_ERR_NONE; 01654 } 01655 01656 int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index) 01657 { 01658 int first,last,mid,result; 01659 char pname[sNAMEMAX+1]; 01660 01661 amx_NumPublics(amx, &last); 01662 last--; /* last valid index is 1 less than the number of functions */ 01663 first=0; 01664 /* binary search */ 01665 while (first<=last) { 01666 mid=(first+last)/2; 01667 amx_GetPublic(amx,mid,pname,NULL); 01668 result=strcmp(pname,name); 01669 if (result>0) { 01670 last=mid-1; 01671 } else if (result<0) { 01672 first=mid+1; 01673 } else { 01674 *index=mid; 01675 return AMX_ERR_NONE; 01676 } /* if */ 01677 } /* while */ 01678 /* not found, set to an invalid index, so amx_Exec() on this index will fail 01679 * with an error 01680 */ 01681 *index=INT_MAX; 01682 return AMX_ERR_NOTFOUND; 01683 } 01684 #endif /* AMX_XXXPUBLICS */ 01685 01686 #if defined AMX_XXXPUBVARS 01687 int AMXAPI amx_NumPubVars(AMX *amx, int *number) 01688 { 01689 AMX_HEADER *hdr; 01690 01691 assert(amx!=NULL); 01692 hdr=(AMX_HEADER *)amx->base; 01693 assert(hdr!=NULL); 01694 assert(hdr->magic==AMX_MAGIC); 01695 assert(hdr->pubvars<=hdr->tags); 01696 *number=NUMENTRIES(hdr,pubvars,tags); 01697 return AMX_ERR_NONE; 01698 } 01699 01700 int AMXAPI amx_GetPubVar(AMX *amx, int index, char *name, cell **address) 01701 { 01702 AMX_HEADER *hdr; 01703 AMX_FUNCSTUB *var; 01704 unsigned char *data; 01705 01706 assert(amx!=NULL); 01707 hdr=(AMX_HEADER *)amx->base; 01708 assert(hdr!=NULL); 01709 assert(hdr->magic==AMX_MAGIC); 01710 assert(hdr->pubvars<=hdr->tags); 01711 if (index>=(cell)NUMENTRIES(hdr,pubvars,tags)) 01712 return AMX_ERR_INDEX; 01713 01714 var=GETENTRY(hdr,pubvars,index); 01715 strcpy(name,GETENTRYNAME(hdr,var)); 01716 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 01717 assert(address!=NULL); 01718 *address=(cell *)(data+(int)var->address); 01719 return AMX_ERR_NONE; 01720 } 01721 01722 int AMXAPI amx_FindPubVar(AMX *amx, const char *name, cell **address) 01723 { 01724 int first,last,mid,result; 01725 char pname[sNAMEMAX+1]; 01726 01727 amx_NumPubVars(amx,&last); 01728 last--; /* last valid index is 1 less than the number of functions */ 01729 first=0; 01730 /* binary search */ 01731 while (first<=last) { 01732 mid=(first+last)/2; 01733 amx_GetPubVar(amx,mid,pname,address); 01734 result=strcmp(pname,name); 01735 if (result>0) 01736 last=mid-1; 01737 else if (result<0) 01738 first=mid+1; 01739 else 01740 return AMX_ERR_NONE; 01741 } /* while */ 01742 /* not found */ 01743 assert(address!=NULL); 01744 *address=NULL; 01745 return AMX_ERR_NOTFOUND; 01746 } 01747 #endif /* AMX_XXXPUBVARS */ 01748 01749 #if defined AMX_XXXTAGS 01750 int AMXAPI amx_NumTags(AMX *amx, int *number) 01751 { 01752 AMX_HEADER *hdr=(AMX_HEADER *)amx->base; 01753 assert(hdr!=NULL); 01754 assert(hdr->magic==AMX_MAGIC); 01755 if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ 01756 *number=0; 01757 return AMX_ERR_VERSION; 01758 } /* if */ 01759 if (hdr->file_version<7) { /* file version 7 introduced the name table */ 01760 assert(hdr->tags<=hdr->cod); 01761 *number=NUMENTRIES(hdr,tags,cod); 01762 } else { 01763 assert(hdr->tags<=hdr->nametable); 01764 *number=NUMENTRIES(hdr,tags,nametable); 01765 } /* if */ 01766 return AMX_ERR_NONE; 01767 } 01768 01769 int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) 01770 { 01771 AMX_HEADER *hdr; 01772 AMX_FUNCSTUB *tag; 01773 01774 hdr=(AMX_HEADER *)amx->base; 01775 assert(hdr!=NULL); 01776 assert(hdr->magic==AMX_MAGIC); 01777 if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ 01778 *tagname='\0'; 01779 *tag_id=0; 01780 return AMX_ERR_VERSION; 01781 } /* if */ 01782 01783 if (hdr->file_version<7) { /* file version 7 introduced the name table */ 01784 assert(hdr->tags<=hdr->cod); 01785 if (index>=(cell)NUMENTRIES(hdr,tags,cod)) 01786 return AMX_ERR_INDEX; 01787 } else { 01788 assert(hdr->tags<=hdr->nametable); 01789 if (index>=(cell)NUMENTRIES(hdr,tags,nametable)) 01790 return AMX_ERR_INDEX; 01791 } /* if */ 01792 01793 tag=GETENTRY(hdr,tags,index); 01794 strcpy(tagname,GETENTRYNAME(hdr,tag)); 01795 *tag_id=tag->address; 01796 01797 return AMX_ERR_NONE; 01798 } 01799 01800 int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) 01801 { 01802 int first,last,mid; 01803 cell mid_id; 01804 01805 #if !defined NDEBUG 01806 /* verify that the tagname table is sorted on the tag_id */ 01807 amx_NumTags(amx, &last); 01808 if (last>0) { 01809 cell cur_id; 01810 amx_GetTag(amx,0,tagname,&cur_id); 01811 for (first=1; first<last; first++) { 01812 amx_GetTag(amx,first,tagname,&mid_id); 01813 assert(cur_id<mid_id); 01814 cur_id=mid_id; 01815 } /* for */ 01816 } /* if */ 01817 #endif 01818 01819 amx_NumTags(amx, &last); 01820 last--; /* last valid index is 1 less than the number of functions */ 01821 first=0; 01822 /* binary search */ 01823 while (first<=last) { 01824 mid=(first+last)/2; 01825 amx_GetTag(amx,mid,tagname,&mid_id); 01826 if (mid_id>tag_id) 01827 last=mid-1; 01828 else if (mid_id<tag_id) 01829 first=mid+1; 01830 else 01831 return AMX_ERR_NONE; 01832 } /* while */ 01833 /* not found */ 01834 *tagname='\0'; 01835 return AMX_ERR_NOTFOUND; 01836 } 01837 #endif /* AMX_XXXTAGS */ 01838 01839 #if defined AMX_XXXUSERDATA 01840 int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr) 01841 { 01842 int index; 01843 01844 assert(amx!=NULL); 01845 assert(tag!=0); 01846 for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++) 01847 /* nothing */; 01848 if (index>=AMX_USERNUM) 01849 return AMX_ERR_USERDATA; 01850 *ptr=amx->userdata[index]; 01851 return AMX_ERR_NONE; 01852 } 01853 01854 int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) 01855 { 01856 int index; 01857 01858 assert(amx!=NULL); 01859 assert(tag!=0); 01860 /* try to find existing tag */ 01861 for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++) 01862 /* nothing */; 01863 /* if not found, try to find empty tag */ 01864 if (index>=AMX_USERNUM) 01865 for (index=0; index<AMX_USERNUM && amx->usertags[index]!=0; index++) 01866 /* nothing */; 01867 /* if still not found, quit with error */ 01868 if (index>=AMX_USERNUM) 01869 return AMX_ERR_INDEX; 01870 /* set the tag and the value */ 01871 amx->usertags[index]=tag; 01872 amx->userdata[index]=ptr; 01873 return AMX_ERR_NONE; 01874 } 01875 #endif /* AMX_XXXUSERDATA */ 01876 01877 #if defined AMX_REGISTER 01878 static AMX_NATIVE findfunction(char *name, const AMX_NATIVE_INFO *list, int number) 01879 { 01880 int i; 01881 01882 assert(list!=NULL); 01883 for (i=0; list[i].name!=NULL && (i<number || number==-1); i++) 01884 if (strcmp(name,list[i].name)==0) 01885 return list[i].func; 01886 return NULL; 01887 } 01888 01889 int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *list, int number) 01890 { 01891 AMX_FUNCSTUB *func; 01892 AMX_HEADER *hdr; 01893 int i,numnatives,err; 01894 AMX_NATIVE funcptr; 01895 01896 assert(amx!=NULL); 01897 hdr=(AMX_HEADER *)amx->base; 01898 assert(hdr!=NULL); 01899 assert(hdr->magic==AMX_MAGIC); 01900 assert(hdr->natives<=hdr->libraries); 01901 numnatives=NUMENTRIES(hdr,natives,libraries); 01902 01903 err=AMX_ERR_NONE; 01904 func=GETENTRY(hdr,natives,0); 01905 for (i=0; i<numnatives; i++) { 01906 if (func->address==0) { 01907 /* this function is not yet located */ 01908 funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL; 01909 if (funcptr!=NULL) 01910 func->address=(ucell)funcptr; 01911 else 01912 err=AMX_ERR_NOTFOUND; 01913 } /* if */ 01914 func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); 01915 } /* for */ 01916 if (err==AMX_ERR_NONE) 01917 amx->flags|=AMX_FLAG_NTVREG; 01918 return err; 01919 } 01920 #endif /* AMX_REGISTER */ 01921 01922 #if defined AMX_NATIVEINFO 01923 AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func) 01924 { 01925 static AMX_NATIVE_INFO n; 01926 n.name=name; 01927 n.func=func; 01928 return &n; 01929 } 01930 #endif /* AMX_NATIVEINFO */ 01931 01932 01933 #define STKMARGIN ((cell)(16*sizeof(cell))) 01934 01935 #if defined AMX_PUSHXXX 01936 01937 int AMXAPI amx_Push(AMX *amx, cell value) 01938 { 01939 AMX_HEADER *hdr; 01940 unsigned char *data; 01941 01942 if (amx->hea+STKMARGIN>amx->stk) 01943 return AMX_ERR_STACKERR; 01944 hdr=(AMX_HEADER *)amx->base; 01945 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 01946 amx->stk-=sizeof(cell); 01947 amx->paramcount+=1; 01948 *(cell *)(data+(int)amx->stk)=value; 01949 return AMX_ERR_NONE; 01950 } 01951 01952 int AMXAPI amx_PushAddress(AMX *amx, cell *address) 01953 { 01954 AMX_HEADER *hdr; 01955 unsigned char *data; 01956 cell xaddr; 01957 01958 /* reverse relocate the address */ 01959 assert(amx!=NULL); 01960 hdr=(AMX_HEADER *)amx->base; 01961 assert(hdr!=NULL); 01962 assert(hdr->magic==AMX_MAGIC); 01963 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 01964 xaddr=(cell)((unsigned char*)address-data); 01965 if ((ucell)xaddr>=(ucell)amx->stp) 01966 return AMX_ERR_MEMACCESS; 01967 return amx_Push(amx,xaddr); 01968 } 01969 01970 int AMXAPI amx_PushArray(AMX *amx, cell **address, const cell array[], int numcells) 01971 { 01972 cell xaddr; 01973 int err; 01974 01975 assert(amx!=NULL); 01976 assert(array!=NULL); 01977 01978 xaddr=amx->hea; /* save, before it is modified by amx_Allot() */ 01979 err=amx_Allot(amx,numcells,address); 01980 if (err==AMX_ERR_NONE) { 01981 memcpy(*address,array,numcells*sizeof(cell)); 01982 err=amx_Push(amx,xaddr); 01983 } /* if */ 01984 return err; 01985 } 01986 01987 int AMXAPI amx_PushString(AMX *amx, cell **address, const char *string, int pack, int use_wchar) 01988 { 01989 cell xaddr; 01990 int numcells,err; 01991 01992 assert(amx!=NULL); 01993 assert(string!=NULL); 01994 01995 #if defined AMX_ANSIONLY 01996 numcells=strlen(string) + 1; 01997 #else 01998 numcells= (use_wchar ? wcslen((const wchar_t*)string) : strlen(string)) + 1; 01999 #endif 02000 if (pack) 02001 numcells=(numcells+sizeof(cell)-1)/sizeof(cell); 02002 xaddr=amx->hea; /* save, before it is modified by amx_Allot() */ 02003 err=amx_Allot(amx,numcells,address); 02004 if (err==AMX_ERR_NONE) { 02005 amx_SetString(*address,string,pack,use_wchar,numcells); 02006 err=amx_Push(amx,xaddr); 02007 } /* if */ 02008 return err; 02009 } 02010 #endif /* AMX_PUSHXXX */ 02011 02012 #if defined AMX_EXEC 02013 02014 /* It is assumed that the abstract machine can simply access the memory area 02015 * for the global data and the stack. If this is not the case, you need to 02016 * define the macro sets _R() and _W(), for reading and writing to memory. 02017 */ 02018 #if !defined _R 02019 #define _R_DEFAULT /* mark default memory access */ 02020 #define _R(base,addr) (* (cell *)((unsigned char*)(base)+(int)(addr))) 02021 #define _R8(base,addr) (* (unsigned char *)((unsigned char*)(base)+(int)(addr))) 02022 #define _R16(base,addr) (* (uint16_t *)((unsigned char*)(base)+(int)(addr))) 02023 #define _R32(base,addr) (* (uint32_t *)((unsigned char*)(base)+(int)(addr))) 02024 #endif 02025 #if !defined _W 02026 #define _W_DEFAULT /* mark default memory access */ 02027 #define _W(base,addr,value) ((*(cell *)((unsigned char*)(base)+(int)(addr)))=(cell)(value)) 02028 #define _W8(base,addr,value) ((*(unsigned char *)((unsigned char*)(base)+(int)(addr)))=(unsigned char)(value)) 02029 #define _W16(base,addr,value) ((*(uint16_t *)((unsigned char*)(base)+(int)(addr)))=(uint16_t)(value)) 02030 #define _W32(base,addr,value) ((*(uint32_t *)((unsigned char*)(base)+(int)(addr)))=(uint32_t)(value)) 02031 #endif 02032 02033 #if -8/3==-2 && 8/-3==-2 02034 #define TRUNC_SDIV /* signed divisions are truncated on this platform */ 02035 #else 02036 #define IABS(a) ((a)>=0 ? (a) : (-a)) 02037 #endif 02038 02039 /* The pseudo-instructions come from the code stream. Normally, these are just 02040 * accessed from memory. When the instructions must be fetched in some other 02041 * way, the definition below must be pre-defined. 02042 * N.B.: 02043 * - reading from a code address should increment the instruction pointer 02044 * (called "cip") 02045 * - only cell-sized accesses occur in code memory 02046 */ 02047 #if !defined _RCODE 02048 #define _RCODE() ( *cip++ ) 02049 #endif 02050 02051 #if !defined GETPARAM 02052 #define GETPARAM(v) ( v=_RCODE() ) /* read a parameter from the opcode stream */ 02053 #endif 02054 #if !defined SKIPPARAM 02055 #define SKIPPARAM(n) ( cip=(cell *)cip+(n) ) /* for obsolete opcodes */ 02056 #endif 02057 02058 #define AMXPUSH(v) ( amx->stk-=sizeof(cell), *(cell*)(data+amx->stk)=(v) ) 02059 #define ABORT(amx,v) { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; } 02060 02061 02062 #if !defined AMX_ALTCORE 02063 int amx_exec_list(AMX *amx,const cell **opcodelist,int *numopcodes) 02064 { 02065 (void)amx; 02066 assert(opcodelist!=NULL); 02067 *opcodelist=NULL; 02068 assert(numopcodes!=NULL); 02069 *numopcodes=OP_NUM_OPCODES; 02070 return 0; 02071 } 02072 #endif 02073 02074 int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) 02075 { 02076 AMX_HEADER *hdr; 02077 AMX_FUNCSTUB *func; 02078 unsigned char *data; 02079 cell reset_stk,reset_hea; 02080 int i; 02081 #if !defined AMX_ALTCORE 02082 cell pri,alt,stk,frm,hea; 02083 cell *cip,op,offs,val; 02084 #endif 02085 02086 assert(amx!=NULL); 02087 if ((amx->flags & AMX_FLAG_INIT)==0) 02088 return AMX_ERR_INIT; 02089 if (amx->callback==NULL) 02090 return AMX_ERR_CALLBACK; 02091 02092 hdr=(AMX_HEADER *)amx->base; 02093 assert(hdr!=NULL); 02094 assert(hdr->magic==AMX_MAGIC); 02095 02096 if ((amx->flags & AMX_FLAG_NTVREG)==0) { 02097 /* verify that all native functions have been registered (or do not 02098 * need registering) 02099 */ 02100 int numnatives; 02101 assert(hdr->natives<=hdr->libraries); 02102 numnatives=NUMENTRIES(hdr,natives,libraries); 02103 func=GETENTRY(hdr,natives,0); 02104 for (i=0; i<numnatives && func->address!=0; i++) 02105 func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); 02106 if (i<numnatives) 02107 return AMX_ERR_NOTFOUND; 02108 amx->flags|=AMX_FLAG_NTVREG; /* no need to check this again */ 02109 } /* if */ 02110 assert((amx->flags & AMX_FLAG_VERIFY)==0); 02111 02112 /* set up the registers */ 02113 assert(hdr!=NULL && hdr->magic==AMX_MAGIC); 02114 assert(amx->code!=NULL || hdr->overlays!=hdr->nametable); 02115 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 02116 reset_stk=amx->stk; 02117 reset_hea=amx->hea; 02118 amx->error=AMX_ERR_NONE; 02119 02120 /* get the start address */ 02121 if (index==AMX_EXEC_MAIN) { 02122 if (hdr->cip<0) 02123 return AMX_ERR_INDEX; 02124 amx->cip=hdr->cip; 02125 if (hdr->overlays!=hdr->nametable) { 02126 assert(hdr->overlays!=0); 02127 assert(amx->overlay!=NULL); 02128 amx->ovl_index=(int)hdr->cip; 02129 if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) 02130 return i; 02131 amx->cip=0; 02132 } /* if */ 02133 } else if (index==AMX_EXEC_CONT) { 02134 /* restore registers reset_stk & reset_hea */ 02135 reset_stk=amx->reset_stk; 02136 reset_hea=amx->reset_hea; 02137 if (hdr->overlays!=hdr->nametable) { 02138 assert(hdr->overlays!=0); 02139 assert(amx->overlay!=NULL); 02140 if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) 02141 return i; 02142 } /* if */ 02143 } else if (index<0) { 02144 return AMX_ERR_INDEX; 02145 } else { 02146 if (index>=(int)NUMENTRIES(hdr,publics,natives)) 02147 return AMX_ERR_INDEX; 02148 func=GETENTRY(hdr,publics,index); 02149 amx->cip=func->address; 02150 if (hdr->overlays!=hdr->nametable) { 02151 assert(hdr->overlays!=0); 02152 assert(amx->overlay!=NULL); 02153 amx->ovl_index=func->address; 02154 if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) 02155 return i; 02156 amx->cip=0; 02157 } /* if */ 02158 } /* if */ 02159 /* check values just copied */ 02160 if (amx->stk>amx->stp) 02161 return AMX_ERR_STACKLOW; 02162 if (amx->hea<amx->hlw) 02163 return AMX_ERR_HEAPLOW; 02164 assert(check_endian()); 02165 02166 /* sanity checks */ 02167 assert_static(OP_XCHG==21); 02168 assert_static(OP_SMUL==42); 02169 assert_static(OP_MOVS==64); 02170 #if !defined AMX_NO_MACRO_INSTR 02171 assert_static(OP_LIDX==81); 02172 assert_static(OP_ZERO_PRI==102); 02173 assert_static(OP_LOAD2==120); 02174 #endif 02175 #if !defined AMX_NO_PACKED_OPC 02176 assert_static(OP_LOAD_P_PRI==124); 02177 assert_static(OP_ALIGN_P_PRI==141); 02178 assert_static(OP_BOUNDS_P==174); 02179 #endif 02180 #if PAWN_CELL_SIZE==16 02181 assert_static(sizeof(cell)==2); 02182 #elif PAWN_CELL_SIZE==32 02183 assert_static(sizeof(cell)==4); 02184 #elif PAWN_CELL_SIZE==64 02185 assert_static(sizeof(cell)==8); 02186 #else 02187 #error Unsupported cell size 02188 #endif 02189 02190 if (index!=AMX_EXEC_CONT) { 02191 reset_stk+=amx->paramcount*sizeof(cell); 02192 AMXPUSH(amx->paramcount*sizeof(cell)); 02193 amx->paramcount=0; /* push the parameter count to the stack & reset */ 02194 AMXPUSH(0); /* return address (for overlays: overlay 0, offset 0) */ 02195 } /* if */ 02196 /* check stack/heap before starting to run */ 02197 if (amx->hea+STKMARGIN>amx->stk) 02198 return AMX_ERR_STACKERR; 02199 02200 #if defined AMX_ALTCORE 02201 02202 /* start running either the ARM or 80x86 assembler abstract machine or the JIT */ 02203 #if defined AMX_ASM && defined AMX_JIT 02204 if ((amx->flags & AMX_FLAG_JITC)!=0) 02205 i = amx_jit_run(amx,retval,data); 02206 else 02207 i = amx_exec_run(amx,retval,data); 02208 #elif defined AMX_JIT 02209 i = amx_jit_run(amx,retval,data); 02210 #else 02211 /* also for GNU GCC and Intel C/C++ versions */ 02212 i = amx_exec_run(amx,retval,data); 02213 #endif 02214 if (i == AMX_ERR_SLEEP) { 02215 amx->reset_stk=reset_stk; 02216 amx->reset_hea=reset_hea; 02217 } else { 02218 /* remove parameters from the stack; do this the "hard" way, because 02219 * the assembler version has no internal knowledge of the local 02220 * variables, so any "clean" way would be a kludge anyway. 02221 */ 02222 amx->stk=reset_stk; 02223 amx->hea=reset_hea; 02224 } /* if */ 02225 return i; 02226 02227 #else 02228 02229 #define CHKMARGIN() if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR 02230 #define CHKSTACK() if (stk>amx->stp) return AMX_ERR_STACKLOW 02231 #define CHKHEAP() if (hea<amx->hlw) return AMX_ERR_HEAPLOW 02232 02233 /* PUSH() and POP() are defined in terms of the _R() and _W() macros */ 02234 #define PUSH(v) ( stk-=sizeof(cell), _W(data,stk,v) ) 02235 #define POP(v) ( v=_R(data,stk), stk+=sizeof(cell) ) 02236 02237 /* set up registers for ANSI-C core: pri, alt, frm, cip, hea, stk */ 02238 pri=amx->pri; 02239 alt=amx->alt; 02240 frm=amx->frm; 02241 cip=(cell *)(amx->code+(int)amx->cip); 02242 hea=amx->hea; 02243 stk=amx->stk; 02244 02245 /* start running */ 02246 for ( ;; ) { 02247 op=_RCODE(); 02248 switch (GETOPCODE(op)) { 02249 /* core instruction set */ 02250 case OP_NOP: 02251 break; 02252 case OP_LOAD_PRI: 02253 GETPARAM(offs); 02254 pri=_R(data,offs); 02255 break; 02256 case OP_LOAD_ALT: 02257 GETPARAM(offs); 02258 alt=_R(data,offs); 02259 break; 02260 case OP_LOAD_S_PRI: 02261 GETPARAM(offs); 02262 pri=_R(data,frm+offs); 02263 break; 02264 case OP_LOAD_S_ALT: 02265 GETPARAM(offs); 02266 alt=_R(data,frm+offs); 02267 break; 02268 case OP_LREF_S_PRI: 02269 GETPARAM(offs); 02270 offs=_R(data,frm+offs); 02271 pri=_R(data,offs); 02272 break; 02273 case OP_LREF_S_ALT: 02274 GETPARAM(offs); 02275 offs=_R(data,frm+offs); 02276 alt=_R(data,offs); 02277 break; 02278 case OP_LOAD_I: 02279 /* verify address */ 02280 if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp) 02281 ABORT(amx,AMX_ERR_MEMACCESS); 02282 pri=_R(data,pri); 02283 break; 02284 case OP_LODB_I: 02285 GETPARAM(offs); 02286 __lodb_i: 02287 /* verify address */ 02288 if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp) 02289 ABORT(amx,AMX_ERR_MEMACCESS); 02290 switch ((int)offs) { 02291 case 1: 02292 pri=_R8(data,pri); 02293 break; 02294 case 2: 02295 pri=_R16(data,pri); 02296 break; 02297 case 4: 02298 pri=_R32(data,pri); 02299 break; 02300 } /* switch */ 02301 break; 02302 case OP_CONST_PRI: 02303 GETPARAM(pri); 02304 break; 02305 case OP_CONST_ALT: 02306 GETPARAM(alt); 02307 break; 02308 case OP_ADDR_PRI: 02309 GETPARAM(pri); 02310 pri+=frm; 02311 break; 02312 case OP_ADDR_ALT: 02313 GETPARAM(alt); 02314 alt+=frm; 02315 break; 02316 case OP_STOR: 02317 GETPARAM(offs); 02318 _W(data,offs,pri); 02319 break; 02320 case OP_STOR_S: 02321 GETPARAM(offs); 02322 _W(data,frm+offs,pri); 02323 break; 02324 case OP_SREF_S: 02325 GETPARAM(offs); 02326 offs=_R(data,frm+offs); 02327 _W(data,offs,pri); 02328 break; 02329 case OP_STOR_I: 02330 /* verify address */ 02331 if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp) 02332 ABORT(amx,AMX_ERR_MEMACCESS); 02333 _W(data,alt,pri); 02334 break; 02335 case OP_STRB_I: 02336 GETPARAM(offs); 02337 __strb_i: 02338 /* verify address */ 02339 if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp) 02340 ABORT(amx,AMX_ERR_MEMACCESS); 02341 switch ((int)offs) { 02342 case 1: 02343 _W8(data,alt,pri); 02344 break; 02345 case 2: 02346 _W16(data,alt,pri); 02347 break; 02348 case 4: 02349 _W32(data,alt,pri); 02350 break; 02351 } /* switch */ 02352 break; 02353 case OP_ALIGN_PRI: 02354 GETPARAM(offs); 02355 #if BYTE_ORDER==LITTLE_ENDIAN 02356 if ((size_t)offs<sizeof(cell)) 02357 pri ^= sizeof(cell)-offs; 02358 #endif 02359 break; 02360 case OP_LCTRL: 02361 GETPARAM(offs); 02362 switch ((int)offs) { 02363 case 0: 02364 pri=hdr->cod; 02365 break; 02366 case 1: 02367 pri=hdr->dat; 02368 break; 02369 case 2: 02370 pri=hea; 02371 break; 02372 case 3: 02373 pri=amx->stp; 02374 break; 02375 case 4: 02376 pri=stk; 02377 break; 02378 case 5: 02379 pri=frm; 02380 break; 02381 case 6: 02382 pri=(cell)((unsigned char *)cip-amx->code); 02383 break; 02384 } /* switch */ 02385 break; 02386 case OP_SCTRL: 02387 GETPARAM(offs); 02388 switch ((int)offs) { 02389 case 0: 02390 case 1: 02391 case 3: 02392 /* cannot change these parameters */ 02393 break; 02394 case 2: 02395 hea=pri; 02396 break; 02397 case 4: 02398 stk=pri; 02399 break; 02400 case 5: 02401 frm=pri; 02402 break; 02403 case 6: 02404 cip=(cell *)(amx->code + (int)pri); 02405 break; 02406 } /* switch */ 02407 break; 02408 case OP_XCHG: 02409 offs=pri; /* offs is a temporary variable */ 02410 pri=alt; 02411 alt=offs; 02412 break; 02413 case OP_PUSH_PRI: 02414 PUSH(pri); 02415 break; 02416 case OP_PUSH_ALT: 02417 PUSH(alt); 02418 break; 02419 case OP_PUSHR_PRI: 02420 PUSH(data+pri); 02421 break; 02422 case OP_POP_PRI: 02423 POP(pri); 02424 break; 02425 case OP_POP_ALT: 02426 POP(alt); 02427 break; 02428 case OP_PICK: 02429 GETPARAM(offs); 02430 pri=_R(data,stk+offs); 02431 break; 02432 case OP_STACK: 02433 GETPARAM(offs); 02434 alt=stk; 02435 stk+=offs; 02436 CHKMARGIN(); 02437 CHKSTACK(); 02438 break; 02439 case OP_HEAP: 02440 GETPARAM(offs); 02441 alt=hea; 02442 hea+=offs; 02443 CHKMARGIN(); 02444 CHKHEAP(); 02445 break; 02446 case OP_PROC: 02447 PUSH(frm); 02448 frm=stk; 02449 CHKMARGIN(); 02450 break; 02451 case OP_RET: 02452 POP(frm); 02453 POP(offs); 02454 /* verify the return address */ 02455 if ((long)offs>=amx->codesize) 02456 ABORT(amx,AMX_ERR_MEMACCESS); 02457 cip=(cell *)(amx->code+(int)offs); 02458 break; 02459 case OP_RETN: 02460 POP(frm); 02461 POP(offs); 02462 /* verify the return address */ 02463 if ((long)offs>=amx->codesize) 02464 ABORT(amx,AMX_ERR_MEMACCESS); 02465 cip=(cell *)(amx->code+(int)offs); 02466 stk+=_R(data,stk)+sizeof(cell); /* remove parameters from the stack */ 02467 break; 02468 case OP_CALL: 02469 PUSH(((unsigned char *)cip-amx->code)+sizeof(cell));/* skip address */ 02470 cip=JUMPREL(cip); /* jump to the address */ 02471 break; 02472 case OP_JUMP: 02473 /* since the GETPARAM() macro modifies cip, you cannot 02474 * do GETPARAM(cip) directly */ 02475 cip=JUMPREL(cip); 02476 break; 02477 case OP_JZER: 02478 if (pri==0) 02479 cip=JUMPREL(cip); 02480 else 02481 SKIPPARAM(1); 02482 break; 02483 case OP_JNZ: 02484 if (pri!=0) 02485 cip=JUMPREL(cip); 02486 else 02487 SKIPPARAM(1); 02488 break; 02489 case OP_SHL: 02490 pri<<=alt; 02491 break; 02492 case OP_SHR: 02493 pri=(ucell)pri >> (int)alt; 02494 break; 02495 case OP_SSHR: 02496 pri>>=alt; 02497 break; 02498 case OP_SHL_C_PRI: 02499 GETPARAM(offs); 02500 pri<<=offs; 02501 break; 02502 case OP_SHL_C_ALT: 02503 GETPARAM(offs); 02504 alt<<=offs; 02505 break; 02506 case OP_SMUL: 02507 pri*=alt; 02508 break; 02509 case OP_SDIV: 02510 if (pri==0) 02511 ABORT(amx,AMX_ERR_DIVIDE); 02512 /* use floored division and matching remainder */ 02513 offs=pri; 02514 #if defined TRUNC_SDIV 02515 pri=alt/offs; 02516 alt=alt%offs; 02517 #else 02518 val=alt; /* portable routine for truncated division */ 02519 pri=IABS(alt)/IABS(offs); 02520 if ((cell)(val ^ offs)<0) 02521 pri=-pri; 02522 alt=val-pri*offs; /* calculate the matching remainder */ 02523 #endif 02524 /* now "fiddle" with the values to get floored division */ 02525 if (alt!=0 && (cell)(alt ^ offs)<0) { 02526 pri--; 02527 alt+=offs; 02528 } /* if */ 02529 break; 02530 case OP_ADD: 02531 pri+=alt; 02532 break; 02533 case OP_SUB: 02534 pri=alt-pri; 02535 break; 02536 case OP_AND: 02537 pri&=alt; 02538 break; 02539 case OP_OR: 02540 pri|=alt; 02541 break; 02542 case OP_XOR: 02543 pri^=alt; 02544 break; 02545 case OP_NOT: 02546 pri=!pri; 02547 break; 02548 case OP_NEG: 02549 pri=-pri; 02550 break; 02551 case OP_INVERT: 02552 pri=~pri; 02553 break; 02554 case OP_EQ: 02555 pri= pri==alt ? 1 : 0; 02556 break; 02557 case OP_NEQ: 02558 pri= pri!=alt ? 1 : 0; 02559 break; 02560 case OP_SLESS: 02561 pri= pri<alt ? 1 : 0; 02562 break; 02563 case OP_SLEQ: 02564 pri= pri<=alt ? 1 : 0; 02565 break; 02566 case OP_SGRTR: 02567 pri= pri>alt ? 1 : 0; 02568 break; 02569 case OP_SGEQ: 02570 pri= pri>=alt ? 1 : 0; 02571 break; 02572 case OP_INC_PRI: 02573 pri++; 02574 break; 02575 case OP_INC_ALT: 02576 alt++; 02577 break; 02578 case OP_INC_I: 02579 #if defined _R_DEFAULT 02580 *(cell *)(data+(int)pri) += 1; 02581 #else 02582 val=_R(data,pri); 02583 _W(data,pri,val+1); 02584 #endif 02585 break; 02586 case OP_DEC_PRI: 02587 pri--; 02588 break; 02589 case OP_DEC_ALT: 02590 alt--; 02591 break; 02592 case OP_DEC_I: 02593 #if defined _R_DEFAULT 02594 *(cell *)(data+(int)pri) -= 1; 02595 #else 02596 val=_R(data,pri); 02597 _W(data,pri,val-1); 02598 #endif 02599 break; 02600 case OP_MOVS: 02601 GETPARAM(offs); 02602 __movs: 02603 /* verify top & bottom memory addresses, for both source and destination 02604 * addresses 02605 */ 02606 if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp) 02607 ABORT(amx,AMX_ERR_MEMACCESS); 02608 if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp) 02609 ABORT(amx,AMX_ERR_MEMACCESS); 02610 if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp) 02611 ABORT(amx,AMX_ERR_MEMACCESS); 02612 if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp) 02613 ABORT(amx,AMX_ERR_MEMACCESS); 02614 #if defined _R_DEFAULT 02615 memcpy(data+(int)alt, data+(int)pri, (int)offs); 02616 #else 02617 for (i=0; i+4<offs; i+=4) { 02618 val=_R32(data,pri+i); 02619 _W32(data,alt+i,val); 02620 } /* for */ 02621 for ( ; i<offs; i++) { 02622 val=_R8(data,pri+i); 02623 _W8(data,alt+i,val); 02624 } /* for */ 02625 #endif 02626 break; 02627 case OP_CMPS: 02628 GETPARAM(offs); 02629 __cmps: 02630 /* verify top & bottom memory addresses, for both source and destination 02631 * addresses 02632 */ 02633 if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp) 02634 ABORT(amx,AMX_ERR_MEMACCESS); 02635 if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp) 02636 ABORT(amx,AMX_ERR_MEMACCESS); 02637 if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp) 02638 ABORT(amx,AMX_ERR_MEMACCESS); 02639 if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp) 02640 ABORT(amx,AMX_ERR_MEMACCESS); 02641 #if defined _R_DEFAULT 02642 pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); 02643 #else 02644 pri=0; 02645 for (i=0; i+4<offs && pri==0; i+=4) 02646 pri=_R32(data,alt+i)-_R32(data,pri+i); 02647 for ( ; i<offs && pri==0; i++) 02648 pri=_R8(data,alt+i)-_R8(data,pri+i); 02649 #endif 02650 break; 02651 case OP_FILL: 02652 GETPARAM(offs); 02653 __fill: 02654 /* verify top & bottom memory addresses (destination only) */ 02655 if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp) 02656 ABORT(amx,AMX_ERR_MEMACCESS); 02657 if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp) 02658 ABORT(amx,AMX_ERR_MEMACCESS); 02659 for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) 02660 _W32(data,i,pri); 02661 break; 02662 case OP_HALT: 02663 GETPARAM(offs); 02664 __halt: 02665 if (retval!=NULL) 02666 *retval=pri; 02667 /* store complete status (stk and hea are already set in the ABORT macro) */ 02668 amx->frm=frm; 02669 amx->pri=pri; 02670 amx->alt=alt; 02671 amx->cip=(cell)((unsigned char*)cip-amx->code); 02672 if (offs==AMX_ERR_SLEEP) { 02673 amx->stk=stk; 02674 amx->hea=hea; 02675 amx->reset_stk=reset_stk; 02676 amx->reset_hea=reset_hea; 02677 return (int)offs; 02678 } /* if */ 02679 ABORT(amx,(int)offs); 02680 case OP_BOUNDS: 02681 GETPARAM(offs); 02682 if ((ucell)pri>(ucell)offs) { 02683 amx->cip=(cell)((unsigned char *)cip-amx->code); 02684 ABORT(amx,AMX_ERR_BOUNDS); 02685 } /* if */ 02686 break; 02687 case OP_SYSREQ: 02688 GETPARAM(offs); 02689 /* save a few registers */ 02690 amx->cip=(cell)((unsigned char *)cip-amx->code); 02691 amx->hea=hea; 02692 amx->frm=frm; 02693 amx->stk=stk; 02694 i=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); 02695 if (i!=AMX_ERR_NONE) { 02696 if (i==AMX_ERR_SLEEP) { 02697 amx->pri=pri; 02698 amx->alt=alt; 02699 amx->reset_stk=reset_stk; 02700 amx->reset_hea=reset_hea; 02701 return i; 02702 } /* if */ 02703 ABORT(amx,i); 02704 } /* if */ 02705 break; 02706 case OP_SWITCH: { 02707 cell *cptr=JUMPREL(cip)+1;/* +1, to skip the "casetbl" opcode */ 02708 assert(*JUMPREL(cip)==OP_CASETBL); 02709 cip=JUMPREL(cptr+1); /* preset to "none-matched" case */ 02710 i=(int)*cptr; /* number of records in the case table */ 02711 for (cptr+=2; i>0 && *cptr!=pri; i--,cptr+=2) 02712 /* nothing */; 02713 if (i>0) 02714 cip=JUMPREL(cptr+1); /* case found */ 02715 break; 02716 } /* case */ 02717 case OP_SWAP_PRI: 02718 offs=_R(data,stk); 02719 _W32(data,stk,pri); 02720 pri=offs; 02721 break; 02722 case OP_SWAP_ALT: 02723 offs=_R(data,stk); 02724 _W32(data,stk,alt); 02725 alt=offs; 02726 break; 02727 case OP_BREAK: 02728 assert((amx->flags & AMX_FLAG_VERIFY)==0); 02729 if (amx->debug!=NULL) { 02730 /* store status */ 02731 amx->frm=frm; 02732 amx->stk=stk; 02733 amx->hea=hea; 02734 amx->cip=(cell)((unsigned char*)cip-amx->code); 02735 i=amx->debug(amx); 02736 if (i!=AMX_ERR_NONE) { 02737 if (i==AMX_ERR_SLEEP) { 02738 amx->pri=pri; 02739 amx->alt=alt; 02740 amx->reset_stk=reset_stk; 02741 amx->reset_hea=reset_hea; 02742 return i; 02743 } /* if */ 02744 ABORT(amx,i); 02745 } /* if */ 02746 } /* if */ 02747 break; 02748 #if !defined AMX_DONT_RELOCATE 02749 case OP_SYSREQ_D: /* see SYSREQ */ 02750 GETPARAM(offs); 02751 /* save a few registers */ 02752 amx->cip=(cell)((unsigned char *)cip-amx->code); 02753 amx->hea=hea; 02754 amx->frm=frm; 02755 amx->stk=stk; 02756 pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); 02757 if (amx->error!=AMX_ERR_NONE) { 02758 if (amx->error==AMX_ERR_SLEEP) { 02759 amx->pri=pri; 02760 amx->alt=alt; 02761 amx->reset_stk=reset_stk; 02762 amx->reset_hea=reset_hea; 02763 return AMX_ERR_SLEEP; 02764 } /* if */ 02765 ABORT(amx,amx->error); 02766 } /* if */ 02767 break; 02768 #endif 02769 #if !defined AMX_NO_MACRO_INSTR && !defined AMX_DONT_RELOCATE 02770 case OP_SYSREQ_ND: /* see SYSREQ_N */ 02771 GETPARAM(offs); 02772 GETPARAM(val); 02773 PUSH(val); 02774 /* save a few registers */ 02775 amx->cip=(cell)((unsigned char *)cip-amx->code); 02776 amx->hea=hea; 02777 amx->frm=frm; 02778 amx->stk=stk; 02779 pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); 02780 stk+=val+4; 02781 if (amx->error!=AMX_ERR_NONE) { 02782 if (amx->error==AMX_ERR_SLEEP) { 02783 amx->pri=pri; 02784 amx->alt=alt; 02785 amx->stk=stk; 02786 amx->reset_stk=reset_stk; 02787 amx->reset_hea=reset_hea; 02788 return AMX_ERR_SLEEP; 02789 } /* if */ 02790 ABORT(amx,amx->error); 02791 } /* if */ 02792 break; 02793 #endif 02794 02795 /* overlay instructions */ 02796 #if !defined AMX_NO_OVERLAY 02797 case OP_CALL_OVL: 02798 offs=(unsigned char *)cip-amx->code+sizeof(cell); /* skip address */ 02799 assert(offs>=0 && offs<(1<<(sizeof(cell)*4))); 02800 PUSH((offs<<(sizeof(cell)*4)) | amx->ovl_index); 02801 amx->ovl_index=(int)*cip; 02802 assert(amx->overlay!=NULL); 02803 if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) 02804 ABORT(amx,i); 02805 cip=(cell*)amx->code; 02806 break; 02807 case OP_RETN_OVL: 02808 assert(amx->overlay!=NULL); 02809 POP(frm); 02810 POP(offs); 02811 amx->ovl_index=offs & (((ucell)~0)>>4*sizeof(cell)); 02812 offs=(ucell)offs >> (sizeof(cell)*4); 02813 /* verify the index */ 02814 stk+=_R(data,stk)+sizeof(cell); /* remove parameters from the stack */ 02815 i=amx->overlay(amx,amx->ovl_index); /* reload overlay */ 02816 if (i!=AMX_ERR_NONE || (long)offs>=amx->codesize) 02817 ABORT(amx,AMX_ERR_MEMACCESS); 02818 cip=(cell *)(amx->code+(int)offs); 02819 break; 02820 case OP_SWITCH_OVL: { 02821 cell *cptr=JUMPREL(cip)+1; /* +1, to skip the "icasetbl" opcode */ 02822 assert(*JUMPREL(cip)==OP_CASETBL_OVL); 02823 amx->ovl_index=*(cptr+1); /* preset to "none-matched" case */ 02824 i=(int)*cptr; /* number of records in the case table */ 02825 for (cptr+=2; i>0 && *cptr!=pri; i--,cptr+=2) 02826 /* nothing */; 02827 if (i>0) 02828 amx->ovl_index=*(cptr+1); /* case found */ 02829 assert(amx->overlay!=NULL); 02830 if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) 02831 ABORT(amx,i); 02832 cip=(cell*)amx->code; 02833 break; 02834 } /* case */ 02835 #endif 02836 02837 /* supplemental and macro instructions */ 02838 #if !defined AMX_NO_MACRO_INSTR 02839 case OP_LIDX: 02840 offs=pri*sizeof(cell)+alt; 02841 /* verify address */ 02842 if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp) 02843 ABORT(amx,AMX_ERR_MEMACCESS); 02844 pri=_R(data,offs); 02845 break; 02846 case OP_LIDX_B: 02847 GETPARAM(offs); 02848 offs=(pri << (int)offs)+alt; 02849 /* verify address */ 02850 if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp) 02851 ABORT(amx,AMX_ERR_MEMACCESS); 02852 pri=_R(data,offs); 02853 break; 02854 case OP_IDXADDR: 02855 pri=pri*sizeof(cell)+alt; 02856 break; 02857 case OP_IDXADDR_B: 02858 GETPARAM(offs); 02859 pri=(pri << (int)offs)+alt; 02860 break; 02861 case OP_PUSH_C: 02862 GETPARAM(offs); 02863 PUSH(offs); 02864 break; 02865 case OP_PUSH: 02866 GETPARAM(offs); 02867 PUSH(_R(data,offs)); 02868 break; 02869 case OP_PUSH_S: 02870 GETPARAM(offs); 02871 PUSH(_R(data,frm+offs)); 02872 break; 02873 case OP_PUSH_ADR: 02874 GETPARAM(offs); 02875 PUSH(frm+offs); 02876 break; 02877 case OP_PUSHR_C: 02878 GETPARAM(offs); 02879 PUSH(data+offs); 02880 break; 02881 case OP_PUSHR_S: 02882 GETPARAM(offs); 02883 PUSH(data+_R(data,frm+offs)); 02884 break; 02885 case OP_PUSHR_ADR: 02886 GETPARAM(offs); 02887 PUSH(data+frm+offs); 02888 break; 02889 case OP_JEQ: 02890 if (pri==alt) 02891 cip=JUMPREL(cip); 02892 else 02893 SKIPPARAM(1); 02894 break; 02895 case OP_JNEQ: 02896 if (pri!=alt) 02897 cip=JUMPREL(cip); 02898 else 02899 SKIPPARAM(1); 02900 break; 02901 case OP_JSLESS: 02902 if (pri<alt) 02903 cip=JUMPREL(cip); 02904 else 02905 SKIPPARAM(1); 02906 break; 02907 case OP_JSLEQ: 02908 if (pri<=alt) 02909 cip=JUMPREL(cip); 02910 else 02911 SKIPPARAM(1); 02912 break; 02913 case OP_JSGRTR: 02914 if (pri>alt) 02915 cip=JUMPREL(cip); 02916 else 02917 SKIPPARAM(1); 02918 break; 02919 case OP_JSGEQ: 02920 if (pri>=alt) 02921 cip=JUMPREL(cip); 02922 else 02923 SKIPPARAM(1); 02924 break; 02925 case OP_SDIV_INV: 02926 if (alt==0) 02927 ABORT(amx,AMX_ERR_DIVIDE); 02928 /* use floored division and matching remainder */ 02929 offs=alt; 02930 #if defined TRUNC_SDIV 02931 pri=pri/offs; 02932 alt=pri%offs; 02933 #else 02934 val=pri; /* portable routine for truncated division */ 02935 pri=IABS(pri)/IABS(offs); 02936 if ((cell)(val ^ offs)<0) 02937 pri=-pri; 02938 alt=val-pri*offs; /* calculate the matching remainder */ 02939 #endif 02940 /* now "fiddle" with the values to get floored division */ 02941 if (alt!=0 && (cell)(alt ^ offs)<0) { 02942 pri--; 02943 alt+=offs; 02944 } /* if */ 02945 break; 02946 case OP_SUB_INV: 02947 pri-=alt; 02948 break; 02949 case OP_ADD_C: 02950 GETPARAM(offs); 02951 pri+=offs; 02952 break; 02953 case OP_SMUL_C: 02954 GETPARAM(offs); 02955 pri*=offs; 02956 break; 02957 case OP_ZERO_PRI: 02958 pri=0; 02959 break; 02960 case OP_ZERO_ALT: 02961 alt=0; 02962 break; 02963 case OP_ZERO: 02964 GETPARAM(offs); 02965 _W(data,offs,0); 02966 break; 02967 case OP_ZERO_S: 02968 GETPARAM(offs); 02969 _W(data,frm+offs,0); 02970 break; 02971 case OP_EQ_C_PRI: 02972 GETPARAM(offs); 02973 pri= pri==offs ? 1 : 0; 02974 break; 02975 case OP_EQ_C_ALT: 02976 GETPARAM(offs); 02977 pri= alt==offs ? 1 : 0; 02978 break; 02979 case OP_INC: 02980 GETPARAM(offs); 02981 #if defined _R_DEFAULT 02982 *(cell *)(data+(int)offs) += 1; 02983 #else 02984 val=_R(data,offs); 02985 _W(data,offs,val+1); 02986 #endif 02987 break; 02988 case OP_INC_S: 02989 GETPARAM(offs); 02990 #if defined _R_DEFAULT 02991 *(cell *)(data+(int)(frm+offs)) += 1; 02992 #else 02993 val=_R(data,frm+offs); 02994 _W(data,frm+offs,val+1); 02995 #endif 02996 break; 02997 case OP_DEC: 02998 GETPARAM(offs); 02999 #if defined _R_DEFAULT 03000 *(cell *)(data+(int)offs) -= 1; 03001 #else 03002 val=_R(data,offs); 03003 _W(data,offs,val-1); 03004 #endif 03005 break; 03006 case OP_DEC_S: 03007 GETPARAM(offs); 03008 #if defined _R_DEFAULT 03009 *(cell *)(data+(int)(frm+offs)) -= 1; 03010 #else 03011 val=_R(data,frm+offs); 03012 _W(data,frm+offs,val-1); 03013 #endif 03014 break; 03015 case OP_SYSREQ_N: 03016 GETPARAM(offs); 03017 GETPARAM(val); 03018 PUSH(val); 03019 /* save a few registers */ 03020 amx->cip=(cell)((unsigned char *)cip-amx->code); 03021 amx->hea=hea; 03022 amx->frm=frm; 03023 amx->stk=stk; 03024 i=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); 03025 stk+=val+4; 03026 if (i!=AMX_ERR_NONE) { 03027 if (i==AMX_ERR_SLEEP) { 03028 amx->pri=pri; 03029 amx->alt=alt; 03030 amx->stk=stk; 03031 amx->reset_stk=reset_stk; 03032 amx->reset_hea=reset_hea; 03033 return i; 03034 } /* if */ 03035 ABORT(amx,i); 03036 } /* if */ 03037 break; 03038 case OP_PUSHM_C: 03039 GETPARAM(val); 03040 while (val--) { 03041 GETPARAM(offs); 03042 PUSH(offs); 03043 } /* while */ 03044 break; 03045 case OP_PUSHM: 03046 GETPARAM(val); 03047 while (val--) { 03048 GETPARAM(offs); 03049 PUSH(_R(data,offs)); 03050 } /* while */ 03051 break; 03052 case OP_PUSHM_S: 03053 GETPARAM(val); 03054 while (val--) { 03055 GETPARAM(offs); 03056 PUSH(_R(data,frm+offs)); 03057 } /* while */ 03058 break; 03059 case OP_PUSHM_ADR: 03060 GETPARAM(val); 03061 while (val--) { 03062 GETPARAM(offs); 03063 PUSH(frm+offs); 03064 } /* while */ 03065 break; 03066 case OP_PUSHRM_C: 03067 GETPARAM(val); 03068 while (val--) { 03069 GETPARAM(offs); 03070 PUSH(data+offs); 03071 } /* while */ 03072 break; 03073 case OP_PUSHRM_S: 03074 GETPARAM(val); 03075 while (val--) { 03076 GETPARAM(offs); 03077 PUSH(data+_R(data,frm+offs)); 03078 } /* while */ 03079 break; 03080 case OP_PUSHRM_ADR: 03081 GETPARAM(val); 03082 while (val--) { 03083 GETPARAM(offs); 03084 PUSH(data+frm+offs); 03085 } /* while */ 03086 break; 03087 case OP_LOAD2: 03088 GETPARAM(offs); 03089 pri=_R(data,offs); 03090 GETPARAM(offs); 03091 alt=_R(data,offs); 03092 break; 03093 case OP_LOAD2_S: 03094 GETPARAM(offs); 03095 pri=_R(data,frm+offs); 03096 GETPARAM(offs); 03097 alt=_R(data,frm+offs); 03098 break; 03099 case OP_CONST: 03100 GETPARAM(offs); 03101 GETPARAM(val); 03102 _W32(data,offs,val); 03103 break; 03104 case OP_CONST_S: 03105 GETPARAM(offs); 03106 GETPARAM(val); 03107 _W32(data,frm+offs,val); 03108 break; 03109 #endif /* AMX_NO_MACRO_INSTR */ 03110 03111 #if !defined AMX_NO_PACKED_OPC 03112 case OP_LOAD_P_PRI: 03113 GETPARAM_P(offs,op); 03114 pri=_R(data,offs); 03115 break; 03116 case OP_LOAD_P_ALT: 03117 GETPARAM_P(offs,op); 03118 alt=_R(data,offs); 03119 break; 03120 case OP_LOAD_P_S_PRI: 03121 GETPARAM_P(offs,op); 03122 pri=_R(data,frm+offs); 03123 break; 03124 case OP_LOAD_P_S_ALT: 03125 GETPARAM_P(offs,op); 03126 alt=_R(data,frm+offs); 03127 break; 03128 case OP_LREF_P_S_PRI: 03129 GETPARAM_P(offs,op); 03130 offs=_R(data,frm+offs); 03131 pri=_R(data,offs); 03132 break; 03133 case OP_LREF_P_S_ALT: 03134 GETPARAM_P(offs,op); 03135 offs=_R(data,frm+offs); 03136 alt=_R(data,offs); 03137 break; 03138 case OP_LODB_P_I: 03139 GETPARAM_P(offs,op); 03140 goto __lodb_i; 03141 case OP_CONST_P_PRI: 03142 GETPARAM_P(pri,op); 03143 break; 03144 case OP_CONST_P_ALT: 03145 GETPARAM_P(alt,op); 03146 break; 03147 case OP_ADDR_P_PRI: 03148 GETPARAM_P(pri,op); 03149 pri+=frm; 03150 break; 03151 case OP_ADDR_P_ALT: 03152 GETPARAM_P(alt,op); 03153 alt+=frm; 03154 break; 03155 case OP_STOR_P: 03156 GETPARAM_P(offs,op); 03157 _W(data,offs,pri); 03158 break; 03159 case OP_STOR_P_S: 03160 GETPARAM_P(offs,op); 03161 _W(data,frm+offs,pri); 03162 break; 03163 case OP_SREF_P_S: 03164 GETPARAM_P(offs,op); 03165 offs=_R(data,frm+offs); 03166 _W(data,offs,pri); 03167 break; 03168 case OP_STRB_P_I: 03169 GETPARAM_P(offs,op); 03170 goto __strb_i; 03171 case OP_LIDX_P_B: 03172 GETPARAM_P(offs,op); 03173 offs=(pri << (int)offs)+alt; 03174 /* verify address */ 03175 if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp) 03176 ABORT(amx,AMX_ERR_MEMACCESS); 03177 pri=_R(data,offs); 03178 break; 03179 case OP_IDXADDR_P_B: 03180 GETPARAM_P(offs,op); 03181 pri=(pri << (int)offs)+alt; 03182 break; 03183 case OP_ALIGN_P_PRI: 03184 GETPARAM_P(offs,op); 03185 #if BYTE_ORDER==LITTLE_ENDIAN 03186 if ((size_t)offs<sizeof(cell)) 03187 pri ^= sizeof(cell)-offs; 03188 #endif 03189 break; 03190 case OP_PUSH_P_C: 03191 GETPARAM_P(offs,op); 03192 PUSH(offs); 03193 break; 03194 case OP_PUSH_P: 03195 GETPARAM_P(offs,op); 03196 PUSH(_R(data,offs)); 03197 break; 03198 case OP_PUSH_P_S: 03199 GETPARAM_P(offs,op); 03200 PUSH(_R(data,frm+offs)); 03201 break; 03202 case OP_PUSH_P_ADR: 03203 GETPARAM_P(offs,op); 03204 PUSH(frm+offs); 03205 break; 03206 case OP_PUSHR_P_C: 03207 GETPARAM_P(offs,op); 03208 PUSH(data+offs); 03209 break; 03210 case OP_PUSHR_P_S: 03211 GETPARAM_P(offs,op); 03212 PUSH(data+_R(data,frm+offs)); 03213 break; 03214 case OP_PUSHR_P_ADR: 03215 GETPARAM_P(offs,op); 03216 PUSH(data+frm+offs); 03217 break; 03218 case OP_PUSHM_P: 03219 GETPARAM_P(val,op); 03220 while (val--) { 03221 GETPARAM(offs); 03222 PUSH(_R(data,offs)); 03223 } /* while */ 03224 break; 03225 case OP_PUSHM_P_S: 03226 GETPARAM_P(val,op); 03227 while (val--) { 03228 GETPARAM(offs); 03229 PUSH(_R(data,frm+offs)); 03230 } /* while */ 03231 break; 03232 case OP_PUSHM_P_C: 03233 GETPARAM_P(val,op); 03234 while (val--) { 03235 GETPARAM(offs); 03236 PUSH(offs); 03237 } /* while */ 03238 break; 03239 case OP_PUSHM_P_ADR: 03240 GETPARAM_P(val,op); 03241 while (val--) { 03242 GETPARAM(offs); 03243 PUSH(frm+offs); 03244 } /* while */ 03245 break; 03246 case OP_PUSHRM_P_C: 03247 GETPARAM_P(val,op); 03248 while (val--) { 03249 GETPARAM(offs); 03250 PUSH(data+offs); 03251 } /* while */ 03252 break; 03253 case OP_PUSHRM_P_S: 03254 GETPARAM_P(val,op); 03255 while (val--) { 03256 GETPARAM(offs); 03257 PUSH(data+_R(data,frm+offs)); 03258 } /* while */ 03259 break; 03260 case OP_PUSHRM_P_ADR: 03261 GETPARAM_P(val,op); 03262 while (val--) { 03263 GETPARAM(offs); 03264 PUSH(data+frm+offs); 03265 } /* while */ 03266 break; 03267 case OP_STACK_P: 03268 GETPARAM_P(offs,op); 03269 alt=stk; 03270 stk+=offs; 03271 CHKMARGIN(); 03272 CHKSTACK(); 03273 break; 03274 case OP_HEAP_P: 03275 GETPARAM_P(offs,op); 03276 alt=hea; 03277 hea+=offs; 03278 CHKMARGIN(); 03279 CHKHEAP(); 03280 break; 03281 case OP_SHL_P_C_PRI: 03282 GETPARAM_P(offs,op); 03283 pri<<=offs; 03284 break; 03285 case OP_SHL_P_C_ALT: 03286 GETPARAM_P(offs,op); 03287 alt<<=offs; 03288 break; 03289 case OP_ADD_P_C: 03290 GETPARAM_P(offs,op); 03291 pri+=offs; 03292 break; 03293 case OP_SMUL_P_C: 03294 GETPARAM_P(offs,op); 03295 pri*=offs; 03296 break; 03297 case OP_ZERO_P: 03298 GETPARAM_P(offs,op); 03299 _W(data,offs,0); 03300 break; 03301 case OP_ZERO_P_S: 03302 GETPARAM_P(offs,op); 03303 _W(data,frm+offs,0); 03304 break; 03305 case OP_EQ_P_C_PRI: 03306 GETPARAM_P(offs,op); 03307 pri= pri==offs ? 1 : 0; 03308 break; 03309 case OP_EQ_P_C_ALT: 03310 GETPARAM_P(offs,op); 03311 pri= alt==offs ? 1 : 0; 03312 break; 03313 case OP_INC_P: 03314 GETPARAM_P(offs,op); 03315 #if defined _R_DEFAULT 03316 *(cell *)(data+(int)offs) += 1; 03317 #else 03318 val=_R(data,offs); 03319 _W(data,offs,val+1); 03320 #endif 03321 break; 03322 case OP_INC_P_S: 03323 GETPARAM_P(offs,op); 03324 #if defined _R_DEFAULT 03325 *(cell *)(data+(int)(frm+offs)) += 1; 03326 #else 03327 val=_R(data,frm+offs); 03328 _W(data,frm+offs,val+1); 03329 #endif 03330 break; 03331 case OP_DEC_P: 03332 GETPARAM_P(offs,op); 03333 #if defined _R_DEFAULT 03334 *(cell *)(data+(int)offs) -= 1; 03335 #else 03336 val=_R(data,offs); 03337 _W(data,offs,val-1); 03338 #endif 03339 break; 03340 case OP_DEC_P_S: 03341 GETPARAM_P(offs,op); 03342 #if defined _R_DEFAULT 03343 *(cell *)(data+(int)(frm+offs)) -= 1; 03344 #else 03345 val=_R(data,frm+offs); 03346 _W(data,frm+offs,val-1); 03347 #endif 03348 break; 03349 case OP_MOVS_P: 03350 GETPARAM_P(offs,op); 03351 goto __movs; 03352 case OP_CMPS_P: 03353 GETPARAM_P(offs,op); 03354 goto __cmps; 03355 case OP_FILL_P: 03356 GETPARAM_P(offs,op); 03357 goto __fill; 03358 case OP_HALT_P: 03359 GETPARAM_P(offs,op); 03360 goto __halt; 03361 case OP_BOUNDS_P: 03362 GETPARAM_P(offs,op); 03363 if ((ucell)pri>(ucell)offs) { 03364 amx->cip=(cell)((unsigned char *)cip-amx->code); 03365 ABORT(amx,AMX_ERR_BOUNDS); 03366 } /* if */ 03367 break; 03368 #endif /* AMX_NO_PACKED_OPC */ 03369 default: 03370 assert(0); /* invalid instructions should already have been caught in VerifyPcode() */ 03371 ABORT(amx,AMX_ERR_INVINSTR); 03372 } /* switch */ 03373 } /* for */ 03374 #endif /* AMX_ALTCORE */ 03375 } 03376 03377 #endif /* AMX_EXEC */ 03378 03379 #if defined AMX_SETCALLBACK 03380 int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) 03381 { 03382 assert(amx!=NULL); 03383 assert(callback!=NULL); 03384 amx->callback=callback; 03385 return AMX_ERR_NONE; 03386 } 03387 #endif /* AMX_SETCALLBACK */ 03388 03389 #if defined AMX_SETDEBUGHOOK 03390 int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) 03391 { 03392 assert(amx!=NULL); 03393 amx->debug=debug; 03394 return AMX_ERR_NONE; 03395 } 03396 #endif /* AMX_SETDEBUGHOOK */ 03397 03398 #if defined AMX_RAISEERROR 03399 int AMXAPI amx_RaiseError(AMX *amx, int error) 03400 { 03401 assert(error>0); 03402 amx->error=error; 03403 return AMX_ERR_NONE; 03404 } 03405 #endif /* AMX_RAISEERROR */ 03406 03407 #if defined AMX_ALLOT || defined AMX_PUSHXXX 03408 int AMXAPI amx_Allot(AMX *amx,int cells,cell **address) 03409 { 03410 AMX_HEADER *hdr; 03411 unsigned char *data; 03412 03413 assert(amx!=NULL); 03414 hdr=(AMX_HEADER *)amx->base; 03415 assert(hdr!=NULL); 03416 assert(hdr->magic==AMX_MAGIC); 03417 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 03418 03419 if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN) 03420 return AMX_ERR_MEMORY; 03421 if (address!=NULL) 03422 *address=(cell *)(data+(int)amx->hea); 03423 amx->hea+=cells*sizeof(cell); 03424 return AMX_ERR_NONE; 03425 } 03426 03427 int AMXAPI amx_Release(AMX *amx,cell *address) 03428 { 03429 AMX_HEADER *hdr; 03430 unsigned char *data; 03431 cell amx_addr; 03432 03433 assert(amx!=NULL); 03434 hdr=(AMX_HEADER *)amx->base; 03435 assert(hdr!=NULL); 03436 assert(hdr->magic==AMX_MAGIC); 03437 data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; 03438 amx_addr=(cell)((unsigned char*)address-data); 03439 if (amx->hea>amx_addr) 03440 amx->hea=amx_addr; 03441 return AMX_ERR_NONE; 03442 } 03443 #endif /* AMX_ALLOT || AMX_PUSHXXX */ 03444 03445 #if defined AMX_XXXSTRING || defined AMX_UTF8XXX 03446 03447 #define CHARBITS (8*sizeof(char)) 03448 #if PAWN_CELL_SIZE==16 03449 #define CHARMASK (0xffffu << 8*(2-sizeof(char))) 03450 #elif PAWN_CELL_SIZE==32 03451 #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) 03452 #elif PAWN_CELL_SIZE==64 03453 #define CHARMASK (0xffffffffffffffffuLL << 8*(8-sizeof(char))) 03454 #else 03455 #error Unsupported cell size 03456 #endif 03457 03458 int AMXAPI amx_StrLen(const cell *cstr, int *length) 03459 { 03460 int len; 03461 #if BYTE_ORDER==LITTLE_ENDIAN 03462 cell c; 03463 #endif 03464 03465 assert(length!=NULL); 03466 if (cstr==NULL) { 03467 *length=0; 03468 return AMX_ERR_PARAMS; 03469 } /* if */ 03470 03471 if ((ucell)*cstr>UNPACKEDMAX) { 03472 /* packed string */ 03473 assert_static(sizeof(char)==1); 03474 len=strlen((char *)cstr); /* find '\0' */ 03475 assert(check_endian()); 03476 #if BYTE_ORDER==LITTLE_ENDIAN 03477 /* on Little Endian machines, toggle the last bytes */ 03478 c=cstr[len/sizeof(cell)]; /* get last cell */ 03479 len=len - len % sizeof(cell); /* len = multiple of "cell" bytes */ 03480 while ((c & CHARMASK)!=0) { 03481 len++; 03482 c <<= 8*sizeof(char); 03483 } /* if */ 03484 #endif 03485 } else { 03486 for (len=0; cstr[len]!=0; len++) 03487 /* nothing */; 03488 } /* if */ 03489 *length = len; 03490 return AMX_ERR_NONE; 03491 } 03492 #endif 03493 03494 #if defined AMX_XXXSTRING || defined AMX_PUSHXXX 03495 int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar,size_t size) 03496 { /* the memory blocks should not overlap */ 03497 int len, i; 03498 03499 assert_static(UNLIMITED>0); 03500 #if defined AMX_ANSIONLY 03501 (void)use_wchar; 03502 len=strlen(source); 03503 #else 03504 len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); 03505 #endif 03506 if (pack) { 03507 /* create a packed string */ 03508 if (size<UNLIMITED/sizeof(cell) && (size_t)len>=size*sizeof(cell)) 03509 len=size*sizeof(cell)-1; 03510 dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ 03511 #if defined AMX_ANSIONLY 03512 memcpy(dest,source,len); 03513 #else 03514 if (use_wchar) { 03515 for (i=0; i<len; i++) 03516 ((char*)dest)[i]=(char)(((wchar_t*)source)[i]); 03517 } else { 03518 memcpy(dest,source,len); 03519 } /* if */ 03520 #endif 03521 /* On Big Endian machines, the characters are well aligned in the 03522 * cells; on Little Endian machines, we must swap all cells. 03523 */ 03524 assert(check_endian()); 03525 #if BYTE_ORDER==LITTLE_ENDIAN 03526 len /= sizeof(cell); 03527 while (len>=0) 03528 swapcell((ucell *)&dest[len--]); 03529 #endif 03530 } else { 03531 /* create an unpacked string */ 03532 if (size<UNLIMITED && (size_t)len>=size) 03533 len=size-1; 03534 #if defined AMX_ANSIONLY 03535 for (i=0; i<len; i++) 03536 dest[i]=(cell)source[i]; 03537 #else 03538 if (use_wchar) { 03539 for (i=0; i<len; i++) 03540 dest[i]=(cell)(((wchar_t*)source)[i]); 03541 } else { 03542 for (i=0; i<len; i++) 03543 dest[i]=(cell)source[i]; 03544 } /* if */ 03545 #endif 03546 dest[len]=0; 03547 } /* if */ 03548 return AMX_ERR_NONE; 03549 } 03550 #endif 03551 03552 #if defined AMX_XXXSTRING 03553 int AMXAPI amx_GetString(char *dest,const cell *source,int use_wchar,size_t size) 03554 { 03555 int len=0; 03556 #if defined AMX_ANSIONLY 03557 (void)use_wchar; /* unused parameter (if ANSI only) */ 03558 #endif 03559 if ((ucell)*source>UNPACKEDMAX) { 03560 /* source string is packed */ 03561 cell c=0; /* initialize to 0 to avoid a compiler warning */ 03562 int i=sizeof(cell)-1; 03563 char ch; 03564 while ((size_t)len<size) { 03565 if (i==sizeof(cell)-1) 03566 c=*source++; 03567 ch=(char)(c >> i*CHARBITS); 03568 if (ch=='\0') 03569 break; /* terminating zero character found */ 03570 #if defined AMX_ANSIONLY 03571 dest[len++]=ch; 03572 #else 03573 if (use_wchar) 03574 ((wchar_t*)dest)[len++]=ch; 03575 else 03576 dest[len++]=ch; 03577 #endif 03578 i=(i+sizeof(cell)-1) % sizeof(cell); 03579 } /* while */ 03580 } else { 03581 /* source string is unpacked */ 03582 #if defined AMX_ANSIONLY 03583 while (*source!=0 && (size_t)len<size) 03584 dest[len++]=(char)*source++; 03585 #else 03586 if (use_wchar) { 03587 while (*source!=0 && (size_t)len<size) 03588 ((wchar_t*)dest)[len++]=(wchar_t)*source++; 03589 } else { 03590 while (*source!=0 && (size_t)len<size) 03591 dest[len++]=(char)*source++; 03592 } /* if */ 03593 #endif 03594 } /* if */ 03595 /* store terminator */ 03596 if ((size_t)len>=size) 03597 len=size-1; 03598 if (len>=0) { 03599 #if defined AMX_ANSIONLY 03600 dest[len]='\0'; 03601 #else 03602 if (use_wchar) 03603 ((wchar_t*)dest)[len]=0; 03604 else 03605 dest[len]='\0'; 03606 #endif 03607 } /* IF */ 03608 return AMX_ERR_NONE; 03609 } 03610 #endif /* AMX_XXXSTRING */ 03611 03612 #if defined AMX_UTF8XXX 03613 #if defined __BORLANDC__ 03614 #pragma warn -amb -8000 /* ambiguous operators need parentheses */ 03615 #endif 03616 /* amx_UTF8Get() 03617 * Extract a single UTF-8 encoded character from a string and return a pointer 03618 * to the character just behind that UTF-8 character. The parameters "endptr" 03619 * and "value" may be NULL. 03620 * If the code is not valid UTF-8, "endptr" has the value of the input 03621 * parameter "string" and "value" is zero. 03622 */ 03623 int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value) 03624 { 03625 static const char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 }; 03626 static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x4000000L }; 03627 unsigned char c; 03628 cell result; 03629 int followup; 03630 03631 assert(string!=NULL); 03632 if (value!=NULL) /* preset, in case of an error */ 03633 *value=0; 03634 if (endptr!=NULL) 03635 *endptr=string; 03636 03637 c = *(const unsigned char*)string++; 03638 if (c<0x80) { 03639 /* ASCII */ 03640 result=c; 03641 } else { 03642 if (c<0xc0 || c>=0xfe) 03643 return AMX_ERR_PARAMS; /* invalid or "follower" code, quit with error */ 03644 /* At this point we know that the two top bits of c are ones. The two 03645 * bottom bits are always part of the code. We only need to consider 03646 * the 4 remaining bits; i.e., a 16-byte table. This is "utf8_count[]". 03647 * (Actually the utf8_count[] table records the number of follow-up 03648 * bytes minus 1. This is just for convenience.) 03649 */ 03650 assert((c & 0xc0)==0xc0); 03651 followup=(int)utf8_count[(c >> 2) & 0x0f]; 03652 /* The mask depends on the code length; this is just a very simple 03653 * relation. 03654 */ 03655 #define utf8_mask (0x1f >> followup) 03656 result= c & utf8_mask; 03657 /* Collect the follow-up codes using a drop-through switch statement; 03658 * this avoids a loop. In each case, verify the two leading bits. 03659 */ 03660 assert(followup>=0 && followup<=4); 03661 switch (followup) { 03662 case 4: 03663 if (((c=*string++) & 0xc0) != 0x80) goto error; 03664 result = (result << 6) | c & 0x3f; 03665 case 3: 03666 if (((c=*string++) & 0xc0) != 0x80) goto error; 03667 result = (result << 6) | c & 0x3f; 03668 case 2: 03669 if (((c=*string++) & 0xc0) != 0x80) goto error; 03670 result = (result << 6) | c & 0x3f; 03671 case 1: 03672 if (((c=*string++) & 0xc0) != 0x80) goto error; 03673 result = (result << 6) | c & 0x3f; 03674 case 0: 03675 if (((c=*string++) & 0xc0) != 0x80) goto error; 03676 result = (result << 6) | c & 0x3f; 03677 } /* switch */ 03678 /* Do additional checks: shortest encoding & reserved positions. The 03679 * lowmark limits also depends on the code length; it can be read from 03680 * a table with 5 elements. This is "utf8_lowmark[]". 03681 */ 03682 if (result<utf8_lowmark[followup]) 03683 goto error; 03684 if (result>=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff) 03685 goto error; 03686 } /* if */ 03687 03688 if (value!=NULL) 03689 *value=result; 03690 if (endptr!=NULL) 03691 *endptr=string; 03692 03693 return AMX_ERR_NONE; 03694 03695 error: 03696 return AMX_ERR_PARAMS; 03697 } 03698 03699 /* amx_UTF8Put() 03700 * Encode a single character into a byte string. The character may result in 03701 * a string of up to 6 bytes. The function returns an error code if "maxchars" 03702 * is lower than the required number of characters; in this case nothing is 03703 * stored. 03704 * The function does not zero-terminate the string. 03705 */ 03706 int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value) 03707 { 03708 assert(string!=NULL); 03709 if (endptr!=NULL) /* preset, in case of an error */ 03710 *endptr=string; 03711 03712 if (value<0x80) { 03713 /* 0xxxxxxx */ 03714 if (maxchars < 1) goto error; 03715 *string++ = (char)value; 03716 } else if (value<0x800) { 03717 /* 110xxxxx 10xxxxxx */ 03718 if (maxchars < 2) goto error; 03719 *string++ = (char)((value>>6) & 0x1f | 0xc0); 03720 *string++ = (char)(value & 0x3f | 0x80); 03721 } else if (value<0x10000) { 03722 /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */ 03723 if (maxchars < 3) goto error; 03724 if (value>=0xd800 && value<=0xdfff || value==0xfffe || value==0xffff) 03725 goto error; /* surrogate pairs and invalid characters */ 03726 *string++ = (char)((value>>12) & 0x0f | 0xe0); 03727 *string++ = (char)((value>>6) & 0x3f | 0x80); 03728 *string++ = (char)(value & 0x3f | 0x80); 03729 } else if (value<0x200000) { 03730 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 03731 if (maxchars < 4) goto error; 03732 *string++ = (char)((value>>18) & 0x07 | 0xf0); 03733 *string++ = (char)((value>>12) & 0x3f | 0x80); 03734 *string++ = (char)((value>>6) & 0x3f | 0x80); 03735 *string++ = (char)(value & 0x3f | 0x80); 03736 } else if (value<0x4000000) { 03737 /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 03738 if (maxchars < 5) goto error; 03739 *string++ = (char)((value>>24) & 0x03 | 0xf8); 03740 *string++ = (char)((value>>18) & 0x3f | 0x80); 03741 *string++ = (char)((value>>12) & 0x3f | 0x80); 03742 *string++ = (char)((value>>6) & 0x3f | 0x80); 03743 *string++ = (char)(value & 0x3f | 0x80); 03744 } else { 03745 /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */ 03746 if (maxchars < 6) goto error; 03747 *string++ = (char)((value>>30) & 0x01 | 0xfc); 03748 *string++ = (char)((value>>24) & 0x3f | 0x80); 03749 *string++ = (char)((value>>18) & 0x3f | 0x80); 03750 *string++ = (char)((value>>12) & 0x3f | 0x80); 03751 *string++ = (char)((value>>6) & 0x3f | 0x80); 03752 *string++ = (char)(value & 0x3f | 0x80); 03753 } /* if */ 03754 03755 if (endptr!=NULL) 03756 *endptr=string; 03757 return AMX_ERR_NONE; 03758 03759 error: 03760 return AMX_ERR_PARAMS; 03761 } 03762 03763 /* amx_UTF8Check() 03764 * Run through a zero-terminated string and check the validity of the UTF-8 03765 * encoding. The function returns an error code, it is AMX_ERR_NONE if the 03766 * string is valid UTF-8 (or valid ASCII for that matter). 03767 */ 03768 int AMXAPI amx_UTF8Check(const char *string, int *length) 03769 { 03770 int err=AMX_ERR_NONE; 03771 int len=0; 03772 while (err==AMX_ERR_NONE && *string!='\0') { 03773 err=amx_UTF8Get(string,&string,NULL); 03774 len++; 03775 } /* while */ 03776 if (length!=NULL) 03777 *length=len; 03778 return err; 03779 } 03780 03781 /* amx_UTF8Len() 03782 * Run through a wide string and return how many 8-bit characters are needed to 03783 * store the string in UTF-8 format. The returned cound excludes the terminating 03784 * zero byte. The function returns an error code. 03785 */ 03786 int AMXAPI amx_UTF8Len(const cell *cstr, int *length) 03787 { 03788 int err; 03789 03790 assert(length!=NULL); 03791 err=amx_StrLen(cstr, length); 03792 if (err==AMX_ERR_NONE && (ucell)*cstr<=UNPACKEDMAX) { 03793 char buffer[10]; /* maximum UTF-8 code is 6 characters */ 03794 char *endptr; 03795 int len=*length, count=0; 03796 while (len-->0) { 03797 amx_UTF8Put(buffer, &endptr, sizeof buffer, *cstr++); 03798 count+=(int)(endptr-buffer); 03799 } /* while */ 03800 *length=count; 03801 } /* while */ 03802 return err; 03803 } 03804 #endif /* AMX_UTF8XXX */
Generated on Sat Jul 16 2022 16:09:35 by 1.7.2