00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "core/alloc_func.hpp"
00009 #include "string_func.h"
00010
00011 #include "table/control_codes.h"
00012
00013 #include <stdarg.h>
00014 #include <ctype.h>
00015
00016 void ttd_strlcat(char *dst, const char *src, size_t size)
00017 {
00018 assert(size > 0);
00019 for (; size > 0 && *dst != '\0'; --size, ++dst) {}
00020 assert(size > 0);
00021 while (--size > 0 && *src != '\0') *dst++ = *src++;
00022 *dst = '\0';
00023 }
00024
00025
00026 void ttd_strlcpy(char *dst, const char *src, size_t size)
00027 {
00028 assert(size > 0);
00029 while (--size > 0 && *src != '\0') *dst++ = *src++;
00030 *dst = '\0';
00031 }
00032
00033
00034 char* strecat(char* dst, const char* src, const char* last)
00035 {
00036 assert(dst <= last);
00037 for (; *dst != '\0'; ++dst)
00038 if (dst == last) return dst;
00039 for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
00040 *dst = '\0';
00041 return strecpy(dst, src, last);
00042 }
00043
00044
00045 char* strecpy(char* dst, const char* src, const char* last)
00046 {
00047 assert(dst <= last);
00048 for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
00049 *dst = '\0';
00050 if (dst == last && *src != '\0') {
00051 #ifdef STRGEN
00052 error("String too long for destination buffer");
00053 #else
00054 DEBUG(misc, 0, "String too long for destination buffer");
00055 *dst = '\0';
00056 #endif
00057 }
00058 return dst;
00059 }
00060
00061
00062 char* CDECL str_fmt(const char* str, ...)
00063 {
00064 char buf[4096];
00065 va_list va;
00066 int len;
00067
00068 va_start(va, str);
00069 len = vsnprintf(buf, lengthof(buf), str, va);
00070 va_end(va);
00071 char* p = MallocT<char>(len + 1);
00072 if (p != NULL) memcpy(p, buf, len + 1);
00073 return p;
00074 }
00075
00076
00077 void str_validate(char *str)
00078 {
00079 char *dst = str;
00080 WChar c;
00081 size_t len;
00082
00083 for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
00084 if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END ||
00085 IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) {
00086
00087
00088
00089 do {
00090 *dst++ = *str++;
00091 } while (--len != 0);
00092 } else {
00093
00094 str += len;
00095 *dst++ = '?';
00096 }
00097 }
00098
00099 *dst = '\0';
00100 }
00101
00102
00103 void str_strip_colours(char *str)
00104 {
00105 char *dst = str;
00106 WChar c;
00107 size_t len;
00108
00109 for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
00110 if (c < SCC_BLUE || c > SCC_BLACK) {
00111
00112
00113
00114 do {
00115 *dst++ = *str++;
00116 } while (--len != 0);
00117 } else {
00118
00119 str += len;
00120 }
00121 }
00122 *dst = '\0';
00123 }
00124
00133 void strtolower(char *str)
00134 {
00135 for (; *str != '\0'; str++) *str = tolower(*str);
00136 }
00137
00145 bool IsValidChar(WChar key, CharSetFilter afilter)
00146 {
00147 switch (afilter) {
00148 case CS_ALPHANUMERAL: return IsPrintable(key);
00149 case CS_NUMERAL: return (key >= '0' && key <= '9');
00150 case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9');
00151 }
00152
00153 return false;
00154 }
00155
00156 #ifdef WIN32
00157
00158 #if (__MINGW32_MAJOR_VERSION < 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION < 14))
00159 int CDECL snprintf(char *str, size_t size, const char *format, ...)
00160 {
00161 va_list ap;
00162 int ret;
00163
00164 va_start(ap, format);
00165 ret = vsnprintf(str, size, format, ap);
00166 va_end(ap);
00167 return ret;
00168 }
00169 #endif
00170
00171 #ifdef _MSC_VER
00172
00173
00174
00175
00176
00177 int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
00178 {
00179 int ret;
00180 ret = _vsnprintf(str, size, format, ap);
00181 if (ret < 0 || ret == size) str[size - 1] = '\0';
00182 return ret;
00183 }
00184 #endif
00185
00186 #endif
00187
00188
00194 char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16])
00195 {
00196 char *p = buf;
00197
00198 for (uint i = 0; i < 16; i++) {
00199 p += snprintf(p, last + 1 - p, "%02X", md5sum[i]);
00200 if (p >= last) break;
00201 }
00202
00203 return p;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 size_t Utf8Decode(WChar *c, const char *s)
00216 {
00217 assert(c != NULL);
00218
00219 if (!HasBit(s[0], 7)) {
00220
00221 *c = s[0];
00222 return 1;
00223 } else if (GB(s[0], 5, 3) == 6) {
00224 if (IsUtf8Part(s[1])) {
00225
00226 *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
00227 if (*c >= 0x80) return 2;
00228 }
00229 } else if (GB(s[0], 4, 4) == 14) {
00230 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
00231
00232 *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
00233 if (*c >= 0x800) return 3;
00234 }
00235 } else if (GB(s[0], 3, 5) == 30) {
00236 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
00237
00238 *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
00239 if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
00240 }
00241 }
00242
00243
00244 *c = '?';
00245 return 1;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254 size_t Utf8Encode(char *buf, WChar c)
00255 {
00256 if (c < 0x80) {
00257 *buf = c;
00258 return 1;
00259 } else if (c < 0x800) {
00260 *buf++ = 0xC0 + GB(c, 6, 5);
00261 *buf = 0x80 + GB(c, 0, 6);
00262 return 2;
00263 } else if (c < 0x10000) {
00264 *buf++ = 0xE0 + GB(c, 12, 4);
00265 *buf++ = 0x80 + GB(c, 6, 6);
00266 *buf = 0x80 + GB(c, 0, 6);
00267 return 3;
00268 } else if (c < 0x110000) {
00269 *buf++ = 0xF0 + GB(c, 18, 3);
00270 *buf++ = 0x80 + GB(c, 12, 6);
00271 *buf++ = 0x80 + GB(c, 6, 6);
00272 *buf = 0x80 + GB(c, 0, 6);
00273 return 4;
00274 }
00275
00276
00277 *buf = '?';
00278 return 1;
00279 }
00280
00288 size_t Utf8TrimString(char *s, size_t maxlen)
00289 {
00290 size_t length = 0;
00291
00292 for (const char *ptr = strchr(s, '\0'); *s != '\0';) {
00293 size_t len = Utf8EncodedCharLen(*s);
00294
00295 if (len == 0) len = 1;
00296
00297
00298
00299 if (length + len >= maxlen || (s + len > ptr)) break;
00300 s += len;
00301 length += len;
00302 }
00303
00304 *s = '\0';
00305 return length;
00306 }