diff --git a/amxmodx/CLang.cpp b/amxmodx/CLang.cpp index 0a6d70df..86dd0977 100755 --- a/amxmodx/CLang.cpp +++ b/amxmodx/CLang.cpp @@ -86,12 +86,28 @@ int Compare(const String &k1, const String &k2) return k1.compare(k2.c_str()); } +template<> +int CompareAlt(char const * const &k1, String const &k2) +{ + return strcmp(k1, k2.c_str()); +} + template<> int HashFunction(const String &k) { unsigned long hash = 5381; - const char *str = k.c_str(); - char c; + register const char *str = k.c_str(); + register char c; + while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c + return hash; +} + +template<> +int HashAlt(char const * const &k) +{ + unsigned long hash = 5381; + register const char *str = k; + register char c; while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c return hash; } @@ -327,7 +343,7 @@ const char * CLangMngr::GetKey(int key) int CLangMngr::GetKeyEntry(const char *key) { - keytbl_val &val = KeyTable[make_string(key)]; + keytbl_val &val = KeyTable[key]; return val.index; } @@ -362,23 +378,103 @@ int CLangMngr::GetKeyEntry(String &key) return 0; \ } \ _addr = params[*param]; \ - addr = get_amxaddr(amx, _addr); \ (*param)++; #define MAX_LEVELS 4 -size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level); +extern "C" size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level); THash BadLang_Table; static cvar_t *amx_mldebug = NULL; +static cvar_t *amx_cl_langs = NULL; -size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int *param, char *output, size_t maxlen, int level) +extern "C" const char *translate(AMX *amx, cell amxaddr, const char *key) { - static char buffer[MAX_LEVELS][2048]; - static char fmt[MAX_LEVELS][32]; + const char *pLangName = NULL; + const char *def = NULL; + int status; + cell *addr = get_amxaddr(amx, amxaddr); + char name[4]; + if (addr[0] == LANG_PLAYER) + { + if (!amx_cl_langs) + amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); + if ( (int)amx_cl_langs->value == 0 ) + { + pLangName = g_vault.get("server_language"); + } else { + pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(g_langMngr.GetDefLang())->pEdict, "lang"); + } + } else if (addr[0] == LANG_SERVER) { + pLangName = g_vault.get("server_language"); + } else if (addr[0] >= 1 && addr[0] <= gpGlobals->maxClients) { + if (!amx_cl_langs) + amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); + if ( (int)amx_cl_langs->value == 0 ) + { + pLangName = g_vault.get("server_language"); + } else { + pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(addr[0])->pEdict, "lang"); + } + } else { + get_amxstring_r(amx, amxaddr, name, 3); + pLangName = name; + } + if (!pLangName || !isalpha(pLangName[0])) + pLangName = "en"; + //next parameter! + def = g_langMngr.GetDef(pLangName, key, status); + + if (!amx_mldebug) + amx_mldebug = CVAR_GET_POINTER("amx_mldebug"); + + bool debug = (amx_mldebug && amx_mldebug->string && (amx_mldebug->string[0] != '\0')); + + if (debug) + { + int debug_status; + bool validlang = true; + const char *testlang = amx_mldebug->string; + if (!g_langMngr.LangExists(testlang)) + { + AMXXLOG_Log("[AMXX] \"%s\" is an invalid debug language", testlang); + validlang = false; + } + + g_langMngr.GetDef(testlang, key, debug_status); + + if (validlang && debug_status == ERR_BADKEY) + AMXXLOG_Log("[AMXX] Language key \"%s\" not found for language \"%s\", check \"%s\"", key, testlang, GetFileName(amx)); + } + + if (def == NULL) + { + if (debug) + { + if (status == ERR_BADLANG && (BadLang_Table[make_string(pLangName)].last + 120.0f < gpGlobals->time)) + { + AMXXLOG_Log("[AMXX] Language \"%s\" not found", pLangName); + BadLang_Table[make_string(pLangName)].last = gpGlobals->time; + } + } + + if (addr[0] != LANG_SERVER) + def = g_langMngr.GetDef(g_vault.get("server_language"), key, status); + + if (!def && (strcmp(pLangName, "en") != 0 && strcmp(g_vault.get("server_language"), "en") != 0)) + def = g_langMngr.GetDef("en", key, status); + } + + return def; +} + +#if defined AMD64 +size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int *param, char *output, size_t maxlen) +{ + char fmt[32]; size_t len = 0; - char *fmtptr = fmt[level]; - const char *fmtsrc = *fmtstr; + char *fmtptr = fmt; + register const char *fmtsrc = *fmtstr; char ctrl_code; int numParams = params[0] / sizeof(cell); cell _addr, *addr; @@ -390,18 +486,20 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int } *fmtptr++ = '%'; - while (fmtsrc[len] && !isalpha((char)fmtsrc[len])) + while (*fmtsrc && !isalpha(*fmtsrc)) { if (len >= sizeof(fmt)-2) break; - *fmtptr++ = static_cast(fmtsrc[len++]); - } + *fmtptr++ = static_cast(*fmtsrc++); + len++; + } + //get the final character - ctrl_code = fmtsrc[len++]; + ctrl_code = *fmtsrc++; if (!ctrl_code) return 0; //inc the source pointer - *fmtstr = &(fmtsrc[len]); + *fmtstr = fmtsrc; //finalize the string *fmtptr++ = ctrl_code; *fmtptr = '\0'; @@ -409,28 +507,29 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int //reset the format pointer fmtptr = fmt[level]; - char *tmp_buf = buffer[level]; - //we now have the format switch (ctrl_code) { case 's': { FMTPM_NEXTPARAM(); - get_amxstring_r(amx, _addr, tmp_buf, 2047); - return _snprintf(output, maxlen, fmtptr, tmp_buf); + char buffer[2048]; + get_amxstring_r(amx, _addr, buffer, 2047); + return _snprintf(output, maxlen, fmtptr, buffer); break; } case 'g': case 'f': { FMTPM_NEXTPARAM(); + addr = get_amxaddr(amx, _addr); return _snprintf(output, maxlen, fmtptr, *(REAL *)addr); break; } case 'p': { FMTPM_NEXTPARAM(); + addr = get_amxaddr(amx, _addr); return _snprintf(output, maxlen, fmtptr, addr); break; } @@ -440,89 +539,23 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int case 'c': { FMTPM_NEXTPARAM(); + addr = get_amxaddr(amx, _addr); return _snprintf(output, maxlen, fmtptr, (int)addr[0]); break; } case 'L': { FMTPM_NEXTPARAM(); - const char *pLangName = NULL; - const char *def = NULL, *key = NULL; - int status; - int tmpLen; - if (addr[0] == LANG_PLAYER) - { - if ( (int)CVAR_GET_FLOAT("amx_client_languages") == 0 ) - { - pLangName = g_vault.get("server_language"); - } else { - pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(g_langMngr.GetDefLang())->pEdict, "lang"); - } - } else if (addr[0] == LANG_SERVER) { - pLangName = g_vault.get("server_language"); - } else if (addr[0] >= 1 && addr[0] <= gpGlobals->maxClients) { - if ( (int)CVAR_GET_FLOAT("amx_client_languages") == 0 ) - { - pLangName = g_vault.get("server_language"); - } else { - pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(addr[0])->pEdict, "lang"); - } - } else { - pLangName = get_amxstring(amx, _addr, 0, tmpLen); - } - if (!pLangName || !isalpha(pLangName[0])) - pLangName = "en"; - //next parameter! + cell lang_addr = _addr; FMTPM_NEXTPARAM(); - key = get_amxstring(amx, _addr, 1, tmpLen); - def = g_langMngr.GetDef(pLangName, key, status); - - if (!amx_mldebug) - amx_mldebug = CVAR_GET_POINTER("amx_mldebug"); + const char *key = get_amxstring(amx, _addr, 3, tmpLen); - bool debug = (amx_mldebug && amx_mldebug->string && (amx_mldebug->string[0] != '\0')); - - if (debug) - { - int debug_status; - bool validlang = true; - const char *testlang = amx_mldebug->string; + const char *def = translate(amx, lang_addr, key); - if (!g_langMngr.LangExists(testlang)) - { - AMXXLOG_Log("[AMXX] \"%s\" is an invalid debug language", testlang); - validlang = false; - } - - g_langMngr.GetDef(testlang, key, debug_status); - - if (validlang && debug_status == ERR_BADKEY) - AMXXLOG_Log("[AMXX] Language key \"%s\" not found for language \"%s\", check \"%s\"", key, testlang, GetFileName(amx)); - } - - if (def == NULL) - { - if (debug) - { - if (status == ERR_BADLANG && (BadLang_Table[make_string(pLangName)].last + 120.0f < gpGlobals->time)) - { - AMXXLOG_Log("[AMXX] Language \"%s\" not found", pLangName); - BadLang_Table[make_string(pLangName)].last = gpGlobals->time; - } - } + if (!def) + return _snprintf(output, maxlen, "ML_NOTFOUND: %s", key); - if (addr[0] != LANG_SERVER) - def = g_langMngr.GetDef(g_vault.get("server_language"), key, status); - - if (!def && (strcmp(pLangName, "en") != 0 && strcmp(g_vault.get("server_language"), "en") != 0)) - def = g_langMngr.GetDef("en", key, status); - - if (!def) - { - return _snprintf(output, maxlen, "ML_NOTFOUND: %s", key); - } - } - return do_amx_format(amx, params, param, &def, output, maxlen, level + 1); + return do_amx_format(amx, params, param, &def, output, maxlen, 1); } default: { @@ -532,7 +565,9 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int } } -size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level) +//we implement this in raw asm for x86 +//we'll do it for AMD64 once VAC2 works on it +extern "C" size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level) { size_t written; size_t orig_maxlen = maxlen; @@ -552,7 +587,7 @@ size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output++ = *lexptr++; maxlen -= 2; } else { - written = do_amx_format_parameter(amx, params, &lexptr, param, output, maxlen, level + 1); + written = do_amx_format_parameter(amx, params, &lexptr, param, output, maxlen); output += written; maxlen -= written; } @@ -599,6 +634,7 @@ size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char return (orig_maxlen-maxlen); } +#endif char * CLangMngr::FormatAmxString(AMX *amx, cell *params, int parm, int &len) { @@ -1027,7 +1063,7 @@ CLangMngr::CLang * CLangMngr::GetLangR(const char *name) const char *CLangMngr::GetDef(const char *langName, const char *key, int &status) { CLang *lang = GetLangR(langName); - keytbl_val &val = KeyTable[make_string(key)]; + keytbl_val &val = KeyTable.AltFindOrInsert(key); //KeyTable[make_string(key)]; if (lang == NULL) { status = ERR_BADLANG; diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 5e5da1d8..3807c576 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -254,7 +254,7 @@ char* format_amxstring(AMX *amx, cell *params, int parm, int& len); AMX* get_amxscript(int, void**, const char**); const char* get_amxscriptname(AMX* amx); char* get_amxstring(AMX *amx, cell amx_addr, int id, int& len); -size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen); +extern "C" size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen); int amxstring_len(cell* cstr); int load_amxscript(AMX* amx, void** program, const char* path, char error[64], int debug); @@ -271,7 +271,7 @@ void free_amxmemory(void **ptr); // get_localinfo const char* get_localinfo(const char* name, const char* def); cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params); -void LogError(AMX *amx, int err, const char *fmt, ...); +extern "C" void LogError(AMX *amx, int err, const char *fmt, ...); enum ModuleCallReason { diff --git a/amxmodx/helpers-x86.asm b/amxmodx/helpers-x86.asm new file mode 100644 index 00000000..4659cb77 --- /dev/null +++ b/amxmodx/helpers-x86.asm @@ -0,0 +1,414 @@ +;(C)2004-2006 AMX Mod X Development Team +;Written by David "BAILOPAN" Anderson +;These routines were very hard to optimize. +;They are basically unoptimizable as far as I can tell, +; but it's one of the most expensive operations in core. + + +section .text + +extern _LogError, _get_amxstring_r, __snprintf, _MNF_GetAmxString +extern _translate + +global do_amx_format, _do_amx_format, format_parameter +global init_format_jumps, _init_format_jumps + +init_format_jumps: +_init_format_jumps: + push ebp + mov ebp, esp + + lea edx, [g_jumptbl] + mov [edx+'c'*4], dword format_parameter.fmt_num + mov [edx+'d'*4], dword format_parameter.fmt_num + mov [edx+'f'*4], dword format_parameter.fmt_float + mov [edx+'g'*4], dword format_parameter.fmt_float + mov [edx+'i'*4], dword format_parameter.fmt_num + mov [edx+'L'*4], dword format_parameter.fmt_ml + mov [edx+'p'*4], dword format_parameter.fmt_ptr + mov [edx+'s'*4], dword format_parameter.fmt_string + mov [edx+'x'*4], dword format_parameter.fmt_num + + pop ebp + ret + + +;size_t do_amx_format_parameter(AMX *amx, cell *params, int *param, size_t maxlen); +;REGISTER USAGE (fmt search) +; edi - fmt output +; esi - lexptr (given) +; ebx - scrach address +; eax - lexchar +; edx - scratch +; ecx - length +;REGISTER USAGE (format) +; edi - real output +; esi - lexptr (given) +format_parameter: + push ebp + mov ebp, esp + + push edi + push ebx + + ;len=30 + mov ecx, 30 + ;edi=char[32] (+1 for offset) + sub esp, 32 + mov [esp], byte '%' + lea edi, [esp+1] + ;esi=lexptr already + ;eax=*lexptr + xor eax, eax + mov al, [esi] + test al, al + jz .abort + ;ebx=g_chartbl + lea ebx, [g_chartbl] + ;start looping +.fmtloop + mov edx, [ebx+eax*4];get char flag + test edx, edx ;is it zero? + jnz .fmtdone ;yes, we've got a format code + test ecx, ecx ;are we over maxlen? + jz .fmtdone ;yes, dump out + mov [edi], al ;copy into destination + inc edi ;dest++ + inc esi ;src++ + dec ecx ;len-- + mov al, [esi] ;get next char + test al, al ;is it zero? + jnz .fmtloop ;no, continue + +.fmtdone: + ;if there's no control code, we dumped out. + ;just abort in that case. + test al, al + jz .abort + ;terminate fmtptr + mov [edi], al + mov [edi+1], byte 0 + ;sto fmtsrc back + inc esi + ;get output ptr + mov edi, [ebp-4] + + lea ebx, [g_jumptbl] + jmp [ebx+eax*4] ;LOLolOLoL. + +.fmt_string + ;check parameter count + mov ebx, [ebp+12] ;params + mov eax, [ebx] ;params[0] + shr eax, 2 ;params[0]/4 + mov edx, [ebp+16] ;param + mov ecx, [edx] ;*param + cmp ecx, eax ;*param / params[0]/4 ? + ja .error + ;get the param - it's in eax + add dword [edx], 1 + mov eax, ebx + sub esp, 2048 + mov ebx, esp + push 2047 ;buffer size + push ebx + push dword [eax+ecx*4] + push dword [ebp+8] ;context + call _get_amxstring_r + push ebx ;push buffer + lea ebx, [ebp-40] + push ebx ;push format + push dword [ebp+28] ;push maxlen + push edi ;push output + call __snprintf + add esp, 4*8 + add esp, 2048 + add edi, eax + jmp .end + +.fmt_num + ;check parameter count + mov ebx, [ebp+12] ;params + mov eax, [ebx] ;params[0] + shr eax, 2 ;params[0]/4 + mov edx, [ebp+16] ;param + mov ecx, [edx] ;*param + cmp ecx, eax ;*param / params[0]/4 ? + ja .error + ;get the param - it's in eax + add dword [edx], 1 ;incr *param + mov edx, [ebp+8] ;get AMX into edx + mov edx, [edx] ;get AMX->base into edx + mov eax, [edx+16] ;get base->dat into eax + add edx, eax ;add dat to base + add edx, dword [ebx+ecx*4] ;add params[ecx] + push dword [edx] + lea ebx, [ebp-40] + push ebx + push dword [ebp+28] + push edi + call __snprintf + add esp, 4*4 + add edi, eax + jmp .end + +.fmt_float + ;check parameter count + mov ebx, [ebp+12] ;params + mov eax, [ebx] ;params[0] + shr eax, 2 ;params[0]/4 + mov edx, [ebp+16] ;param + mov ecx, [edx] ;*param + cmp ecx, eax ;*param / params[0]/4 ? + ja .error + ;get the param - it's in eax + add dword [edx], 1 + mov edx, [ebp+8] + mov edx, [edx] + mov eax, [edx+16] + add edx, eax + add edx, dword [ebx+ecx*4] + ;load the float, convert to double + fld dword [edx] + sub esp, 8 + fstp qword [esp] + ;it's already on the stack now, push rest + lea ebx, [ebp-40] + push ebx + push dword [ebp+28] + push edi + call __snprintf + add esp, 4*5 + add edi, eax + jmp .end + +.fmt_ml + mov ebx, [ebp+12] ;params + mov eax, [ebx] ;params[0] + shr eax, 2 ;params[0]/4 + mov edx, [ebp+16] ;param + mov ecx, [edx] ;*param + inc ecx + cmp ecx, eax ;*param / params[0]/4 ? + ja .error + add dword [edx], 2 + push ecx + push dword 0 ;NULL + push dword 3 ;buffer 3 + push dword [ebx+ecx*4] + push dword [ebp+8] + call _MNF_GetAmxString + add esp, 4*4 + pop ecx + dec ecx + push eax + push eax ;key + push dword [ebx+ecx*4] ;lang_addr + push dword [ebp+8] ;AMX + call _translate + add esp, 4*3 + pop ecx + test eax, eax + je .fmt_error + + ;invoke the translator + ;;store this on the stack so we can pass the address + push eax + mov edx, esp + push 1 ;no reparse ^ + push dword [ebp+20] ;maxlen + push edi ;output + push edx ;lexptr + push dword [ebp+16] ;param + push ebx ;params + push dword [ebp+8] ;amx + call do_amx_format + add esp, 4*8 + ;we don't care about the return lex + add edi, eax + jmp .end + + +.fmt_error + push ecx + lea eax, [g_mlfmt] + push eax + push dword [ebp+20] + push edi + call __snprintf + add esp, 4*4 + add edi, eax + jmp .end + + +.fmt_default + +.fmt_ptr + +.error + push ecx + push eax + push g_errfmt + push 10 ;AMX_ERR_NATIVE + push dword [ebp+8] + call _LogError + add esp, 4*5 + +.abort + xor eax, eax + +.end + add esp, 32 + pop ebx + pop ecx + + pop ebp + ret + +;size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level) +;REGISTER USAGE - +; esi=lex +; edi=output +; ecx=maxlen +; eax=scratch +do_amx_format: +_do_amx_format: + push esi ;input + push edi ;output + + ;current esp offset is 12 (0=edi,4=esi,8=ret) + mov esi, [esp+24] ;lex (dbl addr) + mov esi, [esi] + mov edi, [esp+28] ;get output + mov ecx, [esp+32] ;get maxlen + + ;initial checks + mov al, [esi] + test al, al + jz .done +.loop: + test ecx, ecx + jz .done + cmp al, '%' + je .perc + cmp al, '^' + je .esc + +.copy: + ;*output++ = *lexptr++ + mov [edi], al + inc esi + inc edi + dec ecx +.next + mov al, [esi] + test al, al + jz .done + jmp .loop + +;we got a '^' +.esc: + cmp dword [esp+36], 0 + je .copy + inc esi + mov al, [esi] + cmp al, 'n' + je .escn + cmp al, 't' + je .esct + +;*outptr++ = *lexptr + mov [edi], al + inc edi + +;lexptr++ +;maxlen-- +.escdone + inc esi + dec ecx + jmp .next + +.escn + ;*outptr++ = '\n' + mov [edi], byte 0xA ;'\n' + inc edi + jmp .escdone + +.esct + ;*outptr++ = '\t' + mov [edi], byte 0x9 ;'\t' + inc edi + jmp .escdone + +;we got a '%' +.perc: + inc esi + mov al, [esi] + test al, al ;'\0' + je .percatend + cmp al, '%' + je .percnone + jmp .percfmt +.percatend + dec esi + add ecx, 1 +.percnone: + ;*outptr++=*lexptr++; x2 + ;maxlen -= 2 + ;note we recalculate eax and then + ;only move once, since this is a 2byte move anyway. + mov ax, [esi] + mov [edi], ax + add esi, 2 + add edi, 2 + sub ecx, 2 + jmp .next + +.percfmt: + ;call do_amx_format_parameter. + push ecx + push ecx ;maxlen + push dword [esp+28] ;param + push dword [esp+28] ;params + push dword [esp+28] ;amx + call format_parameter ;will return edi adjusted for us + add esp, 4*4 ;will also return esi adjusted for us + pop ecx + sub ecx, eax ;adjust maxlength + mov al, [esi] ;reiterate + test al, al + jnz .loop + +.done: + ;end the string + mov [edi], dword 0 + mov edi, [esp+24] ;get lexptr ref + mov [edi], esi ;sto into lexptr ref + mov eax, [esp+32] ;get maxlen + sub eax, ecx ;subtract what we did + + pop edi + pop esi + + ret + + +section .data + align 16 + g_errfmt db "String formatted incorrectly - parameter %d (total %d)", 0 + g_mlfmt db "ML_NOTFOUND: %s", 0 + ;Stores whether a character is a letter or not. hAxXx + g_chartbl times 65 dd 0 + times 26 dd 1 + times 6 dd 0 + times 26 dd 1 + times 133 dd 0 + + g_jumptbl times 256 dd format_parameter.fmt_default + +;end + + + + + diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 0f566634..0d29ddb9 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -1144,6 +1144,14 @@ C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_ return (TRUE); } +#if !defined AMD64 +extern "C" init_format_jumps(); +#else +void init_format_jumps() +{ +} +#endif + static META_FUNCTIONS gMetaFunctionTable; C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { @@ -1219,6 +1227,8 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m // This will also call modules Meta_Query and Meta_Attach functions loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), now); + init_format_jumps(); + return (TRUE); } diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index c054e577..55e26040 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -1115,7 +1115,7 @@ int MNF_FindAmxScriptByAmx(const AMX *amx) return i; } -char *MNF_GetAmxString(AMX *amx, cell amx_addr, int bufferId, int *pLen) +extern "C" char *MNF_GetAmxString(AMX *amx, cell amx_addr, int bufferId, int *pLen) { int len; char *retVal = get_amxstring(amx, amx_addr, bufferId, len); @@ -1342,7 +1342,7 @@ void MNF_Log(const char *fmt, ...) //by BAILOPAN // debugger engine front end -void LogError(AMX *amx, int err, const char *fmt, ...) +extern "C" void LogError(AMX *amx, int err, const char *fmt, ...) { Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; diff --git a/amxmodx/sh_tinyhash.h b/amxmodx/sh_tinyhash.h index 7aba1e1d..2690bde4 100644 --- a/amxmodx/sh_tinyhash.h +++ b/amxmodx/sh_tinyhash.h @@ -23,6 +23,12 @@ template int Compare(const K & k1, const K & k2); + template + int CompareAlt(const U &k1, const K &k2); + + template + int HashAlt(const U &u); + /** * This is a tiny, growable hash class. * Meant for quick and dirty dictionaries only! @@ -118,6 +124,35 @@ m_numBuckets = 0; m_items = 0; } + public: + template + V & AltFindOrInsert(const U & ukey) + { + size_t place = HashAlt(ukey) % m_numBuckets; + THashNode *pNode = NULL; + if (!m_Buckets[place]) + { + m_Buckets[place] = new List; + pNode = new THashNode(ukey, V()); + m_Buckets[place]->push_back(pNode); + m_percentUsed += (1.0f / (float)m_numBuckets); + m_items++; + } else { + typename List::iterator iter; + for (iter=m_Buckets[place]->begin(); iter!=m_Buckets[place]->end(); iter++) + { + if (CompareAlt(ukey, (*iter)->key) == 0) + return (*iter)->val; + } + pNode = new THashNode(ukey, V()); + m_Buckets[place]->push_back(pNode); + m_items++; + } + if (PercentUsed() > 0.75f) + _Refactor(); + return pNode->val; + } + private: THashNode *_FindOrInsert(const K & key) { size_t place = HashFunction(key) % m_numBuckets; diff --git a/amxmodx/string.cpp b/amxmodx/string.cpp index b1936572..e51300db 100755 --- a/amxmodx/string.cpp +++ b/amxmodx/string.cpp @@ -87,7 +87,7 @@ int set_amxstring(AMX *amx, cell amx_addr, const char *source, int max) return dest - start; } -size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen) +extern "C" size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen) { register cell *source = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); register char *dest = destination;