1.1 --- a/core/sm_stringutil.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1582 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2008 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 -inline void ReorderTranslationParams(const Translation *pTrans, cell_t *params)
1.57 -{
1.58 - cell_t new_params[MAX_TRANSLATE_PARAMS];
1.59 - for (unsigned int i = 0; i < pTrans->fmt_count; i++)
1.60 - {
1.61 - new_params[i] = params[pTrans->fmt_order[i]];
1.62 - }
1.63 - memcpy(params, new_params, pTrans->fmt_count * sizeof(cell_t));
1.64 -}
1.65 -
1.66 -size_t Translate(char *buffer,
1.67 - size_t maxlen,
1.68 - IPluginContext *pCtx,
1.69 - const char *key,
1.70 - cell_t target,
1.71 - const cell_t *params,
1.72 - int *arg,
1.73 - bool *error)
1.74 -{
1.75 - unsigned int langid;
1.76 - *error = false;
1.77 - Translation pTrans;
1.78 - CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
1.79 - unsigned int max_params = 0;
1.80 - IPhraseCollection *pPhrases;
1.81 -
1.82 - pPhrases = pl->GetPhrases();
1.83 -
1.84 -try_serverlang:
1.85 - if (target == SOURCEMOD_SERVER_LANGUAGE)
1.86 - {
1.87 - langid = g_Translator.GetServerLanguage();
1.88 - }
1.89 - else if ((target >= 1) && (target <= g_Players.GetMaxClients()))
1.90 - {
1.91 - langid = g_Translator.GetClientLanguage(target);
1.92 - }
1.93 - else
1.94 - {
1.95 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
1.96 - goto error_out;
1.97 - }
1.98 -
1.99 - if (pPhrases->FindTranslation(key, langid, &pTrans) != Trans_Okay)
1.100 - {
1.101 - if (target != SOURCEMOD_SERVER_LANGUAGE && langid != g_Translator.GetServerLanguage())
1.102 - {
1.103 - target = SOURCEMOD_SERVER_LANGUAGE;
1.104 - goto try_serverlang;
1.105 - }
1.106 - else if (langid != SOURCEMOD_LANGUAGE_ENGLISH)
1.107 - {
1.108 - if (!pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &pTrans))
1.109 - {
1.110 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
1.111 - goto error_out;
1.112 - }
1.113 - }
1.114 - else
1.115 - {
1.116 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
1.117 - goto error_out;
1.118 - }
1.119 - }
1.120 -
1.121 - max_params = pTrans.fmt_count;
1.122 -
1.123 - if (max_params)
1.124 - {
1.125 - cell_t new_params[MAX_TRANSLATE_PARAMS];
1.126 -
1.127 - /* Check if we're going to over the limit */
1.128 - if ((*arg) + (max_params - 1) > (size_t)params[0])
1.129 - {
1.130 - pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX,
1.131 - "Translation string formatted incorrectly - missing at least %d parameters",
1.132 - ((*arg + (max_params - 1)) - params[0])
1.133 - );
1.134 - goto error_out;
1.135 - }
1.136 -
1.137 - /* If we need to re-order the parameters, do so with a temporary array.
1.138 - * Otherwise, we could run into trouble with continual formats, a la ShowActivity().
1.139 - */
1.140 - memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
1.141 - ReorderTranslationParams(&pTrans, &new_params[*arg]);
1.142 -
1.143 - return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
1.144 - }
1.145 - else
1.146 - {
1.147 - return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
1.148 - }
1.149 -
1.150 -error_out:
1.151 - *error = true;
1.152 - return 0;
1.153 -}
1.154 -
1.155 -void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
1.156 -{
1.157 - int size = 0;
1.158 - char *buf;
1.159 - static char nlstr[] = {'(','n','u','l','l',')','\0'};
1.160 -
1.161 - buf = *buf_p;
1.162 -
1.163 - if (string == NULL)
1.164 - {
1.165 - string = nlstr;
1.166 - prec = -1;
1.167 - }
1.168 -
1.169 - if (prec >= 0)
1.170 - {
1.171 - for (size = 0; size < prec; size++)
1.172 - {
1.173 - if (string[size] == '\0')
1.174 - {
1.175 - break;
1.176 - }
1.177 - }
1.178 - }
1.179 - else
1.180 - {
1.181 - while (string[size++]);
1.182 - size--;
1.183 - }
1.184 -
1.185 - if (size > (int)maxlen)
1.186 - {
1.187 - size = maxlen;
1.188 - }
1.189 -
1.190 - maxlen -= size;
1.191 - width -= size;
1.192 -
1.193 - while (size--)
1.194 - {
1.195 - *buf++ = *string++;
1.196 - }
1.197 -
1.198 - while ((width-- > 0) && maxlen)
1.199 - {
1.200 - *buf++ = ' ';
1.201 - maxlen--;
1.202 - }
1.203 -
1.204 - *buf_p = buf;
1.205 -}
1.206 -
1.207 -void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
1.208 -{
1.209 - int digits; // non-fraction part digits
1.210 - double tmp; // temporary
1.211 - char *buf = *buf_p; // output buffer pointer
1.212 - int val; // temporary
1.213 - int sign = 0; // 0: positive, 1: negative
1.214 - int fieldlength; // for padding
1.215 - int significant_digits = 0; // number of significant digits written
1.216 - const int MAX_SIGNIFICANT_DIGITS = 16;
1.217 -
1.218 - // default precision
1.219 - if (prec < 0)
1.220 - {
1.221 - prec = 6;
1.222 - }
1.223 -
1.224 - // get the sign
1.225 - if (fval < 0)
1.226 - {
1.227 - fval = -fval;
1.228 - sign = 1;
1.229 - }
1.230 -
1.231 - // compute whole-part digits count
1.232 - digits = (int)log10(fval) + 1;
1.233 -
1.234 - // Only print 0.something if 0 < fval < 1
1.235 - if (digits < 1)
1.236 - {
1.237 - digits = 1;
1.238 - }
1.239 -
1.240 - // compute the field length
1.241 - fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
1.242 -
1.243 - // minus sign BEFORE left padding if padding with zeros
1.244 - if (sign && maxlen && (flags & ZEROPAD))
1.245 - {
1.246 - *buf++ = '-';
1.247 - maxlen--;
1.248 - }
1.249 -
1.250 - // right justify if required
1.251 - if ((flags & LADJUST) == 0)
1.252 - {
1.253 - while ((fieldlength < width) && maxlen)
1.254 - {
1.255 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.256 - width--;
1.257 - maxlen--;
1.258 - }
1.259 - }
1.260 -
1.261 - // minus sign AFTER left padding if padding with spaces
1.262 - if (sign && maxlen && !(flags & ZEROPAD))
1.263 - {
1.264 - *buf++ = '-';
1.265 - maxlen--;
1.266 - }
1.267 -
1.268 - // write the whole part
1.269 - tmp = pow(10.0, digits-1);
1.270 - while ((digits--) && maxlen)
1.271 - {
1.272 - if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
1.273 - {
1.274 - *buf++ = '0';
1.275 - }
1.276 - else
1.277 - {
1.278 - val = (int)(fval / tmp);
1.279 - *buf++ = '0' + val;
1.280 - fval -= val * tmp;
1.281 - tmp *= 0.1;
1.282 - }
1.283 - maxlen--;
1.284 - }
1.285 -
1.286 - // write the fraction part
1.287 - if (maxlen)
1.288 - {
1.289 - *buf++ = '.';
1.290 - maxlen--;
1.291 - }
1.292 -
1.293 - tmp = pow(10.0, prec);
1.294 -
1.295 - fval *= tmp;
1.296 - while (prec-- && maxlen)
1.297 - {
1.298 - if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
1.299 - {
1.300 - *buf++ = '0';
1.301 - }
1.302 - else
1.303 - {
1.304 - tmp *= 0.1;
1.305 - val = (int)(fval / tmp);
1.306 - *buf++ = '0' + val;
1.307 - fval -= val * tmp;
1.308 - }
1.309 - maxlen--;
1.310 - }
1.311 -
1.312 - // left justify if required
1.313 - if (flags & LADJUST)
1.314 - {
1.315 - while ((fieldlength < width) && maxlen)
1.316 - {
1.317 - // right-padding only with spaces, ZEROPAD is ignored
1.318 - *buf++ = ' ';
1.319 - width--;
1.320 - maxlen--;
1.321 - }
1.322 - }
1.323 -
1.324 - // update parent's buffer pointer
1.325 - *buf_p = buf;
1.326 -}
1.327 -
1.328 -void AddBinary(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
1.329 -{
1.330 - char text[32];
1.331 - int digits;
1.332 - char *buf;
1.333 -
1.334 - digits = 0;
1.335 - do
1.336 - {
1.337 - if (val & 1)
1.338 - {
1.339 - text[digits++] = '1';
1.340 - }
1.341 - else
1.342 - {
1.343 - text[digits++] = '0';
1.344 - }
1.345 - val >>= 1;
1.346 - } while (val);
1.347 -
1.348 - buf = *buf_p;
1.349 -
1.350 - if (!(flags & LADJUST))
1.351 - {
1.352 - while (digits < width && maxlen)
1.353 - {
1.354 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.355 - width--;
1.356 - maxlen--;
1.357 - }
1.358 - }
1.359 -
1.360 - while (digits-- && maxlen)
1.361 - {
1.362 - *buf++ = text[digits];
1.363 - width--;
1.364 - maxlen--;
1.365 - }
1.366 -
1.367 - if (flags & LADJUST)
1.368 - {
1.369 - while (width-- && maxlen)
1.370 - {
1.371 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.372 - maxlen--;
1.373 - }
1.374 - }
1.375 -
1.376 - *buf_p = buf;
1.377 -}
1.378 -
1.379 -void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
1.380 -{
1.381 - char text[32];
1.382 - int digits;
1.383 - char *buf;
1.384 -
1.385 - digits = 0;
1.386 - do
1.387 - {
1.388 - text[digits++] = '0' + val % 10;
1.389 - val /= 10;
1.390 - } while (val);
1.391 -
1.392 - buf = *buf_p;
1.393 -
1.394 - if (!(flags & LADJUST))
1.395 - {
1.396 - while (digits < width && maxlen)
1.397 - {
1.398 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.399 - width--;
1.400 - maxlen--;
1.401 - }
1.402 - }
1.403 -
1.404 - while (digits-- && maxlen)
1.405 - {
1.406 - *buf++ = text[digits];
1.407 - width--;
1.408 - maxlen--;
1.409 - }
1.410 -
1.411 - if (flags & LADJUST)
1.412 - {
1.413 - while (width-- && maxlen)
1.414 - {
1.415 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.416 - maxlen--;
1.417 - }
1.418 - }
1.419 -
1.420 - *buf_p = buf;
1.421 -}
1.422 -
1.423 -void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
1.424 -{
1.425 - char text[32];
1.426 - int digits;
1.427 - int signedVal;
1.428 - char *buf;
1.429 - unsigned int unsignedVal;
1.430 -
1.431 - digits = 0;
1.432 - signedVal = val;
1.433 - if (val < 0)
1.434 - {
1.435 - /* we want the unsigned version */
1.436 - unsignedVal = abs(val);
1.437 - }
1.438 - else
1.439 - {
1.440 - unsignedVal = val;
1.441 - }
1.442 -
1.443 - do
1.444 - {
1.445 - text[digits++] = '0' + unsignedVal % 10;
1.446 - unsignedVal /= 10;
1.447 - } while (unsignedVal);
1.448 -
1.449 - if (signedVal < 0)
1.450 - {
1.451 - text[digits++] = '-';
1.452 - }
1.453 -
1.454 - buf = *buf_p;
1.455 -
1.456 - if (!(flags & LADJUST))
1.457 - {
1.458 - while ((digits < width) && maxlen)
1.459 - {
1.460 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.461 - width--;
1.462 - maxlen--;
1.463 - }
1.464 - }
1.465 -
1.466 - while (digits-- && maxlen)
1.467 - {
1.468 - *buf++ = text[digits];
1.469 - width--;
1.470 - maxlen--;
1.471 - }
1.472 -
1.473 - if (flags & LADJUST)
1.474 - {
1.475 - while (width-- && maxlen)
1.476 - {
1.477 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.478 - maxlen--;
1.479 - }
1.480 - }
1.481 -
1.482 - *buf_p = buf;
1.483 -}
1.484 -
1.485 -void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
1.486 -{
1.487 - char text[32];
1.488 - int digits;
1.489 - char *buf;
1.490 - char digit;
1.491 - int hexadjust;
1.492 -
1.493 - if (flags & UPPERDIGITS)
1.494 - {
1.495 - hexadjust = 'A' - '9' - 1;
1.496 - }
1.497 - else
1.498 - {
1.499 - hexadjust = 'a' - '9' - 1;
1.500 - }
1.501 -
1.502 - digits = 0;
1.503 - do
1.504 - {
1.505 - digit = ('0' + val % 16);
1.506 - if (digit > '9')
1.507 - {
1.508 - digit += hexadjust;
1.509 - }
1.510 -
1.511 - text[digits++] = digit;
1.512 - val /= 16;
1.513 - } while(val);
1.514 -
1.515 - buf = *buf_p;
1.516 -
1.517 - if (!(flags & LADJUST))
1.518 - {
1.519 - while (digits < width && maxlen)
1.520 - {
1.521 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.522 - width--;
1.523 - maxlen--;
1.524 - }
1.525 - }
1.526 -
1.527 - while (digits-- && maxlen)
1.528 - {
1.529 - *buf++ = text[digits];
1.530 - width--;
1.531 - maxlen--;
1.532 - }
1.533 -
1.534 - if (flags & LADJUST)
1.535 - {
1.536 - while (width-- && maxlen)
1.537 - {
1.538 - *buf++ = (flags & ZEROPAD) ? '0' : ' ';
1.539 - maxlen--;
1.540 - }
1.541 - }
1.542 -
1.543 - *buf_p = buf;
1.544 -}
1.545 -
1.546 -bool gnprintf(char *buffer,
1.547 - size_t maxlen,
1.548 - const char *format,
1.549 - IPhraseCollection *pPhrases,
1.550 - void **params,
1.551 - unsigned int numparams,
1.552 - unsigned int &curparam,
1.553 - size_t *pOutLength,
1.554 - const char **pFailPhrase)
1.555 -{
1.556 - if (!buffer || !maxlen)
1.557 - {
1.558 - if (pOutLength != NULL)
1.559 - {
1.560 - *pOutLength = 0;
1.561 - }
1.562 - return true;
1.563 - }
1.564 -
1.565 - if (numparams > MAX_TRANSLATE_PARAMS)
1.566 - {
1.567 - if (pFailPhrase != NULL)
1.568 - {
1.569 - *pFailPhrase = NULL;
1.570 - }
1.571 - return false;
1.572 - }
1.573 -
1.574 - int arg = 0;
1.575 - char *buf_p;
1.576 - char ch;
1.577 - int flags;
1.578 - int width;
1.579 - int prec;
1.580 - int n;
1.581 - char sign;
1.582 - const char *fmt;
1.583 - size_t llen = maxlen - 1;
1.584 -
1.585 - buf_p = buffer;
1.586 - fmt = format;
1.587 -
1.588 - while (true)
1.589 - {
1.590 - // run through the format string until we hit a '%' or '\0'
1.591 - for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1.592 - {
1.593 - *buf_p++ = ch;
1.594 - llen--;
1.595 - }
1.596 - if ((ch == '\0') || (llen <= 0))
1.597 - {
1.598 - goto done;
1.599 - }
1.600 -
1.601 - // skip over the '%'
1.602 - fmt++;
1.603 -
1.604 - // reset formatting state
1.605 - flags = 0;
1.606 - width = 0;
1.607 - prec = -1;
1.608 - sign = '\0';
1.609 -
1.610 -rflag:
1.611 - ch = *fmt++;
1.612 -reswitch:
1.613 - switch(ch)
1.614 - {
1.615 - case '-':
1.616 - {
1.617 - flags |= LADJUST;
1.618 - goto rflag;
1.619 - }
1.620 - case '.':
1.621 - {
1.622 - n = 0;
1.623 - while(is_digit((ch = *fmt++)))
1.624 - {
1.625 - n = 10 * n + (ch - '0');
1.626 - }
1.627 - prec = (n < 0) ? -1 : n;
1.628 - goto reswitch;
1.629 - }
1.630 - case '0':
1.631 - {
1.632 - flags |= ZEROPAD;
1.633 - goto rflag;
1.634 - }
1.635 - case '1':
1.636 - case '2':
1.637 - case '3':
1.638 - case '4':
1.639 - case '5':
1.640 - case '6':
1.641 - case '7':
1.642 - case '8':
1.643 - case '9':
1.644 - {
1.645 - n = 0;
1.646 - do
1.647 - {
1.648 - n = 10 * n + (ch - '0');
1.649 - ch = *fmt++;
1.650 - } while(is_digit(ch));
1.651 - width = n;
1.652 - goto reswitch;
1.653 - }
1.654 - case 'c':
1.655 - {
1.656 - if (!llen)
1.657 - {
1.658 - goto done;
1.659 - }
1.660 - if (curparam >= numparams)
1.661 - {
1.662 - if (pFailPhrase != NULL)
1.663 - {
1.664 - *pFailPhrase = NULL;
1.665 - }
1.666 - return false;
1.667 - }
1.668 - char *c = (char *)params[curparam];
1.669 - curparam++;
1.670 - *buf_p++ = *c;
1.671 - llen--;
1.672 - arg++;
1.673 - break;
1.674 - }
1.675 - case 'b':
1.676 - {
1.677 - if (curparam >= numparams)
1.678 - {
1.679 - if (pFailPhrase != NULL)
1.680 - {
1.681 - *pFailPhrase = NULL;
1.682 - }
1.683 - return false;
1.684 - }
1.685 - int *value = (int *)params[curparam];
1.686 - curparam++;
1.687 - AddBinary(&buf_p, llen, *value, width, flags);
1.688 - arg++;
1.689 - break;
1.690 - }
1.691 - case 'd':
1.692 - case 'i':
1.693 - {
1.694 - if (curparam >= numparams)
1.695 - {
1.696 - if (pFailPhrase != NULL)
1.697 - {
1.698 - *pFailPhrase = NULL;
1.699 - }
1.700 - return false;
1.701 - }
1.702 - int *value = (int *)params[curparam];
1.703 - curparam++;
1.704 - AddInt(&buf_p, llen, *value, width, flags);
1.705 - arg++;
1.706 - break;
1.707 - }
1.708 - case 'u':
1.709 - {
1.710 - if (curparam >= numparams)
1.711 - {
1.712 - if (pFailPhrase != NULL)
1.713 - {
1.714 - *pFailPhrase = NULL;
1.715 - }
1.716 - return false;
1.717 - }
1.718 - unsigned int *value = (unsigned int *)params[curparam];
1.719 - curparam++;
1.720 - AddUInt(&buf_p, llen, *value, width, flags);
1.721 - arg++;
1.722 - break;
1.723 - }
1.724 - case 'f':
1.725 - {
1.726 - if (curparam >= numparams)
1.727 - {
1.728 - if (pFailPhrase != NULL)
1.729 - {
1.730 - *pFailPhrase = NULL;
1.731 - }
1.732 - return false;
1.733 - }
1.734 - float *value = (float *)params[curparam];
1.735 - curparam++;
1.736 - AddFloat(&buf_p, llen, *value, width, prec, flags);
1.737 - arg++;
1.738 - break;
1.739 - }
1.740 - case 's':
1.741 - {
1.742 - if (curparam >= numparams)
1.743 - {
1.744 - if (pFailPhrase != NULL)
1.745 - {
1.746 - *pFailPhrase = NULL;
1.747 - }
1.748 - return false;
1.749 - }
1.750 - const char *str = (const char *)params[curparam];
1.751 - curparam++;
1.752 - AddString(&buf_p, llen, str, width, prec);
1.753 - arg++;
1.754 - break;
1.755 - }
1.756 - case 'T':
1.757 - case 't':
1.758 - {
1.759 - int target;
1.760 - const char *key;
1.761 - size_t out_length;
1.762 - Translation trans;
1.763 - unsigned int lang_id;
1.764 -
1.765 - if (curparam >= numparams)
1.766 - {
1.767 - if (pFailPhrase != NULL)
1.768 - {
1.769 - *pFailPhrase = NULL;
1.770 - }
1.771 - return false;
1.772 - }
1.773 - key = (const char *)(params[curparam]);
1.774 - curparam++;
1.775 -
1.776 - if (ch == 'T')
1.777 - {
1.778 - if (curparam >= numparams)
1.779 - {
1.780 - if (pFailPhrase != NULL)
1.781 - {
1.782 - *pFailPhrase = NULL;
1.783 - }
1.784 - return false;
1.785 - }
1.786 - target = *((int *)(params[curparam]));
1.787 - curparam++;
1.788 - }
1.789 - else
1.790 - {
1.791 - target = g_Translator.GetGlobalTarget();
1.792 - }
1.793 -
1.794 -try_again:
1.795 - if (target == SOURCEMOD_SERVER_LANGUAGE)
1.796 - {
1.797 - lang_id = g_Translator.GetServerLanguage();
1.798 - }
1.799 - else if (target >= 1 && target <= g_Players.GetMaxClients())
1.800 - {
1.801 - lang_id = g_Translator.GetClientLanguage(target);
1.802 - }
1.803 - else
1.804 - {
1.805 - lang_id = g_Translator.GetServerLanguage();
1.806 - }
1.807 -
1.808 - if (pPhrases == NULL)
1.809 - {
1.810 - if (pFailPhrase != NULL)
1.811 - {
1.812 - *pFailPhrase = key;
1.813 - }
1.814 - return false;
1.815 - }
1.816 -
1.817 - if (pPhrases->FindTranslation(key, lang_id, &trans) != Trans_Okay)
1.818 - {
1.819 - if (target != SOURCEMOD_SERVER_LANGUAGE && lang_id != g_Translator.GetServerLanguage())
1.820 - {
1.821 - target = SOURCEMOD_SERVER_LANGUAGE;
1.822 - goto try_again;
1.823 - }
1.824 - else if (lang_id != SOURCEMOD_LANGUAGE_ENGLISH)
1.825 - {
1.826 - if (pPhrases->FindTranslation(key, SOURCEMOD_LANGUAGE_ENGLISH, &trans) != Trans_Okay)
1.827 - {
1.828 - if (pFailPhrase != NULL)
1.829 - {
1.830 - *pFailPhrase = key;
1.831 - }
1.832 - return false;
1.833 - }
1.834 - }
1.835 - else
1.836 - {
1.837 - if (pFailPhrase != NULL)
1.838 - {
1.839 - *pFailPhrase = key;
1.840 - }
1.841 - return false;
1.842 - }
1.843 - }
1.844 -
1.845 - if (trans.fmt_count)
1.846 - {
1.847 - unsigned int i;
1.848 - void *new_params[MAX_TRANSLATE_PARAMS];
1.849 -
1.850 - if (curparam + trans.fmt_count > numparams)
1.851 - {
1.852 - if (pFailPhrase != NULL)
1.853 - {
1.854 - *pFailPhrase = NULL;
1.855 - }
1.856 - return false;
1.857 - }
1.858 -
1.859 - /* Copy the array and re-order the stack */
1.860 - memcpy(new_params, params, sizeof(void *) * numparams);
1.861 - for (i = 0; i < trans.fmt_count; i++)
1.862 - {
1.863 - new_params[i] = const_cast<void *>(params[curparam + trans.fmt_order[i]]);
1.864 - }
1.865 -
1.866 - if (!gnprintf(buf_p,
1.867 - llen,
1.868 - trans.szPhrase,
1.869 - pPhrases,
1.870 - new_params,
1.871 - numparams,
1.872 - curparam,
1.873 - &out_length,
1.874 - pFailPhrase))
1.875 - {
1.876 - return false;
1.877 - }
1.878 - }
1.879 - else
1.880 - {
1.881 - if (!gnprintf(buf_p,
1.882 - llen,
1.883 - trans.szPhrase,
1.884 - pPhrases,
1.885 - params,
1.886 - numparams,
1.887 - curparam,
1.888 - &out_length,
1.889 - pFailPhrase))
1.890 - {
1.891 - return false;
1.892 - }
1.893 - }
1.894 -
1.895 - buf_p += out_length;
1.896 - llen -= out_length;
1.897 -
1.898 - break;
1.899 - }
1.900 - case 'X':
1.901 - {
1.902 - if (curparam >= numparams)
1.903 - {
1.904 - if (pFailPhrase != NULL)
1.905 - {
1.906 - *pFailPhrase = NULL;
1.907 - }
1.908 - return false;
1.909 - }
1.910 - unsigned int *value = (unsigned int *)params[curparam];
1.911 - curparam++;
1.912 - flags |= UPPERDIGITS;
1.913 - AddHex(&buf_p, llen, *value, width, flags);
1.914 - arg++;
1.915 - break;
1.916 - }
1.917 - case 'x':
1.918 - {
1.919 - if (curparam >= numparams)
1.920 - {
1.921 - if (pFailPhrase != NULL)
1.922 - {
1.923 - *pFailPhrase = NULL;
1.924 - }
1.925 - return false;
1.926 - }
1.927 - unsigned int *value = (unsigned int *)params[curparam];
1.928 - curparam++;
1.929 - AddHex(&buf_p, llen, *value, width, flags);
1.930 - arg++;
1.931 - break;
1.932 - }
1.933 - case '%':
1.934 - {
1.935 - if (!llen)
1.936 - {
1.937 - goto done;
1.938 - }
1.939 - *buf_p++ = ch;
1.940 - llen--;
1.941 - break;
1.942 - }
1.943 - case '\0':
1.944 - {
1.945 - if (!llen)
1.946 - {
1.947 - goto done;
1.948 - }
1.949 - *buf_p++ = '%';
1.950 - llen--;
1.951 - goto done;
1.952 - }
1.953 - default:
1.954 - {
1.955 - if (!llen)
1.956 - {
1.957 - goto done;
1.958 - }
1.959 - *buf_p++ = ch;
1.960 - llen--;
1.961 - break;
1.962 - }
1.963 - }
1.964 - }
1.965 -
1.966 -done:
1.967 - *buf_p = '\0';
1.968 -
1.969 - if (pOutLength != NULL)
1.970 - {
1.971 - *pOutLength = (maxlen - llen - 1);
1.972 - }
1.973 -
1.974 - return true;
1.975 -}
1.976 -
1.977 -size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
1.978 -{
1.979 - if (!buffer || !maxlen)
1.980 - {
1.981 - return 0;
1.982 - }
1.983 -
1.984 - int arg;
1.985 - int args = params[0];
1.986 - char *buf_p;
1.987 - char ch;
1.988 - int flags;
1.989 - int width;
1.990 - int prec;
1.991 - int n;
1.992 - char sign;
1.993 - const char *fmt;
1.994 - size_t llen = maxlen - 1;
1.995 -
1.996 - buf_p = buffer;
1.997 - arg = *param;
1.998 - fmt = format;
1.999 -
1.1000 - while (true)
1.1001 - {
1.1002 - // run through the format string until we hit a '%' or '\0'
1.1003 - for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
1.1004 - {
1.1005 - *buf_p++ = ch;
1.1006 - llen--;
1.1007 - }
1.1008 - if ((ch == '\0') || (llen <= 0))
1.1009 - {
1.1010 - goto done;
1.1011 - }
1.1012 -
1.1013 - // skip over the '%'
1.1014 - fmt++;
1.1015 -
1.1016 - // reset formatting state
1.1017 - flags = 0;
1.1018 - width = 0;
1.1019 - prec = -1;
1.1020 - sign = '\0';
1.1021 -
1.1022 -rflag:
1.1023 - ch = *fmt++;
1.1024 -reswitch:
1.1025 - switch(ch)
1.1026 - {
1.1027 - case '-':
1.1028 - {
1.1029 - flags |= LADJUST;
1.1030 - goto rflag;
1.1031 - }
1.1032 - case '.':
1.1033 - {
1.1034 - n = 0;
1.1035 - while(is_digit((ch = *fmt++)))
1.1036 - {
1.1037 - n = 10 * n + (ch - '0');
1.1038 - }
1.1039 - prec = (n < 0) ? -1 : n;
1.1040 - goto reswitch;
1.1041 - }
1.1042 - case '0':
1.1043 - {
1.1044 - flags |= ZEROPAD;
1.1045 - goto rflag;
1.1046 - }
1.1047 - case '1':
1.1048 - case '2':
1.1049 - case '3':
1.1050 - case '4':
1.1051 - case '5':
1.1052 - case '6':
1.1053 - case '7':
1.1054 - case '8':
1.1055 - case '9':
1.1056 - {
1.1057 - n = 0;
1.1058 - do
1.1059 - {
1.1060 - n = 10 * n + (ch - '0');
1.1061 - ch = *fmt++;
1.1062 - } while(is_digit(ch));
1.1063 - width = n;
1.1064 - goto reswitch;
1.1065 - }
1.1066 - case 'c':
1.1067 - {
1.1068 - CHECK_ARGS(0);
1.1069 - if (!llen)
1.1070 - {
1.1071 - goto done;
1.1072 - }
1.1073 - char *c;
1.1074 - pCtx->LocalToString(params[arg], &c);
1.1075 - *buf_p++ = *c;
1.1076 - llen--;
1.1077 - arg++;
1.1078 - break;
1.1079 - }
1.1080 - case 'b':
1.1081 - {
1.1082 - CHECK_ARGS(0);
1.1083 - cell_t *value;
1.1084 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1085 - AddBinary(&buf_p, llen, *value, width, flags);
1.1086 - arg++;
1.1087 - break;
1.1088 - }
1.1089 - case 'd':
1.1090 - case 'i':
1.1091 - {
1.1092 - CHECK_ARGS(0);
1.1093 - cell_t *value;
1.1094 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1095 - AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
1.1096 - arg++;
1.1097 - break;
1.1098 - }
1.1099 - case 'u':
1.1100 - {
1.1101 - CHECK_ARGS(0);
1.1102 - cell_t *value;
1.1103 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1104 - AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.1105 - arg++;
1.1106 - break;
1.1107 - }
1.1108 - case 'f':
1.1109 - {
1.1110 - CHECK_ARGS(0);
1.1111 - cell_t *value;
1.1112 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1113 - AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
1.1114 - arg++;
1.1115 - break;
1.1116 - }
1.1117 - case 'L':
1.1118 - {
1.1119 - CHECK_ARGS(0);
1.1120 - cell_t *value;
1.1121 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1122 - char buffer[255];
1.1123 - if (*value)
1.1124 - {
1.1125 - CPlayer *player = g_Players.GetPlayerByIndex(*value);
1.1126 - if (!player || !player->IsConnected())
1.1127 - {
1.1128 - return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1.1129 - }
1.1130 - const char *auth = player->GetAuthString();
1.1131 - if (!auth || auth[0] == '\0')
1.1132 - {
1.1133 - auth = "STEAM_ID_PENDING";
1.1134 - }
1.1135 - int userid = engine->GetPlayerUserId(player->GetEdict());
1.1136 - UTIL_Format(buffer,
1.1137 - sizeof(buffer),
1.1138 - "%s<%d><%s><>",
1.1139 - player->GetName(),
1.1140 - userid,
1.1141 - auth);
1.1142 - }
1.1143 - else
1.1144 - {
1.1145 - UTIL_Format(buffer,
1.1146 - sizeof(buffer),
1.1147 - "Console<0><Console><Console>");
1.1148 - }
1.1149 - AddString(&buf_p, llen, buffer, width, prec);
1.1150 - arg++;
1.1151 - break;
1.1152 - }
1.1153 - case 'N':
1.1154 - {
1.1155 - CHECK_ARGS(0);
1.1156 - cell_t *value;
1.1157 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1158 -
1.1159 - const char *name = "Console";
1.1160 - if (*value)
1.1161 - {
1.1162 - CPlayer *player = g_Players.GetPlayerByIndex(*value);
1.1163 - if (!player || !player->IsConnected())
1.1164 - {
1.1165 - return pCtx->ThrowNativeError("Client index %d is invalid", *value);
1.1166 - }
1.1167 - name = player->GetName();
1.1168 - }
1.1169 - AddString(&buf_p, llen, name, width, prec);
1.1170 - arg++;
1.1171 - break;
1.1172 - }
1.1173 - case 's':
1.1174 - {
1.1175 - CHECK_ARGS(0);
1.1176 - char *str;
1.1177 - int err;
1.1178 - if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
1.1179 - {
1.1180 - pCtx->ThrowNativeErrorEx(err, "Could not deference string");
1.1181 - return 0;
1.1182 - }
1.1183 - AddString(&buf_p, llen, str, width, prec);
1.1184 - arg++;
1.1185 - break;
1.1186 - }
1.1187 - case 'T':
1.1188 - {
1.1189 - CHECK_ARGS(1);
1.1190 - char *key;
1.1191 - bool error;
1.1192 - size_t res;
1.1193 - cell_t *target;
1.1194 - pCtx->LocalToString(params[arg++], &key);
1.1195 - pCtx->LocalToPhysAddr(params[arg++], &target);
1.1196 - res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
1.1197 - if (error)
1.1198 - {
1.1199 - return 0;
1.1200 - }
1.1201 - buf_p += res;
1.1202 - llen -= res;
1.1203 - break;
1.1204 - }
1.1205 - case 't':
1.1206 - {
1.1207 - CHECK_ARGS(0);
1.1208 - char *key;
1.1209 - bool error;
1.1210 - size_t res;
1.1211 - cell_t target = g_SourceMod.GetGlobalTarget();
1.1212 - pCtx->LocalToString(params[arg++], &key);
1.1213 - res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
1.1214 - if (error)
1.1215 - {
1.1216 - return 0;
1.1217 - }
1.1218 - buf_p += res;
1.1219 - llen -= res;
1.1220 - break;
1.1221 - }
1.1222 - case 'X':
1.1223 - {
1.1224 - CHECK_ARGS(0);
1.1225 - cell_t *value;
1.1226 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1227 - flags |= UPPERDIGITS;
1.1228 - AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.1229 - arg++;
1.1230 - break;
1.1231 - }
1.1232 - case 'x':
1.1233 - {
1.1234 - CHECK_ARGS(0);
1.1235 - cell_t *value;
1.1236 - pCtx->LocalToPhysAddr(params[arg], &value);
1.1237 - AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
1.1238 - arg++;
1.1239 - break;
1.1240 - }
1.1241 - case '%':
1.1242 - {
1.1243 - if (!llen)
1.1244 - {
1.1245 - goto done;
1.1246 - }
1.1247 - *buf_p++ = ch;
1.1248 - llen--;
1.1249 - break;
1.1250 - }
1.1251 - case '\0':
1.1252 - {
1.1253 - if (!llen)
1.1254 - {
1.1255 - goto done;
1.1256 - }
1.1257 - *buf_p++ = '%';
1.1258 - llen--;
1.1259 - goto done;
1.1260 - }
1.1261 - default:
1.1262 - {
1.1263 - if (!llen)
1.1264 - {
1.1265 - goto done;
1.1266 - }
1.1267 - *buf_p++ = ch;
1.1268 - llen--;
1.1269 - break;
1.1270 - }
1.1271 - }
1.1272 - }
1.1273 -
1.1274 -done:
1.1275 - *buf_p = '\0';
1.1276 - *param = arg;
1.1277 - return (maxlen - llen - 1);
1.1278 -}
1.1279 -
1.1280 -const char *stristr(const char *str, const char *substr)
1.1281 -{
1.1282 - if (!*substr)
1.1283 - {
1.1284 - return ((char *)str);
1.1285 - }
1.1286 -
1.1287 - char *needle = (char *)substr;
1.1288 - char *prevloc = (char *)str;
1.1289 - char *haystack = (char *)str;
1.1290 -
1.1291 - while (*haystack)
1.1292 - {
1.1293 - if (tolower(*haystack) == tolower(*needle))
1.1294 - {
1.1295 - haystack++;
1.1296 - if (!*++needle)
1.1297 - {
1.1298 - return prevloc;
1.1299 - }
1.1300 - }
1.1301 - else
1.1302 - {
1.1303 - haystack = ++prevloc;
1.1304 - needle = (char *)substr;
1.1305 - }
1.1306 - }
1.1307 -
1.1308 - return NULL;
1.1309 -}
1.1310 -
1.1311 -unsigned int strncopy(char *dest, const char *src, size_t count)
1.1312 -{
1.1313 - if (!count)
1.1314 - {
1.1315 - return 0;
1.1316 - }
1.1317 -
1.1318 - char *start = dest;
1.1319 - while ((*src) && (--count))
1.1320 - {
1.1321 - *dest++ = *src++;
1.1322 - }
1.1323 - *dest = '\0';
1.1324 -
1.1325 - return (dest - start);
1.1326 -}
1.1327 -
1.1328 -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1.1329 -{
1.1330 - va_list ap;
1.1331 - va_start(ap, fmt);
1.1332 - size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1.1333 - va_end(ap);
1.1334 -
1.1335 - if (len >= maxlength)
1.1336 - {
1.1337 - buffer[maxlength - 1] = '\0';
1.1338 - return (maxlength - 1);
1.1339 - }
1.1340 - else
1.1341 - {
1.1342 - return len;
1.1343 - }
1.1344 -}
1.1345 -
1.1346 -size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
1.1347 -{
1.1348 - size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1.1349 -
1.1350 - if (len >= maxlength)
1.1351 - {
1.1352 - buffer[maxlength - 1] = '\0';
1.1353 - return (maxlength - 1);
1.1354 - }
1.1355 - else
1.1356 - {
1.1357 - return len;
1.1358 - }
1.1359 -}
1.1360 -
1.1361 -char *sm_strdup(const char *str)
1.1362 -{
1.1363 - char *ptr = new char[strlen(str)+1];
1.1364 - strcpy(ptr, str);
1.1365 - return ptr;
1.1366 -}
1.1367 -
1.1368 -unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace)
1.1369 -{
1.1370 - size_t searchLen = strlen(search);
1.1371 - size_t replaceLen = strlen(replace);
1.1372 -
1.1373 - char *ptr = subject;
1.1374 - unsigned int total = 0;
1.1375 - while ((ptr = UTIL_ReplaceEx(ptr, maxlength, search, searchLen, replace, replaceLen)) != NULL)
1.1376 - {
1.1377 - total++;
1.1378 - if (*ptr == '\0')
1.1379 - {
1.1380 - break;
1.1381 - }
1.1382 - }
1.1383 -
1.1384 - return total;
1.1385 -}
1.1386 -
1.1387 -/**
1.1388 - * NOTE: Do not edit this for the love of god unless you have
1.1389 - * read the test cases and understand the code behind each one.
1.1390 - * While I don't guarantee there aren't mistakes, I do guarantee
1.1391 - * that plugins will end up relying on tiny idiosyncrasies of this
1.1392 - * function, just like they did with AMX Mod X.
1.1393 - *
1.1394 - * There are explicitly more cases than the AMX Mod X version because
1.1395 - * we're not doing a blind copy. Each case is specifically optimized
1.1396 - * for what needs to be done. Even better, we don't have to error on
1.1397 - * bad buffer sizes. Instead, this function will smartly cut off the
1.1398 - * string in a way that pushes old data out.
1.1399 - */
1.1400 -char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen)
1.1401 -{
1.1402 - char *ptr = subject;
1.1403 - size_t browsed = 0;
1.1404 - size_t textLen = strlen(subject);
1.1405 -
1.1406 - /* It's not possible to search or replace */
1.1407 - if (searchLen > textLen)
1.1408 - {
1.1409 - return NULL;
1.1410 - }
1.1411 -
1.1412 - /* Handle the case of one byte replacement.
1.1413 - * It's only valid in one case.
1.1414 - */
1.1415 - if (maxLen == 1)
1.1416 - {
1.1417 - /* If the search matches and the replace length is 0,
1.1418 - * we can just terminate the string and be done.
1.1419 - */
1.1420 - if (strcmp(subject, search) == 0 && replaceLen == 0)
1.1421 - {
1.1422 - *subject = '\0';
1.1423 - return subject;
1.1424 - }
1.1425 - else
1.1426 - {
1.1427 - return NULL;
1.1428 - }
1.1429 - }
1.1430 -
1.1431 - /* Subtract one off the maxlength so we can include the null terminator */
1.1432 - maxLen--;
1.1433 -
1.1434 - while (*ptr != '\0' && (browsed <= textLen - searchLen))
1.1435 - {
1.1436 - /* See if we get a comparison */
1.1437 - if (strncmp(ptr, search, searchLen) == 0)
1.1438 - {
1.1439 - if (replaceLen > searchLen)
1.1440 - {
1.1441 - /* First, see if we have enough space to do this operation */
1.1442 - if (maxLen - textLen < replaceLen - searchLen)
1.1443 - {
1.1444 - /* First, see if the replacement length goes out of bounds. */
1.1445 - if (browsed + replaceLen >= maxLen)
1.1446 - {
1.1447 - /* EXAMPLE CASE:
1.1448 - * Subject: AABBBCCC
1.1449 - * Buffer : 12 bytes
1.1450 - * Search : BBB
1.1451 - * Replace: DDDDDDDDDD
1.1452 - * OUTPUT : AADDDDDDDDD
1.1453 - * POSITION: ^
1.1454 - */
1.1455 - /* If it does, we'll just bound the length and do a strcpy. */
1.1456 - replaceLen = maxLen - browsed;
1.1457 - /* Note, we add one to the final result for the null terminator */
1.1458 - strncopy(ptr, replace, replaceLen+1);
1.1459 - }
1.1460 - else
1.1461 - {
1.1462 - /* EXAMPLE CASE:
1.1463 - * Subject: AABBBCCC
1.1464 - * Buffer : 12 bytes
1.1465 - * Search : BBB
1.1466 - * Replace: DDDDDDD
1.1467 - * OUTPUT : AADDDDDDDCC
1.1468 - * POSITION: ^
1.1469 - */
1.1470 - /* We're going to have some bytes left over... */
1.1471 - size_t origBytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1472 - size_t realBytesToCopy = (maxLen - (browsed + replaceLen)) + 1;
1.1473 - char *moveFrom = ptr + searchLen + (origBytesToCopy - realBytesToCopy);
1.1474 - char *moveTo = ptr + replaceLen;
1.1475 -
1.1476 - /* First, move our old data out of the way. */
1.1477 - memmove(moveTo, moveFrom, realBytesToCopy);
1.1478 -
1.1479 - /* Now, do our replacement. */
1.1480 - memcpy(ptr, replace, replaceLen);
1.1481 - }
1.1482 - }
1.1483 - else
1.1484 - {
1.1485 - /* EXAMPLE CASE:
1.1486 - * Subject: AABBBCCC
1.1487 - * Buffer : 12 bytes
1.1488 - * Search : BBB
1.1489 - * Replace: DDDD
1.1490 - * OUTPUT : AADDDDCCC
1.1491 - * POSITION: ^
1.1492 - */
1.1493 - /* Yes, we have enough space. Do a normal move operation. */
1.1494 - char *moveFrom = ptr + searchLen;
1.1495 - char *moveTo = ptr + replaceLen;
1.1496 -
1.1497 - /* First move our old data out of the way. */
1.1498 - size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1499 - memmove(moveTo, moveFrom, bytesToCopy);
1.1500 -
1.1501 - /* Now do our replacement. */
1.1502 - memcpy(ptr, replace, replaceLen);
1.1503 - }
1.1504 - }
1.1505 - else if (replaceLen < searchLen)
1.1506 - {
1.1507 - /* EXAMPLE CASE:
1.1508 - * Subject: AABBBCCC
1.1509 - * Buffer : 12 bytes
1.1510 - * Search : BBB
1.1511 - * Replace: D
1.1512 - * OUTPUT : AADCCC
1.1513 - * POSOTION: ^
1.1514 - */
1.1515 - /* If the replacement does not grow the string length, we do not
1.1516 - * need to do any fancy checking at all. Yay!
1.1517 - */
1.1518 - char *moveFrom = ptr + searchLen; /* Start after the search pointer */
1.1519 - char *moveTo = ptr + replaceLen; /* Copy to where the replacement ends */
1.1520 -
1.1521 - /* Copy our replacement in, if any */
1.1522 - if (replaceLen)
1.1523 - {
1.1524 - memcpy(ptr, replace, replaceLen);
1.1525 - }
1.1526 -
1.1527 - /* Figure out how many bytes to move down, including null terminator */
1.1528 - size_t bytesToCopy = (textLen - (browsed + searchLen)) + 1;
1.1529 -
1.1530 - /* Move the rest of the string down */
1.1531 - memmove(moveTo, moveFrom, bytesToCopy);
1.1532 - }
1.1533 - else
1.1534 - {
1.1535 - /* EXAMPLE CASE:
1.1536 - * Subject: AABBBCCC
1.1537 - * Buffer : 12 bytes
1.1538 - * Search : BBB
1.1539 - * Replace: DDD
1.1540 - * OUTPUT : AADDDCCC
1.1541 - * POSITION: ^
1.1542 - */
1.1543 - /* We don't have to move anything around, just do a straight copy */
1.1544 - memcpy(ptr, replace, replaceLen);
1.1545 - }
1.1546 -
1.1547 - return ptr + replaceLen;
1.1548 - }
1.1549 - ptr++;
1.1550 - browsed++;
1.1551 - }
1.1552 -
1.1553 - return NULL;
1.1554 -}
1.1555 -
1.1556 -char *UTIL_TrimWhitespace(char *str, size_t &len)
1.1557 -{
1.1558 - char *end = str + len - 1;
1.1559 -
1.1560 - if (!len)
1.1561 - {
1.1562 - return str;
1.1563 - }
1.1564 -
1.1565 - /* Iterate backwards through string until we reach first non-whitespace char */
1.1566 - while (end >= str && textparsers->IsWhitespace(end))
1.1567 - {
1.1568 - end--;
1.1569 - len--;
1.1570 - }
1.1571 -
1.1572 - /* Replace first whitespace char (at the end) with null terminator.
1.1573 - * If there is none, we're just replacing the null terminator.
1.1574 - */
1.1575 - *(end + 1) = '\0';
1.1576 -
1.1577 - while (*str != '\0' && textparsers->IsWhitespace(str))
1.1578 - {
1.1579 - str++;
1.1580 - len--;
1.1581 - }
1.1582 -
1.1583 - return str;
1.1584 -}
1.1585 -