Added msvc9 Project files to sdktools. Badly.
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 "Translator.h"
39 #include "PlayerManager.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 size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const char *phrase, void **params)
58 err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetClientLanguage(client), &pTrans);
59 if (err != Trans_Okay)
61 err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans);
62 if (err != Trans_Okay && g_Translator.GetServerLanguage() != CORELANG_ENGLISH)
64 err = g_pCorePhrases->GetTranslation(phrase, CORELANG_ENGLISH, &pTrans);
68 if (err != Trans_Okay)
70 return UTIL_Format(buffer, maxlength, "%s", phrase);
73 return g_Translator.Translate(buffer, maxlength, params, &pTrans);
76 inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans)
78 TransError err = Trans_BadLanguage;
81 for (size_t i=0; i<langcount && err!=Trans_Okay; i++)
83 phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i));
84 err = phrfl->GetTranslation(key, langid, pTrans);
87 return (err == Trans_Okay) ? true : false;
90 inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
92 cell_t new_params[MAX_TRANSLATE_PARAMS];
93 for (unsigned int i = 0; i < pTrans->fmt_count; i++)
95 new_params[i] = params[pTrans->fmt_order[i]];
97 memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
100 size_t Translate(char *buffer,
102 IPluginContext *pCtx,
105 const cell_t *params,
112 CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
113 size_t langcount = pl->GetLangFileCount();
114 unsigned int max_params = 0;
117 if (target == LANG_SERVER)
119 langid = g_Translator.GetServerLanguage();
121 else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
123 langid = g_Translator.GetClientLanguage(target);
127 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
131 if (!TryTranslation(pl, key, langid, langcount, &pTrans))
133 if (target != LANG_SERVER && langid != g_Translator.GetServerLanguage())
135 target = LANG_SERVER;
138 else if (langid != LANGUAGE_ENGLISH)
140 if (!TryTranslation(pl, key, LANGUAGE_ENGLISH, langcount, &pTrans))
142 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
148 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
153 max_params = pTrans.fmt_count;
157 cell_t new_params[MAX_TRANSLATE_PARAMS];
159 /* Check if we're going to over the limit */
160 if ((*arg) + (max_params - 1) > (size_t)params[0])
162 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
163 "Translation string formatted incorrectly - missing at least %d parameters",
164 ((*arg + (max_params - 1)) - params[0])
169 /* If we need to re-order the parameters, do so with a temporary array.
170 * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
172 memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
173 ReorderTranslationParams(&pTrans, &new_params[*arg]);
175 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
179 return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
187 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
191 static char nlstr[] = {'(','n','u','l','l',')','\0'};
203 for (size = 0; size < prec; size++)
205 if (string[size] == '\0')
213 while (string[size++]);
217 if (size > (int)maxlen)
230 while ((width-- > 0) && maxlen)
239 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
241 int digits; // non-fraction part digits
242 double tmp; // temporary
243 char *buf = *buf_p; // output buffer pointer
244 int val; // temporary
245 int sign = 0; // 0: positive, 1: negative
246 int fieldlength; // for padding
247 int significant_digits = 0; // number of significant digits written
248 const int MAX_SIGNIFICANT_DIGITS = 16;
263 // compute whole-part digits count
264 digits = (int)log10(fval) + 1;
266 // Only print 0.something if 0 < fval < 1
272 // compute the field length
273 fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
275 // minus sign BEFORE left padding if padding with zeros
276 if (sign && maxlen && (flags & ZEROPAD))
282 // right justify if required
283 if ((flags & LADJUST) == 0)
285 while ((fieldlength < width) && maxlen)
287 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
293 // minus sign AFTER left padding if padding with spaces
294 if (sign && maxlen && !(flags & ZEROPAD))
300 // write the whole part
301 tmp = pow(10.0, digits-1);
302 while ((digits--) && maxlen)
304 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
310 val = (int)(fval / tmp);
318 // write the fraction part
325 tmp = pow(10.0, prec);
328 while (prec-- && maxlen)
330 if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
337 val = (int)(fval / tmp);
344 // left justify if required
347 while ((fieldlength < width) && maxlen)
349 // right-padding only with spaces, ZEROPAD is ignored
356 // update parent's buffer pointer
360 void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
371 text[digits++] = '1';
375 text[digits++] = '0';
382 if (!(flags & LADJUST))
384 while (digits < width && maxlen)
386 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
392 while (digits-- && maxlen)
394 *buf++ = text[digits];
401 while (width-- && maxlen)
403 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
411 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
420 text[digits++] = '0' + val % 10;
426 if (!(flags & LADJUST))
428 while (digits < width && maxlen)
430 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
436 while (digits-- && maxlen)
438 *buf++ = text[digits];
445 while (width-- && maxlen)
447 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
455 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
461 unsigned int unsignedVal;
467 /* we want the unsigned version */
468 unsignedVal = abs(val);
477 text[digits++] = '0' + unsignedVal % 10;
479 } while (unsignedVal);
483 text[digits++] = '-';
488 if (!(flags & LADJUST))
490 while ((digits < width) && maxlen)
492 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
498 while (digits-- && maxlen)
500 *buf++ = text[digits];
507 while (width-- && maxlen)
509 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
517 void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
525 if (flags & UPPERDIGITS)
527 hexadjust = 'A' - '9' - 1;
531 hexadjust = 'a' - '9' - 1;
537 digit = ('0' + val % 16);
543 text[digits++] = digit;
549 if (!(flags & LADJUST))
551 while (digits < width && maxlen)
553 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
559 while (digits-- && maxlen)
561 *buf++ = text[digits];
568 while (width-- && maxlen)
570 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
578 size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
580 if (!buffer || !maxlen)
594 size_t llen = maxlen - 1;
601 // run through the format string until we hit a '%' or '\0'
602 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
607 if ((ch == '\0') || (llen <= 0))
615 // reset formatting state
634 while(is_digit((ch = *fmt++)))
636 n = 10 * n + (ch - '0');
638 prec = (n < 0) ? -1 : n;
659 n = 10 * n + (ch - '0');
661 } while(is_digit(ch));
671 char *c = (char *)args[arg];
679 int *value = (int *)args[arg];
680 AddBinary(&buf_p, llen, *value, width, flags);
687 int *value = (int *)args[arg];
688 AddInt(&buf_p, llen, *value, width, flags);
694 unsigned int *value = (unsigned int *)args[arg];
695 AddUInt(&buf_p, llen, *value, width, flags);
701 float *value = (float *)args[arg];
702 AddFloat(&buf_p, llen, *value, width, prec, flags);
708 const char *str = (const char *)args[arg];
709 AddString(&buf_p, llen, str, width, prec);
715 unsigned int *value = (unsigned int *)args[arg];
716 flags |= UPPERDIGITS;
717 AddHex(&buf_p, llen, *value, width, flags);
723 unsigned int *value = (unsigned int *)args[arg];
724 AddHex(&buf_p, llen, *value, width, flags);
764 return (maxlen - llen - 1);
767 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
769 if (!buffer || !maxlen)
775 int args = params[0];
784 size_t llen = maxlen - 1;
792 // run through the format string until we hit a '%' or '\0'
793 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
798 if ((ch == '\0') || (llen <= 0))
806 // reset formatting state
825 while(is_digit((ch = *fmt++)))
827 n = 10 * n + (ch - '0');
829 prec = (n < 0) ? -1 : n;
850 n = 10 * n + (ch - '0');
852 } while(is_digit(ch));
864 pCtx->LocalToString(params[arg], &c);
874 pCtx->LocalToPhysAddr(params[arg], &value);
875 AddBinary(&buf_p, llen, *value, width, flags);
884 pCtx->LocalToPhysAddr(params[arg], &value);
885 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
893 pCtx->LocalToPhysAddr(params[arg], &value);
894 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
902 pCtx->LocalToPhysAddr(params[arg], &value);
903 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
911 pCtx->LocalToPhysAddr(params[arg], &value);
915 CPlayer *player = g_Players.GetPlayerByIndex(*value);
916 if (!player || !player->IsConnected())
918 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
920 const char *auth = player->GetAuthString();
921 if (!auth || auth[0] == '\0')
923 auth = "STEAM_ID_PENDING";
925 int userid = engine->GetPlayerUserId(player->GetEdict());
937 "Console<0><Console><Console>");
939 AddString(&buf_p, llen, buffer, width, prec);
947 pCtx->LocalToPhysAddr(params[arg], &value);
949 const char *name = "Console";
952 CPlayer *player = g_Players.GetPlayerByIndex(*value);
953 if (!player || !player->IsConnected())
955 return pCtx->ThrowNativeError("Client index %d is invalid", *value);
957 name = player->GetName();
959 AddString(&buf_p, llen, name, width, prec);
968 if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
970 pCtx->ThrowNativeErrorEx(err, "Could not deference string");
973 AddString(&buf_p, llen, str, width, prec);
984 pCtx->LocalToString(params[arg++], &key);
985 pCtx->LocalToPhysAddr(params[arg++], &target);
986 res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1001 cell_t target = g_SourceMod.GetGlobalTarget();
1002 pCtx->LocalToString(params[arg++], &key);
1003 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1016 pCtx->LocalToPhysAddr(params[arg], &value);
1017 flags |= UPPERDIGITS;
1018 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1026 pCtx->LocalToPhysAddr(params[arg], &value);
1027 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1067 return (maxlen - llen - 1);
1070 const char *stristr(const char *str, const char *substr)
1074 return ((char *)str);
1077 char *needle = (char *)substr;
1078 char *prevloc = (char *)str;
1079 char *haystack = (char *)str;
1083 if (tolower(*haystack) == tolower(*needle))
1093 haystack = ++prevloc;
1094 needle = (char *)substr;
1101 unsigned int strncopy(char *dest, const char *src, size_t count)
1109 while ((*src) && (--count))
1115 return (dest - start);
1118 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1122 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1125 if (len >= maxlength)
1127 buffer[maxlength - 1] = '\0';
1128 return (maxlength - 1);
1136 size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1138 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1140 if (len >= maxlength)
1142 buffer[maxlength - 1] = '\0';
1143 return (maxlength - 1);
1151 char *sm_strdup(const char *str)
1153 char *ptr = new char[strlen(str)+1];
1158 unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace)
1160 size_t searchLen = strlen(search);
1161 size_t replaceLen = strlen(replace);
1163 char *ptr = subject;
1164 unsigned int total = 0;
1165 while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen)) != NULL)
1178 * NOTE: Do not edit this for the love of god unless you have
1179 * read the test cases and understand the code behind each one.
1180 * While I don't guarantee there aren't mistakes, I do guarantee
1181 * that plugins will end up relying on tiny idiosyncracies of this
1182 * function, just like they did with AMX Mod X.
1184 * There are explicitly more cases than the AMX Mod X version because
1185 * we're not doing a blind copy. Each case is specifically optimized
1186 * for what needs to be done. Even better, we don't have to error on
1187 * bad buffer sizes. Instead, this function will smartly cut off the
1188 * string in a way that pushes old data out.
1190 char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen)
1192 char *ptr = subject;
1194 size_t textLen = strlen(subject);
1196 /* It's not possible to search or replace */
1197 if (searchLen > textLen)
1202 /* Handle the case of one byte replacement.
1203 * It's only valid in one case.
1207 /* If the search matches and the replace length is 0,
1208 * we can just terminate the string and be done.
1210 if (strcmp(subject, search) == 0 && replaceLen == 0)
1221 /* Subtract one off the maxlength so we can include the null terminator */
1224 while (*ptr != '\0' && (browsed <= textLen - searchLen))
1226 /* See if we get a comparison */
1227 if (strncmp(ptr, search, searchLen) == 0)
1229 if (replaceLen > searchLen)
1231 /* First, see if we have enough space to do this operation */
1232 if (maxLen - textLen < replaceLen - searchLen)
1234 /* First, see if the replacement length goes out of bounds. */
1235 if (browsed + replaceLen >= maxLen)
1241 * Replace: DDDDDDDDDD
1242 * OUTPUT : AADDDDDDDDD
1245 /* If it does, we'll just bound the length and do a strcpy. */
1246 replaceLen = maxLen - browsed;
1247 /* Note, we add one to the final result for the null terminator */
1248 strncopy(ptr, replace, replaceLen+1);
1257 * OUTPUT : AADDDDDDDCC
1260 /* We're going to have some bytes left over... */
1261 size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
1262 size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
1263 char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
1264 char *moveTo = ptr + replaceLen;
1266 /* First, move our old data out of the way. */
1267 memmove(moveTo, moveFrom, realBytesToCopy);
1269 /* Now, do our replacement. */
1270 memcpy(ptr, replace, replaceLen);
1280 * OUTPUT : AADDDDCCC
1283 /* Yes, we have enough space. Do a normal move operation. */
1284 char *moveFrom = ptr + searchLen;
1285 char *moveTo = ptr + replaceLen;
1287 /* First move our old data out of the way. */
1288 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1289 memmove(moveTo, moveFrom, bytesToCopy);
1291 /* Now do our replacement. */
1292 memcpy(ptr, replace, replaceLen);
1295 else if (replaceLen < searchLen)
1305 /* If the replacement does not grow the string length, we do not
1306 * need to do any fancy checking at all. Yay!
1308 char *moveFrom = ptr + searchLen; /* Start after the search pointer */
1309 char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
1311 /* Copy our replacement in, if any */
1314 memcpy(ptr, replace, replaceLen);
1317 /* Figure out how many bytes to move down, including null terminator */
1318 size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1320 /* Move the rest of the string down */
1321 memmove(moveTo, moveFrom, bytesToCopy);
1333 /* We don't have to move anything around, just do a straight copy */
1334 memcpy(ptr, replace, replaceLen);
1337 return ptr + replaceLen;
1346 char *UTIL_TrimWhitespace(char *str, size_t &len)
1348 char *end = str + len - 1;
1355 /* Iterate backwards through string until we reach first non-whitespace char */
1356 while (end >= str && textparsers->IsWhitespace(end))
1362 /* Replace first whitespace char (at the end) with null terminator.
1363 * If there is none, we're just replacing the null terminator.
1367 while (*str != '\0' && textparsers->IsWhitespace(str))