|
OpenTTD Source
13.0-beta1
|
Go to the documentation of this file.
15 #include "string_base.h"
38 #include <unicode/ustring.h>
43 #if defined(WITH_COCOA)
62 int CDECL
vseprintf(
char *str,
const char *last,
const char *format, va_list ap)
64 ptrdiff_t diff = last - str;
65 if (diff < 0)
return 0;
66 return std::min(
static_cast<int>(diff), vsnprintf(str, diff + 1, format, ap));
85 char *
strecat(
char *dst,
const char *src,
const char *last)
88 while (*dst !=
'\0') {
89 if (dst == last)
return dst;
113 char *
strecpy(
char *dst,
const char *src,
const char *last)
116 while (dst != last && *src !=
'\0') {
121 if (dst == last && *src !=
'\0') {
122 #if defined(STRGEN) || defined(SETTINGSGEN)
123 error(
"String too long for destination buffer");
125 Debug(misc, 0,
"String too long for destination buffer");
138 char *
stredup(
const char *s,
const char *last)
140 size_t len = last ==
nullptr ? strlen(s) :
ttd_strnlen(s, last - s + 1);
141 char *tmp = CallocT<char>(len + 1);
159 char *p = MallocT<char>(len + 1);
160 memcpy(p, buf, len + 1);
171 std::ostringstream ss;
172 ss << std::uppercase << std::setfill(
'0') << std::setw(2) << std::hex;
174 for (
auto b : data) {
189 while (str <= last && *str !=
'\0') {
191 if ((len == 0 && str + 4 > last) || str + len > last)
break;
195 if (c ==
'\0')
break;
197 if (c == 0xE028 || c == 0xE02A) {
211 while (str <= last && *str !=
'\0') {
237 if (len == 0 || str + len > last || len !=
Utf8Decode(&c, str)) {
249 }
while (--len != 0);
301 auto buf = str.data();
302 auto last = buf + str.size();
304 std::ostringstream dst;
305 std::ostreambuf_iterator<char> dst_iter(dst);
322 while (str <= last && *str !=
'\0') {
328 if (len == 0 || str + len > last)
return false;
332 if (!IsPrintable(c) || (c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) {
350 size_t pos = str.find_first_not_of(
' ');
362 size_t pos = str.find_last_not_of(
' ');
363 if (pos != std::string::npos) str.erase(pos + 1);
385 bool StrStartsWith(
const std::string_view str,
const std::string_view prefix)
387 size_t prefix_len = prefix.size();
388 if (str.size() < prefix_len)
return false;
389 return str.compare(0, prefix_len, prefix, 0, prefix_len) == 0;
398 bool StrEndsWith(
const std::string_view str,
const std::string_view suffix)
400 size_t suffix_len = suffix.size();
401 if (str.size() < suffix_len)
return false;
402 return str.compare(str.size() - suffix_len, suffix_len, suffix, 0, suffix_len) == 0;
414 if (c < SCC_BLUE || c > SCC_BLACK) {
420 }
while (--len != 0);
439 while (Utf8Consume(&t) != 0) len++;
467 bool changed =
false;
468 for (; *str !=
'\0'; str++) {
469 char new_str = tolower(*str);
470 changed |= new_str != *str;
476 bool strtolower(std::string &str, std::string::size_type offs)
478 bool changed =
false;
479 for (
auto ch = str.begin() + offs; ch != str.end(); ++ch) {
480 auto new_ch =
static_cast<char>(tolower(
static_cast<unsigned char>(*ch)));
481 changed |= new_ch != *ch;
498 case CS_NUMERAL:
return (key >=
'0' && key <=
'9');
500 case CS_ALPHA:
return IsPrintable(key) && !(key >=
'0' && key <=
'9');
501 case CS_HEXADECIMAL:
return (key >=
'0' && key <=
'9') || (key >=
'a' && key <=
'f') || (key >=
'A' && key <=
'F');
502 default: NOT_REACHED();
507 #if defined(_MSC_VER) && _MSC_VER < 1900
515 int CDECL vsnprintf(
char *str,
size_t size,
const char *format, va_list ap)
517 if (size == 0)
return 0;
520 int ret = _vsnprintf(str, size, format, ap);
523 if (errno != ERANGE) {
528 }
else if ((
size_t)ret < size) {
537 str[size - 1] =
'\0';
553 int CDECL
seprintf(
char *str,
const char *last,
const char *format, ...)
557 va_start(ap, format);
558 int ret =
vseprintf(str, last, format, ap);
575 for (uint i = 0; i < 16; i++) {
576 p +=
seprintf(p, last,
"%02X", md5sum[i]);
594 assert(c !=
nullptr);
600 }
else if (
GB(s[0], 5, 3) == 6) {
601 if (IsUtf8Part(s[1])) {
603 *c =
GB(s[0], 0, 5) << 6 |
GB(s[1], 0, 6);
604 if (*c >= 0x80)
return 2;
606 }
else if (
GB(s[0], 4, 4) == 14) {
607 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
609 *c =
GB(s[0], 0, 4) << 12 |
GB(s[1], 0, 6) << 6 |
GB(s[2], 0, 6);
610 if (*c >= 0x800)
return 3;
612 }
else if (
GB(s[0], 3, 5) == 30) {
613 if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
615 *c =
GB(s[0], 0, 3) << 18 |
GB(s[1], 0, 6) << 12 |
GB(s[2], 0, 6) << 6 |
GB(s[3], 0, 6);
616 if (*c >= 0x10000 && *c <= 0x10FFFF)
return 4;
639 }
else if (c < 0x800) {
640 *buf++ = 0xC0 +
GB(c, 6, 5);
641 *buf = 0x80 +
GB(c, 0, 6);
643 }
else if (c < 0x10000) {
644 *buf++ = 0xE0 +
GB(c, 12, 4);
645 *buf++ = 0x80 +
GB(c, 6, 6);
646 *buf = 0x80 +
GB(c, 0, 6);
648 }
else if (c < 0x110000) {
649 *buf++ = 0xF0 +
GB(c, 18, 3);
650 *buf++ = 0x80 +
GB(c, 12, 6);
651 *buf++ = 0x80 +
GB(c, 6, 6);
652 *buf = 0x80 +
GB(c, 0, 6);
663 return Utf8Encode<char *>(buf, c);
668 return Utf8Encode<std::ostreambuf_iterator<char> &>(buf, c);
682 for (
const char *ptr = strchr(s,
'\0'); *s !=
'\0';) {
685 if (len == 0) len = 1;
689 if (length + len >= maxlen || (s + len > ptr))
break;
698 #ifdef DEFINE_STRCASESTR
699 char *strcasestr(
const char *haystack,
const char *needle)
701 size_t hay_len = strlen(haystack);
702 size_t needle_len = strlen(needle);
703 while (hay_len >= needle_len) {
704 if (strncasecmp(haystack, needle, needle_len) == 0)
return const_cast<char *
>(haystack);
736 int strnatcmp(
const char *s1,
const char *s2,
bool ignore_garbage_at_front)
738 if (ignore_garbage_at_front) {
745 UErrorCode status = U_ZERO_ERROR;
747 if (U_SUCCESS(status))
return result;
751 #if defined(_WIN32) && !defined(STRGEN) && !defined(SETTINGSGEN)
752 int res = OTTDStringCompare(s1, s2);
753 if (res != 0)
return res - 2;
756 #if defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN)
758 if (res != 0)
return res - 2;
762 return strcasecmp(s1, s2);
765 #ifdef WITH_UNISCRIBE
772 #elif defined(WITH_ICU_I18N)
774 #include <unicode/utext.h>
775 #include <unicode/brkiter.h>
789 UErrorCode status = U_ZERO_ERROR;
793 this->utf16_str.push_back(
'\0');
794 this->utf16_to_utf8.push_back(0);
805 const char *string_base = s;
811 this->utf16_str.clear();
812 this->utf16_to_utf8.clear();
815 size_t idx = s - string_base;
817 WChar c = Utf8Consume(&s);
819 this->utf16_str.push_back((UChar)c);
822 this->utf16_str.push_back((UChar)(0xD800 + ((c - 0x10000) >> 10)));
823 this->utf16_str.push_back((UChar)(0xDC00 + ((c - 0x10000) & 0x3FF)));
824 this->utf16_to_utf8.push_back(idx);
826 this->utf16_to_utf8.push_back(idx);
828 this->utf16_str.push_back(
'\0');
829 this->utf16_to_utf8.push_back(s - string_base);
831 UText text = UTEXT_INITIALIZER;
832 UErrorCode status = U_ZERO_ERROR;
833 utext_openUChars(&text, this->utf16_str.data(), this->utf16_str.size() - 1, &status);
834 this->char_itr->setText(&text, status);
835 this->word_itr->setText(&text, status);
836 this->char_itr->first();
837 this->word_itr->first();
844 for (uint i = 0; i < this->utf16_to_utf8.size(); i++) {
845 if (this->utf16_to_utf8[i] == pos) {
854 this->char_itr->isBoundary(utf16_pos);
855 return this->utf16_to_utf8[this->char_itr->current()];
863 pos = this->char_itr->next();
867 pos = this->word_itr->following(this->char_itr->current());
871 while (pos != icu::BreakIterator::DONE &&
873 int32_t new_pos = this->word_itr->next();
876 if (new_pos == icu::BreakIterator::DONE)
break;
880 this->char_itr->isBoundary(pos);
887 return pos == icu::BreakIterator::DONE ?
END : this->utf16_to_utf8[pos];
895 pos = this->char_itr->previous();
899 pos = this->word_itr->preceding(this->char_itr->current());
903 while (pos != icu::BreakIterator::DONE &&
905 int32_t new_pos = this->word_itr->previous();
908 if (new_pos == icu::BreakIterator::DONE)
break;
912 this->char_itr->isBoundary(pos);
919 return pos == icu::BreakIterator::DONE ?
END : this->utf16_to_utf8[pos];
938 DefaultStringIterator() : string(nullptr), len(0), cur_pos(0)
945 this->len = strlen(s);
951 assert(this->
string !=
nullptr && pos <= this->len);
953 while (pos > 0 && IsUtf8Part(this->
string[pos])) pos--;
954 return this->cur_pos = pos;
957 virtual size_t Next(IterType what)
959 assert(this->
string !=
nullptr);
962 if (this->cur_pos >= this->len)
return END;
967 this->cur_pos +=
Utf8Decode(&c, this->
string + this->cur_pos);
968 return this->cur_pos;
974 size_t offs =
Utf8Decode(&c, this->
string + this->cur_pos);
976 this->cur_pos += offs;
977 offs =
Utf8Decode(&c, this->
string + this->cur_pos);
981 this->cur_pos += offs;
982 offs =
Utf8Decode(&c, this->
string + this->cur_pos);
985 return this->cur_pos;
995 virtual size_t Prev(IterType what)
997 assert(this->
string !=
nullptr);
1000 if (this->cur_pos == 0)
return END;
1004 return this->cur_pos =
Utf8PrevChar(this->
string + this->cur_pos) - this->string;
1007 const char *s = this->
string + this->cur_pos;
1022 return this->cur_pos = s - this->string;
1033 #if defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN)
1037 if (i !=
nullptr)
return i;
1039 return new DefaultStringIterator();
1044 return new DefaultStringIterator();
static constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
virtual size_t Prev(IterType what=ITER_CHARACTER)=0
Move the cursor back by one iteration unit.
std::vector< size_t > utf16_to_utf8
Mapping from UTF-16 code point position to index in the UTF-8 source string.
char32_t WChar
Type for wide characters, i.e.
@ SVS_ALLOW_NEWLINE
Allow newlines.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
IterType
Type of the iterator.
bool strtolower(char *str)
Convert a given ASCII string to lowercase.
static void StrRightTrimInPlace(std::string &str)
Trim the spaces from the end of given string in place, i.e.
static const size_t END
Sentinel to indicate end-of-iteration.
void str_fix_scc_encoded(char *str, const char *last)
Scan the string for old values of SCC_ENCODED and fix it to it's new, static value.
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
icu::BreakIterator * word_itr
ICU iterator for words.
std::unique_ptr< icu::Collator > _current_collator
Collator for the language currently in use.
size_t Utf8Encode(T buf, WChar c)
Encode a unicode character and place it in the buffer.
virtual size_t Next(IterType what=ITER_CHARACTER)=0
Advance the cursor by one iteration unit.
@ CS_ALPHA
Only alphabetic values.
String iterator using Uniscribe as a backend.
static WChar Utf16DecodeChar(const uint16 *c)
Decode an UTF-16 character.
virtual void SetString(const char *s)=0
Set a new iteration string.
icu::BreakIterator * char_itr
ICU iterator for characters.
@ ITER_CHARACTER
Iterate over characters (or more exactly grapheme clusters).
size_t Next(IterType what) override
Advance the cursor by one iteration unit.
std::string FormatArrayAsHex(span< const byte > data)
Format a byte array into a continuous hex string.
size_t Utf8StringLength(const char *s)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
bool StrValid(const char *str, const char *last)
Checks whether the given string is valid, i.e.
static StringIterator * Create()
Create a new iterator instance.
@ SVS_ALLOW_CONTROL_CODE
Allow the special control codes.
Class for iterating over different kind of parts of a string.
size_t SetCurPosition(size_t pos) override
Change the current string cursor.
virtual size_t SetCurPosition(size_t pos)=0
Change the current string cursor.
void StrMakeValidInPlace(char *str, const char *last, StringValidationSettings settings)
Scans the string for invalid characters and replaces then with a question mark '?' (if not ignored).
void StrTrimInPlace(std::string &str)
Trim the spaces from given string in place, i.e.
void str_strip_colours(char *str)
Scans the string for colour codes and strips them.
bool StrStartsWith(const std::string_view str, const std::string_view prefix)
Check whether the given string starts with the given prefix.
const LanguageMetadata * _current_language
The currently loaded language.
std::vector< UChar > utf16_str
UTF-16 copy of the string.
bool IsValidChar(WChar key, CharSetFilter afilter)
Only allow certain keys.
static size_t ttd_strnlen(const char *str, size_t maxlen)
Get the length of a string, within a limited buffer.
fluid_settings_t * settings
FluidSynth settings handle.
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
Safer implementation of vsnprintf; same as vsnprintf except:
@ ITER_WORD
Iterate over words.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
StringValidationSettings
Settings for the string validation.
bool StrEndsWith(const std::string_view str, const std::string_view suffix)
Check whether the given string ends with the given suffix.
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
std::string StrMakeValid(const std::string &str, StringValidationSettings settings)
Scans the string for invalid characters and replaces then with a question mark '?' (if not ignored).
char *CDECL str_fmt(const char *str,...)
Format, "printf", into a newly allocated string.
void SetString(const char *s) override
Set a new iteration string.
static void StrLeftTrimInPlace(std::string &str)
Trim the spaces from the begin of given string in place, i.e.
String iterator using ICU as a backend.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
#define Debug(name, level, format_string,...)
Ouptut a line of debugging information.
size_t Utf8TrimString(char *s, size_t maxlen)
Properly terminate an UTF8 string to some maximum length.
@ CS_NUMERAL_SPACE
Only numbers and spaces.
static const char * SkipGarbage(const char *str)
Skip some of the 'garbage' in the string that we don't want to use to sort on.
static bool IsWhitespace(WChar c)
Check whether UNICODE character is whitespace or not, i.e.
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
char * md5sumToString(char *buf, const char *last, const uint8 md5sum[16])
Convert the md5sum to a hexadecimal string representation.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
@ CS_HEXADECIMAL
Only hexadecimal characters.
char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
int MacOSStringCompare(const char *s1, const char *s2)
Compares two strings using case insensitive natural sort.
#define lastof(x)
Get the last element of an fixed size array.
@ SVS_REPLACE_WITH_QUESTION_MARK
Replace the unknown/bad bits with question marks.
@ CS_NUMERAL
Only numeric ones.
CharSetFilter
Valid filter types for IsValidChar.
static char * Utf8PrevChar(char *s)
Retrieve the previous UNICODE character in an UTF-8 encoded string.
static int8 Utf8EncodedCharLen(char c)
Return the length of an UTF-8 encoded value based on a single char.
size_t Prev(IterType what) override
Move the cursor back by one iteration unit.