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: