From e78fe93e926366453c3d143c24d2d7e64aeca7bf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 26 Aug 2015 02:28:50 -0400 Subject: [PATCH] Move gnprintf/atcprintf from core to logic. --- core/logic/AMBuilder | 1 + core/logic/PhraseCollection.cpp | 5 +- core/logic/Translator.cpp | 3 +- core/logic/common_logic.cpp | 2 + core/logic/intercom.h | 9 +- core/logic/smn_console.cpp | 5 +- core/logic/smn_fakenatives.cpp | 3 +- core/logic/smn_filesystem.cpp | 5 +- core/logic/smn_string.cpp | 7 +- core/logic/sprintf.cpp | 1261 +++++++++++++++++++++++++++++++ core/logic/sprintf.h | 56 ++ core/logic_bridge.cpp | 32 +- core/sm_stringutil.cpp | 1237 ------------------------------ core/sm_stringutil.h | 10 - core/sourcemod.cpp | 2 +- 15 files changed, 1373 insertions(+), 1265 deletions(-) create mode 100644 core/logic/sprintf.cpp create mode 100644 core/logic/sprintf.h diff --git a/core/logic/AMBuilder b/core/logic/AMBuilder index 02ca251e..35755ef5 100644 --- a/core/logic/AMBuilder +++ b/core/logic/AMBuilder @@ -75,6 +75,7 @@ binary.sources += [ 'Logger.cpp', 'smn_core.cpp', 'smn_menus.cpp', + 'sprintf.cpp', ] if builder.target_platform == 'windows': binary.sources += ['thread/WinThreads.cpp'] diff --git a/core/logic/PhraseCollection.cpp b/core/logic/PhraseCollection.cpp index 6486f0b2..124f0094 100644 --- a/core/logic/PhraseCollection.cpp +++ b/core/logic/PhraseCollection.cpp @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet : * ============================================================================= * SourceMod * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -32,6 +32,7 @@ #include "common_logic.h" #include "PhraseCollection.h" #include "Translator.h" +#include "sprintf.h" #include CPhraseCollection::CPhraseCollection() @@ -114,7 +115,7 @@ bool CPhraseCollection::FormatString(char *buffer, unsigned int arg; arg = 0; - if (!smcore.gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase)) + if (!gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase)) { return false; } diff --git a/core/logic/Translator.cpp b/core/logic/Translator.cpp index c4bd01dc..5ca83506 100644 --- a/core/logic/Translator.cpp +++ b/core/logic/Translator.cpp @@ -40,6 +40,7 @@ #include #include "PhraseCollection.h" #include "stringutil.h" +#include "sprintf.h" #include Translator g_Translator; @@ -1059,7 +1060,7 @@ bool Translator::FormatString(char *buffer, unsigned int arg; arg = 0; - if (!smcore.gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase)) + if (!gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase)) { return false; } diff --git a/core/logic/common_logic.cpp b/core/logic/common_logic.cpp index d58864ee..bfd1d1d0 100644 --- a/core/logic/common_logic.cpp +++ b/core/logic/common_logic.cpp @@ -51,6 +51,7 @@ #include "AdminCache.h" #include "ProfileTools.h" #include "Logger.h" +#include "sprintf.h" sm_core_t smcore; IHandleSys *handlesys = &g_HandleSys; @@ -124,6 +125,7 @@ static sm_logic_t logic = g_pThreader, &g_Translator, stristr, + atcprintf, CoreTranslate, AddCorePhraseFile, UTIL_ReplaceAll, diff --git a/core/logic/intercom.h b/core/logic/intercom.h index c4280940..45cb7742 100644 --- a/core/logic/intercom.h +++ b/core/logic/intercom.h @@ -52,7 +52,7 @@ using namespace SourceHook; * Add 1 to the RHS of this expression to bump the intercom file * This is to prevent mismatching core/logic binaries */ -#define SM_LOGIC_MAGIC (0x0F47C0DE - 33) +#define SM_LOGIC_MAGIC (0x0F47C0DE - 34) #if defined SM_LOGIC class IVEngineServer @@ -297,9 +297,6 @@ struct sm_core_t void (*ConPrint)(const char *message); const char * (*GetCvarString)(ConVar*); bool (*GetCvarBool)(ConVar*); - bool (*gnprintf)(char *, size_t, const char *, IPhraseCollection *, void **, - unsigned int, unsigned int &, size_t *, const char **); - size_t (*atcprintf)(char *, size_t, const char *, IPluginContext *, const cell_t *, int *); bool (*GetGameName)(char *buffer, size_t maxlength); const char * (*GetGameDescription)(); const char * (*GetSourceEngineName)(); @@ -319,6 +316,9 @@ struct sm_core_t int (*GetImmunityMode)(); void (*UpdateAdminCmdFlags)(const char *cmd, OverrideType type, FlagBits bits, bool remove); bool (*LookForCommandAdminFlags)(const char *cmd, FlagBits *pFlags); + bool (*DescribePlayer)(int index, const char **namep, const char **authp, int *useridp); + int (*MaxClients)(); + int (*GetGlobalTarget)(); const char *gamesuffix; /* Data */ ServerGlobals *serverGlobals; @@ -334,6 +334,7 @@ struct sm_logic_t IThreader *threader; ITranslator *translator; const char *(*stristr)(const char *, const char *); + size_t (*atcprintf)(char *, size_t, const char *, IPluginContext *, const cell_t *, int *); bool (*CoreTranslate)(char *, size_t, const char *, unsigned int, size_t *, ...); void (*AddCorePhraseFile)(const char *filename); unsigned int (*ReplaceAll)(char*, size_t, const char *, const char *, bool); diff --git a/core/logic/smn_console.cpp b/core/logic/smn_console.cpp index 9b0ee6fa..2a8835a1 100644 --- a/core/logic/smn_console.cpp +++ b/core/logic/smn_console.cpp @@ -35,6 +35,7 @@ #include #include #include +#include "sprintf.h" static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params) { @@ -90,7 +91,7 @@ static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params) int arg = 2; pCtx->LocalToString(params[1], &fmt); - size_t res = smcore.atcprintf(buffer, sizeof(buffer) - 2, fmt, pCtx, params, &arg); + size_t res = atcprintf(buffer, sizeof(buffer) - 2, fmt, pCtx, params, &arg); buffer[res++] = '\n'; buffer[res] = '\0'; @@ -129,7 +130,7 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) int arg = 3; pCtx->LocalToString(params[2], &fmt); - size_t res = smcore.atcprintf(buffer, sizeof(buffer) - 2, fmt, pCtx, params, &arg); + size_t res = atcprintf(buffer, sizeof(buffer) - 2, fmt, pCtx, params, &arg); buffer[res++] = '\n'; buffer[res] = '\0'; diff --git a/core/logic/smn_fakenatives.cpp b/core/logic/smn_fakenatives.cpp index 3d785804..40baa604 100644 --- a/core/logic/smn_fakenatives.cpp +++ b/core/logic/smn_fakenatives.cpp @@ -35,6 +35,7 @@ #include "common_logic.h" #include "ShareSys.h" #include "PluginSys.h" +#include "sprintf.h" using namespace SourceHook; @@ -412,7 +413,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params) size_t written; { DetectExceptions eh(pContext); - written = smcore.atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param); + written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param); if (eh.HasException()) return 0; } diff --git a/core/logic/smn_filesystem.cpp b/core/logic/smn_filesystem.cpp index 6dd3d169..768306ed 100644 --- a/core/logic/smn_filesystem.cpp +++ b/core/logic/smn_filesystem.cpp @@ -40,6 +40,7 @@ #include #include "common_logic.h" #include "Logger.h" +#include "sprintf.h" #include #include "handle_helpers.h" @@ -774,7 +775,7 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) char buffer[2048]; { DetectExceptions eh(pContext); - smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); + atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); if (eh.HasException()) return 0; } @@ -809,7 +810,7 @@ static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params) { DetectExceptions eh(pContext); - smcore.atcprintf(path, sizeof(path), fmt, pContext, params, &arg); + atcprintf(path, sizeof(path), fmt, pContext, params, &arg); if (eh.HasException()) return 0; } diff --git a/core/logic/smn_string.cpp b/core/logic/smn_string.cpp index 828c2f96..2a9402ad 100644 --- a/core/logic/smn_string.cpp +++ b/core/logic/smn_string.cpp @@ -35,6 +35,7 @@ #include #include #include "stringutil.h" +#include "sprintf.h" #include inline const char *_strstr(const char *str, const char *substr) @@ -188,7 +189,7 @@ static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params) pCtx->LocalToString(params[1], &buf); pCtx->LocalToString(params[3], &fmt); - res = smcore.atcprintf(buf, static_cast(params[2]), fmt, pCtx, params, &arg); + res = atcprintf(buf, static_cast(params[2]), fmt, pCtx, params, &arg); return static_cast(res); } @@ -257,7 +258,7 @@ static cell_t sm_format(IPluginContext *pCtx, const cell_t *params) } buf = (copy) ? __copy_buf : destbuf; - res = smcore.atcprintf(buf, maxlen, fmt, pCtx, params, &arg); + res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg); if (copy) { @@ -307,7 +308,7 @@ static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params) pContext->LocalToString(params[3], &format); - size_t total = smcore.atcprintf(destination, maxlen, format, pContext, local_params, &vargPos); + size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos); /* Perform copy-on-write if we need to */ if (copy) diff --git a/core/logic/sprintf.cpp b/core/logic/sprintf.cpp new file mode 100644 index 00000000..0bd4d027 --- /dev/null +++ b/core/logic/sprintf.cpp @@ -0,0 +1,1261 @@ +// 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 . +// +// 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 . + +#include "common_logic.h" +#include "Translator.h" +#include "sprintf.h" +#include +#include + +using namespace SourceMod; + +#define LADJUST 0x00000004 /* left adjustment */ +#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ +#define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */ +#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(); + } + else if ((target >= 1) && (target <= smcore.MaxClients())) + { + langid = g_Translator.GetClientLanguage(target); + } + else + { + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target); + 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) + { + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); + goto error_out; + } + } + else + { + pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); + 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, + "Translation string formatted incorrectly - missing at least %d parameters", + ((*arg + (max_params - 1)) - params[0]) + ); + 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; +} + +void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) +{ + 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; +} + +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)) + { + AddString(buf_p, maxlen, "NaN", width, prec); + 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++; + AddString(&buf_p, llen, str, width, prec); + 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(); + } + else if (target >= 1 && target <= smcore.MaxClients()) + { + 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(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(*value), width, flags); + arg++; + break; + } + case 'u': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddUInt(&buf_p, llen, static_cast(*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; + if (!smcore.DescribePlayer(*value, &name, &auth, &userid)) + return pCtx->ThrowNativeError("Client index %d is invalid", *value); + ke::SafeSprintf(buffer, + sizeof(buffer), + "%s<%d><%s><>", + name, + userid, + auth); + } + else + { + ke::SafeSprintf(buffer, + sizeof(buffer), + "Console<0>"); + } + AddString(&buf_p, llen, buffer, width, prec); + arg++; + break; + } + case 'N': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + + const char *name = "Console"; + if (*value) { + if (!smcore.DescribePlayer(*value, &name, nullptr, nullptr)) + return pCtx->ThrowNativeError("Client index %d is invalid", *value); + } + AddString(&buf_p, llen, name, width, prec); + arg++; + break; + } + case 's': + { + CHECK_ARGS(0); + char *str; + pCtx->LocalToString(params[arg], &str); + AddString(&buf_p, llen, str, width, prec); + 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; + cell_t target = smcore.GetGlobalTarget(); + 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(*value), width, flags); + arg++; + break; + } + case 'x': + { + CHECK_ARGS(0); + cell_t *value; + pCtx->LocalToPhysAddr(params[arg], &value); + AddHex(&buf_p, llen, static_cast(*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); +} + diff --git a/core/logic/sprintf.h b/core/logic/sprintf.h new file mode 100644 index 00000000..f8870b57 --- /dev/null +++ b/core/logic/sprintf.h @@ -0,0 +1,56 @@ +// 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 . +// +// 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 . +#ifndef _include_sourcemod_core_logic_sprintf_h_ +#define _include_sourcemod_core_logic_sprintf_h_ + +#include + +// "AMX Templated Cell Printf", originally. SourceMod doesn't have cell-strings +// so this is a normal sprintf(), except that its variadic arguments are +// derived from scripted arguments. +size_t atcprintf(char *buffer, + size_t maxlen, + const char *format, + SourcePawn::IPluginContext *pCtx, + const cell_t *params, + int *param); + +// "Generic Printf", originally. This is similar to atcprintf, except arguments +// are provided as an array of opaque pointers, rather than scripted arguments +// or C++ va_lists. This is essentially what Core uses to translate and format +// phrases internally. +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); + +#endif // _include_sourcemod_core_logic_sprintf_h_ diff --git a/core/logic_bridge.cpp b/core/logic_bridge.cpp index e7ea4043..845e51c2 100644 --- a/core/logic_bridge.cpp +++ b/core/logic_bridge.cpp @@ -516,6 +516,33 @@ void do_global_plugin_loads() g_SourceMod.DoGlobalPluginLoads(); } +static bool describe_player(int index, const char **namep, const char **authp, int *useridp) +{ + CPlayer *player = g_Players.GetPlayerByIndex(index); + if (!player || !player->IsConnected()) + return false; + + if (namep) + *namep = player->GetName(); + if (authp) { + const char *auth = player->GetAuthString(); + *authp = (auth && *auth) ? auth : "STEAM_ID_PENDING"; + } + if (useridp) + *useridp = GetPlayerUserId(player->GetEdict()); + return true; +} + +static int get_max_clients() +{ + return g_Players.MaxClients(); +} + +static int get_global_target() +{ + return g_SourceMod.GetGlobalTarget(); +} + #if defined METAMOD_PLAPI_VERSION #if SOURCE_ENGINE == SE_LEFT4DEAD #define GAMEFIX "2.l4d" @@ -587,8 +614,6 @@ static sm_core_t core_bridge = conprint, get_cvar_string, get_cvar_bool, - gnprintf, - atcprintf, get_game_name, get_game_description, get_source_engine_name, @@ -608,6 +633,9 @@ static sm_core_t core_bridge = get_immunity_mode, update_admin_cmd_flags, look_for_cmd_admin_flags, + describe_player, + get_max_clients, + get_global_target, GAMEFIX, &serverGlobals, }; diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index c0507bb1..ad214677 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -41,1243 +41,6 @@ #include #include -#define LADJUST 0x00000004 /* left adjustment */ -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */ -#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 = translator->GetServerLanguage(); - } - else if ((target >= 1) && (target <= g_Players.GetMaxClients())) - { - langid = translator->GetClientLanguage(target); - } - else - { - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target); - goto error_out; - } - - if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay) - { - if (target != SOURCEMOD_SERVER_LANGUAGE && langid != 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) - { - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); - goto error_out; - } - } - else - { - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key); - 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, - "Translation string formatted incorrectly - missing at least %d parameters", - ((*arg + (max_params - 1)) - params[0]) - ); - 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; -} - -void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec) -{ - 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; -} - -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)) - { - AddString(buf_p, maxlen, "NaN", width, prec); - 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++; - AddString(&buf_p, llen, str, width, prec); - 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 = translator->GetGlobalTarget(); - } - -try_again: - if (target == SOURCEMOD_SERVER_LANGUAGE) - { - lang_id = translator->GetServerLanguage(); - } - else if (target >= 1 && target <= g_Players.GetMaxClients()) - { - lang_id = translator->GetClientLanguage(target); - } - else - { - lang_id = 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 != 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(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(*value), width, flags); - arg++; - break; - } - case 'u': - { - CHECK_ARGS(0); - cell_t *value; - pCtx->LocalToPhysAddr(params[arg], &value); - AddUInt(&buf_p, llen, static_cast(*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) - { - CPlayer *player = g_Players.GetPlayerByIndex(*value); - if (!player || !player->IsConnected()) - { - return pCtx->ThrowNativeError("Client index %d is invalid", *value); - } - const char *auth = player->GetAuthString(); - if (!auth || auth[0] == '\0') - { - auth = "STEAM_ID_PENDING"; - } - int userid = GetPlayerUserId(player->GetEdict()); - UTIL_Format(buffer, - sizeof(buffer), - "%s<%d><%s><>", - player->GetName(), - userid, - auth); - } - else - { - UTIL_Format(buffer, - sizeof(buffer), - "Console<0>"); - } - AddString(&buf_p, llen, buffer, width, prec); - arg++; - break; - } - case 'N': - { - CHECK_ARGS(0); - cell_t *value; - pCtx->LocalToPhysAddr(params[arg], &value); - - const char *name = "Console"; - if (*value) - { - CPlayer *player = g_Players.GetPlayerByIndex(*value); - if (!player || !player->IsConnected()) - { - return pCtx->ThrowNativeError("Client index %d is invalid", *value); - } - name = player->GetName(); - } - AddString(&buf_p, llen, name, width, prec); - arg++; - break; - } - case 's': - { - CHECK_ARGS(0); - char *str; - pCtx->LocalToString(params[arg], &str); - AddString(&buf_p, llen, str, width, prec); - 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; - cell_t target = g_SourceMod.GetGlobalTarget(); - 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(*value), width, flags); - arg++; - break; - } - case 'x': - { - CHECK_ARGS(0); - cell_t *value; - pCtx->LocalToPhysAddr(params[arg], &value); - AddHex(&buf_p, llen, static_cast(*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); -} - unsigned int strncopy(char *dest, const char *src, size_t count) { return ke::SafeStrcpy(dest, count, src); diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 699b941d..f5e786c7 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -42,17 +42,7 @@ using namespace SourceMod; #define IS_STR_FILLED(var) (var[0] != '\0') -size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); unsigned int strncopy(char *dest, const char *src, size_t count); -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); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); char *sm_strdup(const char *str); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 095e04ef..11fc9226 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -588,7 +588,7 @@ size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContex int lparam = ++param; - return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); + return logicore.atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); } const char *SourceModBase::GetSourceModPath() const