Updated CS:S SDKTools gamedata.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
35 #include "sm_stringutil.h"
37 #include "PluginSys.h"
38 #include "PlayerManager.h"
39 #include "logic_bridge.h"
41 #define LADJUST 0x00000004 /* left adjustment */
42 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
43 #define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
44 #define to_digit(c) ((c) - '0')
45 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
47 #define CHECK_ARGS(x) \
48 if ((arg+x) > args) { \
49 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
53 inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
55 cell_t new_params[MAX_TRANSLATE_PARAMS];
56 for (unsigned int i = 0; i < pTrans->fmt_count; i++)
58 new_params[i] = params[pTrans->fmt_order[i]];
60 memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
63 size_t Translate(char *buffer,
75 CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
76 unsigned int max_params = 0;
77 IPhraseCollection *pPhrases;
79 pPhrases = pl->GetPhrases();
82 if (target == SOURCEMOD_SERVER_LANGUAGE)
84 langid = translator->GetServerLanguage();
86 else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
88 langid = translator->GetClientLanguage(target);
92 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
96 if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
98 if (target != SOURCEMOD_SERVER_LANGUAGE && langid != translator->GetServerLanguage())
100 target = SOURCEMOD_SERVER_LANGUAGE;
103 else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
105 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
107 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
113 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
118 max_params = pTrans.fmt_count;
122 cell_t new_params[MAX_TRANSLATE_PARAMS];
124 /* Check if we're going to over the limit */
125 if ((*arg) + (max_params - 1) > (size_t)params[0])
127 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
128 "Translation string formatted incorrectly - missing at least %d parameters",
129 ((*arg + (max_params - 1)) - params[0])
134 /* If we need to re-order the parameters, do so with a temporary array.
135 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
137 memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
138 ReorderTranslationParams(&pTrans, &new_params[*arg]);
140 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
144 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
152 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
156 static char nlstr[] = {'(','n','u','l','l',')','\0'};
168 for (size = 0; size < prec; size++)
170 if (string[size] == '\0')
178 while (string[size++]);
182 if (size > (int)maxlen)
195 while ((width-- > 0) && maxlen)
204 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
206 int digits; // non-fraction part digits
207 double tmp; // temporary
208 char *buf = *buf_p; // output buffer pointer
209 int val; // temporary
210 int sign = 0; // 0: positive, 1: negative
211 int fieldlength; // for padding
212 int significant_digits = 0; // number of significant digits written
213 const int MAX_SIGNIFICANT_DIGITS = 16;
228 // compute whole-part digits count
229 digits = (int)log10(fval) + 1;
231 // Only print 0.something if 0 < fval < 1
237 // compute the field length
238 fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
240 // minus sign BEFORE left padding if padding with zeros
241 if (sign && maxlen && (flags & ZEROPAD))
247 // right justify if required
248 if ((flags & LADJUST) == 0)
250 while ((fieldlength < width) && maxlen)
252 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
258 // minus sign AFTER left padding if padding with spaces
259 if (sign && maxlen && !(flags & ZEROPAD))
265 // write the whole part
266 tmp = pow(10.0, digits-1);
267 while ((digits--) && maxlen)
269 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
275 val = (int)(fval / tmp);
283 // write the fraction part
290 tmp = pow(10.0, prec);
293 while (prec-- && maxlen)
295 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
302 val = (int)(fval / tmp);
309 // left justify if required
312 while ((fieldlength < width) && maxlen)
314 // right-padding only with spaces, ZEROPAD is ignored
321 // update parent's buffer pointer
325 void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
336 text[digits++] = '1';
340 text[digits++] = '0';
347 if (!(flags & LADJUST))
349 while (digits < width && maxlen)
351 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
357 while (digits-- && maxlen)
359 *buf++ = text[digits];
366 while (width-- && maxlen)
368 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
376 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
385 text[digits++] = '0' + val % 10;
391 if (!(flags & LADJUST))
393 while (digits < width && maxlen)
395 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
401 while (digits-- && maxlen)
403 *buf++ = text[digits];
410 while (width-- && maxlen)
412 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
420 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
426 unsigned int unsignedVal;
432 /* we want the unsigned version */
433 unsignedVal = abs(val);
442 text[digits++] = '0' + unsignedVal % 10;
444 } while (unsignedVal);
448 text[digits++] = '-';
453 if (!(flags & LADJUST))
455 while ((digits < width) && maxlen)
457 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
463 while (digits-- && maxlen)
465 *buf++ = text[digits];
472 while (width-- && maxlen)
474 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
482 void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
490 if (flags & UPPERDIGITS)
492 hexadjust = 'A' - '9' - 1;
496 hexadjust = 'a' - '9' - 1;
502 digit = ('0' + val % 16);
508 text[digits++] = digit;
514 if (!(flags & LADJUST))
516 while (digits < width && maxlen)
518 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
524 while (digits-- && maxlen)
526 *buf++ = text[digits];
533 while (width-- && maxlen)
535 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
543 bool gnprintf(char *buffer,
546 IPhraseCollection *pPhrases,
548 unsigned int numparams,
549 unsigned int &curparam,
551 const char **pFailPhrase)
553 if (!buffer || !maxlen)
555 if (pOutLength != NULL)
562 if (numparams > MAX_TRANSLATE_PARAMS)
564 if (pFailPhrase != NULL)
580 size_t llen = maxlen - 1;
587 // run through the format string until we hit a '%' or '\0'
588 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
593 if ((ch == '\0') || (llen <= 0))
601 // reset formatting state
620 while(is_digit((ch = *fmt++)))
622 n = 10 * n + (ch - '0');
624 prec = (n < 0) ? -1 : n;
645 n = 10 * n + (ch - '0');
647 } while(is_digit(ch));
657 if (curparam >= numparams)
659 if (pFailPhrase != NULL)
665 char *c = (char *)params[curparam];
674 if (curparam >= numparams)
676 if (pFailPhrase != NULL)
682 int *value = (int *)params[curparam];
684 AddBinary(&buf_p, llen, *value, width, flags);
691 if (curparam >= numparams)
693 if (pFailPhrase != NULL)
699 int *value = (int *)params[curparam];
701 AddInt(&buf_p, llen, *value, width, flags);
707 if (curparam >= numparams)
709 if (pFailPhrase != NULL)
715 unsigned int *value = (unsigned int *)params[curparam];
717 AddUInt(&buf_p, llen, *value, width, flags);
723 if (curparam >= numparams)
725 if (pFailPhrase != NULL)
731 float *value = (float *)params[curparam];
733 AddFloat(&buf_p, llen, *value, width, prec, flags);
739 if (curparam >= numparams)
741 if (pFailPhrase != NULL)
747 const char *str = (const char *)params[curparam];
749 AddString(&buf_p, llen, str, width, prec);
760 unsigned int lang_id;
762 if (curparam >= numparams)
764 if (pFailPhrase != NULL)
770 key = (const char *)(params[curparam]);
775 if (curparam >= numparams)
777 if (pFailPhrase != NULL)
783 target = *((int *)(params[curparam]));
788 target = translator->GetGlobalTarget();
792 if (target == SOURCEMOD_SERVER_LANGUAGE)
794 lang_id = translator->GetServerLanguage();
796 else if (target >= 1 && target <= g_Players.GetMaxClients())
798 lang_id = translator->GetClientLanguage(target);
802 lang_id = translator->GetServerLanguage();
805 if (pPhrases == NULL)
807 if (pFailPhrase != NULL)
814 if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
816 if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != translator->GetServerLanguage())
818 target = SOURCEMOD_SERVER_LANGUAGE;
821 else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
823 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
825 if (pFailPhrase != NULL)
834 if (pFailPhrase != NULL)
845 void *new_params[MAX_TRANSLATE_PARAMS];
847 if (curparam + trans.fmt_count > numparams)
849 if (pFailPhrase != NULL)
856 /* Copy the array and re-order the stack */
857 memcpy(new_params, params, sizeof(void *) * numparams);
858 for (i = 0; i < trans.fmt_count; i++)
860 new_params[curparam + i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
899 if (curparam >= numparams)
901 if (pFailPhrase != NULL)
907 unsigned int *value = (unsigned int *)params[curparam];
909 flags |= UPPERDIGITS;
910 AddHex(&buf_p, llen, *value, width, flags);
916 if (curparam >= numparams)
918 if (pFailPhrase != NULL)
924 unsigned int *value = (unsigned int *)params[curparam];
926 AddHex(&buf_p, llen, *value, width, flags);
966 if (pOutLength != NULL)
968 *pOutLength = (maxlen - llen - 1);
974 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
976 if (!buffer || !maxlen)
982 int args = params[0];
991 size_t llen = maxlen - 1;
999 // run through the format string until we hit a '%' or '\0'
1000 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1005 if ((ch == '\0') || (llen <= 0))
1010 // skip over the '%'
1013 // reset formatting state
1032 while(is_digit((ch = *fmt++)))
1034 n = 10 * n + (ch - '0');
1036 prec = (n < 0) ? -1 : n;
1057 n = 10 * n + (ch - '0');
1059 } while(is_digit(ch));
1071 pCtx->LocalToString(params[arg], &c);
1081 pCtx->LocalToPhysAddr(params[arg], &value);
1082 AddBinary(&buf_p, llen, *value, width, flags);
1091 pCtx->LocalToPhysAddr(params[arg], &value);
1092 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
1100 pCtx->LocalToPhysAddr(params[arg], &value);
1101 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1109 pCtx->LocalToPhysAddr(params[arg], &value);
1110 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
1118 pCtx->LocalToPhysAddr(params[arg], &value);
1122 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1123 if (!player || !player->IsConnected())
1125 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1127 const char *auth = player->GetAuthString();
1128 if (!auth || auth[0] == '\0')
1130 auth = "STEAM_ID_PENDING";
1132 int userid = engine->GetPlayerUserId(player->GetEdict());
1144 "Console<0><Console><Console>");
1146 AddString(&buf_p, llen, buffer, width, prec);
1154 pCtx->LocalToPhysAddr(params[arg], &value);
1156 const char *name = "Console";
1159 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1160 if (!player || !player->IsConnected())
1162 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1164 name = player->GetName();
1166 AddString(&buf_p, llen, name, width, prec);
1175 if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
1177 pCtx->ThrowNativeErrorEx(err, "Could not deference string");
1180 AddString(&buf_p, llen, str, width, prec);
1191 pCtx->LocalToString(params[arg++], &key);
1192 pCtx->LocalToPhysAddr(params[arg++], &target);
1193 res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1208 cell_t target = g_SourceMod.GetGlobalTarget();
1209 pCtx->LocalToString(params[arg++], &key);
1210 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1223 pCtx->LocalToPhysAddr(params[arg], &value);
1224 flags |= UPPERDIGITS;
1225 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1233 pCtx->LocalToPhysAddr(params[arg], &value);
1234 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1274 return (maxlen - llen - 1);
1277 unsigned int strncopy(char *dest, const char *src, size_t count)
1285 while ((*src) && (--count))
1291 return (dest - start);
1294 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1298 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1301 if (len >= maxlength)
1303 buffer[maxlength - 1] = '\0';
1304 return (maxlength - 1);
1312 size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1314 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1316 if (len >= maxlength)
1318 buffer[maxlength - 1] = '\0';
1319 return (maxlength - 1);
1327 char *sm_strdup(const char *str)
1329 char *ptr = new char[strlen(str)+1];
1334 char *UTIL_TrimWhitespace(char *str, size_t &len)
1336 char *end = str + len - 1;
1343 /* Iterate backwards through string until we reach first non-whitespace char */
1344 while (end >= str && textparsers->IsWhitespace(end))
1350 /* Replace first whitespace char (at the end) with null terminator.
1351 * If there is none, we're just replacing the null terminator.
1355 while (*str != '\0' && textparsers->IsWhitespace(str))
1364 char *UTIL_ToLowerCase(const char *str)
1366 size_t len = strlen(str);
1367 char *buffer = new char[len + 1];
1368 for (size_t i = 0; i < len; i++)
1370 if (str[i] >= 'A' && str[i] <= 'Z')
1371 buffer[i] = tolower(str[i]);