tron@2186: /* $Id$ */ tron@2186: tron@1317: #include "stdafx.h" Darkvater@4912: #include "openttd.h" Darkvater@4912: #include "functions.h" tron@1317: #include "string.h" peter1138@5108: #include "macros.h" peter1138@5108: #include "table/control_codes.h" tron@1317: tron@2234: #include Darkvater@4200: #include // required for tolower() tron@2234: tron@1317: void ttd_strlcat(char *dst, const char *src, size_t size) tron@1317: { tron@1317: assert(size > 0); tron@1317: for (; size > 0 && *dst != '\0'; --size, ++dst) {} tron@1317: assert(size > 0); tron@1317: while (--size > 0 && *src != '\0') *dst++ = *src++; tron@1317: *dst = '\0'; tron@1317: } tron@1317: tron@1317: tron@1317: void ttd_strlcpy(char *dst, const char *src, size_t size) tron@1317: { tron@1317: assert(size > 0); tron@1317: while (--size > 0 && *src != '\0') *dst++ = *src++; tron@1317: *dst = '\0'; tron@1317: } tron@1317: tron@1317: tron@1317: char* strecat(char* dst, const char* src, const char* last) tron@1317: { Darkvater@4912: assert(dst <= last); tron@1317: for (; *dst != '\0'; ++dst) tron@1317: if (dst == last) return dst; tron@1317: for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src; tron@1317: *dst = '\0'; tron@1317: return strecpy(dst, src, last); tron@1317: } tron@1317: tron@1317: tron@1317: char* strecpy(char* dst, const char* src, const char* last) tron@1317: { Darkvater@4912: assert(dst <= last); tron@1317: for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src; tron@1317: *dst = '\0'; Darkvater@4914: #if 1 Darkvater@4912: if (dst == last && *src != '\0') { Darkvater@4912: error("String too long for destination buffer"); Darkvater@4912: } Darkvater@4912: #endif tron@1317: return dst; tron@1317: } tron@2234: tron@2234: tron@2234: char* CDECL str_fmt(const char* str, ...) tron@2234: { tron@2234: char buf[4096]; tron@2234: va_list va; tron@2234: int len; tron@2234: char* p; tron@2234: tron@2234: va_start(va, str); truelight@4370: len = vsnprintf(buf, lengthof(buf), str, va); tron@2234: va_end(va); tron@2234: p = malloc(len + 1); tron@2234: if (p != NULL) memcpy(p, buf, len + 1); tron@2234: return p; tron@2234: } Darkvater@2775: Darkvater@2775: void str_validate(char *str) Darkvater@2775: { peter1138@5108: char *dst = str; peter1138@5108: WChar c; peter1138@5108: size_t len = Utf8Decode(&c, str); peter1138@5108: peter1138@5108: for (; c != '\0'; len = Utf8Decode(&c, str)) { peter1138@5108: if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END || peter1138@5108: IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) { peter1138@5108: /* Copy the character back. Even if dst is current the same as str peter1138@5108: * (i.e. no characters have been changed) this is quicker than peter1138@5108: * moving the pointers ahead by len */ peter1138@5108: do { peter1138@5108: *dst++ = *str++; peter1138@5108: } while (--len); peter1138@5108: } else { peter1138@5108: /* Replace the undesirable character with a question mark */ peter1138@5108: str += len; peter1138@5108: *dst++ = '?'; peter1138@5108: } peter1138@5108: } peter1138@5108: peter1138@5108: *dst = '\0'; Darkvater@2775: } Darkvater@4200: Darkvater@5101: void str_strip_colours(char *str) Darkvater@5101: { Darkvater@5101: char *dst = str; Darkvater@5101: for (; *str != '\0';) { Darkvater@5101: if (*str >= 15 && *str <= 31) { // magic colour codes Darkvater@5101: str++; Darkvater@5101: } else { Darkvater@5101: *dst++ = *str++; Darkvater@5101: } Darkvater@5101: } Darkvater@5101: *dst = '\0'; Darkvater@5101: } Darkvater@5101: truelight@4300: /** truelight@4300: * Only allow certain keys. You can define the filter to be used. This makes truelight@4300: * sure no invalid keys can get into an editbox, like BELL. truelight@4299: * @param key character to be checked truelight@4300: * @param afilter the filter to use truelight@4300: * @return true or false depending if the character is printable/valid or not truelight@4300: */ peter1138@5108: bool IsValidChar(WChar key, CharSetFilter afilter) truelight@4299: { truelight@4299: switch (afilter) { peter1138@5108: case CS_ALPHANUMERAL: return IsPrintable(key); peter1138@5108: case CS_NUMERAL: return (key >= '0' && key <= '9'); peter1138@5108: case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9'); truelight@4299: } truelight@4299: peter1138@5108: return false; truelight@4299: } truelight@4300: truelight@4300: void strtolower(char *str) truelight@4300: { truelight@4300: for (; *str != '\0'; str++) *str = tolower(*str); truelight@4300: } truelight@4370: truelight@4370: #ifdef WIN32 truelight@4370: int CDECL snprintf(char *str, size_t size, const char *format, ...) truelight@4370: { truelight@4370: va_list ap; truelight@4370: int ret; truelight@4370: truelight@4370: va_start(ap, format); truelight@4370: ret = vsnprintf(str, size, format, ap); truelight@4370: va_end(ap); truelight@4370: return ret; truelight@4370: } truelight@4370: truelight@4370: #ifdef _MSC_VER truelight@4370: int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap) truelight@4370: { truelight@4370: int ret; truelight@4370: ret = _vsnprintf(str, size, format, ap); truelight@4370: if (ret < 0) str[size - 1] = '\0'; truelight@4370: return ret; truelight@4370: } truelight@4370: #endif /* _MSC_VER */ truelight@4370: truelight@4370: #endif /* WIN32 */ peter1138@5108: peter1138@5108: peter1138@5108: /* UTF-8 handling routines */ peter1138@5108: peter1138@5108: peter1138@5108: /* Decode and consume the next UTF-8 encoded character peter1138@5108: * @param c Buffer to place decoded character. peter1138@5108: * @param s Character stream to retrieve character from. peter1138@5108: * @return Number of characters in the sequence. peter1138@5108: */ peter1138@5108: size_t Utf8Decode(WChar *c, const char *s) peter1138@5108: { peter1138@5108: assert(c != NULL); peter1138@5108: peter1138@5108: if (!HASBIT(s[0], 7)) { peter1138@5108: /* Single byte character: 0xxxxxxx */ peter1138@5108: *c = s[0]; peter1138@5108: return 1; peter1138@5108: } else if (GB(s[0], 5, 3) == 6) { peter1138@5108: if (IsUtf8Part(s[1])) { peter1138@5108: /* Double byte character: 110xxxxx 10xxxxxx */ peter1138@5108: *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6); peter1138@5108: if (*c >= 0x80) return 2; peter1138@5108: } peter1138@5108: } else if (GB(s[0], 4, 4) == 14) { peter1138@5108: if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) { peter1138@5108: /* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */ peter1138@5108: *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6); peter1138@5108: if (*c >= 0x800) return 3; peter1138@5108: } peter1138@5108: } else if (GB(s[0], 3, 5) == 30) { peter1138@5108: if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) { peter1138@5108: /* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ peter1138@5108: *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6); peter1138@5108: if (*c >= 0x10000 && *c <= 0x10FFFF) return 4; peter1138@5108: } peter1138@5108: } peter1138@5108: peter1138@5108: //DEBUG(misc, 1) ("Invalid UTF-8 sequence"); peter1138@5108: *c = '?'; peter1138@5108: return 1; peter1138@5108: } peter1138@5108: peter1138@5108: peter1138@5108: /* Encode a unicode character and place it in the buffer peter1138@5108: * @param buf Buffer to place character. peter1138@5108: * @param c Unicode character to encode. peter1138@5108: * @return Number of characters in the encoded sequence. peter1138@5108: */ peter1138@5108: size_t Utf8Encode(char *buf, WChar c) peter1138@5108: { peter1138@5108: if (c < 0x80) { peter1138@5108: *buf = c; peter1138@5108: return 1; peter1138@5108: } else if (c < 0x800) { peter1138@5108: *buf++ = 0xC0 + GB(c, 6, 5); peter1138@5108: *buf = 0x80 + GB(c, 0, 6); peter1138@5108: return 2; peter1138@5108: } else if (c < 0x10000) { peter1138@5108: *buf++ = 0xE0 + GB(c, 12, 4); peter1138@5108: *buf++ = 0x80 + GB(c, 6, 6); peter1138@5108: *buf = 0x80 + GB(c, 0, 6); peter1138@5108: return 3; peter1138@5108: } else if (c < 0x110000) { peter1138@5108: *buf++ = 0xF0 + GB(c, 18, 3); peter1138@5108: *buf++ = 0x80 + GB(c, 12, 6); peter1138@5108: *buf++ = 0x80 + GB(c, 6, 6); peter1138@5108: *buf = 0x80 + GB(c, 0, 6); peter1138@5108: return 4; peter1138@5108: } peter1138@5108: peter1138@5108: //DEBUG(misc, 1) ("Can't UTF-8 encode value 0x%X", c); peter1138@5108: *buf = '?'; peter1138@5108: return 1; peter1138@5108: }