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 <= last && *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
00153
00154 if (c == SCC_SETX) {
00155 str++;
00156 } else if (c == SCC_SETXY) {
00157 str += 2;
00158 }
00159 }
00160 }
00161
00162 *dst = '\0';
00163 }
00164
00165
00166 void str_strip_colours(char *str)
00167 {
00168 char *dst = str;
00169 WChar c;
00170 size_t len;
00171
00172 for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
00173 if (c < SCC_BLUE || c > SCC_BLACK) {
00174
00175
00176
00177 do {
00178 *dst++ = *str++;
00179 } while (--len != 0);
00180 } else {
00181
00182 str += len;
00183 }
00184 }
00185 *dst = '\0';
00186 }
00187
00196 void strtolower(char *str)
00197 {
00198 for (; *str != '\0'; str++) *str = tolower(*str);
00199 }
00200
00208 bool IsValidChar(WChar key, CharSetFilter afilter)
00209 {
00210 switch (afilter) {
00211 case CS_ALPHANUMERAL: return IsPrintable(key);
00212 case CS_NUMERAL: return (key >= '0' && key <= '9');
00213 case CS_NUMERAL_SPACE: return (key >= '0' && key <= '9') || key == ' ';
00214 case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9');
00215 }
00216
00217 return false;
00218 }
00219
00220 #ifdef WIN32
00221
00222 #if (__MINGW32_MAJOR_VERSION < 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION < 14))
00223 int CDECL snprintf(char *str, size_t size, const char *format, ...)
00224 {
00225 va_list ap;
00226 int ret;
00227
00228 va_start(ap, format);
00229 ret = vsnprintf(str, size, format, ap);
00230 va_end(ap);
00231 return ret;
00232 }
00233 #endif
00234
00235 #ifdef _MSC_VER
00236
00243 int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
00244 {
00245 if (size == 0) return 0;
00246
00247 errno = 0;
00248 int ret = _vsnprintf(str, size, format, ap);
00249
00250 if (ret < 0) {
00251 if (errno != ERANGE) {
00252
00253
00254 NOT_REACHED();
00255 }
00256 } else if ((size_t)ret < size) {
00257
00258
00259
00260 return ret;
00261 }
00262
00263
00264
00265 str[size - 1] = '\0';
00266 return (int)size;
00267 }
00268 #endif
00269
00270 #endif
00271
00281 int CDECL seprintf(char *str, const char *last, const char *format, ...)
00282 {
00283 va_list ap;
00284
00285 va_start(ap, format);
00286 int ret = vseprintf(str, last, format, ap);
00287 va_end(ap);
00288 return ret;
00289 }
00290
00291
00297 char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16])
00298 {
00299 char *p = buf;
00300
00301 for (uint i = 0; i < 16; i++) {
00302 p += seprintf(p, last, "%02X", md5sum[i]);
00303 }
00304
00305 return p;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 size_t Utf8Decode(WChar *c, const char *s)
00318 {
00319 assert(c != NULL);
00320
00321 if (!HasBit(s[0], 7)) {
00322
00323 *c = s[0];
00324 return 1;
00325 } else if (GB(s[0], 5, 3) == 6) {
00326 if (IsUtf8Part(s[1])) {
00327
00328 *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
00329 if (*c >= 0x80) return 2;
00330 }
00331 } else if (GB(s[0], 4, 4) == 14) {
00332 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
00333
00334 *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
00335 if (*c >= 0x800) return 3;
00336 }
00337 } else if (GB(s[0], 3, 5) == 30) {
00338 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
00339
00340 *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
00341 if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
00342 }
00343 }
00344
00345
00346 *c = '?';
00347 return 1;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356 size_t Utf8Encode(char *buf, WChar c)
00357 {
00358 if (c < 0x80) {
00359 *buf = c;
00360 return 1;
00361 } else if (c < 0x800) {
00362 *buf++ = 0xC0 + GB(c, 6, 5);
00363 *buf = 0x80 + GB(c, 0, 6);
00364 return 2;
00365 } else if (c < 0x10000) {
00366 *buf++ = 0xE0 + GB(c, 12, 4);
00367 *buf++ = 0x80 + GB(c, 6, 6);
00368 *buf = 0x80 + GB(c, 0, 6);
00369 return 3;
00370 } else if (c < 0x110000) {
00371 *buf++ = 0xF0 + GB(c, 18, 3);
00372 *buf++ = 0x80 + GB(c, 12, 6);
00373 *buf++ = 0x80 + GB(c, 6, 6);
00374 *buf = 0x80 + GB(c, 0, 6);
00375 return 4;
00376 }
00377
00378
00379 *buf = '?';
00380 return 1;
00381 }
00382
00390 size_t Utf8TrimString(char *s, size_t maxlen)
00391 {
00392 size_t length = 0;
00393
00394 for (const char *ptr = strchr(s, '\0'); *s != '\0';) {
00395 size_t len = Utf8EncodedCharLen(*s);
00396
00397 if (len == 0) len = 1;
00398
00399
00400
00401 if (length + len >= maxlen || (s + len > ptr)) break;
00402 s += len;
00403 length += len;
00404 }
00405
00406 *s = '\0';
00407 return length;
00408 }
00409
00410 #ifdef DEFINE_STRNDUP
00411 #include "core/math_func.hpp"
00412 char *strndup(const char *s, size_t len)
00413 {
00414 len = min(strlen(s), len);
00415 char *tmp = CallocT<char>(len + 1);
00416 memcpy(tmp, s, len);
00417 return tmp;
00418 }
00419 #endif
00420
00421 #ifdef DEFINE_STRCASESTR
00422 char *strcasestr(const char *haystack, const char *needle)
00423 {
00424 size_t hay_len = strlen(haystack);
00425 size_t needle_len = strlen(needle);
00426 while (hay_len >= needle_len) {
00427 if (strncasecmp(haystack, needle, needle_len) == 0) return const_cast<char *>(haystack);
00428
00429 haystack++;
00430 hay_len--;
00431 }
00432
00433 return NULL;
00434 }
00435 #endif