2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
17 #include "sm_stringutil.h"
19 #include "PluginSys.h"
20 #include "CTranslator.h"
21 #include "CPlayerManager.h"
23 #define LADJUST 0x00000004 /* left adjustment */
24 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
25 #define to_digit(c) ((c) - '0')
26 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
28 #define CHECK_ARGS(x) \
29 if ((arg+x) > args) { \
30 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
34 inline bool TryServerLanguage(const char *serverlang, unsigned int *langid)
36 if (!g_Translator.GetLanguageByCode(serverlang, langid))
38 if (!g_Translator.GetLanguageByCode("en", langid))
46 inline bool TryTranslation(CPlugin *pl, const char *key, unsigned int langid, unsigned int langcount, Translation *pTrans)
48 TransError err = Trans_BadLanguage;
51 for (size_t i=0; i<langcount && err!=Trans_Okay; i++)
53 phrfl = g_Translator.GetFileByIndex(pl->GetLangFileByIndex(i));
54 err = phrfl->GetTranslation(key, langid, pTrans);
57 return (err == Trans_Okay) ? true : false;
60 size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *key, cell_t target, const cell_t *params, int *arg, bool *error)
63 char *langname = NULL;
66 CPlugin *pl = (CPlugin *)g_PluginSys.FindPluginByContext(pCtx->GetContext());
67 size_t langcount = pl->GetLangFileCount();
68 void *new_params[MAX_TRANSLATE_PARAMS];
69 unsigned int max_params = 0;
72 if (target == LANG_SERVER)
74 langname = "en"; //:TODO: read serverlang
75 if (!TryServerLanguage(langname ? langname : "en", &langid))
77 pCtx->ThrowNativeError("Translation failure: English language not found");
80 } else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
81 langname = "en"; //:TODO: read player's lang
82 if (!langname || !g_Translator.GetLanguageByCode(langname, &langid))
84 if (langname && !strcmp(langname, "en"))
86 pCtx->ThrowNativeError("Translation failure: English language not found");
93 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
97 if (!TryTranslation(pl, key, langid, langcount, &pTrans))
99 if (target != LANG_SERVER)
101 target = LANG_SERVER;
104 if (!g_Translator.GetLanguageByCode("en", &langid)
105 || !TryTranslation(pl, key, langid, langcount, &pTrans))
107 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
113 max_params = pTrans.fmt_count;
115 for (size_t i=0; i<max_params; i++)
117 pCtx->LocalToPhysAddr(params[*arg], reinterpret_cast<cell_t **>(&new_params[i]));
119 if ((*arg) + i > (size_t)params[0])
121 pCtx->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, "Translation string formatted incorrectly - parameter %d (total %d)", (*arg) + i, params[0]);
126 return g_Translator.Translate(buffer, maxlen, new_params, &pTrans);
132 //:TODO: review this code before we choose a license
134 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
138 static char nlstr[] = {'(','n','u','l','l',')','\0'};
150 for (size = 0; size < prec; size++)
152 if (string[size] == '\0')
158 while (string[size++]);
162 if (size > (int)maxlen)
175 while ((width-- > 0) && maxlen)
184 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
199 // write the float number
204 text[digits++] = '0' + val % 10;
210 text[digits++] = '-';
215 while ((digits < width) && maxlen)
222 while ((digits--) && maxlen)
224 *buf++ = text[digits];
234 // write the fraction
236 while (digits < prec)
241 text[digits++] = '0' + val % 10;
244 if ((digits > 0) && maxlen)
249 for (prec = 0; maxlen && (prec < digits); prec++)
258 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
267 text[digits++] = '0' + val % 10;
273 if (!(flags & LADJUST))
275 while (digits < width && maxlen)
277 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
283 while (digits-- && maxlen)
285 *buf++ = text[digits];
292 while (width-- && maxlen)
294 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
302 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
308 unsigned int unsignedVal;
314 /* we want the unsigned version */
315 unsignedVal = abs(val);
321 text[digits++] = '0' + unsignedVal % 10;
323 } while (unsignedVal);
327 text[digits++] = '-';
332 if (!(flags & LADJUST))
334 while ((digits < width) && maxlen)
336 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
342 while (digits-- && maxlen)
344 *buf++ = text[digits];
351 while (width-- && maxlen)
353 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
361 size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args)
363 if (!buffer || !maxlen)
377 size_t llen = maxlen - 1;
384 // run through the format string until we hit a '%' or '\0'
385 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
390 if ((ch == '\0') || (llen <= 0))
398 // reset formatting state
417 while(is_digit((ch = *fmt++)))
419 n = 10 * n + (ch - '0');
421 prec = (n < 0) ? -1 : n;
442 n = 10 * n + (ch - '0');
444 } while(is_digit(ch));
454 char *c = (char *)args[arg];
463 int *value = (int *)args[arg];
464 AddInt(&buf_p, llen, *value, width, flags);
470 unsigned int *value = (unsigned int *)args[arg];
471 AddUInt(&buf_p, llen, *value, width, flags);
477 float *value = (float *)args[arg];
478 AddFloat(&buf_p, llen, *value, width, prec);
484 const char *str = (const char *)args[arg];
485 AddString(&buf_p, llen, str, width, prec);
525 return (maxlen - llen - 1);
528 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
530 if (!buffer || !maxlen)
536 int args = params[0];
545 size_t llen = maxlen - 1;
553 // run through the format string until we hit a '%' or '\0'
554 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
559 if ((ch == '\0') || (llen <= 0))
567 // reset formatting state
586 while(is_digit((ch = *fmt++)))
588 n = 10 * n + (ch - '0');
590 prec = (n < 0) ? -1 : n;
611 n = 10 * n + (ch - '0');
613 } while(is_digit(ch));
625 pCtx->LocalToString(params[arg], &c);
636 pCtx->LocalToPhysAddr(params[arg], &value);
637 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
645 pCtx->LocalToPhysAddr(params[arg], &value);
646 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
654 pCtx->LocalToPhysAddr(params[arg], &value);
655 AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
663 pCtx->LocalToString(params[arg], &str);
664 AddString(&buf_p, llen, str, width, prec);
674 cell_t target = params[arg++];
675 pCtx->LocalToString(params[arg++], &key);
676 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
691 cell_t target = g_SourceMod.GetGlobalTarget();
692 pCtx->LocalToString(params[arg++], &key);
693 res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
738 return (maxlen - llen - 1);
741 const char *stristr(const char *str, const char *substr)
745 return ((char *)str);
748 char *needle = (char *)substr;
749 char *prevloc = (char *)str;
750 char *haystack = (char *)str;
754 if (tolower(*haystack) == tolower(*needle))
762 haystack = ++prevloc;
763 needle = (char *)substr;
770 unsigned int strncopy(char *dest, const char *src, size_t count)
778 while ((*src) && (--count))
784 return (dest - start);
787 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
791 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
794 return (len >= maxlength) ? (maxlength - 1) : len;
797 char *sm_strdup(const char *str)
799 char *ptr = new char[strlen(str)+1];