Fixed build.
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"
42 #define LADJUST 0x00000004 /* left adjustment */
43 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
44 #define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
45 #define to_digit(c) ((c) - '0')
46 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
48 #define CHECK_ARGS(x) \
49 if ((arg+x) > args) { \
50 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
54 inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
56 cell_t new_params[MAX_TRANSLATE_PARAMS];
57 for (unsigned int i = 0; i < pTrans->fmt_count; i++)
59 new_params[i] = params[pTrans->fmt_order[i]];
61 memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
64 size_t Translate(char *buffer,
76 IPlugin *pl = scripts->FindPluginByContext(pCtx->GetContext());
77 unsigned int max_params = 0;
78 IPhraseCollection *pPhrases;
80 pPhrases = pl->GetPhrases();
83 if (target == SOURCEMOD_SERVER_LANGUAGE)
85 langid = translator->GetServerLanguage();
87 else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
89 langid = translator->GetClientLanguage(target);
93 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
97 if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
99 if (target != SOURCEMOD_SERVER_LANGUAGE && langid != translator->GetServerLanguage())
101 target = SOURCEMOD_SERVER_LANGUAGE;
104 else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
106 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans) != Trans_Okay)
108 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
114 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
119 max_params = pTrans.fmt_count;
123 cell_t new_params[MAX_TRANSLATE_PARAMS];
125 /* Check if we're going to over the limit */
126 if ((*arg) + (max_params - 1) > (size_t)params[0])
128 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
129 "Translation string formatted incorrectly - missing at least %d parameters",
130 ((*arg + (max_params - 1)) - params[0])
135 /* If we need to re-order the parameters, do so with a temporary array.
136 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
138 memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
139 ReorderTranslationParams(&pTrans, &new_params[*arg]);
141 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
145 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
153 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
157 static char nlstr[] = {'(','n','u','l','l',')','\0'};
169 for (size = 0; size < prec; size++)
171 if (string[size] == '\0')
179 while (string[size++]);
183 if (size > (int)maxlen)
196 while ((width-- > 0) && maxlen)
205 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
207 int digits; // non-fraction part digits
208 double tmp; // temporary
209 char *buf = *buf_p; // output buffer pointer
210 int val; // temporary
211 int sign = 0; // 0: positive, 1: negative
212 int fieldlength; // for padding
213 int significant_digits = 0; // number of significant digits written
214 const int MAX_SIGNIFICANT_DIGITS = 16;
229 // compute whole-part digits count
230 digits = (int)log10(fval) + 1;
232 // Only print 0.something if 0 < fval < 1
238 // compute the field length
239 fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
241 // minus sign BEFORE left padding if padding with zeros
242 if (sign && maxlen && (flags & ZEROPAD))
248 // right justify if required
249 if ((flags & LADJUST) == 0)
251 while ((fieldlength < width) && maxlen)
253 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
259 // minus sign AFTER left padding if padding with spaces
260 if (sign && maxlen && !(flags & ZEROPAD))
266 // write the whole part
267 tmp = pow(10.0, digits-1);
268 while ((digits--) && maxlen)
270 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
276 val = (int)(fval / tmp);
284 // write the fraction part
291 tmp = pow(10.0, prec);
294 while (prec-- && maxlen)
296 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
303 val = (int)(fval / tmp);
310 // left justify if required
313 while ((fieldlength < width) && maxlen)
315 // right-padding only with spaces, ZEROPAD is ignored
322 // update parent's buffer pointer
326 void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
337 text[digits++] = '1';
341 text[digits++] = '0';
348 if (!(flags & LADJUST))
350 while (digits < width && maxlen)
352 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
358 while (digits-- && maxlen)
360 *buf++ = text[digits];
367 while (width-- && maxlen)
369 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
377 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
386 text[digits++] = '0' + val % 10;
392 if (!(flags & LADJUST))
394 while (digits < width && maxlen)
396 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
402 while (digits-- && maxlen)
404 *buf++ = text[digits];
411 while (width-- && maxlen)
413 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
421 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
427 unsigned int unsignedVal;
433 /* we want the unsigned version */
434 unsignedVal = abs(val);
443 text[digits++] = '0' + unsignedVal % 10;
445 } while (unsignedVal);
449 text[digits++] = '-';
454 if (!(flags & LADJUST))
456 while ((digits < width) && maxlen)
458 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
464 while (digits-- && maxlen)
466 *buf++ = text[digits];
473 while (width-- && maxlen)
475 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
483 void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
491 if (flags & UPPERDIGITS)
493 hexadjust = 'A' - '9' - 1;
497 hexadjust = 'a' - '9' - 1;
503 digit = ('0' + val % 16);
509 text[digits++] = digit;
515 if (!(flags & LADJUST))
517 while (digits < width && maxlen)
519 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
525 while (digits-- && maxlen)
527 *buf++ = text[digits];
534 while (width-- && maxlen)
536 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
544 bool gnprintf(char *buffer,
547 IPhraseCollection *pPhrases,
549 unsigned int numparams,
550 unsigned int &curparam,
552 const char **pFailPhrase)
554 if (!buffer || !maxlen)
556 if (pOutLength != NULL)
563 if (numparams > MAX_TRANSLATE_PARAMS)
565 if (pFailPhrase != NULL)
581 size_t llen = maxlen - 1;
588 // run through the format string until we hit a '%' or '\0'
589 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
594 if ((ch == '\0') || (llen <= 0))
602 // reset formatting state
621 while(is_digit((ch = *fmt++)))
623 n = 10 * n + (ch - '0');
625 prec = (n < 0) ? -1 : n;
646 n = 10 * n + (ch - '0');
648 } while(is_digit(ch));
658 if (curparam >= numparams)
660 if (pFailPhrase != NULL)
666 char *c = (char *)params[curparam];
675 if (curparam >= numparams)
677 if (pFailPhrase != NULL)
683 int *value = (int *)params[curparam];
685 AddBinary(&buf_p, llen, *value, width, flags);
692 if (curparam >= numparams)
694 if (pFailPhrase != NULL)
700 int *value = (int *)params[curparam];
702 AddInt(&buf_p, llen, *value, width, flags);
708 if (curparam >= numparams)
710 if (pFailPhrase != NULL)
716 unsigned int *value = (unsigned int *)params[curparam];
718 AddUInt(&buf_p, llen, *value, width, flags);
724 if (curparam >= numparams)
726 if (pFailPhrase != NULL)
732 float *value = (float *)params[curparam];
734 AddFloat(&buf_p, llen, *value, width, prec, flags);
740 if (curparam >= numparams)
742 if (pFailPhrase != NULL)
748 const char *str = (const char *)params[curparam];
750 AddString(&buf_p, llen, str, width, prec);
761 unsigned int lang_id;
763 if (curparam >= numparams)
765 if (pFailPhrase != NULL)
771 key = (const char *)(params[curparam]);
776 if (curparam >= numparams)
778 if (pFailPhrase != NULL)
784 target = *((int *)(params[curparam]));
789 target = translator->GetGlobalTarget();
793 if (target == SOURCEMOD_SERVER_LANGUAGE)
795 lang_id = translator->GetServerLanguage();
797 else if (target >= 1 && target <= g_Players.GetMaxClients())
799 lang_id = translator->GetClientLanguage(target);
803 lang_id = translator->GetServerLanguage();
806 if (pPhrases == NULL)
808 if (pFailPhrase != NULL)
815 if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
817 if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != translator->GetServerLanguage())
819 target = SOURCEMOD_SERVER_LANGUAGE;
822 else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
824 if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
826 if (pFailPhrase != NULL)
835 if (pFailPhrase != NULL)
846 void *new_params[MAX_TRANSLATE_PARAMS];
848 if (curparam + trans.fmt_count > numparams)
850 if (pFailPhrase != NULL)
857 /* Copy the array and re-order the stack */
858 memcpy(new_params, params, sizeof(void *) * numparams);
859 for (i = 0; i < trans.fmt_count; i++)
861 new_params[curparam + i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
900 if (curparam >= numparams)
902 if (pFailPhrase != NULL)
908 unsigned int *value = (unsigned int *)params[curparam];
910 flags |= UPPERDIGITS;
911 AddHex(&buf_p, llen, *value, width, flags);
917 if (curparam >= numparams)
919 if (pFailPhrase != NULL)
925 unsigned int *value = (unsigned int *)params[curparam];
927 AddHex(&buf_p, llen, *value, width, flags);
967 if (pOutLength != NULL)
969 *pOutLength = (maxlen - llen - 1);
975 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
977 if (!buffer || !maxlen)
983 int args = params[0];
992 size_t llen = maxlen - 1;
1000 // run through the format string until we hit a '%' or '\0'
1001 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1006 if ((ch == '\0') || (llen <= 0))
1011 // skip over the '%'
1014 // reset formatting state
1033 while(is_digit((ch = *fmt++)))
1035 n = 10 * n + (ch - '0');
1037 prec = (n < 0) ? -1 : n;
1058 n = 10 * n + (ch - '0');
1060 } while(is_digit(ch));
1072 pCtx->LocalToString(params[arg], &c);
1082 pCtx->LocalToPhysAddr(params[arg], &value);
1083 AddBinary(&buf_p, llen, *value, width, flags);
1092 pCtx->LocalToPhysAddr(params[arg], &value);
1093 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
1101 pCtx->LocalToPhysAddr(params[arg], &value);
1102 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1110 pCtx->LocalToPhysAddr(params[arg], &value);
1111 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
1119 pCtx->LocalToPhysAddr(params[arg], &value);
1123 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1124 if (!player || !player->IsConnected())
1126 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1128 const char *auth = player->GetAuthString();
1129 if (!auth || auth[0] == '\0')
1131 auth = "STEAM_ID_PENDING";
1133 int userid = GetPlayerUserId(player->GetEdict());
1145 "Console<0><Console><Console>");
1147 AddString(&buf_p, llen, buffer, width, prec);
1155 pCtx->LocalToPhysAddr(params[arg], &value);
1157 const char *name = "Console";
1160 CPlayer *player = g_Players.GetPlayerByIndex(*value);
1161 if (!player || !player->IsConnected())
1163 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1165 name = player->GetName();
1167 AddString(&buf_p, llen, name, width, prec);
1176 if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
1178 pCtx->ThrowNativeErrorEx(err, "Could not deference string");
1181 AddString(&buf_p, llen, str, width, prec);
1192 pCtx->LocalToString(params[arg++], &key);
1193 pCtx->LocalToPhysAddr(params[arg++], &target);
1194 res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1209 cell_t target = g_SourceMod.GetGlobalTarget();
1210 pCtx->LocalToString(params[arg++], &key);
1211 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1224 pCtx->LocalToPhysAddr(params[arg], &value);
1225 flags |= UPPERDIGITS;
1226 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1234 pCtx->LocalToPhysAddr(params[arg], &value);
1235 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1275 return (maxlen - llen - 1);
1278 unsigned int strncopy(char *dest, const char *src, size_t count)
1286 while ((*src) && (--count))
1292 return (dest - start);
1295 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1299 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1302 if (len >= maxlength)
1304 buffer[maxlength - 1] = '\0';
1305 return (maxlength - 1);
1313 size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1315 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1317 if (len >= maxlength)
1319 buffer[maxlength - 1] = '\0';
1320 return (maxlength - 1);
1328 char *sm_strdup(const char *str)
1330 char *ptr = new char[strlen(str)+1];
1335 char *UTIL_TrimWhitespace(char *str, size_t &len)
1337 char *end = str + len - 1;
1344 /* Iterate backwards through string until we reach first non-whitespace char */
1345 while (end >= str && textparsers->IsWhitespace(end))
1351 /* Replace first whitespace char (at the end) with null terminator.
1352 * If there is none, we're just replacing the null terminator.
1356 while (*str != '\0' && textparsers->IsWhitespace(str))
1365 char *UTIL_ToLowerCase(const char *str)
1367 size_t len = strlen(str);
1368 char *buffer = new char[len + 1];
1369 for (size_t i = 0; i < len; i++)
1371 if (str[i] >= 'A' && str[i] <= 'Z')
1372 buffer[i] = tolower(str[i]);