3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
18 #include "sm_stringutil.h"
20 #include "PluginSys.h"
21 #include "Translator.h"
22 #include "PlayerManager.h"
24 #define LADJUST 0x00000004 /* left adjustment */
25 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
26 #define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
27 #define to_digit(c) ((c) - '0')
28 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
30 #define CHECK_ARGS(x) \
31 if ((arg+x) > args) { \
32 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
36 inline bool TryServerLanguage(const char *serverlang, unsigned int *langid)
38 if (!g_Translator.GetLanguageByCode(serverlang, langid))
40 if (!g_Translator.GetLanguageByCode("en", langid))
48 inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans)
50 TransError err = Trans_BadLanguage;
53 for (size_t i=0; i<langcount && err!=Trans_Okay; i++)
55 phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i));
56 err = phrfl->GetTranslation(key, langid, pTrans);
59 return (err == Trans_Okay) ? true : false;
62 size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error)
65 const char *langname = NULL;
68 CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
69 size_t langcount = pl->GetLangFileCount();
70 void *new_params[MAX_TRANSLATE_PARAMS];
71 unsigned int max_params = 0;
74 if (target == LANG_SERVER)
76 langid = g_Translator.GetServerLanguage();
77 } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
78 langid = g_Translator.GetServerLanguage();
80 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
84 if (!TryTranslation(pl, key, langid, langcount, &pTrans))
86 if (target != LANG_SERVER)
90 } else if (langid != LANGUAGE_ENGLISH) {
91 if (!TryTranslation(pl, key, LANGUAGE_ENGLISH, langcount, &pTrans))
93 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
99 max_params = pTrans.fmt_count;
101 for (size_t i=0; i<max_params; i++)
103 pCtx->LocalToPhysAddr(params[*arg], reinterpret_cast<cell_t **>(&new_params[i]));
105 if ((*arg) + i > (size_t)params[0])
107 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "Translation string formatted incorrectly - parameter %d (total %d)", (*arg) + i, params[0]);
112 return g_Translator.Translate(buffer, maxlen, new_params, &pTrans);
118 //:TODO: review this code before we choose a license
120 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
124 static char nlstr[] = {'(','n','u','l','l',')','\0'};
136 for (size = 0; size < prec; size++)
138 if (string[size] == '\0')
144 while (string[size++]);
148 if (size > (int)maxlen)
161 while ((width-- > 0) && maxlen)
170 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
185 // write the float number
190 text[digits++] = '0' + val % 10;
196 text[digits++] = '-';
201 while ((digits < width) && maxlen)
208 while ((digits--) && maxlen)
210 *buf++ = text[digits];
220 // write the fraction
222 while (digits < prec)
227 text[digits++] = '0' + val % 10;
230 if ((digits > 0) && maxlen)
235 for (prec = 0; maxlen && (prec < digits); prec++)
244 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
253 text[digits++] = '0' + val % 10;
259 if (!(flags & LADJUST))
261 while (digits < width && maxlen)
263 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
269 while (digits-- && maxlen)
271 *buf++ = text[digits];
278 while (width-- && maxlen)
280 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
288 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
294 unsigned int unsignedVal;
300 /* we want the unsigned version */
301 unsignedVal = abs(val);
307 text[digits++] = '0' + unsignedVal % 10;
309 } while (unsignedVal);
313 text[digits++] = '-';
318 if (!(flags & LADJUST))
320 while ((digits < width) && maxlen)
322 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
328 while (digits-- && maxlen)
330 *buf++ = text[digits];
337 while (width-- && maxlen)
339 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
347 void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
355 if (flags & UPPERDIGITS)
357 hexadjust = 'A' - '9' - 1;
359 hexadjust = 'a' - '9' - 1;
365 digit = ('0' + val % 16);
371 text[digits++] = digit;
377 if (!(flags & LADJUST))
379 while (digits < width && maxlen)
381 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
387 while (digits-- && maxlen)
389 *buf++ = text[digits];
396 while (width-- && maxlen)
398 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
406 size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
408 if (!buffer || !maxlen)
422 size_t llen = maxlen - 1;
429 // run through the format string until we hit a '%' or '\0'
430 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
435 if ((ch == '\0') || (llen <= 0))
443 // reset formatting state
462 while(is_digit((ch = *fmt++)))
464 n = 10 * n + (ch - '0');
466 prec = (n < 0) ? -1 : n;
487 n = 10 * n + (ch - '0');
489 } while(is_digit(ch));
499 char *c = (char *)args[arg];
508 int *value = (int *)args[arg];
509 AddInt(&buf_p, llen, *value, width, flags);
515 unsigned int *value = (unsigned int *)args[arg];
516 AddUInt(&buf_p, llen, *value, width, flags);
522 float *value = (float *)args[arg];
523 AddFloat(&buf_p, llen, *value, width, prec);
529 const char *str = (const char *)args[arg];
530 AddString(&buf_p, llen, str, width, prec);
536 unsigned int *value = (unsigned int *)args[arg];
537 flags |= UPPERDIGITS;
538 AddHex(&buf_p, llen, *value, width, flags);
544 unsigned int *value = (unsigned int *)args[arg];
545 AddHex(&buf_p, llen, *value, width, flags);
585 return (maxlen - llen - 1);
588 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
590 if (!buffer || !maxlen)
596 int args = params[0];
605 size_t llen = maxlen - 1;
613 // run through the format string until we hit a '%' or '\0'
614 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
619 if ((ch == '\0') || (llen <= 0))
627 // reset formatting state
646 while(is_digit((ch = *fmt++)))
648 n = 10 * n + (ch - '0');
650 prec = (n < 0) ? -1 : n;
671 n = 10 * n + (ch - '0');
673 } while(is_digit(ch));
685 pCtx->LocalToString(params[arg], &c);
696 pCtx->LocalToPhysAddr(params[arg], &value);
697 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
705 pCtx->LocalToPhysAddr(params[arg], &value);
706 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
714 pCtx->LocalToPhysAddr(params[arg], &value);
715 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
724 if ((err=pCtx->LocalToString(params[arg], &str)) != SP_ERROR_NONE)
726 pCtx->ThrowNativeErrorEx(err, "Could not deference string");
729 AddString(&buf_p, llen, str, width, prec);
740 pCtx->LocalToPhysAddr(params[arg++], &target);
741 pCtx->LocalToString(params[arg++], &key);
742 printf("target = %d\n", target);
743 res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
758 cell_t target = g_SourceMod.GetGlobalTarget();
759 pCtx->LocalToString(params[arg++], &key);
760 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
773 pCtx->LocalToPhysAddr(params[arg], &value);
774 flags |= UPPERDIGITS;
775 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
783 pCtx->LocalToPhysAddr(params[arg], &value);
784 AddHex(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
824 return (maxlen - llen - 1);
827 const char *stristr(const char *str, const char *substr)
831 return ((char *)str);
834 char *needle = (char *)substr;
835 char *prevloc = (char *)str;
836 char *haystack = (char *)str;
840 if (tolower(*haystack) == tolower(*needle))
848 haystack = ++prevloc;
849 needle = (char *)substr;
856 unsigned int strncopy(char *dest, const char *src, size_t count)
864 while ((*src) && (--count))
870 return (dest - start);
873 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
877 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
880 if (len >= maxlength)
882 buffer[maxlength - 1] = '\0';
883 return (maxlength - 1);
889 size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
891 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
893 if (len >= maxlength)
895 buffer[maxlength - 1] = '\0';
896 return (maxlength - 1);
902 char *sm_strdup(const char *str)
904 char *ptr = new char[strlen(str)+1];