2015-08-26 08:28:50 +02:00
|
|
|
// vim: set ts=4 sw=4 tw=99 noet :
|
|
|
|
// =============================================================================
|
|
|
|
// SourceMod
|
|
|
|
// Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
|
|
|
|
// =============================================================================
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify it under
|
|
|
|
// the terms of the GNU General Public License, version 3.0, as published by the
|
|
|
|
// Free Software Foundation.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
// details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License along with
|
|
|
|
// this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
|
|
// As a special exception, AlliedModders LLC gives you permission to link the
|
|
|
|
// code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
|
|
// "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
|
|
// by the Valve Corporation. You must obey the GNU General Public License in
|
|
|
|
// all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
|
|
// this exception to all derivative works. AlliedModders LLC defines further
|
|
|
|
// exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
|
|
// or <http://www.sourcemod.net/license.php>.
|
|
|
|
|
|
|
|
#include "common_logic.h"
|
|
|
|
#include "Translator.h"
|
|
|
|
#include "sprintf.h"
|
|
|
|
#include <am-float.h>
|
|
|
|
#include <am-string.h>
|
2015-08-31 06:27:32 +02:00
|
|
|
#include <ITranslator.h>
|
|
|
|
#include <bridge/include/IScriptManager.h>
|
|
|
|
#include <bridge/include/CoreProvider.h>
|
2015-08-26 08:28:50 +02:00
|
|
|
|
|
|
|
using namespace SourceMod;
|
|
|
|
|
2016-02-15 11:09:48 +01:00
|
|
|
#define LADJUST 0x00000001 /* left adjustment */
|
|
|
|
#define ZEROPAD 0x00000002 /* zero (as opposed to blank) pad */
|
|
|
|
#define UPPERDIGITS 0x00000004 /* make alpha digits uppercase */
|
2015-08-26 08:28:50 +02:00
|
|
|
#define to_digit(c) ((c) - '0')
|
|
|
|
#define is_digit(c) ((unsigned)to_digit(c) <= 9)
|
|
|
|
|
|
|
|
#define CHECK_ARGS(x) \
|
|
|
|
if ((arg+x) > args) { \
|
|
|
|
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
|
|
|
|
return 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
|
|
|
|
{
|
|
|
|
cell_t new_params[MAX_TRANSLATE_PARAMS];
|
|
|
|
for (unsigned int i = 0; i < pTrans->fmt_count; i++)
|
|
|
|
{
|
|
|
|
new_params[i] = params[pTrans->fmt_order[i]];
|
|
|
|
}
|
|
|
|
memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t Translate(char *buffer,
|
|
|
|
size_t maxlen,
|
|
|
|
IPluginContext *pCtx,
|
|
|
|
const char *key,
|
|
|
|
cell_t target,
|
|
|
|
const cell_t *params,
|
|
|
|
int *arg,
|
|
|
|
bool *error)
|
|
|
|
{
|
|
|
|
unsigned int langid;
|
|
|
|
*error = false;
|
|
|
|
Translation pTrans;
|
|
|
|
IPlugin *pl = scripts->FindPluginByContext(pCtx->GetContext());
|
|
|
|
unsigned int max_params = 0;
|
|
|
|
IPhraseCollection *pPhrases;
|
|
|
|
|
|
|
|
pPhrases = pl->GetPhrases();
|
|
|
|
|
|
|
|
try_serverlang:
|
|
|
|
if (target == SOURCEMOD_SERVER_LANGUAGE)
|
|
|
|
{
|
|
|
|
langid = g_Translator.GetServerLanguage();
|
|
|
|
}
|
2015-08-30 01:23:50 +02:00
|
|
|
else if ((target >= 1) && (target <= bridge->MaxClients()))
|
2015-08-26 08:28:50 +02:00
|
|
|
{
|
|
|
|
langid = g_Translator.GetClientLanguage(target);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-15 11:20:08 +01:00
|
|
|
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d (arg %d)", target, *arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
goto error_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
|
|
|
|
{
|
|
|
|
if (target != SOURCEMOD_SERVER_LANGUAGE && langid != g_Translator.GetServerLanguage())
|
|
|
|
{
|
|
|
|
target = SOURCEMOD_SERVER_LANGUAGE;
|
|
|
|
goto try_serverlang;
|
|
|
|
}
|
|
|
|
else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
|
|
|
|
{
|
|
|
|
if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
|
|
|
|
{
|
2016-02-15 11:20:08 +01:00
|
|
|
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found (arg %d)", key, *arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
goto error_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-15 11:20:08 +01:00
|
|
|
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found (arg %d)", key, *arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
goto error_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
max_params = pTrans.fmt_count;
|
|
|
|
|
|
|
|
if (max_params)
|
|
|
|
{
|
|
|
|
cell_t new_params[MAX_TRANSLATE_PARAMS];
|
|
|
|
|
|
|
|
/* Check if we're going to over the limit */
|
|
|
|
if ((*arg) + (max_params - 1) > (size_t)params[0])
|
|
|
|
{
|
|
|
|
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
|
2016-02-15 11:20:08 +01:00
|
|
|
"Translation string formatted incorrectly - missing at least %d parameters (arg %d)",
|
|
|
|
((*arg + (max_params - 1)) - params[0]), *arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
goto error_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we need to re-order the parameters, do so with a temporary array.
|
|
|
|
* Otherwise, we could run into trouble with continual formats, a la ShowActivity().
|
|
|
|
*/
|
|
|
|
memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
|
|
|
|
ReorderTranslationParams(&pTrans, &new_params[*arg]);
|
|
|
|
|
|
|
|
return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
*error = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-15 15:57:56 +01:00
|
|
|
bool AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec, int flags)
|
2015-08-26 08:28:50 +02:00
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
char *buf;
|
|
|
|
static char nlstr[] = {'(','n','u','l','l',')','\0'};
|
|
|
|
|
|
|
|
buf = *buf_p;
|
|
|
|
|
|
|
|
if (string == NULL)
|
|
|
|
{
|
|
|
|
string = nlstr;
|
|
|
|
prec = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prec >= 0)
|
|
|
|
{
|
|
|
|
for (size = 0; size < prec; size++)
|
|
|
|
{
|
|
|
|
if (string[size] == '\0')
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (string[size++]);
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size > (int)maxlen)
|
|
|
|
{
|
|
|
|
size = maxlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
maxlen -= size;
|
|
|
|
width -= size;
|
|
|
|
|
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
*buf++ = *string++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((width-- > 0) && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = ' ';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf_p = buf;
|
2016-02-15 15:57:56 +01:00
|
|
|
|
|
|
|
return true;
|
2015-08-26 08:28:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
|
|
|
|
{
|
|
|
|
int digits; // non-fraction part digits
|
|
|
|
double tmp; // temporary
|
|
|
|
char *buf = *buf_p; // output buffer pointer
|
|
|
|
int val; // temporary
|
|
|
|
int sign = 0; // 0: positive, 1: negative
|
|
|
|
int fieldlength; // for padding
|
|
|
|
int significant_digits = 0; // number of significant digits written
|
|
|
|
const int MAX_SIGNIFICANT_DIGITS = 16;
|
|
|
|
|
|
|
|
if (ke::IsNaN(fval))
|
|
|
|
{
|
2016-02-15 11:16:14 +01:00
|
|
|
AddString(buf_p, maxlen, "NaN", width, prec, flags);
|
2015-08-26 08:28:50 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// default precision
|
|
|
|
if (prec < 0)
|
|
|
|
{
|
|
|
|
prec = 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the sign
|
|
|
|
if (fval < 0)
|
|
|
|
{
|
|
|
|
fval = -fval;
|
|
|
|
sign = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute whole-part digits count
|
|
|
|
digits = (int)log10(fval) + 1;
|
|
|
|
|
|
|
|
// Only print 0.something if 0 < fval < 1
|
|
|
|
if (digits < 1)
|
|
|
|
{
|
|
|
|
digits = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute the field length
|
|
|
|
fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
|
|
|
|
|
|
|
|
// minus sign BEFORE left padding if padding with zeros
|
|
|
|
if (sign && maxlen && (flags & ZEROPAD))
|
|
|
|
{
|
|
|
|
*buf++ = '-';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// right justify if required
|
|
|
|
if ((flags & LADJUST) == 0)
|
|
|
|
{
|
|
|
|
while ((fieldlength < width) && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// minus sign AFTER left padding if padding with spaces
|
|
|
|
if (sign && maxlen && !(flags & ZEROPAD))
|
|
|
|
{
|
|
|
|
*buf++ = '-';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the whole part
|
|
|
|
tmp = pow(10.0, digits-1);
|
|
|
|
while ((digits--) && maxlen)
|
|
|
|
{
|
|
|
|
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
|
|
|
{
|
|
|
|
*buf++ = '0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
val = (int)(fval / tmp);
|
|
|
|
*buf++ = '0' + val;
|
|
|
|
fval -= val * tmp;
|
|
|
|
tmp *= 0.1;
|
|
|
|
}
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the fraction part
|
|
|
|
if (maxlen && prec)
|
|
|
|
{
|
|
|
|
*buf++ = '.';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = pow(10.0, prec);
|
|
|
|
|
|
|
|
fval *= tmp;
|
|
|
|
while (prec-- && maxlen)
|
|
|
|
{
|
|
|
|
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
|
|
|
{
|
|
|
|
*buf++ = '0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp *= 0.1;
|
|
|
|
val = (int)(fval / tmp);
|
|
|
|
*buf++ = '0' + val;
|
|
|
|
fval -= val * tmp;
|
|
|
|
}
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// left justify if required
|
|
|
|
if (flags & LADJUST)
|
|
|
|
{
|
|
|
|
while ((fieldlength < width) && maxlen)
|
|
|
|
{
|
|
|
|
// right-padding only with spaces, ZEROPAD is ignored
|
|
|
|
*buf++ = ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update parent's buffer pointer
|
|
|
|
*buf_p = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
|
|
{
|
|
|
|
char text[32];
|
|
|
|
int digits;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
digits = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (val & 1)
|
|
|
|
{
|
|
|
|
text[digits++] = '1';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text[digits++] = '0';
|
|
|
|
}
|
|
|
|
val >>= 1;
|
|
|
|
} while (val);
|
|
|
|
|
|
|
|
buf = *buf_p;
|
|
|
|
|
|
|
|
if (!(flags & LADJUST))
|
|
|
|
{
|
|
|
|
while (digits < width && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (digits-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = text[digits];
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & LADJUST)
|
|
|
|
{
|
|
|
|
while (width-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf_p = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
|
|
{
|
|
|
|
char text[32];
|
|
|
|
int digits;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
digits = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
text[digits++] = '0' + val % 10;
|
|
|
|
val /= 10;
|
|
|
|
} while (val);
|
|
|
|
|
|
|
|
buf = *buf_p;
|
|
|
|
|
|
|
|
if (!(flags & LADJUST))
|
|
|
|
{
|
|
|
|
while (digits < width && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (digits-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = text[digits];
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & LADJUST)
|
|
|
|
{
|
|
|
|
while (width-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf_p = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
|
|
|
|
{
|
|
|
|
char text[32];
|
|
|
|
int digits;
|
|
|
|
int signedVal;
|
|
|
|
char *buf;
|
|
|
|
unsigned int unsignedVal;
|
|
|
|
|
|
|
|
digits = 0;
|
|
|
|
signedVal = val;
|
|
|
|
if (val < 0)
|
|
|
|
{
|
|
|
|
/* we want the unsigned version */
|
|
|
|
unsignedVal = abs(val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsignedVal = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
text[digits++] = '0' + unsignedVal % 10;
|
|
|
|
unsignedVal /= 10;
|
|
|
|
} while (unsignedVal);
|
|
|
|
|
|
|
|
if (signedVal < 0)
|
|
|
|
{
|
|
|
|
text[digits++] = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = *buf_p;
|
|
|
|
|
|
|
|
if (!(flags & LADJUST))
|
|
|
|
{
|
|
|
|
while ((digits < width) && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (digits-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = text[digits];
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & LADJUST)
|
|
|
|
{
|
|
|
|
while (width-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf_p = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
|
|
{
|
|
|
|
char text[32];
|
|
|
|
int digits;
|
|
|
|
char *buf;
|
|
|
|
char digit;
|
|
|
|
int hexadjust;
|
|
|
|
|
|
|
|
if (flags & UPPERDIGITS)
|
|
|
|
{
|
|
|
|
hexadjust = 'A' - '9' - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hexadjust = 'a' - '9' - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
digits = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
digit = ('0' + val % 16);
|
|
|
|
if (digit > '9')
|
|
|
|
{
|
|
|
|
digit += hexadjust;
|
|
|
|
}
|
|
|
|
|
|
|
|
text[digits++] = digit;
|
|
|
|
val /= 16;
|
|
|
|
} while(val);
|
|
|
|
|
|
|
|
buf = *buf_p;
|
|
|
|
|
|
|
|
if (!(flags & LADJUST))
|
|
|
|
{
|
|
|
|
while (digits < width && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (digits-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = text[digits];
|
|
|
|
width--;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & LADJUST)
|
|
|
|
{
|
|
|
|
while (width-- && maxlen)
|
|
|
|
{
|
|
|
|
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf_p = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gnprintf(char *buffer,
|
|
|
|
size_t maxlen,
|
|
|
|
const char *format,
|
|
|
|
IPhraseCollection *pPhrases,
|
|
|
|
void **params,
|
|
|
|
unsigned int numparams,
|
|
|
|
unsigned int &curparam,
|
|
|
|
size_t *pOutLength,
|
|
|
|
const char **pFailPhrase)
|
|
|
|
{
|
|
|
|
if (!buffer || !maxlen)
|
|
|
|
{
|
|
|
|
if (pOutLength != NULL)
|
|
|
|
{
|
|
|
|
*pOutLength = 0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numparams > MAX_TRANSLATE_PARAMS)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int arg = 0;
|
|
|
|
char *buf_p;
|
|
|
|
char ch;
|
|
|
|
int flags;
|
|
|
|
int width;
|
|
|
|
int prec;
|
|
|
|
int n;
|
|
|
|
char sign;
|
|
|
|
const char *fmt;
|
|
|
|
size_t llen = maxlen - 1;
|
|
|
|
|
|
|
|
buf_p = buffer;
|
|
|
|
fmt = format;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
// run through the format string until we hit a '%' or '\0'
|
|
|
|
for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
|
|
|
|
{
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
}
|
|
|
|
if ((ch == '\0') || (llen <= 0))
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip over the '%'
|
|
|
|
fmt++;
|
|
|
|
|
|
|
|
// reset formatting state
|
|
|
|
flags = 0;
|
|
|
|
width = 0;
|
|
|
|
prec = -1;
|
|
|
|
sign = '\0';
|
|
|
|
|
|
|
|
rflag:
|
|
|
|
ch = *fmt++;
|
|
|
|
reswitch:
|
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
case '-':
|
|
|
|
{
|
|
|
|
flags |= LADJUST;
|
|
|
|
goto rflag;
|
|
|
|
}
|
|
|
|
case '.':
|
|
|
|
{
|
|
|
|
n = 0;
|
|
|
|
while(is_digit((ch = *fmt++)))
|
|
|
|
{
|
|
|
|
n = 10 * n + (ch - '0');
|
|
|
|
}
|
|
|
|
prec = (n < 0) ? -1 : n;
|
|
|
|
goto reswitch;
|
|
|
|
}
|
|
|
|
case '0':
|
|
|
|
{
|
|
|
|
flags |= ZEROPAD;
|
|
|
|
goto rflag;
|
|
|
|
}
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
{
|
|
|
|
n = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
n = 10 * n + (ch - '0');
|
|
|
|
ch = *fmt++;
|
|
|
|
} while(is_digit(ch));
|
|
|
|
width = n;
|
|
|
|
goto reswitch;
|
|
|
|
}
|
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char *c = (char *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
*buf_p++ = *c;
|
|
|
|
llen--;
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'b':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int *value = (int *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
AddBinary(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int *value = (int *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
AddInt(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'u':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unsigned int *value = (unsigned int *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
AddUInt(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
float *value = (float *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
AddFloat(&buf_p, llen, *value, width, prec, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const char *str = (const char *)params[curparam];
|
|
|
|
curparam++;
|
2016-02-15 11:16:14 +01:00
|
|
|
AddString(&buf_p, llen, str, width, prec, flags);
|
2015-08-26 08:28:50 +02:00
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'T':
|
|
|
|
case 't':
|
|
|
|
{
|
|
|
|
int target;
|
|
|
|
const char *key;
|
|
|
|
size_t out_length;
|
|
|
|
Translation trans;
|
|
|
|
unsigned int lang_id;
|
|
|
|
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
key = (const char *)(params[curparam]);
|
|
|
|
curparam++;
|
|
|
|
|
|
|
|
if (ch == 'T')
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
target = *((int *)(params[curparam]));
|
|
|
|
curparam++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
target = g_Translator.GetGlobalTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
try_again:
|
|
|
|
if (target == SOURCEMOD_SERVER_LANGUAGE)
|
|
|
|
{
|
|
|
|
lang_id = g_Translator.GetServerLanguage();
|
|
|
|
}
|
2015-08-30 01:23:50 +02:00
|
|
|
else if (target >= 1 && target <= bridge->MaxClients())
|
2015-08-26 08:28:50 +02:00
|
|
|
{
|
|
|
|
lang_id = g_Translator.GetClientLanguage(target);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lang_id = g_Translator.GetServerLanguage();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pPhrases == NULL)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = key;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
|
|
|
|
{
|
|
|
|
if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != g_Translator.GetServerLanguage())
|
|
|
|
{
|
|
|
|
target = SOURCEMOD_SERVER_LANGUAGE;
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
|
|
|
|
{
|
|
|
|
if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = key;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = key;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trans.fmt_count)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
void *new_params[MAX_TRANSLATE_PARAMS];
|
|
|
|
|
|
|
|
if (curparam + trans.fmt_count > numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the array and re-order the stack */
|
|
|
|
memcpy(new_params, params, sizeof(void *) * numparams);
|
|
|
|
for (i = 0; i < trans.fmt_count; i++)
|
|
|
|
{
|
|
|
|
new_params[curparam + i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gnprintf(buf_p,
|
|
|
|
llen,
|
|
|
|
trans.szPhrase,
|
|
|
|
pPhrases,
|
|
|
|
new_params,
|
|
|
|
numparams,
|
|
|
|
curparam,
|
|
|
|
&out_length,
|
|
|
|
pFailPhrase))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!gnprintf(buf_p,
|
|
|
|
llen,
|
|
|
|
trans.szPhrase,
|
|
|
|
pPhrases,
|
|
|
|
params,
|
|
|
|
numparams,
|
|
|
|
curparam,
|
|
|
|
&out_length,
|
|
|
|
pFailPhrase))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_p += out_length;
|
|
|
|
llen -= out_length;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'X':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unsigned int *value = (unsigned int *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
flags |= UPPERDIGITS;
|
|
|
|
AddHex(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'x':
|
|
|
|
{
|
|
|
|
if (curparam >= numparams)
|
|
|
|
{
|
|
|
|
if (pFailPhrase != NULL)
|
|
|
|
{
|
|
|
|
*pFailPhrase = NULL;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unsigned int *value = (unsigned int *)params[curparam];
|
|
|
|
curparam++;
|
|
|
|
AddHex(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '%':
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\0':
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = '%';
|
|
|
|
llen--;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
*buf_p = '\0';
|
|
|
|
|
|
|
|
if (pOutLength != NULL)
|
|
|
|
{
|
|
|
|
*pOutLength = (maxlen - llen - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
|
|
|
|
{
|
|
|
|
if (!buffer || !maxlen)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int arg;
|
|
|
|
int args = params[0];
|
|
|
|
char *buf_p;
|
|
|
|
char ch;
|
|
|
|
int flags;
|
|
|
|
int width;
|
|
|
|
int prec;
|
|
|
|
int n;
|
|
|
|
char sign;
|
|
|
|
const char *fmt;
|
|
|
|
size_t llen = maxlen - 1;
|
|
|
|
|
|
|
|
buf_p = buffer;
|
|
|
|
arg = *param;
|
|
|
|
fmt = format;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
// run through the format string until we hit a '%' or '\0'
|
|
|
|
for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
|
|
|
|
{
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
}
|
|
|
|
if ((ch == '\0') || (llen <= 0))
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip over the '%'
|
|
|
|
fmt++;
|
|
|
|
|
|
|
|
// reset formatting state
|
|
|
|
flags = 0;
|
|
|
|
width = 0;
|
|
|
|
prec = -1;
|
|
|
|
sign = '\0';
|
|
|
|
|
|
|
|
rflag:
|
|
|
|
ch = *fmt++;
|
|
|
|
reswitch:
|
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
case '-':
|
|
|
|
{
|
|
|
|
flags |= LADJUST;
|
|
|
|
goto rflag;
|
|
|
|
}
|
|
|
|
case '.':
|
|
|
|
{
|
|
|
|
n = 0;
|
|
|
|
while(is_digit((ch = *fmt++)))
|
|
|
|
{
|
|
|
|
n = 10 * n + (ch - '0');
|
|
|
|
}
|
|
|
|
prec = (n < 0) ? -1 : n;
|
|
|
|
goto reswitch;
|
|
|
|
}
|
|
|
|
case '0':
|
|
|
|
{
|
|
|
|
flags |= ZEROPAD;
|
|
|
|
goto rflag;
|
|
|
|
}
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
{
|
|
|
|
n = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
n = 10 * n + (ch - '0');
|
|
|
|
ch = *fmt++;
|
|
|
|
} while(is_digit(ch));
|
|
|
|
width = n;
|
|
|
|
goto reswitch;
|
|
|
|
}
|
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
char *c;
|
|
|
|
pCtx->LocalToString(params[arg], &c);
|
|
|
|
*buf_p++ = *c;
|
|
|
|
llen--;
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'b':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
AddBinary(&buf_p, llen, *value, width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'u':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'L':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
char buffer[255];
|
|
|
|
if (*value)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
const char *auth;
|
|
|
|
int userid;
|
2015-08-30 01:23:50 +02:00
|
|
|
if (!bridge->DescribePlayer(*value, &name, &auth, &userid))
|
2016-02-15 11:20:08 +01:00
|
|
|
return pCtx->ThrowNativeError("Client index %d is invalid (arg %d)", *value, arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
ke::SafeSprintf(buffer,
|
|
|
|
sizeof(buffer),
|
|
|
|
"%s<%d><%s><>",
|
|
|
|
name,
|
|
|
|
userid,
|
|
|
|
auth);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ke::SafeSprintf(buffer,
|
|
|
|
sizeof(buffer),
|
|
|
|
"Console<0><Console><Console>");
|
|
|
|
}
|
2016-02-15 15:57:56 +01:00
|
|
|
if (!AddString(&buf_p, llen, buffer, width, prec, flags))
|
|
|
|
return pCtx->ThrowNativeError("Escaped string would be truncated (arg %d)", arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'N':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
|
|
|
|
const char *name = "Console";
|
|
|
|
if (*value) {
|
2015-08-30 01:23:50 +02:00
|
|
|
if (!bridge->DescribePlayer(*value, &name, nullptr, nullptr))
|
2016-02-15 11:20:08 +01:00
|
|
|
return pCtx->ThrowNativeError("Client index %d is invalid (arg %d)", *value, arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
}
|
2016-02-15 15:57:56 +01:00
|
|
|
if (!AddString(&buf_p, llen, name, width, prec, flags))
|
|
|
|
return pCtx->ThrowNativeError("Escaped string would be truncated (arg %d)", arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
char *str;
|
|
|
|
pCtx->LocalToString(params[arg], &str);
|
2016-02-15 15:57:56 +01:00
|
|
|
if (!AddString(&buf_p, llen, str, width, prec, flags))
|
|
|
|
return pCtx->ThrowNativeError("Escaped string would be truncated (arg %d)", arg);
|
2015-08-26 08:28:50 +02:00
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'T':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(1);
|
|
|
|
char *key;
|
|
|
|
bool error;
|
|
|
|
size_t res;
|
|
|
|
cell_t *target;
|
|
|
|
pCtx->LocalToString(params[arg++], &key);
|
|
|
|
pCtx->LocalToPhysAddr(params[arg++], &target);
|
|
|
|
res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
buf_p += res;
|
|
|
|
llen -= res;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 't':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
char *key;
|
|
|
|
bool error;
|
|
|
|
size_t res;
|
2015-08-30 01:23:50 +02:00
|
|
|
cell_t target = bridge->GetGlobalTarget();
|
2015-08-26 08:28:50 +02:00
|
|
|
pCtx->LocalToString(params[arg++], &key);
|
|
|
|
res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
buf_p += res;
|
|
|
|
llen -= res;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'X':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
flags |= UPPERDIGITS;
|
|
|
|
AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'x':
|
|
|
|
{
|
|
|
|
CHECK_ARGS(0);
|
|
|
|
cell_t *value;
|
|
|
|
pCtx->LocalToPhysAddr(params[arg], &value);
|
|
|
|
AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
|
|
|
|
arg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '%':
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\0':
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = '%';
|
|
|
|
llen--;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (!llen)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
*buf_p++ = ch;
|
|
|
|
llen--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
*buf_p = '\0';
|
|
|
|
*param = arg;
|
|
|
|
return (maxlen - llen - 1);
|
|
|
|
}
|
|
|
|
|