Update gamedata for CS:S update.
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 <ITextParsers.h>
36 #include "sm_stringutil.h"
38 #include "PlayerManager.h"
39 #include "logic_bridge.h"
40 #include "sourcemod.h"
41 #include <am-utility.h>
43 #define LADJUST 0x00000004 /* left adjustment */
44 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
45 #define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
46 #define to_digit(c) ((c) - '0')
47 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
49 #define CHECK_ARGS(x) \
50 if ((arg+x) > args) { \
51 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
55 inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
57 cell_t new_params[MAX_TRANSLATE_PARAMS];
58 for (unsigned int i = 0; i < pTrans->fmt_count; i++)
60 new_params[i] = params[pTrans->fmt_order[i]];
62 memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
65 size_t Translate(char *buffer,
77 IPlugin *pl = scripts->FindPluginByContext(pCtx->GetContext());
78 unsigned int max_params = 0;
79 IPhraseCollection *pPhrases;
81 pPhrases = pl->GetPhrases();
84 if (target == SOURCEMOD_SERVER_LANGUAGE)
86 langid = translator->GetServerLanguage();
88 else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
90 langid = translator->GetClientLanguage(target);
94 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
98 if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
100 if (target != SOURCEMOD_SERVER_LANGUAGE && langid != translator->GetServerLanguage())
102 target = SOURCEMOD_SERVER_LANGUAGE;
105 else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
107 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
109 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
115 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
120 max_params = pTrans.fmt_count;
124 cell_t new_params[MAX_TRANSLATE_PARAMS];
126 /* Check if we're going to over the limit */
127 if ((*arg) + (max_params - 1) > (size_t)params[0])
129 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
130 "Translation string formatted incorrectly - missing at least %d parameters",
131 ((*arg + (max_params - 1)) - params[0])
136 /* If we need to re-order the parameters, do so with a temporary array.
137 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
139 memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
140 ReorderTranslationParams(&pTrans, &new_params[*arg]);
142 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
146 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
154 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
158 static char nlstr[] = {'(','n','u','l','l',')','\0'};
170 for (size = 0; size < prec; size++)
172 if (string[size] == '\0')
180 while (string[size++]);
184 if (size > (int)maxlen)
197 while ((width-- > 0) && maxlen)
206 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
208 int digits; // non-fraction part digits
209 double tmp; // temporary
210 char *buf = *buf_p; // output buffer pointer
211 int val; // temporary
212 int sign = 0; // 0: positive, 1: negative
213 int fieldlength; // for padding
214 int significant_digits = 0; // number of significant digits written
215 const int MAX_SIGNIFICANT_DIGITS = 16;
219 AddString(buf_p, maxlen, "NaN", width, prec);
236 // compute whole-part digits count
237 digits = (int)log10(fval) + 1;
239 // Only print 0.something if 0 < fval < 1
245 // compute the field length
246 fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
248 // minus sign BEFORE left padding if padding with zeros
249 if (sign && maxlen && (flags & ZEROPAD))
255 // right justify if required
256 if ((flags & LADJUST) == 0)
258 while ((fieldlength < width) && maxlen)
260 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
266 // minus sign AFTER left padding if padding with spaces
267 if (sign && maxlen && !(flags & ZEROPAD))
273 // write the whole part
274 tmp = pow(10.0, digits-1);
275 while ((digits--) && maxlen)
277 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
283 val = (int)(fval / tmp);
291 // write the fraction part
298 tmp = pow(10.0, prec);
301 while (prec-- && maxlen)
303 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
310 val = (int)(fval / tmp);
317 // left justify if required
320 while ((fieldlength < width) && maxlen)
322 // right-padding only with spaces, ZEROPAD is ignored
329 // update parent's buffer pointer
333 void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
344 text[digits++] = '1';
348 text[digits++] = '0';
355 if (!(flags & LADJUST))
357 while (digits < width && maxlen)
359 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
365 while (digits-- && maxlen)
367 *buf++ = text[digits];
374 while (width-- && maxlen)
376 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
384 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
393 text[digits++] = '0' + val % 10;
399 if (!(flags & LADJUST))
401 while (digits < width && maxlen)
403 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
409 while (digits-- && maxlen)
411 *buf++ = text[digits];
418 while (width-- && maxlen)
420 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
428 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
434 unsigned int unsignedVal;
440 /* we want the unsigned version */
441 unsignedVal = abs(val);
450 text[digits++] = '0' + unsignedVal % 10;
452 } while (unsignedVal);
456 text[digits++] = '-';
461 if (!(flags & LADJUST))
463 while ((digits < width) && maxlen)
465 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
471 while (digits-- && maxlen)
473 *buf++ = text[digits];
480 while (width-- && maxlen)
482 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
490 void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
498 if (flags & UPPERDIGITS)
500 hexadjust = 'A' - '9' - 1;
504 hexadjust = 'a' - '9' - 1;
510 digit = ('0' + val % 16);
516 text[digits++] = digit;
522 if (!(flags & LADJUST))
524 while (digits < width && maxlen)
526 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
532 while (digits-- && maxlen)
534 *buf++ = text[digits];
541 while (width-- && maxlen)
543 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
551 bool gnprintf(char *buffer,
554 IPhraseCollection *pPhrases,
556 unsigned int numparams,
557 unsigned int &curparam,
559 const char **pFailPhrase)
561 if (!buffer || !maxlen)
563 if (pOutLength != NULL)
570 if (numparams > MAX_TRANSLATE_PARAMS)
572 if (pFailPhrase != NULL)
588 size_t llen = maxlen - 1;
595 // run through the format string until we hit a '%' or '\0'
596 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
601 if ((ch == '\0') || (llen <= 0))
609 // reset formatting state
628 while(is_digit((ch = *fmt++)))
630 n = 10 * n + (ch - '0');
632 prec = (n < 0) ? -1 : n;
653 n = 10 * n + (ch - '0');
655 } while(is_digit(ch));
665 if (curparam >= numparams)
667 if (pFailPhrase != NULL)
673 char *c = (char *)params[curparam];
682 if (curparam >= numparams)
684 if (pFailPhrase != NULL)
690 int *value = (int *)params[curparam];
692 AddBinary(&buf_p, llen, *value, width, flags);
699 if (curparam >= numparams)
701 if (pFailPhrase != NULL)
707 int *value = (int *)params[curparam];
709 AddInt(&buf_p, llen, *value, width, flags);
715 if (curparam >= numparams)
717 if (pFailPhrase != NULL)
723 unsigned int *value = (unsigned int *)params[curparam];
725 AddUInt(&buf_p, llen, *value, width, flags);
731 if (curparam >= numparams)
733 if (pFailPhrase != NULL)
739 float *value = (float *)params[curparam];
741 AddFloat(&buf_p, llen, *value, width, prec, flags);
747 if (curparam >= numparams)
749 if (pFailPhrase != NULL)
755 const char *str = (const char *)params[curparam];
757 AddString(&buf_p, llen, str, width, prec);
768 unsigned int lang_id;
770 if (curparam >= numparams)
772 if (pFailPhrase != NULL)
778 key = (const char *)(params[curparam]);
783 if (curparam >= numparams)
785 if (pFailPhrase != NULL)
791 target = *((int *)(params[curparam]));
796 target = translator->GetGlobalTarget();
800 if (target == SOURCEMOD_SERVER_LANGUAGE)
802 lang_id = translator->GetServerLanguage();
804 else if (target >= 1 && target <= g_Players.GetMaxClients())
806 lang_id = translator->GetClientLanguage(target);
810 lang_id = translator->GetServerLanguage();
813 if (pPhrases == NULL)
815 if (pFailPhrase != NULL)
822 if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
824 if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != translator->GetServerLanguage())
826 target = SOURCEMOD_SERVER_LANGUAGE;
829 else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
831 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
833 if (pFailPhrase != NULL)
842 if (pFailPhrase != NULL)
853 void *new_params[MAX_TRANSLATE_PARAMS];
855 if (curparam + trans.fmt_count > numparams)
857 if (pFailPhrase != NULL)
864 /* Copy the array and re-order the stack */
865 memcpy(new_params, params, sizeof(void *) * numparams);
866 for (i = 0; i < trans.fmt_count; i++)
868 new_params[curparam + i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
907 if (curparam >= numparams)
909 if (pFailPhrase != NULL)
915 unsigned int *value = (unsigned int *)params[curparam];
917 flags |= UPPERDIGITS;
918 AddHex(&buf_p, llen, *value, width, flags);
924 if (curparam >= numparams)
926 if (pFailPhrase != NULL)
932 unsigned int *value = (unsigned int *)params[curparam];
934 AddHex(&buf_p, llen, *value, width, flags);
974 if (pOutLength != NULL)
976 *pOutLength = (maxlen - llen - 1);
982 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
984 if (!buffer || !maxlen)
990 int args = params[0];
999 size_t llen = maxlen - 1;
1007 // run through the format string until we hit a '%' or '\0'
1008 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1013 if ((ch == '\0') || (llen <= 0))
1018 // skip over the '%'
1021 // reset formatting state
1040 while(is_digit((ch = *fmt++)))
1042 n = 10 * n + (ch - '0');
1044 prec = (n < 0) ? -1 : n;
1065 n = 10 * n + (ch - '0');
1067 } while(is_digit(ch));
1079 pCtx->LocalToString(params[arg], &c);
1089 pCtx->LocalToPhysAddr(params[arg], &value);
1090 AddBinary(&buf_p, llen, *value, width, flags);
1099 pCtx->LocalToPhysAddr(params[arg], &value);
1100 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
1108 pCtx->LocalToPhysAddr(params[arg], &value);
1109 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1117 pCtx->LocalToPhysAddr(params[arg], &value);
1118 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
1126 pCtx->LocalToPhysAddr(params[arg], &value);
1130 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1131 if (!player || !player->IsConnected())
1133 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1135 const char *auth = player->GetAuthString();
1136 if (!auth || auth[0] == '\0')
1138 auth = "STEAM_ID_PENDING";
1140 int userid = GetPlayerUserId(player->GetEdict());
1152 "Console<0><Console><Console>");
1154 AddString(&buf_p, llen, buffer, width, prec);
1162 pCtx->LocalToPhysAddr(params[arg], &value);
1164 const char *name = "Console";
1167 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1168 if (!player || !player->IsConnected())
1170 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1172 name = player->GetName();
1174 AddString(&buf_p, llen, name, width, prec);
1183 if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
1185 pCtx->ThrowNativeErrorEx(err, "Could not deference string");
1188 AddString(&buf_p, llen, str, width, prec);
1199 pCtx->LocalToString(params[arg++], &key);
1200 pCtx->LocalToPhysAddr(params[arg++], &target);
1201 res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1216 cell_t target = g_SourceMod.GetGlobalTarget();
1217 pCtx->LocalToString(params[arg++], &key);
1218 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1231 pCtx->LocalToPhysAddr(params[arg], &value);
1232 flags |= UPPERDIGITS;
1233 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1241 pCtx->LocalToPhysAddr(params[arg], &value);
1242 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1282 return (maxlen - llen - 1);
1285 unsigned int strncopy(char *dest, const char *src, size_t count)
1293 while ((*src) && (--count))
1299 return (dest - start);
1302 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1306 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1309 if (len >= maxlength)
1311 buffer[maxlength - 1] = '\0';
1312 return (maxlength - 1);
1320 size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1322 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1324 if (len >= maxlength)
1326 buffer[maxlength - 1] = '\0';
1327 return (maxlength - 1);
1335 char *sm_strdup(const char *str)
1337 char *ptr = new char[strlen(str)+1];
1342 char *UTIL_TrimWhitespace(char *str, size_t &len)
1344 char *end = str + len - 1;
1351 /* Iterate backwards through string until we reach first non-whitespace char */
1352 while (end >= str && textparsers->IsWhitespace(end))
1358 /* Replace first whitespace char (at the end) with null terminator.
1359 * If there is none, we're just replacing the null terminator.
1363 while (*str != '\0' && textparsers->IsWhitespace(str))
1372 char *UTIL_ToLowerCase(const char *str)
1374 size_t len = strlen(str);
1375 char *buffer = new char[len + 1];
1376 for (size_t i = 0; i < len; i++)
1378 if (str[i] >= 'A' && str[i] <= 'Z')
1379 buffer[i] = tolower(str[i]);