Fixed dictionary parsing not obeying the carat backtick
Fixed failed translations crashing Added formatex() Fixed buffer copyback problems in old usages
This commit is contained in:
parent
0852dfa112
commit
01b58a4635
|
@ -47,10 +47,10 @@
|
||||||
#define INSERT_STRING 3
|
#define INSERT_STRING 3
|
||||||
#define INSERT_NEWLINE 4
|
#define INSERT_NEWLINE 4
|
||||||
|
|
||||||
// dictionary format is Fast-Format-Hash-Lookup, v5
|
// dictionary format is Fast-Format-Hash-Lookup, v6
|
||||||
#define MAGIC_HDR 0x4646484C
|
#define MAGIC_HDR 0x4646484C
|
||||||
#define FFHL_VERSION 5
|
#define FFHL_VERSION 6
|
||||||
#define FFHL_MIN_VERSION 4
|
#define FFHL_MIN_VERSION 6
|
||||||
|
|
||||||
/*version history:
|
/*version history:
|
||||||
* 1 (BAILOPAN) - Simplest form possible, no reverse
|
* 1 (BAILOPAN) - Simplest form possible, no reverse
|
||||||
|
@ -58,6 +58,7 @@
|
||||||
* 3 (PM OnoTo) - 2^32 languages per file with full reverse
|
* 3 (PM OnoTo) - 2^32 languages per file with full reverse
|
||||||
* 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization)
|
* 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization)
|
||||||
* 5 (BAILOPAN) - Removed hash storage
|
* 5 (BAILOPAN) - Removed hash storage
|
||||||
|
* 6 (BAILOPAN) - Arbitrary bump to force reparse.
|
||||||
FORMAT:
|
FORMAT:
|
||||||
Magic 4bytes
|
Magic 4bytes
|
||||||
Version 1byte
|
Version 1byte
|
||||||
|
@ -403,192 +404,10 @@ const char *CLangMngr::Format(const char *fmt, ...)
|
||||||
#define ZEROTERM(buf) buf[(sizeof(buf)/sizeof(buf[0]))-1]=0;
|
#define ZEROTERM(buf) buf[(sizeof(buf)/sizeof(buf[0]))-1]=0;
|
||||||
#define NEXT_PARAM()
|
#define NEXT_PARAM()
|
||||||
|
|
||||||
|
//this is not implemented....
|
||||||
char *CLangMngr::FormatString(const char *fmt, va_list &ap)
|
char *CLangMngr::FormatString(const char *fmt, va_list &ap)
|
||||||
{
|
{
|
||||||
// the output buffer
|
return "";
|
||||||
static char outbuf[4096];
|
|
||||||
char *outptr = outbuf;
|
|
||||||
const char *src = fmt;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
while (*src)
|
|
||||||
{
|
|
||||||
if (*src == '%')
|
|
||||||
{
|
|
||||||
++src;
|
|
||||||
if (*src == 'L')
|
|
||||||
{
|
|
||||||
NEXT_PARAM();
|
|
||||||
const char *pAmxLangName = va_arg(ap, const char*);
|
|
||||||
const char *cpLangName=NULL;
|
|
||||||
// Handle player ids (1-32) and server language
|
|
||||||
|
|
||||||
if (pAmxLangName == (const char *)LANG_PLAYER) // LANG_PLAYER
|
|
||||||
{
|
|
||||||
if ((int)CVAR_GET_FLOAT("amx_client_languages"))
|
|
||||||
{
|
|
||||||
cpLangName = g_vault.get("server_language");
|
|
||||||
} else {
|
|
||||||
cpLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(m_CurGlobId)->pEdict, "lang");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pAmxLangName == (const char *)LANG_SERVER) // LANG_SERVER
|
|
||||||
{
|
|
||||||
cpLangName = g_vault.get("server_language");
|
|
||||||
}
|
|
||||||
else if (pAmxLangName >= (const char *)1 && pAmxLangName <= (const char *)32) // Direct Client Id
|
|
||||||
{
|
|
||||||
if ((int)CVAR_GET_FLOAT("amx_client_languages"))
|
|
||||||
{
|
|
||||||
cpLangName = g_vault.get("server_language");
|
|
||||||
} else {
|
|
||||||
cpLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I((int)pAmxLangName)->pEdict, "lang");
|
|
||||||
}
|
|
||||||
} else { // Language Name
|
|
||||||
int tmplen = 0;
|
|
||||||
cpLangName = pAmxLangName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cpLangName || strlen(cpLangName) < 1)
|
|
||||||
cpLangName = "en";
|
|
||||||
|
|
||||||
int tmplen = 0;
|
|
||||||
const char *key = va_arg(ap, const char *);
|
|
||||||
const char *def = GetDef(cpLangName, key, status);
|
|
||||||
|
|
||||||
if (def == NULL)
|
|
||||||
{
|
|
||||||
if (pAmxLangName != LANG_SERVER)
|
|
||||||
{
|
|
||||||
def = GetDef(g_vault.get("server_language"), key, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(cpLangName, "en") != 0 && strcmp(g_vault.get("server_language"), "en") != 0)
|
|
||||||
{
|
|
||||||
def = GetDef("en", key, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!def)
|
|
||||||
{
|
|
||||||
static char buf[512];
|
|
||||||
CHECK_PTR((char*)(buf + 17 + strlen(key)), buf, sizeof(buf));
|
|
||||||
sprintf(buf, "ML_LNOTFOUND: %s", key);
|
|
||||||
def = buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*def)
|
|
||||||
{
|
|
||||||
if (*def == '%')
|
|
||||||
{
|
|
||||||
++def;
|
|
||||||
static char format[32];
|
|
||||||
format[0] = '%';
|
|
||||||
char *ptr = format + 1;
|
|
||||||
while (ptr-format<sizeof(format) && !isalpha(*ptr++ = *def++))
|
|
||||||
/*nothing*/;
|
|
||||||
ZEROTERM(format);
|
|
||||||
|
|
||||||
*ptr = 0;
|
|
||||||
vsprintf(outptr, format, ap);
|
|
||||||
// vsprintf doesnt alter the ap, increment here
|
|
||||||
|
|
||||||
switch (*(ptr - 1))
|
|
||||||
{
|
|
||||||
case 'f':
|
|
||||||
va_arg(ap, double);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
va_arg(ap, char *);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
default: // default: assume int-like parameter
|
|
||||||
va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outptr += strlen(outptr);
|
|
||||||
}
|
|
||||||
else if (*def == '^')
|
|
||||||
{
|
|
||||||
++def;
|
|
||||||
|
|
||||||
switch (*def)
|
|
||||||
{
|
|
||||||
case 'n':
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = '\n';
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = '\t';
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = '^';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CHECK_OUTPTR(2);
|
|
||||||
*outptr++ = '^';
|
|
||||||
*outptr++ = *def;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++def;
|
|
||||||
} else {
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = *def++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
static char format[32] = {'%'};
|
|
||||||
char *ptr = format + 1;
|
|
||||||
|
|
||||||
if (*src != '%')
|
|
||||||
{
|
|
||||||
while (*src != 0 && ptr-format < sizeof(format) && !isalpha(*ptr++ = *src++))
|
|
||||||
/*nothing*/;
|
|
||||||
*ptr = 0;
|
|
||||||
ZEROTERM(format);
|
|
||||||
--src;
|
|
||||||
vsprintf(outptr, format, ap);
|
|
||||||
// vsprintf doesnt alter the ap, increment here
|
|
||||||
|
|
||||||
switch (*(ptr - 1))
|
|
||||||
{
|
|
||||||
case 'f':
|
|
||||||
va_arg(ap, double);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
va_arg(ap, char *);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
default: // default: assume int-like parameter
|
|
||||||
va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outptr += strlen(outptr);
|
|
||||||
} else {
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = '%';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = *src;
|
|
||||||
}
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_OUTPTR(1);
|
|
||||||
*outptr++ = 0;
|
|
||||||
|
|
||||||
return outbuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef> &tmpVec)
|
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef> &tmpVec)
|
||||||
|
@ -712,6 +531,7 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||||
tmpEntry.definition = new String;
|
tmpEntry.definition = new String;
|
||||||
tmpEntry.definition->assign(def.c_str());
|
tmpEntry.definition->assign(def.c_str());
|
||||||
tmpEntry.definition->trim();
|
tmpEntry.definition->trim();
|
||||||
|
tmpEntry.definition->reparse_newlines();
|
||||||
Defq.push(tmpEntry);
|
Defq.push(tmpEntry);
|
||||||
tmpEntry.key = -1;
|
tmpEntry.key = -1;
|
||||||
tmpEntry.definition = NULL;
|
tmpEntry.definition = NULL;
|
||||||
|
@ -738,6 +558,7 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||||
} else {
|
} else {
|
||||||
if (buf[0] == ':')
|
if (buf[0] == ':')
|
||||||
{
|
{
|
||||||
|
tmpEntry.definition->reparse_newlines();
|
||||||
Defq.push(tmpEntry);
|
Defq.push(tmpEntry);
|
||||||
tmpEntry.key = -1;
|
tmpEntry.key = -1;
|
||||||
tmpEntry.definition = NULL;
|
tmpEntry.definition = NULL;
|
||||||
|
|
|
@ -179,6 +179,30 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reparse_newlines()
|
||||||
|
{
|
||||||
|
size_t len = size();
|
||||||
|
int offs = 0;
|
||||||
|
char c;
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
for (size_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
c = v[i];
|
||||||
|
if (c == '^' && (i != len-1))
|
||||||
|
{
|
||||||
|
c = v[++i];
|
||||||
|
if (c == 'n')
|
||||||
|
c = '\n';
|
||||||
|
else if (c == 't')
|
||||||
|
c = '\t';
|
||||||
|
offs++;
|
||||||
|
}
|
||||||
|
v[i-offs] = c;
|
||||||
|
}
|
||||||
|
v[len-offs] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
void trim()
|
void trim()
|
||||||
{
|
{
|
||||||
if (!v)
|
if (!v)
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
#include "amxmodx.h"
|
#include "amxmodx.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
//Adapted from Quake3's snprintf
|
//Adapted from Quake3's vsprintf
|
||||||
|
// thanks to cybermind for linking me to this :)
|
||||||
|
//I made the following changes:
|
||||||
|
// - Fixed spacing to be AMX Mod X standard
|
||||||
|
// - Added 'n' support, no buffer overflows
|
||||||
|
// - Templatized input/output buffers
|
||||||
|
|
||||||
#define ALT 0x00000001 /* alternate form */
|
#define ALT 0x00000001 /* alternate form */
|
||||||
#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */
|
#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */
|
||||||
|
@ -372,6 +377,12 @@ reswitch:
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[arg++], 3, len);
|
const char *key = get_amxstring(amx, params[arg++], 3, len);
|
||||||
const char *def = translate(amx, addr, key);
|
const char *def = translate(amx, addr, key);
|
||||||
|
if (!def)
|
||||||
|
{
|
||||||
|
static char buf[255];
|
||||||
|
snprintf(buf, sizeof(buf)-1, "ML_NOTFOUND: %s", key);
|
||||||
|
def = buf;
|
||||||
|
}
|
||||||
size_t written = atcprintf(buf_p, llen, def, amx, params, &arg);
|
size_t written = atcprintf(buf_p, llen, def, amx, params, &arg);
|
||||||
buf_p += written;
|
buf_p += written;
|
||||||
llen -= written;
|
llen -= written;
|
||||||
|
@ -408,7 +419,7 @@ void __WHOA_DONT_CALL_ME_PLZ_K_lol_o_O()
|
||||||
atcprintf((cell *)NULL, 0, (const char *)NULL, NULL, NULL, NULL);
|
atcprintf((cell *)NULL, 0, (const char *)NULL, NULL, NULL, NULL);
|
||||||
//accprintf
|
//accprintf
|
||||||
atcprintf((cell *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
atcprintf((cell *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
||||||
//acsprintf
|
//ascprintf
|
||||||
atcprintf((char *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
atcprintf((char *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -462,15 +462,53 @@ static cell AMX_NATIVE_CALL equali(AMX *amx, cell *params) /* 3 param */
|
||||||
return (f - l) ? 0 : 1;
|
return (f - l) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell g_cpbuf[4096];
|
||||||
|
|
||||||
|
static cell AMX_NATIVE_CALL formatex(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
cell *buf = get_amxaddr(amx, params[1]);
|
||||||
|
size_t maxlen = static_cast<size_t>(params[2]);
|
||||||
|
cell *fmt = get_amxaddr(amx, params[3]);
|
||||||
|
int param = 4;
|
||||||
|
size_t total = atcprintf(buf, maxlen, fmt, amx, params, ¶m);
|
||||||
|
return static_cast<cell>(total);
|
||||||
|
}
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL format(AMX *amx, cell *params) /* 3 param */
|
static cell AMX_NATIVE_CALL format(AMX *amx, cell *params) /* 3 param */
|
||||||
{
|
{
|
||||||
//int len;
|
|
||||||
//return set_amxstring(amx, params[1], format_amxstring(amx, params, 3, len), params[2]);
|
|
||||||
cell *buf = get_amxaddr(amx, params[1]);
|
cell *buf = get_amxaddr(amx, params[1]);
|
||||||
cell *fmt = get_amxaddr(amx, params[3]);
|
cell *fmt = get_amxaddr(amx, params[3]);
|
||||||
size_t maxlen = params[2];
|
size_t maxlen = params[2];
|
||||||
|
/**
|
||||||
|
* SPECIAL CASE - check if the buffers overlap.
|
||||||
|
* some users, for whatever reason, do things like:
|
||||||
|
* format(buf, 255, buf....
|
||||||
|
* this is considered "deprecated" but we have to support it.
|
||||||
|
* we do this by checking to see if reading from buf will overlap
|
||||||
|
*/
|
||||||
|
cell addr_start = params[1];
|
||||||
|
cell addr_end = params[1] + maxlen * sizeof(cell);
|
||||||
|
cell max = params[0] / sizeof(cell);
|
||||||
|
bool copy = false;
|
||||||
|
for (cell i = 3; i <= max; i++)
|
||||||
|
{
|
||||||
|
//does this clip the bounds?!?!? WELL, DOES IT!?!?! i am a loud dog
|
||||||
|
if (params[i] >= addr_start && params[i] <= addr_end)
|
||||||
|
{
|
||||||
|
copy = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copy)
|
||||||
|
buf = g_cpbuf;
|
||||||
int param = 4;
|
int param = 4;
|
||||||
size_t total = atcprintf(buf, maxlen, fmt, amx, params, ¶m);
|
size_t total = atcprintf(buf, maxlen, fmt, amx, params, ¶m);
|
||||||
|
if (copy)
|
||||||
|
{
|
||||||
|
/* copy back */
|
||||||
|
cell *old = get_amxaddr(amx, params[1]);
|
||||||
|
memcpy(old, g_cpbuf, total * sizeof(cell));
|
||||||
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,6 +944,7 @@ AMX_NATIVE_INFO string_Natives[] =
|
||||||
{"equal", equal},
|
{"equal", equal},
|
||||||
{"equali", equali},
|
{"equali", equali},
|
||||||
{"format", format},
|
{"format", format},
|
||||||
|
{"formatex", formatex},
|
||||||
{"format_args", format_args},
|
{"format_args", format_args},
|
||||||
{"isdigit", is_digit},
|
{"isdigit", is_digit},
|
||||||
{"isalnum", is_alnum},
|
{"isalnum", is_alnum},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user