00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "core/alloc_func.hpp"
00015 #include "core/math_func.hpp"
00016 #include "string_func.h"
00017
00018 #include "table/control_codes.h"
00019
00020 #include <stdarg.h>
00021 #include <ctype.h>
00022
00023 #ifdef _MSC_VER
00024 #include <errno.h>
00025 #endif
00026
00037 static int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
00038 {
00039 ptrdiff_t diff = last - str;
00040 if (diff < 0) return 0;
00041 return min((int)diff, vsnprintf(str, diff + 1, format, ap));
00042 }
00043
00044 void ttd_strlcat(char *dst, const char *src, size_t size)
00045 {
00046 assert(size > 0);
00047 while (size > 0 && *dst != '\0') {
00048 size--;
00049 dst++;
00050 }
00051
00052 ttd_strlcpy(dst, src, size);
00053 }
00054
00055
00056 void ttd_strlcpy(char *dst, const char *src, size_t size)
00057 {
00058 assert(size > 0);
00059 while (--size > 0 && *src != '\0') {
00060 *dst++ = *src++;
00061 }
00062 *dst = '\0';
00063 }
00064
00065
00066 char *strecat(char *dst, const char *src, const char *last)
00067 {
00068 assert(dst <= last);
00069 while (*dst != '\0') {
00070 if (dst == last) return dst;
00071 dst++;
00072 }
00073
00074 return strecpy(dst, src, last);
00075 }
00076
00077
00078 char *strecpy(char *dst, const char *src, const char *last)
00079 {
00080 assert(dst <= last);
00081 while (dst != last && *src != '\0') {
00082 *dst++ = *src++;
00083 }
00084 *dst = '\0';
00085
00086 if (dst == last && *src != '\0') {
00087 #ifdef STRGEN
00088 error("String too long for destination buffer");
00089 #else
00090 DEBUG(misc, 0, "String too long for destination buffer");
00091 #endif
00092 }
00093 return dst;
00094 }
00095
00096
00097 char *CDECL str_fmt(const char *str, ...)
00098 {
00099 char buf[4096];
00100 va_list va;
00101
00102 va_start(va, str);
00103 int len = vseprintf(buf, lastof(buf), str, va);
00104 va_end(va);
00105 char *p = MallocT<char>(len + 1);
00106 memcpy(p, buf, len + 1);
00107 return p;
00108 }
00109
00110
00111 void str_validate(char *str, const char *last, bool allow_newlines, bool ignore)
00112 {
00113
00114
00115 char *dst = str;
00116 while (*str != '\0') {
00117 size_t len = Utf8EncodedCharLen(*str);
00118
00119
00120
00121
00122
00123 if ((len == 0 && str + 4 > last) || str + len > last) break;
00124
00125 WChar c;
00126 len = Utf8Decode(&c, str);
00127
00128
00129
00130 if (c == '\0') break;
00131
00132 if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) {
00133
00134
00135
00136 do {
00137 *dst++ = *str++;
00138 } while (--len != 0);
00139 } else if (allow_newlines && c == '\n') {
00140 *dst++ = *str++;
00141 } else {
00142 if (allow_newlines && c == '\r' && str[1] == '\n') {
00143 str += len;
00144 continue;
00145 }
00146
00147 str += len;
00148 if (!ignore) *dst++ = '?';
00149 }
00150 }
00151
00152 *dst = '\0';
00153 }
00154
00155
00156 void str_strip_colours(char *str)
00157 {
00158 char *dst = str;
00159 WChar c;
00160 size_t len;
00161
00162 for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
00163 if (c < SCC_BLUE || c > SCC_BLACK) {
00164
00165
00166
00167 do {
00168 *dst++ = *str++;
00169 } while (--len != 0);
00170 } else {
00171
00172 str += len;
00173 }
00174 }
00175 *dst = '\0';
00176 }
00177
00186 void strtolower(char *str)
00187 {
00188 for (; *str != '\0'; str++) *str = tolower(*str);
00189 }
00190
00198 bool IsValidChar(WChar key, CharSetFilter afilter)
00199 {
00200 switch (afilter) {
00201 case CS_ALPHANUMERAL: return IsPrintable(key);
00202 case CS_NUMERAL: return (key >= '0' && key <= '9');
00203 case CS_NUMERAL_SPACE: return (key >= '0' && key <= '9') || key == ' ';
00204 case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9');
00205 }
00206
00207 return false;
00208 }
00209
00210 #ifdef WIN32
00211
00212 #if (__MINGW32_MAJOR_VERSION < 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION < 14))
00213 int CDECL snprintf(char *str, size_t size, const char *format, ...)
00214 {
00215 va_list ap;
00216 int ret;
00217
00218 va_start(ap, format);
00219 ret = vsnprintf(str, size, format, ap);
00220 va_end(ap);
00221 return ret;
00222 }
00223 #endif
00224
00225 #ifdef _MSC_VER
00226
00233 int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
00234 {
00235 if (size == 0) return 0;
00236
00237 errno = 0;
00238 int ret = _vsnprintf(str, size, format, ap);
00239
00240 if (ret < 0) {
00241 if (errno != ERANGE) {
00242
00243
00244 NOT_REACHED();
00245 }
00246 } else if ((size_t)ret < size) {
00247
00248
00249
00250 return ret;
00251 }
00252
00253
00254
00255 str[size - 1] = '\0';
00256 return size;
00257 }
00258 #endif
00259
00260 #endif
00261
00271 int CDECL seprintf(char *str, const char *last, const char *format, ...)
00272 {
00273 va_list ap;
00274
00275 va_start(ap, format);
00276 int ret = vseprintf(str, last, format, ap);
00277 va_end(ap);
00278 return ret;
00279 }
00280
00281
00287 char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16])
00288 {
00289 char *p = buf;
00290
00291 for (uint i = 0; i < 16; i++) {
00292 p += seprintf(p, last, "%02X", md5sum[i]);
00293 }
00294
00295 return p;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 size_t Utf8Decode(WChar *c, const char *s)
00308 {
00309 assert(c != NULL);
00310
00311 if (!HasBit(s[0], 7)) {
00312
00313 *c = s[0];
00314 return 1;
00315 } else if (GB(s[0], 5, 3) == 6) {
00316 if (IsUtf8Part(s[1])) {
00317
00318 *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
00319 if (*c >= 0x80) return 2;
00320 }
00321 } else if (GB(s[0], 4, 4) == 14) {
00322 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
00323
00324 *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
00325 if (*c >= 0x800) return 3;
00326 }
00327 } else if (GB(s[0], 3, 5) == 30) {
00328 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
00329
00330 *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
00331 if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
00332 }
00333 }
00334
00335
00336 *c = '?';
00337 return 1;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 size_t Utf8Encode(char *buf, WChar c)
00347 {
00348 if (c < 0x80) {
00349 *buf = c;
00350 return 1;
00351 } else if (c < 0x800) {
00352 *buf++ = 0xC0 + GB(c, 6, 5);
00353 *buf = 0x80 + GB(c, 0, 6);
00354 return 2;
00355 } else if (c < 0x10000) {
00356 *buf++ = 0xE0 + GB(c, 12, 4);
00357 *buf++ = 0x80 + GB(c, 6, 6);
00358 *buf = 0x80 + GB(c, 0, 6);
00359 return 3;
00360 } else if (c < 0x110000) {
00361 *buf++ = 0xF0 + GB(c, 18, 3);
00362 *buf++ = 0x80 + GB(c, 12, 6);
00363 *buf++ = 0x80 + GB(c, 6, 6);
00364 *buf = 0x80 + GB(c, 0, 6);
00365 return 4;
00366 }
00367
00368
00369 *buf = '?';
00370 return 1;
00371 }
00372
00380 size_t Utf8TrimString(char *s, size_t maxlen)
00381 {
00382 size_t length = 0;
00383
00384 for (const char *ptr = strchr(s, '\0'); *s != '\0';) {
00385 size_t len = Utf8EncodedCharLen(*s);
00386
00387 if (len == 0) len = 1;
00388
00389
00390
00391 if (length + len >= maxlen || (s + len > ptr)) break;
00392 s += len;
00393 length += len;
00394 }
00395
00396 *s = '\0';
00397 return length;
00398 }
00399
00400 #ifndef _GNU_SOURCE
00401 #include "core/math_func.hpp"
00402 char *strndup(const char *s, size_t len)
00403 {
00404 len = min(strlen(s), len);
00405 char *tmp = CallocT<char>(len + 1);
00406 memcpy(tmp, s, len);
00407 return tmp;
00408 }
00409 #endif
00410
00411 #ifdef DEFINE_STRCASESTR
00412 char *strcasestr(const char *haystack, const char *needle)
00413 {
00414 size_t hay_len = strlen(haystack);
00415 size_t needle_len = strlen(needle);
00416 while (hay_len >= needle_len) {
00417 if (strncasecmp(haystack, needle, needle_len) == 0) return const_cast<char *>(haystack);
00418
00419 haystack++;
00420 hay_len--;
00421 }
00422
00423 return NULL;
00424 }
00425 #endif