1.1 --- a/core/sm_stringutil.cpp Fri Mar 28 06:21:34 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1277 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include <stdlib.h>
1.36 -#include <ctype.h>
1.37 -#include <stdarg.h>
1.38 -#include "sm_stringutil.h"
1.39 -#include "Logger.h"
1.40 -#include "PluginSys.h"
1.41 -#include "Translator.h"
1.42 -#include "PlayerManager.h"
1.43 -
1.44 -#define LADJUST 0x00000004 /* left adjustment */
1.45 -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
1.46 -#define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
1.47 -#define to_digit(c) ((c) - '0')
1.48 -#define is_digit(c) ((unsigned)to_digit(c) <= 9)
1.49 -
1.50 -#define CHECK_ARGS(x) \
1.51 - if ((arg+x) > args) { \
1.52 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
1.53 - return 0; \
1.54 - }
1.55 -
1.56 -size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const char *phrase, void **params)
1.57 -{
1.58 - Translation pTrans;
1.59 - TransError err;
1.60 -
1.61 - err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetClientLanguage(client), &pTrans);
1.62 - if (err != Trans_Okay)
1.63 - {
1.64 - err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans);
1.65 - if (err != Trans_Okay && g_Translator.GetServerLanguage() != CORELANG_ENGLISH)
1.66 - {
1.67 - err = g_pCorePhrases->GetTranslation(phrase, CORELANG_ENGLISH, &pTrans);
1.68 - }
1.69 - }
1.70 -
1.71 - if (err != Trans_Okay)
1.72 - {
1.73 - return UTIL_Format(buffer, maxlength, "%s", phrase);
1.74 - }
1.75 -
1.76 - return g_Translator.Translate(buffer, maxlength, params, &pTrans);
1.77 -}
1.78 -
1.79 -inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans)
1.80 -{
1.81 - TransError err = Trans_BadLanguage;
1.82 - CPhraseFile *phrfl;
1.83 -
1.84 - for (size_t i=0; i<langcount && err!=Trans_Okay; i++)
1.85 - {
1.86 - phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i));
1.87 - err = phrfl->GetTranslation(key, langid, pTrans);
1.88 - }
1.89 -
1.90 - return (err == Trans_Okay) ? true : false;
1.91 -}
1.92 -
1.93 -inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
1.94 -{
1.95 - cell_t new_params[MAX_TRANSLATE_PARAMS];
1.96 - for (unsigned int i = 0; i < pTrans->fmt_count; i++)
1.97 - {
1.98 - new_params[i] = params[pTrans->fmt_order[i]];
1.99 - }
1.100 - memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
1.101 -}
1.102 -
1.103 -size_t Translate(char *buffer,
1.104 - size_t maxlen,
1.105 - IPluginContext *pCtx,
1.106 - const char *key,
1.107 - cell_t target,
1.108 - const cell_t *params,
1.109 - int *arg,
1.110 - bool *error)
1.111 -{
1.112 - unsigned int langid;
1.113 - *error = false;
1.114 - Translation pTrans;
1.115 - CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
1.116 - size_t langcount = pl->GetLangFileCount();
1.117 - unsigned int max_params = 0;
1.118 -
1.119 -try_serverlang:
1.120 - if (target == LANG_SERVER)
1.121 - {
1.122 - langid = g_Translator.GetServerLanguage();
1.123 - }
1.124 - else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
1.125 - {
1.126 - langid = g_Translator.GetClientLanguage(target);
1.127 - }
1.128 - else
1.129 - {
1.130 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
1.131 - goto error_out;
1.132 - }
1.133 -
1.134 - if (!TryTranslation(pl, key, langid, langcount, &pTrans))
1.135 - {
1.136 - if (target != LANG_SERVER && langid != g_Translator.GetServerLanguage())
1.137 - {
1.138 - target = LANG_SERVER;
1.139 - goto try_serverlang;
1.140 - }
1.141 - else if (langid != LANGUAGE_ENGLISH)
1.142 - {
1.143 - if (!TryTranslation(pl, key, LANGUAGE_ENGLISH, langcount, &pTrans))
1.144 - {
1.145 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
1.146 - goto error_out;
1.147 - }
1.148 - }
1.149 - else
1.150 - {
1.151 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
1.152 - goto error_out;
1.153 - }
1.154 - }
1.155 -
1.156 - max_params = pTrans.fmt_count;
1.157 -
1.158 - if (max_params)
1.159 - {
1.160 - cell_t new_params[MAX_TRANSLATE_PARAMS];
1.161 -
1.162 - /* Check if we're going to over the limit */
1.163 - if ((*arg) + (max_params - 1) > (size_t)params[0])
1.164 - {
1.165 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
1.166 - "Translation string formatted incorrectly - missing at least %d parameters",
1.167 - ((*arg + (max_params - 1)) - params[0])
1.168 - );
1.169 - goto error_out;
1.170 - }
1.171 -
1.172 - /* If we need to re-order the parameters, do so with a temporary array.
1.173 - * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
1.174 - */
1.175 - memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
1.176 - ReorderTranslationParams(&pTrans, &new_params[*arg]);
1.177 -
1.178 - return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
1.179 - }
1.180 - else
1.181 - {
1.182 - return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
1.183 - }
1.184 -
1.185 -error_out:
1.186 - *error = true;
1.187 - return 0;
1.188 -}
1.189 -
1.190 -void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
1.191 -{
1.192 - int size = 0;
1.193 - char *buf;
1.194 - static char nlstr[] = {'(','n','u','l','l',')','\0'};
1.195 -
1.196 - buf = *buf_p;
1.197 -
1.198 - if (string == NULL)
1.199 - {
1.200 - string = nlstr;
1.201 - prec = -1;
1.202 - }
1.203 -
1.204 - if (prec >= 0)
1.205 - {
1.206 - for (size = 0; size < prec; size++)
1.207 - {
1.208 - if (string[size] == '\0')
1.209 - {
1.210 - break;
1.211 - }
1.212 - }
1.213 - }
1.214 - else
1.215 - {
1.216 - while (string[size++]);
1.217 - size--;
1.218 - }
1.219 -
1.220 - if (size > (int)maxlen)
1.221 - {
1.222 - size = maxlen;
1.223 - }
1.224 -
1.225 - maxlen -= size;
1.226 - width -= size;
1.227 -
1.228 - while (size--)
1.229 - {
1.230 - *buf++ = *string++;
1.231 - }
1.232 -
1.233 - while ((width-- > 0) && maxlen)
1.234 - {
1.235 - *buf++ = ' ';
1.236 - maxlen--;
1.237 - }
1.238 -
1.239 - *buf_p = buf;
1.240 -}
1.241 -
1.242 -void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
1.243 -{
1.244 - int digits; // non-fraction part digits
1.245 - double tmp; // temporary
1.246 - char *buf = *buf_p; // output buffer pointer
1.247 - int val; // temporary
1.248 - int sign = 0; // 0: positive, 1: negative
1.249 - int fieldlength; // for padding
1.250 - int significant_digits = 0; // number of significant digits written
1.251 - const int MAX_SIGNIFICANT_DIGITS = 16;
1.252 -
1.253 - // default precision
1.254 - if (prec < 0)
1.255 - {
1.256 - prec = 6;
1.257 - }
1.258 -
1.259 - // get the sign
1.260 - if (fval < 0)
1.261 - {
1.262 - fval = -fval;
1.263 - sign = 1;
1.264 - }
1.265 -
1.266 - // compute whole-part digits count
1.267 - digits = (int)log10(fval) + 1;
1.268 -
1.269 - // Only print 0.something if 0 < fval < 1
1.270 - if (digits < 1)
1.271 - {
1.272 - digits = 1;
1.273 - }
1.274 -
1.275 - // compute the field length
1.276 - fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
1.277 -
1.278 - // minus sign BEFORE left padding if padding with zeros
1.279 - if (sign && maxlen && (flags & ZEROPAD))
1.280 - {
1.281 - *buf++ = '-';
1.282 - maxlen--;
1.283 - }
1.284 -
1.285 - // right justify if required
1.286 - if ((flags & LADJUST) == 0)
1.287 - {
1.288 - while ((fieldlength < width) && maxlen)
1.289 - {
1.290 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.291 - width--;
1.292 - maxlen--;
1.293 - }
1.294 - }
1.295 -
1.296 - // minus sign AFTER left padding if padding with spaces
1.297 - if (sign && maxlen && !(flags & ZEROPAD))
1.298 - {
1.299 - *buf++ = '-';
1.300 - maxlen--;
1.301 - }
1.302 -
1.303 - // write the whole part
1.304 - tmp = pow(10.0, digits-1);
1.305 - while ((digits--) && maxlen)
1.306 - {
1.307 - if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
1.308 - {
1.309 - *buf++ = '0';
1.310 - }
1.311 - else
1.312 - {
1.313 - val = (int)(fval / tmp);
1.314 - *buf++ = '0' + val;
1.315 - fval -= val * tmp;
1.316 - tmp *= 0.1;
1.317 - }
1.318 - maxlen--;
1.319 - }
1.320 -
1.321 - // write the fraction part
1.322 - if (maxlen)
1.323 - {
1.324 - *buf++ = '.';
1.325 - maxlen--;
1.326 - }
1.327 -
1.328 - tmp = pow(10.0, prec);
1.329 -
1.330 - fval *= tmp;
1.331 - while (prec-- && maxlen)
1.332 - {
1.333 - if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
1.334 - {
1.335 - *buf++ = '0';
1.336 - }
1.337 - else
1.338 - {
1.339 - tmp *= 0.1;
1.340 - val = (int)(fval / tmp);
1.341 - *buf++ = '0' + val;
1.342 - fval -= val * tmp;
1.343 - }
1.344 - maxlen--;
1.345 - }
1.346 -
1.347 - // left justify if required
1.348 - if (flags & LADJUST)
1.349 - {
1.350 - while ((fieldlength < width) && maxlen)
1.351 - {
1.352 - // right-padding only with spaces, ZEROPAD is ignored
1.353 - *buf++ = ' ';
1.354 - width--;
1.355 - maxlen--;
1.356 - }
1.357 - }
1.358 -
1.359 - // update parent's buffer pointer
1.360 - *buf_p = buf;
1.361 -}
1.362 -
1.363 -void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
1.364 -{
1.365 - char text[32];
1.366 - int digits;
1.367 - char *buf;
1.368 -
1.369 - digits = 0;
1.370 - do
1.371 - {
1.372 - text[digits++] = '0' + val % 10;
1.373 - val /= 10;
1.374 - } while (val);
1.375 -
1.376 - buf = *buf_p;
1.377 -
1.378 - if (!(flags & LADJUST))
1.379 - {
1.380 - while (digits < width && maxlen)
1.381 - {
1.382 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.383 - width--;
1.384 - maxlen--;
1.385 - }
1.386 - }
1.387 -
1.388 - while (digits-- && maxlen)
1.389 - {
1.390 - *buf++ = text[digits];
1.391 - width--;
1.392 - maxlen--;
1.393 - }
1.394 -
1.395 - if (flags & LADJUST)
1.396 - {
1.397 - while (width-- && maxlen)
1.398 - {
1.399 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.400 - maxlen--;
1.401 - }
1.402 - }
1.403 -
1.404 - *buf_p = buf;
1.405 -}
1.406 -
1.407 -void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
1.408 -{
1.409 - char text[32];
1.410 - int digits;
1.411 - int signedVal;
1.412 - char *buf;
1.413 - unsigned int unsignedVal;
1.414 -
1.415 - digits = 0;
1.416 - signedVal = val;
1.417 - if (val < 0)
1.418 - {
1.419 - /* we want the unsigned version */
1.420 - unsignedVal = abs(val);
1.421 - }
1.422 - else
1.423 - {
1.424 - unsignedVal = val;
1.425 - }
1.426 -
1.427 - do
1.428 - {
1.429 - text[digits++] = '0' + unsignedVal % 10;
1.430 - unsignedVal /= 10;
1.431 - } while (unsignedVal);
1.432 -
1.433 - if (signedVal < 0)
1.434 - {
1.435 - text[digits++] = '-';
1.436 - }
1.437 -
1.438 - buf = *buf_p;
1.439 -
1.440 - if (!(flags & LADJUST))
1.441 - {
1.442 - while ((digits < width) && maxlen)
1.443 - {
1.444 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.445 - width--;
1.446 - maxlen--;
1.447 - }
1.448 - }
1.449 -
1.450 - while (digits-- && maxlen)
1.451 - {
1.452 - *buf++ = text[digits];
1.453 - width--;
1.454 - maxlen--;
1.455 - }
1.456 -
1.457 - if (flags & LADJUST)
1.458 - {
1.459 - while (width-- && maxlen)
1.460 - {
1.461 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.462 - maxlen--;
1.463 - }
1.464 - }
1.465 -
1.466 - *buf_p = buf;
1.467 -}
1.468 -
1.469 -void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
1.470 -{
1.471 - char text[32];
1.472 - int digits;
1.473 - char *buf;
1.474 - char digit;
1.475 - int hexadjust;
1.476 -
1.477 - if (flags & UPPERDIGITS)
1.478 - {
1.479 - hexadjust = 'A' - '9' - 1;
1.480 - }
1.481 - else
1.482 - {
1.483 - hexadjust = 'a' - '9' - 1;
1.484 - }
1.485 -
1.486 - digits = 0;
1.487 - do
1.488 - {
1.489 - digit = ('0' + val % 16);
1.490 - if (digit > '9')
1.491 - {
1.492 - digit += hexadjust;
1.493 - }
1.494 -
1.495 - text[digits++] = digit;
1.496 - val /= 16;
1.497 - } while(val);
1.498 -
1.499 - buf = *buf_p;
1.500 -
1.501 - if (!(flags & LADJUST))
1.502 - {
1.503 - while (digits < width && maxlen)
1.504 - {
1.505 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.506 - width--;
1.507 - maxlen--;
1.508 - }
1.509 - }
1.510 -
1.511 - while (digits-- && maxlen)
1.512 - {
1.513 - *buf++ = text[digits];
1.514 - width--;
1.515 - maxlen--;
1.516 - }
1.517 -
1.518 - if (flags & LADJUST)
1.519 - {
1.520 - while (width-- && maxlen)
1.521 - {
1.522 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.523 - maxlen--;
1.524 - }
1.525 - }
1.526 -
1.527 - *buf_p = buf;
1.528 -}
1.529 -
1.530 -size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
1.531 -{
1.532 - if (!buffer || !maxlen)
1.533 - {
1.534 - return 0;
1.535 - }
1.536 -
1.537 - int arg = 0;
1.538 - char *buf_p;
1.539 - char ch;
1.540 - int flags;
1.541 - int width;
1.542 - int prec;
1.543 - int n;
1.544 - char sign;
1.545 - const char *fmt;
1.546 - size_t llen = maxlen - 1;
1.547 -
1.548 - buf_p = buffer;
1.549 - fmt = format;
1.550 -
1.551 - while (true)
1.552 - {
1.553 - // run through the format string until we hit a '%' or '\0'
1.554 - for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1.555 - {
1.556 - *buf_p++ = ch;
1.557 - llen--;
1.558 - }
1.559 - if ((ch == '\0') || (llen <= 0))
1.560 - {
1.561 - goto done;
1.562 - }
1.563 -
1.564 - // skip over the '%'
1.565 - fmt++;
1.566 -
1.567 - // reset formatting state
1.568 - flags = 0;
1.569 - width = 0;
1.570 - prec = -1;
1.571 - sign = '\0';
1.572 -
1.573 -rflag:
1.574 - ch = *fmt++;
1.575 -reswitch:
1.576 - switch(ch)
1.577 - {
1.578 - case '-':
1.579 - {
1.580 - flags |= LADJUST;
1.581 - goto rflag;
1.582 - }
1.583 - case '.':
1.584 - {
1.585 - n = 0;
1.586 - while(is_digit((ch = *fmt++)))
1.587 - {
1.588 - n = 10 * n + (ch - '0');
1.589 - }
1.590 - prec = (n < 0) ? -1 : n;
1.591 - goto reswitch;
1.592 - }
1.593 - case '0':
1.594 - {
1.595 - flags |= ZEROPAD;
1.596 - goto rflag;
1.597 - }
1.598 - case '1':
1.599 - case '2':
1.600 - case '3':
1.601 - case '4':
1.602 - case '5':
1.603 - case '6':
1.604 - case '7':
1.605 - case '8':
1.606 - case '9':
1.607 - {
1.608 - n = 0;
1.609 - do
1.610 - {
1.611 - n = 10 * n + (ch - '0');
1.612 - ch = *fmt++;
1.613 - } while(is_digit(ch));
1.614 - width = n;
1.615 - goto reswitch;
1.616 - }
1.617 - case 'c':
1.618 - {
1.619 - if (!llen)
1.620 - {
1.621 - goto done;
1.622 - }
1.623 - char *c = (char *)args[arg];
1.624 - *buf_p++ = *c;
1.625 - llen--;
1.626 - arg++;
1.627 - break;
1.628 - }
1.629 - case 'd':
1.630 - case 'i':
1.631 - {
1.632 - int *value = (int *)args[arg];
1.633 - AddInt(&buf_p, llen, *value, width, flags);
1.634 - arg++;
1.635 - break;
1.636 - }
1.637 - case 'u':
1.638 - {
1.639 - unsigned int *value = (unsigned int *)args[arg];
1.640 - AddUInt(&buf_p, llen, *value, width, flags);
1.641 - arg++;
1.642 - break;
1.643 - }
1.644 - case 'f':
1.645 - {
1.646 - float *value = (float *)args[arg];
1.647 - AddFloat(&buf_p, llen, *value, width, prec, flags);
1.648 - arg++;
1.649 - break;
1.650 - }
1.651 - case 's':
1.652 - {
1.653 - const char *str = (const char *)args[arg];
1.654 - AddString(&buf_p, llen, str, width, prec);
1.655 - arg++;
1.656 - break;
1.657 - }
1.658 - case 'X':
1.659 - {
1.660 - unsigned int *value = (unsigned int *)args[arg];
1.661 - flags |= UPPERDIGITS;
1.662 - AddHex(&buf_p, llen, *value, width, flags);
1.663 - arg++;
1.664 - break;
1.665 - }
1.666 - case 'x':
1.667 - {
1.668 - unsigned int *value = (unsigned int *)args[arg];
1.669 - AddHex(&buf_p, llen, *value, width, flags);
1.670 - arg++;
1.671 - break;
1.672 - }
1.673 - case '%':
1.674 - {
1.675 - if (!llen)
1.676 - {
1.677 - goto done;
1.678 - }
1.679 - *buf_p++ = ch;
1.680 - llen--;
1.681 - break;
1.682 - }
1.683 - case '\0':
1.684 - {
1.685 - if (!llen)
1.686 - {
1.687 - goto done;
1.688 - }
1.689 - *buf_p++ = '%';
1.690 - llen--;
1.691 - goto done;
1.692 - }
1.693 - default:
1.694 - {
1.695 - if (!llen)
1.696 - {
1.697 - goto done;
1.698 - }
1.699 - *buf_p++ = ch;
1.700 - llen--;
1.701 - break;
1.702 - }
1.703 - }
1.704 - }
1.705 -
1.706 -done:
1.707 - *buf_p = '\0';
1.708 -
1.709 - return (maxlen - llen - 1);
1.710 -}
1.711 -
1.712 -size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
1.713 -{
1.714 - if (!buffer || !maxlen)
1.715 - {
1.716 - return 0;
1.717 - }
1.718 -
1.719 - int arg;
1.720 - int args = params[0];
1.721 - char *buf_p;
1.722 - char ch;
1.723 - int flags;
1.724 - int width;
1.725 - int prec;
1.726 - int n;
1.727 - char sign;
1.728 - const char *fmt;
1.729 - size_t llen = maxlen - 1;
1.730 -
1.731 - buf_p = buffer;
1.732 - arg = *param;
1.733 - fmt = format;
1.734 -
1.735 - while (true)
1.736 - {
1.737 - // run through the format string until we hit a '%' or '\0'
1.738 - for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1.739 - {
1.740 - *buf_p++ = ch;
1.741 - llen--;
1.742 - }
1.743 - if ((ch == '\0') || (llen <= 0))
1.744 - {
1.745 - goto done;
1.746 - }
1.747 -
1.748 - // skip over the '%'
1.749 - fmt++;
1.750 -
1.751 - // reset formatting state
1.752 - flags = 0;
1.753 - width = 0;
1.754 - prec = -1;
1.755 - sign = '\0';
1.756 -
1.757 -rflag:
1.758 - ch = *fmt++;
1.759 -reswitch:
1.760 - switch(ch)
1.761 - {
1.762 - case '-':
1.763 - {
1.764 - flags |= LADJUST;
1.765 - goto rflag;
1.766 - }
1.767 - case '.':
1.768 - {
1.769 - n = 0;
1.770 - while(is_digit((ch = *fmt++)))
1.771 - {
1.772 - n = 10 * n + (ch - '0');
1.773 - }
1.774 - prec = (n < 0) ? -1 : n;
1.775 - goto reswitch;
1.776 - }
1.777 - case '0':
1.778 - {
1.779 - flags |= ZEROPAD;
1.780 - goto rflag;
1.781 - }
1.782 - case '1':
1.783 - case '2':
1.784 - case '3':
1.785 - case '4':
1.786 - case '5':
1.787 - case '6':
1.788 - case '7':
1.789 - case '8':
1.790 - case '9':
1.791 - {
1.792 - n = 0;
1.793 - do
1.794 - {
1.795 - n = 10 * n + (ch - '0');
1.796 - ch = *fmt++;
1.797 - } while(is_digit(ch));
1.798 - width = n;
1.799 - goto reswitch;
1.800 - }
1.801 - case 'c':
1.802 - {
1.803 - CHECK_ARGS(0);
1.804 - if (!llen)
1.805 - {
1.806 - goto done;
1.807 - }
1.808 - char *c;
1.809 - pCtx->LocalToString(params[arg], &c);
1.810 - *buf_p++ = *c;
1.811 - llen--;
1.812 - arg++;
1.813 - break;
1.814 - }
1.815 - case 'd':
1.816 - case 'i':
1.817 - {
1.818 - CHECK_ARGS(0);
1.819 - cell_t *value;
1.820 - pCtx->LocalToPhysAddr(params[arg], &value);
1.821 - AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
1.822 - arg++;
1.823 - break;
1.824 - }
1.825 - case 'u':
1.826 - {
1.827 - CHECK_ARGS(0);
1.828 - cell_t *value;
1.829 - pCtx->LocalToPhysAddr(params[arg], &value);
1.830 - AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.831 - arg++;
1.832 - break;
1.833 - }
1.834 - case 'f':
1.835 - {
1.836 - CHECK_ARGS(0);
1.837 - cell_t *value;
1.838 - pCtx->LocalToPhysAddr(params[arg], &value);
1.839 - AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
1.840 - arg++;
1.841 - break;
1.842 - }
1.843 - case 'L':
1.844 - {
1.845 - CHECK_ARGS(0);
1.846 - cell_t *value;
1.847 - pCtx->LocalToPhysAddr(params[arg], &value);
1.848 - char buffer[255];
1.849 - if (*value)
1.850 - {
1.851 - CPlayer *player = g_Players.GetPlayerByIndex(*value);
1.852 - if (!player || !player->IsConnected())
1.853 - {
1.854 - return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1.855 - }
1.856 - const char *auth = player->GetAuthString();
1.857 - if (!auth || auth[0] == '\0')
1.858 - {
1.859 - auth = "STEAM_ID_PENDING";
1.860 - }
1.861 - int userid = engine->GetPlayerUserId(player->GetEdict());
1.862 - UTIL_Format(buffer,
1.863 - sizeof(buffer),
1.864 - "%s<%d><%s><>",
1.865 - player->GetName(),
1.866 - userid,
1.867 - auth);
1.868 - }
1.869 - else
1.870 - {
1.871 - UTIL_Format(buffer,
1.872 - sizeof(buffer),
1.873 - "Console<0><Console><Console>");
1.874 - }
1.875 - AddString(&buf_p, llen, buffer, width, prec);
1.876 - arg++;
1.877 - break;
1.878 - }
1.879 - case 'N':
1.880 - {
1.881 - CHECK_ARGS(0);
1.882 - cell_t *value;
1.883 - pCtx->LocalToPhysAddr(params[arg], &value);
1.884 -
1.885 - const char *name = "Console";
1.886 - if (*value)
1.887 - {
1.888 - CPlayer *player = g_Players.GetPlayerByIndex(*value);
1.889 - if (!player || !player->IsConnected())
1.890 - {
1.891 - return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1.892 - }
1.893 - name = player->GetName();
1.894 - }
1.895 - AddString(&buf_p, llen, name, width, prec);
1.896 - arg++;
1.897 - break;
1.898 - }
1.899 - case 's':
1.900 - {
1.901 - CHECK_ARGS(0);
1.902 - char *str;
1.903 - int err;
1.904 - if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
1.905 - {
1.906 - pCtx->ThrowNativeErrorEx(err, "Could not deference string");
1.907 - return 0;
1.908 - }
1.909 - AddString(&buf_p, llen, str, width, prec);
1.910 - arg++;
1.911 - break;
1.912 - }
1.913 - case 'T':
1.914 - {
1.915 - CHECK_ARGS(1);
1.916 - char *key;
1.917 - bool error;
1.918 - size_t res;
1.919 - cell_t *target;
1.920 - pCtx->LocalToString(params[arg++], &key);
1.921 - pCtx->LocalToPhysAddr(params[arg++], &target);
1.922 - res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1.923 - if (error)
1.924 - {
1.925 - return 0;
1.926 - }
1.927 - buf_p += res;
1.928 - llen -= res;
1.929 - break;
1.930 - }
1.931 - case 't':
1.932 - {
1.933 - CHECK_ARGS(0);
1.934 - char *key;
1.935 - bool error;
1.936 - size_t res;
1.937 - cell_t target = g_SourceMod.GetGlobalTarget();
1.938 - pCtx->LocalToString(params[arg++], &key);
1.939 - res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1.940 - if (error)
1.941 - {
1.942 - return 0;
1.943 - }
1.944 - buf_p += res;
1.945 - llen -= res;
1.946 - break;
1.947 - }
1.948 - case 'X':
1.949 - {
1.950 - CHECK_ARGS(0);
1.951 - cell_t *value;
1.952 - pCtx->LocalToPhysAddr(params[arg], &value);
1.953 - flags |= UPPERDIGITS;
1.954 - AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.955 - arg++;
1.956 - break;
1.957 - }
1.958 - case 'x':
1.959 - {
1.960 - CHECK_ARGS(0);
1.961 - cell_t *value;
1.962 - pCtx->LocalToPhysAddr(params[arg], &value);
1.963 - AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.964 - arg++;
1.965 - break;
1.966 - }
1.967 - case '%':
1.968 - {
1.969 - if (!llen)
1.970 - {
1.971 - goto done;
1.972 - }
1.973 - *buf_p++ = ch;
1.974 - llen--;
1.975 - break;
1.976 - }
1.977 - case '\0':
1.978 - {
1.979 - if (!llen)
1.980 - {
1.981 - goto done;
1.982 - }
1.983 - *buf_p++ = '%';
1.984 - llen--;
1.985 - goto done;
1.986 - }
1.987 - default:
1.988 - {
1.989 - if (!llen)
1.990 - {
1.991 - goto done;
1.992 - }
1.993 - *buf_p++ = ch;
1.994 - llen--;
1.995 - break;
1.996 - }
1.997 - }
1.998 - }
1.999 -
1.1000 -done:
1.1001 - *buf_p = '\0';
1.1002 - *param = arg;
1.1003 - return (maxlen - llen - 1);
1.1004 -}
1.1005 -
1.1006 -const char *stristr(const char *str, const char *substr)
1.1007 -{
1.1008 - if (!*substr)
1.1009 - {
1.1010 - return ((char *)str);
1.1011 - }
1.1012 -
1.1013 - char *needle = (char *)substr;
1.1014 - char *prevloc = (char *)str;
1.1015 - char *haystack = (char *)str;
1.1016 -
1.1017 - while (*haystack)
1.1018 - {
1.1019 - if (tolower(*haystack) == tolower(*needle))
1.1020 - {
1.1021 - haystack++;
1.1022 - if (!*++needle)
1.1023 - {
1.1024 - return prevloc;
1.1025 - }
1.1026 - }
1.1027 - else
1.1028 - {
1.1029 - haystack = ++prevloc;
1.1030 - needle = (char *)substr;
1.1031 - }
1.1032 - }
1.1033 -
1.1034 - return NULL;
1.1035 -}
1.1036 -
1.1037 -unsigned int strncopy(char *dest, const char *src, size_t count)
1.1038 -{
1.1039 - if (!count)
1.1040 - {
1.1041 - return 0;
1.1042 - }
1.1043 -
1.1044 - char *start = dest;
1.1045 - while ((*src) && (--count))
1.1046 - {
1.1047 - *dest++ = *src++;
1.1048 - }
1.1049 - *dest = '\0';
1.1050 -
1.1051 - return (dest - start);
1.1052 -}
1.1053 -
1.1054 -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1.1055 -{
1.1056 - va_list ap;
1.1057 - va_start(ap, fmt);
1.1058 - size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1.1059 - va_end(ap);
1.1060 -
1.1061 - if (len >= maxlength)
1.1062 - {
1.1063 - buffer[maxlength - 1] = '\0';
1.1064 - return (maxlength - 1);
1.1065 - }
1.1066 - else
1.1067 - {
1.1068 - return len;
1.1069 - }
1.1070 -}
1.1071 -
1.1072 -size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1.1073 -{
1.1074 - size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1.1075 -
1.1076 - if (len >= maxlength)
1.1077 - {
1.1078 - buffer[maxlength - 1] = '\0';
1.1079 - return (maxlength - 1);
1.1080 - }
1.1081 - else
1.1082 - {
1.1083 - return len;
1.1084 - }
1.1085 -}
1.1086 -
1.1087 -char *sm_strdup(const char *str)
1.1088 -{
1.1089 - char *ptr = new char[strlen(str)+1];
1.1090 - strcpy(ptr, str);
1.1091 - return ptr;
1.1092 -}
1.1093 -
1.1094 -unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace)
1.1095 -{
1.1096 - size_t searchLen = strlen(search);
1.1097 - size_t replaceLen = strlen(replace);
1.1098 -
1.1099 - char *ptr = subject;
1.1100 - unsigned int total = 0;
1.1101 - while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen)) != NULL)
1.1102 - {
1.1103 - total++;
1.1104 - if (*ptr == '\0')
1.1105 - {
1.1106 - break;
1.1107 - }
1.1108 - }
1.1109 -
1.1110 - return total;
1.1111 -}
1.1112 -
1.1113 -/**
1.1114 - * NOTE: Do not edit this for the love of god unless you have
1.1115 - * read the test cases and understand the code behind each one.
1.1116 - * While I don't guarantee there aren't mistakes, I do guarantee
1.1117 - * that plugins will end up relying on tiny idiosyncracies of this
1.1118 - * function, just like they did with AMX Mod X.
1.1119 - *
1.1120 - * There are explicitly more cases than the AMX Mod X version because
1.1121 - * we're not doing a blind copy. Each case is specifically optimized
1.1122 - * for what needs to be done. Even better, we don't have to error on
1.1123 - * bad buffer sizes. Instead, this function will smartly cut off the
1.1124 - * string in a way that pushes old data out.
1.1125 - */
1.1126 -char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen)
1.1127 -{
1.1128 - char *ptr = subject;
1.1129 - size_t browsed = 0;
1.1130 - size_t textLen = strlen(subject);
1.1131 -
1.1132 - /* It's not possible to search or replace */
1.1133 - if (searchLen > textLen)
1.1134 - {
1.1135 - return NULL;
1.1136 - }
1.1137 -
1.1138 - /* Handle the case of one byte replacement.
1.1139 - * It's only valid in one case.
1.1140 - */
1.1141 - if (maxLen == 1)
1.1142 - {
1.1143 - /* If the search matches and the replace length is 0,
1.1144 - * we can just terminate the string and be done.
1.1145 - */
1.1146 - if (strcmp(subject, search) == 0 && replaceLen == 0)
1.1147 - {
1.1148 - *subject = '\0';
1.1149 - return subject;
1.1150 - }
1.1151 - else
1.1152 - {
1.1153 - return NULL;
1.1154 - }
1.1155 - }
1.1156 -
1.1157 - /* Subtract one off the maxlength so we can include the null terminator */
1.1158 - maxLen--;
1.1159 -
1.1160 - while (*ptr != '\0' && (browsed <= textLen - searchLen))
1.1161 - {
1.1162 - /* See if we get a comparison */
1.1163 - if (strncmp(ptr, search, searchLen) == 0)
1.1164 - {
1.1165 - if (replaceLen > searchLen)
1.1166 - {
1.1167 - /* First, see if we have enough space to do this operation */
1.1168 - if (maxLen - textLen < replaceLen - searchLen)
1.1169 - {
1.1170 - /* First, see if the replacement length goes out of bounds. */
1.1171 - if (browsed + replaceLen >= maxLen)
1.1172 - {
1.1173 - /* EXAMPLE CASE:
1.1174 - * Subject: AABBBCCC
1.1175 - * Buffer : 12 bytes
1.1176 - * Search : BBB
1.1177 - * Replace: DDDDDDDDDD
1.1178 - * OUTPUT : AADDDDDDDDD
1.1179 - * POSITION: ^
1.1180 - */
1.1181 - /* If it does, we'll just bound the length and do a strcpy. */
1.1182 - replaceLen = maxLen - browsed;
1.1183 - /* Note, we add one to the final result for the null terminator */
1.1184 - strncopy(ptr, replace, replaceLen+1);
1.1185 - }
1.1186 - else
1.1187 - {
1.1188 - /* EXAMPLE CASE:
1.1189 - * Subject: AABBBCCC
1.1190 - * Buffer : 12 bytes
1.1191 - * Search : BBB
1.1192 - * Replace: DDDDDDD
1.1193 - * OUTPUT : AADDDDDDDCC
1.1194 - * POSITION: ^
1.1195 - */
1.1196 - /* We're going to have some bytes left over... */
1.1197 - size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1198 - size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
1.1199 - char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
1.1200 - char *moveTo = ptr + replaceLen;
1.1201 -
1.1202 - /* First, move our old data out of the way. */
1.1203 - memmove(moveTo, moveFrom, realBytesToCopy);
1.1204 -
1.1205 - /* Now, do our replacement. */
1.1206 - memcpy(ptr, replace, replaceLen);
1.1207 - }
1.1208 - }
1.1209 - else
1.1210 - {
1.1211 - /* EXAMPLE CASE:
1.1212 - * Subject: AABBBCCC
1.1213 - * Buffer : 12 bytes
1.1214 - * Search : BBB
1.1215 - * Replace: DDDD
1.1216 - * OUTPUT : AADDDDCCC
1.1217 - * POSITION: ^
1.1218 - */
1.1219 - /* Yes, we have enough space. Do a normal move operation. */
1.1220 - char *moveFrom = ptr + searchLen;
1.1221 - char *moveTo = ptr + replaceLen;
1.1222 -
1.1223 - /* First move our old data out of the way. */
1.1224 - size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1225 - memmove(moveTo, moveFrom, bytesToCopy);
1.1226 -
1.1227 - /* Now do our replacement. */
1.1228 - memcpy(ptr, replace, replaceLen);
1.1229 - }
1.1230 - }
1.1231 - else if (replaceLen < searchLen)
1.1232 - {
1.1233 - /* EXAMPLE CASE:
1.1234 - * Subject: AABBBCCC
1.1235 - * Buffer : 12 bytes
1.1236 - * Search : BBB
1.1237 - * Replace: D
1.1238 - * OUTPUT : AADCCC
1.1239 - * POSOTION: ^
1.1240 - */
1.1241 - /* If the replacement does not grow the string length, we do not
1.1242 - * need to do any fancy checking at all. Yay!
1.1243 - */
1.1244 - char *moveFrom = ptr + searchLen; /* Start after the search pointer */
1.1245 - char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
1.1246 -
1.1247 - /* Copy our replacement in, if any */
1.1248 - if (replaceLen)
1.1249 - {
1.1250 - memcpy(ptr, replace, replaceLen);
1.1251 - }
1.1252 -
1.1253 - /* Figure out how many bytes to move down, including null terminator */
1.1254 - size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1255 -
1.1256 - /* Move the rest of the string down */
1.1257 - memmove(moveTo, moveFrom, bytesToCopy);
1.1258 - }
1.1259 - else
1.1260 - {
1.1261 - /* EXAMPLE CASE:
1.1262 - * Subject: AABBBCCC
1.1263 - * Buffer : 12 bytes
1.1264 - * Search : BBB
1.1265 - * Replace: DDD
1.1266 - * OUTPUT : AADDDCCC
1.1267 - * POSITION: ^
1.1268 - */
1.1269 - /* We don't have to move anything around, just do a straight copy */
1.1270 - memcpy(ptr, replace, replaceLen);
1.1271 - }
1.1272 -
1.1273 - return ptr + replaceLen;
1.1274 - }
1.1275 - ptr++;
1.1276 - browsed++;
1.1277 - }
1.1278 -
1.1279 - return NULL;
1.1280 -}