dvander@370: /**
ds@653: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@370: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@370: *
dvander@370: * Version: $Id$
dvander@370: */
dvander@370:
faluco@230: #include
faluco@230: #include
faluco@274: #include
dvander@3872: #include
faluco@227: #include "sm_stringutil.h"
dvander@592: #include "Logger.h"
dvander@591: #include "PlayerManager.h"
dvander@3004: #include "logic_bridge.h"
dvander@3872: #include "sourcemod.h"
faluco@227:
faluco@227: #define LADJUST 0x00000004 /* left adjustment */
faluco@227: #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
ds@609: #define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
faluco@227: #define to_digit(c) ((c) - '0')
faluco@227: #define is_digit(c) ((unsigned)to_digit(c) <= 9)
faluco@227:
faluco@288: #define CHECK_ARGS(x) \
faluco@288: if ((arg+x) > args) { \
dvander@599: pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
faluco@288: return 0; \
faluco@227: }
faluco@227:
dvander@1620: inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
dvander@1620: {
dvander@1620: cell_t new_params[MAX_TRANSLATE_PARAMS];
dvander@1620: for (unsigned int i = 0; i < pTrans->fmt_count; i++)
dvander@1620: {
dvander@1620: new_params[i] = params[pTrans->fmt_order[i]];
dvander@1620: }
dvander@1620: memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
dvander@1620: }
dvander@1620:
dvander@1620: size_t Translate(char *buffer,
dvander@1620: size_t maxlen,
dvander@1620: IPluginContext *pCtx,
dvander@1620: const char *key,
dvander@1620: cell_t target,
dvander@1620: const cell_t *params,
dvander@1620: int *arg,
dvander@1620: bool *error)
faluco@422: {
faluco@422: unsigned int langid;
faluco@422: *error = false;
dvander@464: Translation pTrans;
dvander@3872: IPlugin *pl = scripts->FindPluginByContext(pCtx->GetContext());
dvander@464: unsigned int max_params = 0;
dvander@2042: IPhraseCollection *pPhrases;
dvander@2042:
dvander@2042: pPhrases = pl->GetPhrases();
faluco@422:
faluco@422: try_serverlang:
dvander@2042: if (target == SOURCEMOD_SERVER_LANGUAGE)
faluco@389: {
dvander@3004: langid = translator->GetServerLanguage();
dvander@1620: }
dvander@1620: else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
dvander@1620: {
dvander@3004: langid = translator->GetClientLanguage(target);
dvander@1620: }
dvander@1620: else
dvander@1620: {
faluco@422: pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
faluco@422: goto error_out;
faluco@422: }
faluco@422:
dvander@2042: if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
faluco@422: {
dvander@3004: if (target != SOURCEMOD_SERVER_LANGUAGE && langid != translator->GetServerLanguage())
faluco@422: {
dvander@2042: target = SOURCEMOD_SERVER_LANGUAGE;
faluco@422: goto try_serverlang;
dvander@1620: }
dvander@2042: else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
dvander@1620: {
dvander@2339: if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
faluco@422: {
faluco@422: pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
faluco@422: goto error_out;
faluco@422: }
dvander@1620: }
dvander@1620: else
dvander@1620: {
dvander@919: pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
dvander@909: goto error_out;
faluco@422: }
faluco@389: }
faluco@389:
dvander@474: max_params = pTrans.fmt_count;
faluco@1352:
dvander@909: if (max_params)
faluco@389: {
dvander@1621: cell_t new_params[MAX_TRANSLATE_PARAMS];
dvander@1621:
dvander@909: /* Check if we're going to over the limit */
dvander@909: if ((*arg) + (max_params - 1) > (size_t)params[0])
faluco@389: {
dvander@909: pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
dvander@909: "Translation string formatted incorrectly - missing at least %d parameters",
dvander@909: ((*arg + (max_params - 1)) - params[0])
dvander@909: );
faluco@422: goto error_out;
faluco@389: }
dvander@909:
dvander@1621: /* If we need to re-order the parameters, do so with a temporary array.
dvander@1621: * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
dvander@1621: */
dvander@1621: memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
dvander@1621: ReorderTranslationParams(&pTrans, &new_params[*arg]);
dvander@1621:
dvander@1621: return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
faluco@389: }
dvander@1621: else
dvander@1621: {
dvander@1621: return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
dvander@1621: }
dvander@1620:
faluco@422: error_out:
faluco@422: *error = true;
faluco@422: return 0;
faluco@389: }
faluco@389:
faluco@227: void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
faluco@227: {
faluco@227: int size = 0;
faluco@227: char *buf;
faluco@227: static char nlstr[] = {'(','n','u','l','l',')','\0'};
faluco@227:
faluco@227: buf = *buf_p;
faluco@227:
faluco@227: if (string == NULL)
faluco@227: {
faluco@227: string = nlstr;
faluco@227: prec = -1;
faluco@227: }
faluco@227:
faluco@227: if (prec >= 0)
faluco@227: {
faluco@227: for (size = 0; size < prec; size++)
faluco@227: {
faluco@227: if (string[size] == '\0')
faluco@227: {
faluco@227: break;
faluco@227: }
faluco@227: }
faluco@1677: }
faluco@1677: else
faluco@1677: {
faluco@227: while (string[size++]);
faluco@227: size--;
faluco@227: }
faluco@227:
faluco@227: if (size > (int)maxlen)
faluco@227: {
faluco@227: size = maxlen;
faluco@227: }
faluco@227:
faluco@227: maxlen -= size;
faluco@227: width -= size;
faluco@227:
faluco@227: while (size--)
faluco@227: {
faluco@227: *buf++ = *string++;
faluco@227: }
faluco@227:
faluco@227: while ((width-- > 0) && maxlen)
faluco@227: {
faluco@227: *buf++ = ' ';
faluco@227: maxlen--;
faluco@227: }
faluco@227:
faluco@227: *buf_p = buf;
faluco@227: }
faluco@227:
faluco@1677: void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
faluco@227: {
faluco@1677: int digits; // non-fraction part digits
faluco@1677: double tmp; // temporary
faluco@1677: char *buf = *buf_p; // output buffer pointer
faluco@1677: int val; // temporary
faluco@1677: int sign = 0; // 0: positive, 1: negative
faluco@1677: int fieldlength; // for padding
faluco@1677: int significant_digits = 0; // number of significant digits written
faluco@1677: const int MAX_SIGNIFICANT_DIGITS = 16;
faluco@227:
faluco@1677: // default precision
faluco@227: if (prec < 0)
faluco@227: {
faluco@227: prec = 6;
faluco@227: }
faluco@1677:
faluco@1677: // get the sign
faluco@1677: if (fval < 0)
faluco@1677: {
faluco@1677: fval = -fval;
faluco@1677: sign = 1;
faluco@1677: }
faluco@1677:
faluco@1677: // compute whole-part digits count
faluco@1677: digits = (int)log10(fval) + 1;
faluco@1677:
faluco@1677: // Only print 0.something if 0 < fval < 1
faluco@1677: if (digits < 1)
faluco@227: {
faluco@1677: digits = 1;
faluco@1677: }
faluco@1677:
faluco@1677: // compute the field length
faluco@1677: fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
faluco@1677:
faluco@1677: // minus sign BEFORE left padding if padding with zeros
faluco@1677: if (sign && maxlen && (flags & ZEROPAD))
faluco@1677: {
faluco@1677: *buf++ = '-';
faluco@1677: maxlen--;
faluco@1677: }
faluco@1677:
faluco@1677: // right justify if required
faluco@1677: if ((flags & LADJUST) == 0)
faluco@1677: {
faluco@1677: while ((fieldlength < width) && maxlen)
faluco@1677: {
faluco@1677: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@1677: width--;
faluco@1677: maxlen--;
faluco@1677: }
faluco@1677: }
faluco@1677:
faluco@1677: // minus sign AFTER left padding if padding with spaces
faluco@1677: if (sign && maxlen && !(flags & ZEROPAD))
faluco@1677: {
faluco@1677: *buf++ = '-';
faluco@1677: maxlen--;
faluco@227: }
faluco@227:
faluco@1677: // write the whole part
faluco@1677: tmp = pow(10.0, digits-1);
faluco@1677: while ((digits--) && maxlen)
faluco@227: {
faluco@1677: if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
faluco@1677: {
faluco@1677: *buf++ = '0';
faluco@1677: }
faluco@1677: else
faluco@1677: {
faluco@1677: val = (int)(fval / tmp);
faluco@1677: *buf++ = '0' + val;
faluco@1677: fval -= val * tmp;
faluco@1677: tmp *= 0.1;
faluco@1677: }
faluco@1677: maxlen--;
faluco@1677: }
faluco@1677:
faluco@1677: // write the fraction part
dvander@2515: if (maxlen && prec)
faluco@1677: {
faluco@227: *buf++ = '.';
faluco@227: maxlen--;
faluco@1677: }
faluco@1677:
faluco@1677: tmp = pow(10.0, prec);
faluco@1677:
faluco@1677: fval *= tmp;
faluco@1677: while (prec-- && maxlen)
faluco@1677: {
faluco@1677: if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
faluco@1677: {
faluco@1677: *buf++ = '0';
faluco@1677: }
faluco@1677: else
faluco@227: {
faluco@1677: tmp *= 0.1;
faluco@1677: val = (int)(fval / tmp);
faluco@1677: *buf++ = '0' + val;
faluco@1677: fval -= val * tmp;
faluco@1677: }
faluco@1677: maxlen--;
faluco@1677: }
faluco@1677:
faluco@1677: // left justify if required
faluco@1677: if (flags & LADJUST)
faluco@1677: {
faluco@1677: while ((fieldlength < width) && maxlen)
faluco@1677: {
faluco@1677: // right-padding only with spaces, ZEROPAD is ignored
faluco@1677: *buf++ = ' ';
faluco@1677: width--;
faluco@227: maxlen--;
faluco@227: }
faluco@227: }
faluco@1677:
faluco@1677: // update parent's buffer pointer
faluco@1677: *buf_p = buf;
faluco@227: }
faluco@227:
dvander@1965: void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
dvander@1965: {
dvander@1965: char text[32];
dvander@1965: int digits;
dvander@1965: char *buf;
dvander@1965:
dvander@1965: digits = 0;
dvander@1965: do
dvander@1965: {
dvander@1965: if (val & 1)
dvander@1965: {
dvander@1965: text[digits++] = '1';
dvander@1965: }
dvander@1965: else
dvander@1965: {
dvander@1965: text[digits++] = '0';
dvander@1965: }
dvander@1965: val >>= 1;
dvander@1965: } while (val);
dvander@1965:
dvander@1965: buf = *buf_p;
dvander@1965:
dvander@1965: if (!(flags & LADJUST))
dvander@1965: {
dvander@1965: while (digits < width && maxlen)
dvander@1965: {
dvander@1965: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
dvander@1965: width--;
dvander@1965: maxlen--;
dvander@1965: }
dvander@1965: }
dvander@1965:
dvander@1965: while (digits-- && maxlen)
dvander@1965: {
dvander@1965: *buf++ = text[digits];
dvander@1965: width--;
dvander@1965: maxlen--;
dvander@1965: }
dvander@1965:
dvander@1965: if (flags & LADJUST)
dvander@1965: {
dvander@1965: while (width-- && maxlen)
dvander@1965: {
dvander@1965: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
dvander@1965: maxlen--;
dvander@1965: }
dvander@1965: }
dvander@1965:
dvander@1965: *buf_p = buf;
dvander@1965: }
dvander@1965:
faluco@227: void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
faluco@227: {
faluco@227: char text[32];
faluco@227: int digits;
faluco@227: char *buf;
faluco@227:
faluco@227: digits = 0;
faluco@227: do
faluco@227: {
faluco@227: text[digits++] = '0' + val % 10;
faluco@227: val /= 10;
faluco@227: } while (val);
faluco@227:
faluco@227: buf = *buf_p;
faluco@227:
faluco@227: if (!(flags & LADJUST))
faluco@227: {
faluco@227: while (digits < width && maxlen)
faluco@227: {
faluco@227: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227: width--;
faluco@227: maxlen--;
faluco@227: }
faluco@227: }
faluco@227:
faluco@227: while (digits-- && maxlen)
faluco@227: {
faluco@227: *buf++ = text[digits];
faluco@227: width--;
faluco@227: maxlen--;
faluco@227: }
faluco@227:
faluco@227: if (flags & LADJUST)
faluco@227: {
faluco@227: while (width-- && maxlen)
faluco@227: {
faluco@227: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227: maxlen--;
faluco@227: }
faluco@227: }
faluco@227:
faluco@227: *buf_p = buf;
faluco@227: }
faluco@227:
faluco@227: void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
faluco@227: {
faluco@227: char text[32];
faluco@227: int digits;
faluco@227: int signedVal;
faluco@227: char *buf;
faluco@227: unsigned int unsignedVal;
faluco@227:
faluco@227: digits = 0;
faluco@227: signedVal = val;
faluco@227: if (val < 0)
faluco@227: {
faluco@227: /* we want the unsigned version */
faluco@227: unsignedVal = abs(val);
faluco@1677: }
faluco@1677: else
faluco@1677: {
faluco@227: unsignedVal = val;
faluco@227: }
faluco@1677:
faluco@227: do
faluco@227: {
faluco@227: text[digits++] = '0' + unsignedVal % 10;
faluco@227: unsignedVal /= 10;
faluco@227: } while (unsignedVal);
faluco@227:
faluco@227: if (signedVal < 0)
faluco@227: {
faluco@227: text[digits++] = '-';
faluco@227: }
faluco@227:
faluco@227: buf = *buf_p;
faluco@227:
faluco@227: if (!(flags & LADJUST))
faluco@227: {
faluco@227: while ((digits < width) && maxlen)
faluco@227: {
faluco@227: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227: width--;
faluco@227: maxlen--;
faluco@227: }
faluco@227: }
faluco@227:
faluco@227: while (digits-- && maxlen)
faluco@227: {
faluco@227: *buf++ = text[digits];
faluco@227: width--;
faluco@227: maxlen--;
faluco@227: }
faluco@227:
faluco@227: if (flags & LADJUST)
faluco@227: {
faluco@227: while (width-- && maxlen)
faluco@227: {
faluco@227: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
faluco@227: maxlen--;
faluco@227: }
faluco@227: }
faluco@227:
faluco@227: *buf_p = buf;
faluco@227: }
faluco@227:
ds@544: void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
ds@544: {
ds@544: char text[32];
ds@544: int digits;
ds@544: char *buf;
ds@544: char digit;
ds@544: int hexadjust;
ds@544:
ds@544: if (flags & UPPERDIGITS)
ds@544: {
ds@544: hexadjust = 'A' - '9' - 1;
faluco@1677: }
faluco@1677: else
faluco@1677: {
ds@544: hexadjust = 'a' - '9' - 1;
ds@544: }
ds@544:
ds@544: digits = 0;
ds@544: do
ds@544: {
ds@544: digit = ('0' + val % 16);
ds@544: if (digit > '9')
ds@544: {
ds@544: digit += hexadjust;
ds@544: }
ds@544:
ds@544: text[digits++] = digit;
ds@544: val /= 16;
ds@544: } while(val);
ds@544:
ds@544: buf = *buf_p;
ds@544:
ds@544: if (!(flags & LADJUST))
ds@544: {
ds@544: while (digits < width && maxlen)
ds@544: {
ds@544: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544: width--;
ds@544: maxlen--;
ds@544: }
ds@544: }
ds@544:
ds@544: while (digits-- && maxlen)
ds@544: {
ds@544: *buf++ = text[digits];
ds@544: width--;
ds@544: maxlen--;
ds@544: }
ds@544:
ds@544: if (flags & LADJUST)
ds@544: {
ds@544: while (width-- && maxlen)
ds@544: {
ds@544: *buf++ = (flags & ZEROPAD) ? '0' : ' ';
ds@544: maxlen--;
ds@544: }
ds@544: }
ds@544:
ds@544: *buf_p = buf;
ds@544: }
ds@544:
dvander@2042: bool gnprintf(char *buffer,
dvander@2042: size_t maxlen,
dvander@2042: const char *format,
dvander@2042: IPhraseCollection *pPhrases,
dvander@2042: void **params,
dvander@2042: unsigned int numparams,
dvander@2042: unsigned int &curparam,
dvander@2042: size_t *pOutLength,
dvander@2042: const char **pFailPhrase)
dvander@276: {
dvander@276: if (!buffer || !maxlen)
dvander@276: {
dvander@2042: if (pOutLength != NULL)
dvander@2042: {
dvander@2042: *pOutLength = 0;
dvander@2042: }
dvander@2042: return true;
dvander@2042: }
dvander@2042:
dvander@2042: if (numparams > MAX_TRANSLATE_PARAMS)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@276: }
dvander@276:
dvander@276: int arg = 0;
dvander@276: char *buf_p;
dvander@276: char ch;
dvander@276: int flags;
dvander@276: int width;
dvander@276: int prec;
dvander@276: int n;
dvander@276: char sign;
dvander@276: const char *fmt;
dvander@276: size_t llen = maxlen - 1;
dvander@276:
dvander@276: buf_p = buffer;
dvander@276: fmt = format;
dvander@276:
dvander@276: while (true)
dvander@276: {
dvander@276: // run through the format string until we hit a '%' or '\0'
dvander@276: for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
dvander@276: {
dvander@276: *buf_p++ = ch;
dvander@276: llen--;
dvander@276: }
dvander@276: if ((ch == '\0') || (llen <= 0))
dvander@276: {
dvander@276: goto done;
dvander@276: }
dvander@276:
dvander@276: // skip over the '%'
dvander@276: fmt++;
dvander@276:
dvander@276: // reset formatting state
dvander@276: flags = 0;
dvander@276: width = 0;
dvander@276: prec = -1;
dvander@276: sign = '\0';
dvander@276:
dvander@276: rflag:
dvander@276: ch = *fmt++;
dvander@276: reswitch:
dvander@276: switch(ch)
dvander@276: {
dvander@276: case '-':
dvander@276: {
dvander@276: flags |= LADJUST;
dvander@276: goto rflag;
dvander@276: }
dvander@276: case '.':
dvander@276: {
dvander@276: n = 0;
dvander@276: while(is_digit((ch = *fmt++)))
dvander@276: {
dvander@276: n = 10 * n + (ch - '0');
dvander@276: }
dvander@276: prec = (n < 0) ? -1 : n;
dvander@276: goto reswitch;
dvander@276: }
dvander@276: case '0':
dvander@276: {
dvander@276: flags |= ZEROPAD;
dvander@276: goto rflag;
dvander@276: }
dvander@276: case '1':
dvander@276: case '2':
dvander@276: case '3':
dvander@276: case '4':
dvander@276: case '5':
dvander@276: case '6':
dvander@276: case '7':
dvander@276: case '8':
dvander@276: case '9':
dvander@276: {
dvander@276: n = 0;
dvander@276: do
dvander@276: {
dvander@276: n = 10 * n + (ch - '0');
dvander@276: ch = *fmt++;
dvander@276: } while(is_digit(ch));
dvander@276: width = n;
dvander@276: goto reswitch;
dvander@276: }
dvander@276: case 'c':
dvander@276: {
dvander@276: if (!llen)
dvander@276: {
dvander@276: goto done;
dvander@276: }
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: char *c = (char *)params[curparam];
dvander@2042: curparam++;
dvander@276: *buf_p++ = *c;
dvander@276: llen--;
dvander@276: arg++;
dvander@276: break;
dvander@276: }
dvander@1965: case 'b':
dvander@1965: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: int *value = (int *)params[curparam];
dvander@2042: curparam++;
dvander@1965: AddBinary(&buf_p, llen, *value, width, flags);
dvander@1965: arg++;
dvander@1965: break;
dvander@1965: }
dvander@276: case 'd':
dvander@276: case 'i':
dvander@276: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: int *value = (int *)params[curparam];
dvander@2042: curparam++;
dvander@276: AddInt(&buf_p, llen, *value, width, flags);
dvander@276: arg++;
dvander@276: break;
dvander@276: }
dvander@276: case 'u':
dvander@276: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: unsigned int *value = (unsigned int *)params[curparam];
dvander@2042: curparam++;
dvander@276: AddUInt(&buf_p, llen, *value, width, flags);
dvander@276: arg++;
dvander@276: break;
dvander@276: }
dvander@276: case 'f':
dvander@276: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: float *value = (float *)params[curparam];
dvander@2042: curparam++;
faluco@1677: AddFloat(&buf_p, llen, *value, width, prec, flags);
dvander@276: arg++;
dvander@276: break;
dvander@276: }
dvander@276: case 's':
dvander@276: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: const char *str = (const char *)params[curparam];
dvander@2042: curparam++;
dvander@276: AddString(&buf_p, llen, str, width, prec);
dvander@276: arg++;
dvander@276: break;
dvander@276: }
dvander@2042: case 'T':
dvander@2042: case 't':
dvander@2042: {
dvander@2042: int target;
dvander@2042: const char *key;
dvander@2042: size_t out_length;
dvander@2042: Translation trans;
dvander@2042: unsigned int lang_id;
dvander@2042:
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: key = (const char *)(params[curparam]);
dvander@2042: curparam++;
dvander@2042:
dvander@2042: if (ch == 'T')
dvander@2042: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: target = *((int *)(params[curparam]));
dvander@2042: curparam++;
dvander@2042: }
dvander@2042: else
dvander@2042: {
dvander@3004: target = translator->GetGlobalTarget();
dvander@2042: }
dvander@2042:
dvander@2042: try_again:
dvander@2042: if (target == SOURCEMOD_SERVER_LANGUAGE)
dvander@2042: {
dvander@3004: lang_id = translator->GetServerLanguage();
dvander@2042: }
dvander@2042: else if (target >= 1 && target <= g_Players.GetMaxClients())
dvander@2042: {
dvander@3004: lang_id = translator->GetClientLanguage(target);
dvander@2042: }
dvander@2042: else
dvander@2042: {
dvander@3004: lang_id = translator->GetServerLanguage();
dvander@2042: }
dvander@2042:
dvander@2042: if (pPhrases == NULL)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = key;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042:
dvander@2042: if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
dvander@2042: {
dvander@3004: if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != translator->GetServerLanguage())
dvander@2042: {
dvander@2042: target = SOURCEMOD_SERVER_LANGUAGE;
dvander@2042: goto try_again;
dvander@2042: }
dvander@2042: else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
dvander@2042: {
dvander@2042: if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = key;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: }
dvander@2042: else
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = key;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: }
dvander@2042:
dvander@2042: if (trans.fmt_count)
dvander@2042: {
dvander@2042: unsigned int i;
dvander@2042: void *new_params[MAX_TRANSLATE_PARAMS];
dvander@2042:
dvander@2042: if (curparam + trans.fmt_count > numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042:
dvander@2042: /* Copy the array and re-order the stack */
dvander@2042: memcpy(new_params, params, sizeof(void *) * numparams);
dvander@2042: for (i = 0; i < trans.fmt_count; i++)
dvander@2042: {
pred@2799: new_params[curparam + i] = const_cast(params[curparam + trans.fmt_order[i]]);
dvander@2042: }
dvander@2042:
dvander@2042: if (!gnprintf(buf_p,
dvander@2042: llen,
dvander@2042: trans.szPhrase,
dvander@2042: pPhrases,
dvander@2042: new_params,
dvander@2042: numparams,
dvander@2042: curparam,
dvander@2042: &out_length,
dvander@2042: pFailPhrase))
dvander@2042: {
dvander@2042: return false;
dvander@2042: }
dvander@2042: }
dvander@2042: else
dvander@2042: {
dvander@2042: if (!gnprintf(buf_p,
dvander@2042: llen,
dvander@2042: trans.szPhrase,
dvander@2042: pPhrases,
dvander@2042: params,
dvander@2042: numparams,
dvander@2042: curparam,
dvander@2042: &out_length,
dvander@2042: pFailPhrase))
dvander@2042: {
dvander@2042: return false;
dvander@2042: }
dvander@2042: }
dvander@2042:
dvander@2042: buf_p += out_length;
dvander@2042: llen -= out_length;
dvander@2042:
dvander@2042: break;
dvander@2042: }
ds@544: case 'X':
ds@544: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: unsigned int *value = (unsigned int *)params[curparam];
dvander@2042: curparam++;
ds@544: flags |= UPPERDIGITS;
ds@544: AddHex(&buf_p, llen, *value, width, flags);
ds@544: arg++;
ds@544: break;
ds@544: }
ds@544: case 'x':
ds@544: {
dvander@2042: if (curparam >= numparams)
dvander@2042: {
dvander@2042: if (pFailPhrase != NULL)
dvander@2042: {
dvander@2042: *pFailPhrase = NULL;
dvander@2042: }
dvander@2042: return false;
dvander@2042: }
dvander@2042: unsigned int *value = (unsigned int *)params[curparam];
dvander@2042: curparam++;
ds@544: AddHex(&buf_p, llen, *value, width, flags);
ds@544: arg++;
ds@544: break;
ds@544: }
dvander@276: case '%':
dvander@276: {
dvander@276: if (!llen)
dvander@276: {
dvander@276: goto done;
dvander@276: }
dvander@276: *buf_p++ = ch;
dvander@276: llen--;
dvander@276: break;
dvander@276: }
dvander@276: case '\0':
dvander@276: {
dvander@276: if (!llen)
dvander@276: {
dvander@276: goto done;
dvander@276: }
dvander@276: *buf_p++ = '%';
dvander@276: llen--;
dvander@276: goto done;
dvander@276: }
dvander@276: default:
dvander@276: {
dvander@276: if (!llen)
dvander@276: {
dvander@276: goto done;
dvander@276: }
dvander@276: *buf_p++ = ch;
dvander@276: llen--;
dvander@276: break;
dvander@276: }
dvander@276: }
dvander@276: }
dvander@276:
dvander@276: done:
dvander@276: *buf_p = '\0';
dvander@276:
dvander@2042: if (pOutLength != NULL)
dvander@2042: {
dvander@2042: *pOutLength = (maxlen - llen - 1);
dvander@2042: }
dvander@2042:
dvander@2042: return true;
dvander@276: }
dvander@276:
faluco@227: size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
faluco@227: {
dvander@276: if (!buffer || !maxlen)
dvander@276: {
dvander@276: return 0;
dvander@276: }
dvander@276:
faluco@227: int arg;
faluco@288: int args = params[0];
faluco@227: char *buf_p;
faluco@227: char ch;
faluco@227: int flags;
faluco@227: int width;
faluco@227: int prec;
faluco@227: int n;
faluco@227: char sign;
faluco@227: const char *fmt;
faluco@230: size_t llen = maxlen - 1;
faluco@227:
faluco@227: buf_p = buffer;
faluco@227: arg = *param;
faluco@227: fmt = format;
faluco@227:
faluco@227: while (true)
faluco@227: {
faluco@227: // run through the format string until we hit a '%' or '\0'
faluco@227: for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
faluco@227: {
faluco@227: *buf_p++ = ch;
faluco@227: llen--;
faluco@227: }
faluco@227: if ((ch == '\0') || (llen <= 0))
faluco@227: {
faluco@227: goto done;
faluco@227: }
faluco@227:
faluco@227: // skip over the '%'
faluco@227: fmt++;
faluco@227:
faluco@227: // reset formatting state
faluco@227: flags = 0;
faluco@227: width = 0;
faluco@227: prec = -1;
faluco@227: sign = '\0';
faluco@227:
faluco@227: rflag:
faluco@227: ch = *fmt++;
faluco@227: reswitch:
faluco@227: switch(ch)
faluco@227: {
faluco@227: case '-':
faluco@227: {
faluco@227: flags |= LADJUST;
faluco@227: goto rflag;
faluco@227: }
faluco@227: case '.':
faluco@227: {
faluco@227: n = 0;
faluco@227: while(is_digit((ch = *fmt++)))
faluco@227: {
faluco@227: n = 10 * n + (ch - '0');
faluco@227: }
faluco@227: prec = (n < 0) ? -1 : n;
faluco@227: goto reswitch;
faluco@227: }
faluco@227: case '0':
faluco@227: {
faluco@227: flags |= ZEROPAD;
faluco@227: goto rflag;
faluco@227: }
faluco@227: case '1':
faluco@227: case '2':
faluco@227: case '3':
faluco@227: case '4':
faluco@227: case '5':
faluco@227: case '6':
faluco@227: case '7':
faluco@227: case '8':
faluco@227: case '9':
faluco@227: {
faluco@227: n = 0;
faluco@227: do
faluco@227: {
faluco@227: n = 10 * n + (ch - '0');
faluco@227: ch = *fmt++;
faluco@227: } while(is_digit(ch));
faluco@227: width = n;
faluco@227: goto reswitch;
faluco@227: }
faluco@227: case 'c':
faluco@227: {
faluco@227: CHECK_ARGS(0);
faluco@230: if (!llen)
faluco@227: {
faluco@227: goto done;
faluco@227: }
faluco@227: char *c;
faluco@227: pCtx->LocalToString(params[arg], &c);
faluco@227: *buf_p++ = *c;
faluco@227: llen--;
faluco@227: arg++;
faluco@227: break;
faluco@227: }
dvander@1965: case 'b':
dvander@1965: {
dvander@1965: CHECK_ARGS(0);
dvander@1965: cell_t *value;
dvander@1965: pCtx->LocalToPhysAddr(params[arg], &value);
dvander@1965: AddBinary(&buf_p, llen, *value, width, flags);
dvander@1965: arg++;
dvander@1965: break;
dvander@1965: }
faluco@227: case 'd':
faluco@227: case 'i':
faluco@227: {
faluco@227: CHECK_ARGS(0);
faluco@227: cell_t *value;
faluco@227: pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227: AddInt(&buf_p, llen, static_cast(*value), width, flags);
faluco@227: arg++;
faluco@227: break;
faluco@227: }
faluco@227: case 'u':
faluco@227: {
faluco@227: CHECK_ARGS(0);
faluco@227: cell_t *value;
faluco@227: pCtx->LocalToPhysAddr(params[arg], &value);
faluco@227: AddUInt(&buf_p, llen, static_cast(*value), width, flags);
faluco@227: arg++;
faluco@227: break;
faluco@227: }
faluco@227: case 'f':
faluco@227: {
faluco@227: CHECK_ARGS(0);
faluco@227: cell_t *value;
faluco@227: pCtx->LocalToPhysAddr(params[arg], &value);
faluco@1677: AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
faluco@227: arg++;
faluco@227: break;
faluco@227: }
dvander@905: case 'L':
dvander@905: {
dvander@905: CHECK_ARGS(0);
dvander@905: cell_t *value;
dvander@905: pCtx->LocalToPhysAddr(params[arg], &value);
dvander@905: char buffer[255];
dvander@906: if (*value)
dvander@905: {
dvander@906: CPlayer *player = g_Players.GetPlayerByIndex(*value);
dvander@906: if (!player || !player->IsConnected())
dvander@906: {
dvander@906: return pCtx->ThrowNativeError("Client index %d is invalid", *value);
dvander@906: }
dvander@906: const char *auth = player->GetAuthString();
dvander@906: if (!auth || auth[0] == '\0')
dvander@906: {
dvander@906: auth = "STEAM_ID_PENDING";
dvander@906: }
skamonkey@3913: int userid = GetPlayerUserId(player->GetEdict());
dvander@906: UTIL_Format(buffer,
dvander@906: sizeof(buffer),
dvander@906: "%s<%d><%s><>",
dvander@906: player->GetName(),
dvander@906: userid,
dvander@906: auth);
faluco@1677: }
faluco@1677: else
faluco@1677: {
dvander@906: UTIL_Format(buffer,
dvander@906: sizeof(buffer),
dvander@906: "Console<0>");
dvander@905: }
dvander@905: AddString(&buf_p, llen, buffer, width, prec);
dvander@905: arg++;
dvander@905: break;
dvander@905: }
dvander@1420: case 'N':
dvander@1420: {
dvander@1420: CHECK_ARGS(0);
dvander@1420: cell_t *value;
dvander@1420: pCtx->LocalToPhysAddr(params[arg], &value);
dvander@1420:
dvander@1420: const char *name = "Console";
dvander@1420: if (*value)
dvander@1420: {
dvander@1420: CPlayer *player = g_Players.GetPlayerByIndex(*value);
dvander@1420: if (!player || !player->IsConnected())
dvander@1420: {
dvander@1420: return pCtx->ThrowNativeError("Client index %d is invalid", *value);
dvander@1420: }
dvander@1420: name = player->GetName();
dvander@1420: }
dvander@1420: AddString(&buf_p, llen, name, width, prec);
dvander@1420: arg++;
dvander@1420: break;
dvander@1420: }
faluco@227: case 's':
faluco@227: {
faluco@227: CHECK_ARGS(0);
faluco@227: char *str;
dvander@535: int err;
dvander@535: if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
dvander@535: {
dvander@535: pCtx->ThrowNativeErrorEx(err, "Could not deference string");
dvander@535: return 0;
dvander@535: }
faluco@227: AddString(&buf_p, llen, str, width, prec);
faluco@227: arg++;
faluco@227: break;
faluco@227: }
faluco@389: case 'T':
faluco@389: {
dvander@888: CHECK_ARGS(1);
faluco@389: char *key;
faluco@422: bool error;
faluco@422: size_t res;
ds@669: cell_t *target;
dvander@888: pCtx->LocalToString(params[arg++], &key);
ds@669: pCtx->LocalToPhysAddr(params[arg++], &target);
ds@669: res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
faluco@422: if (error)
faluco@422: {
faluco@422: return 0;
faluco@422: }
faluco@422: buf_p += res;
faluco@422: llen -= res;
faluco@422: break;
faluco@422: }
faluco@422: case 't':
faluco@422: {
faluco@422: CHECK_ARGS(0);
faluco@422: char *key;
faluco@422: bool error;
faluco@422: size_t res;
faluco@422: cell_t target = g_SourceMod.GetGlobalTarget();
faluco@422: pCtx->LocalToString(params[arg++], &key);
faluco@422: res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
faluco@422: if (error)
faluco@422: {
faluco@422: return 0;
faluco@422: }
faluco@422: buf_p += res;
faluco@422: llen -= res;
faluco@389: break;
faluco@389: }
ds@544: case 'X':
ds@544: {
ds@544: CHECK_ARGS(0);
ds@544: cell_t *value;
ds@544: pCtx->LocalToPhysAddr(params[arg], &value);
ds@544: flags |= UPPERDIGITS;
ds@544: AddHex(&buf_p, llen, static_cast(*value), width, flags);
ds@544: arg++;
ds@544: break;
ds@544: }
ds@544: case 'x':
ds@544: {
ds@544: CHECK_ARGS(0);
ds@544: cell_t *value;
ds@544: pCtx->LocalToPhysAddr(params[arg], &value);
ds@544: AddHex(&buf_p, llen, static_cast(*value), width, flags);
ds@544: arg++;
ds@544: break;
ds@544: }
faluco@227: case '%':
faluco@227: {
faluco@230: if (!llen)
faluco@227: {
faluco@227: goto done;
faluco@227: }
faluco@227: *buf_p++ = ch;
faluco@227: llen--;
faluco@227: break;
faluco@227: }
faluco@227: case '\0':
faluco@227: {
faluco@230: if (!llen)
faluco@227: {
faluco@227: goto done;
faluco@227: }
faluco@227: *buf_p++ = '%';
faluco@227: llen--;
faluco@227: goto done;
faluco@227: }
faluco@227: default:
faluco@227: {
faluco@230: if (!llen)
faluco@227: {
faluco@227: goto done;
faluco@227: }
faluco@227: *buf_p++ = ch;
faluco@227: llen--;
faluco@227: break;
faluco@227: }
faluco@227: }
faluco@227: }
faluco@227:
faluco@227: done:
faluco@227: *buf_p = '\0';
faluco@227: *param = arg;
faluco@236: return (maxlen - llen - 1);
faluco@227: }
faluco@230:
dvander@233: unsigned int strncopy(char *dest, const char *src, size_t count)
faluco@230: {
faluco@230: if (!count)
faluco@230: {
faluco@230: return 0;
faluco@230: }
faluco@230:
faluco@230: char *start = dest;
faluco@230: while ((*src) && (--count))
faluco@230: {
faluco@230: *dest++ = *src++;
faluco@230: }
faluco@230: *dest = '\0';
faluco@230:
faluco@230: return (dest - start);
faluco@230: }
faluco@274:
faluco@274: size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
faluco@274: {
faluco@274: va_list ap;
faluco@274: va_start(ap, fmt);
faluco@274: size_t len = vsnprintf(buffer, maxlength, fmt, ap);
faluco@274: va_end(ap);
faluco@274:
faluco@651: if (len >= maxlength)
faluco@651: {
faluco@651: buffer[maxlength - 1] = '\0';
faluco@651: return (maxlength - 1);
faluco@1677: }
faluco@1677: else
faluco@1677: {
faluco@651: return len;
faluco@651: }
dvander@351: }
dvander@351:
dvander@663: size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
dvander@663: {
dvander@663: size_t len = vsnprintf(buffer, maxlength, fmt, ap);
dvander@663:
dvander@663: if (len >= maxlength)
dvander@663: {
dvander@663: buffer[maxlength - 1] = '\0';
dvander@663: return (maxlength - 1);
faluco@1677: }
faluco@1677: else
faluco@1677: {
dvander@663: return len;
dvander@663: }
dvander@663: }
dvander@663:
ds@504: char *sm_strdup(const char *str)
ds@504: {
ds@504: char *ptr = new char[strlen(str)+1];
ds@504: strcpy(ptr, str);
ds@504: return ptr;
ds@504: }
dvander@833:
dvander@1738: char *UTIL_TrimWhitespace(char *str, size_t &len)
dvander@1738: {
dvander@1738: char *end = str + len - 1;
dvander@1738:
dvander@1738: if (!len)
dvander@1738: {
dvander@1738: return str;
dvander@1738: }
dvander@1738:
dvander@1738: /* Iterate backwards through string until we reach first non-whitespace char */
dvander@1738: while (end >= str && textparsers->IsWhitespace(end))
dvander@1738: {
dvander@1738: end--;
dvander@1738: len--;
dvander@1738: }
dvander@1738:
dvander@1738: /* Replace first whitespace char (at the end) with null terminator.
dvander@1738: * If there is none, we're just replacing the null terminator.
dvander@1738: */
dvander@1738: *(end + 1) = '\0';
dvander@1738:
dvander@1738: while (*str != '\0' && textparsers->IsWhitespace(str))
dvander@1738: {
dvander@1738: str++;
dvander@1738: len--;
dvander@1738: }
dvander@1738:
dvander@1738: return str;
dvander@1738: }
dvander@1738:
dvander@2806: char *UTIL_ToLowerCase(const char *str)
dvander@2806: {
dvander@2806: size_t len = strlen(str);
dvander@2806: char *buffer = new char[len + 1];
dvander@2806: for (size_t i = 0; i < len; i++)
dvander@2806: {
dvander@2806: if (str[i] >= 'A' && str[i] <= 'Z')
dvander@2806: buffer[i] = tolower(str[i]);
dvander@2806: else
dvander@2806: buffer[i] = str[i];
dvander@2806: }
dvander@2806: buffer[len] = '\0';
dvander@2806: return buffer;
dvander@2806: }
dvander@2806: