mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-25 14:25:38 +03:00
committed new format() code
This commit is contained in:
parent
a8c01e4865
commit
bf0c1990dd
@ -86,12 +86,28 @@ int Compare<String>(const String &k1, const String &k2)
|
|||||||
return k1.compare(k2.c_str());
|
return k1.compare(k2.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int CompareAlt<char const *, String>(char const * const &k1, String const &k2)
|
||||||
|
{
|
||||||
|
return strcmp(k1, k2.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
int HashFunction<String>(const String &k)
|
int HashFunction<String>(const String &k)
|
||||||
{
|
{
|
||||||
unsigned long hash = 5381;
|
unsigned long hash = 5381;
|
||||||
const char *str = k.c_str();
|
register const char *str = k.c_str();
|
||||||
char c;
|
register char c;
|
||||||
|
while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int HashAlt<const char *>(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
|
while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@ -327,7 +343,7 @@ const char * CLangMngr::GetKey(int key)
|
|||||||
|
|
||||||
int CLangMngr::GetKeyEntry(const char *key)
|
int CLangMngr::GetKeyEntry(const char *key)
|
||||||
{
|
{
|
||||||
keytbl_val &val = KeyTable[make_string(key)];
|
keytbl_val &val = KeyTable[key];
|
||||||
|
|
||||||
return val.index;
|
return val.index;
|
||||||
}
|
}
|
||||||
@ -362,23 +378,103 @@ int CLangMngr::GetKeyEntry(String &key)
|
|||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
_addr = params[*param]; \
|
_addr = params[*param]; \
|
||||||
addr = get_amxaddr(amx, _addr); \
|
|
||||||
(*param)++;
|
(*param)++;
|
||||||
|
|
||||||
#define MAX_LEVELS 4
|
#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<String, lang_err> BadLang_Table;
|
THash<String, lang_err> BadLang_Table;
|
||||||
|
|
||||||
static cvar_t *amx_mldebug = NULL;
|
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];
|
const char *pLangName = NULL;
|
||||||
static char fmt[MAX_LEVELS][32];
|
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;
|
size_t len = 0;
|
||||||
char *fmtptr = fmt[level];
|
char *fmtptr = fmt;
|
||||||
const char *fmtsrc = *fmtstr;
|
register const char *fmtsrc = *fmtstr;
|
||||||
char ctrl_code;
|
char ctrl_code;
|
||||||
int numParams = params[0] / sizeof(cell);
|
int numParams = params[0] / sizeof(cell);
|
||||||
cell _addr, *addr;
|
cell _addr, *addr;
|
||||||
@ -390,18 +486,20 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
*fmtptr++ = '%';
|
*fmtptr++ = '%';
|
||||||
while (fmtsrc[len] && !isalpha((char)fmtsrc[len]))
|
while (*fmtsrc && !isalpha(*fmtsrc))
|
||||||
{
|
{
|
||||||
if (len >= sizeof(fmt)-2)
|
if (len >= sizeof(fmt)-2)
|
||||||
break;
|
break;
|
||||||
*fmtptr++ = static_cast<char>(fmtsrc[len++]);
|
*fmtptr++ = static_cast<char>(*fmtsrc++);
|
||||||
}
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
//get the final character
|
//get the final character
|
||||||
ctrl_code = fmtsrc[len++];
|
ctrl_code = *fmtsrc++;
|
||||||
if (!ctrl_code)
|
if (!ctrl_code)
|
||||||
return 0;
|
return 0;
|
||||||
//inc the source pointer
|
//inc the source pointer
|
||||||
*fmtstr = &(fmtsrc[len]);
|
*fmtstr = fmtsrc;
|
||||||
//finalize the string
|
//finalize the string
|
||||||
*fmtptr++ = ctrl_code;
|
*fmtptr++ = ctrl_code;
|
||||||
*fmtptr = '\0';
|
*fmtptr = '\0';
|
||||||
@ -409,28 +507,29 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int
|
|||||||
//reset the format pointer
|
//reset the format pointer
|
||||||
fmtptr = fmt[level];
|
fmtptr = fmt[level];
|
||||||
|
|
||||||
char *tmp_buf = buffer[level];
|
|
||||||
|
|
||||||
//we now have the format
|
//we now have the format
|
||||||
switch (ctrl_code)
|
switch (ctrl_code)
|
||||||
{
|
{
|
||||||
case 's':
|
case 's':
|
||||||
{
|
{
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
get_amxstring_r(amx, _addr, tmp_buf, 2047);
|
char buffer[2048];
|
||||||
return _snprintf(output, maxlen, fmtptr, tmp_buf);
|
get_amxstring_r(amx, _addr, buffer, 2047);
|
||||||
|
return _snprintf(output, maxlen, fmtptr, buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'f':
|
case 'f':
|
||||||
{
|
{
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
|
addr = get_amxaddr(amx, _addr);
|
||||||
return _snprintf(output, maxlen, fmtptr, *(REAL *)addr);
|
return _snprintf(output, maxlen, fmtptr, *(REAL *)addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p':
|
case 'p':
|
||||||
{
|
{
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
|
addr = get_amxaddr(amx, _addr);
|
||||||
return _snprintf(output, maxlen, fmtptr, addr);
|
return _snprintf(output, maxlen, fmtptr, addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -440,89 +539,23 @@ size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int
|
|||||||
case 'c':
|
case 'c':
|
||||||
{
|
{
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
|
addr = get_amxaddr(amx, _addr);
|
||||||
return _snprintf(output, maxlen, fmtptr, (int)addr[0]);
|
return _snprintf(output, maxlen, fmtptr, (int)addr[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'L':
|
case 'L':
|
||||||
{
|
{
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
const char *pLangName = NULL;
|
cell lang_addr = _addr;
|
||||||
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!
|
|
||||||
FMTPM_NEXTPARAM();
|
FMTPM_NEXTPARAM();
|
||||||
key = get_amxstring(amx, _addr, 1, tmpLen);
|
const char *key = get_amxstring(amx, _addr, 3, tmpLen);
|
||||||
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'));
|
const char *def = translate(amx, lang_addr, key);
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
int debug_status;
|
|
||||||
bool validlang = true;
|
|
||||||
const char *testlang = amx_mldebug->string;
|
|
||||||
|
|
||||||
if (!g_langMngr.LangExists(testlang))
|
if (!def)
|
||||||
{
|
return _snprintf(output, maxlen, "ML_NOTFOUND: %s", key);
|
||||||
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)
|
return do_amx_format(amx, params, param, &def, output, maxlen, 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
default:
|
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 written;
|
||||||
size_t orig_maxlen = maxlen;
|
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++;
|
*output++ = *lexptr++;
|
||||||
maxlen -= 2;
|
maxlen -= 2;
|
||||||
} else {
|
} 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;
|
output += written;
|
||||||
maxlen -= 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);
|
return (orig_maxlen-maxlen);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
char * CLangMngr::FormatAmxString(AMX *amx, cell *params, int parm, int &len)
|
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)
|
const char *CLangMngr::GetDef(const char *langName, const char *key, int &status)
|
||||||
{
|
{
|
||||||
CLang *lang = GetLangR(langName);
|
CLang *lang = GetLangR(langName);
|
||||||
keytbl_val &val = KeyTable[make_string(key)];
|
keytbl_val &val = KeyTable.AltFindOrInsert(key); //KeyTable[make_string(key)];
|
||||||
if (lang == NULL)
|
if (lang == NULL)
|
||||||
{
|
{
|
||||||
status = ERR_BADLANG;
|
status = ERR_BADLANG;
|
||||||
|
@ -254,7 +254,7 @@ char* format_amxstring(AMX *amx, cell *params, int parm, int& len);
|
|||||||
AMX* get_amxscript(int, void**, const char**);
|
AMX* get_amxscript(int, void**, const char**);
|
||||||
const char* get_amxscriptname(AMX* amx);
|
const char* get_amxscriptname(AMX* amx);
|
||||||
char* get_amxstring(AMX *amx, cell amx_addr, int id, int& len);
|
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 amxstring_len(cell* cstr);
|
||||||
int load_amxscript(AMX* amx, void** program, const char* path, char error[64], int debug);
|
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
|
// get_localinfo
|
||||||
const char* get_localinfo(const char* name, const char* def);
|
const char* get_localinfo(const char* name, const char* def);
|
||||||
cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params);
|
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
|
enum ModuleCallReason
|
||||||
{
|
{
|
||||||
|
414
amxmodx/helpers-x86.asm
Normal file
414
amxmodx/helpers-x86.asm
Normal file
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1144,6 +1144,14 @@ C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_
|
|||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined AMD64
|
||||||
|
extern "C" init_format_jumps();
|
||||||
|
#else
|
||||||
|
void init_format_jumps()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static META_FUNCTIONS gMetaFunctionTable;
|
static META_FUNCTIONS gMetaFunctionTable;
|
||||||
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
|
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
|
// This will also call modules Meta_Query and Meta_Attach functions
|
||||||
loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), now);
|
loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), now);
|
||||||
|
|
||||||
|
init_format_jumps();
|
||||||
|
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1115,7 +1115,7 @@ int MNF_FindAmxScriptByAmx(const AMX *amx)
|
|||||||
return i;
|
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;
|
int len;
|
||||||
char *retVal = get_amxstring(amx, amx_addr, bufferId, len);
|
char *retVal = get_amxstring(amx, amx_addr, bufferId, len);
|
||||||
@ -1342,7 +1342,7 @@ void MNF_Log(const char *fmt, ...)
|
|||||||
|
|
||||||
//by BAILOPAN
|
//by BAILOPAN
|
||||||
// debugger engine front end
|
// 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];
|
Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER];
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@
|
|||||||
template <class K>
|
template <class K>
|
||||||
int Compare(const K & k1, const K & k2);
|
int Compare(const K & k1, const K & k2);
|
||||||
|
|
||||||
|
template <class U, class K>
|
||||||
|
int CompareAlt(const U &k1, const K &k2);
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
int HashAlt(const U &u);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a tiny, growable hash class.
|
* This is a tiny, growable hash class.
|
||||||
* Meant for quick and dirty dictionaries only!
|
* Meant for quick and dirty dictionaries only!
|
||||||
@ -118,6 +124,35 @@
|
|||||||
m_numBuckets = 0;
|
m_numBuckets = 0;
|
||||||
m_items = 0;
|
m_items = 0;
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
template <typename U>
|
||||||
|
V & AltFindOrInsert(const U & ukey)
|
||||||
|
{
|
||||||
|
size_t place = HashAlt(ukey) % m_numBuckets;
|
||||||
|
THashNode *pNode = NULL;
|
||||||
|
if (!m_Buckets[place])
|
||||||
|
{
|
||||||
|
m_Buckets[place] = new List<THashNode *>;
|
||||||
|
pNode = new THashNode(ukey, V());
|
||||||
|
m_Buckets[place]->push_back(pNode);
|
||||||
|
m_percentUsed += (1.0f / (float)m_numBuckets);
|
||||||
|
m_items++;
|
||||||
|
} else {
|
||||||
|
typename List<THashNode *>::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)
|
THashNode *_FindOrInsert(const K & key)
|
||||||
{
|
{
|
||||||
size_t place = HashFunction(key) % m_numBuckets;
|
size_t place = HashFunction(key) % m_numBuckets;
|
||||||
|
@ -87,7 +87,7 @@ int set_amxstring(AMX *amx, cell amx_addr, const char *source, int max)
|
|||||||
return dest - start;
|
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 cell *source = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr));
|
||||||
register char *dest = destination;
|
register char *dest = destination;
|
||||||
|
Loading…
Reference in New Issue
Block a user