| 
									
										
										
										
											2019-09-06 15:34:26 +02:00
										 |  |  | #include <AK/StdLibExtras.h>
 | 
					
						
							|  |  |  | #include <AK/String.h>
 | 
					
						
							|  |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  | #include <stdarg.h>
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace AK { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool String::operator==(const String& other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_impl) | 
					
						
							|  |  |  |         return !other.m_impl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!other.m_impl) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (length() != other.length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2019-05-26 03:08:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     return !memcmp(characters(), other.characters(), length()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-24 22:28:42 +02:00
										 |  |  | bool String::operator==(const StringView& other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_impl) | 
					
						
							|  |  |  |         return !other.m_characters; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!other.m_characters) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (length() != other.length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return !memcmp(characters(), other.characters_without_null_termination(), length()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 13:33:52 +01:00
										 |  |  | bool String::operator<(const String& other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_impl) | 
					
						
							|  |  |  |         return other.m_impl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!other.m_impl) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 14:24:34 +01:00
										 |  |  |     return strcmp(characters(), other.characters()) < 0; | 
					
						
							| 
									
										
										
										
											2019-03-09 13:33:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | String String::empty() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     return StringImpl::the_empty_stringimpl(); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  | String String::isolated_copy() const | 
					
						
							| 
									
										
										
										
											2018-10-26 09:54:29 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_impl) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2018-10-26 09:54:29 +02:00
										 |  |  |     if (!m_impl->length()) | 
					
						
							|  |  |  |         return empty(); | 
					
						
							|  |  |  |     char* buffer; | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     auto impl = StringImpl::create_uninitialized(length(), buffer); | 
					
						
							| 
									
										
										
										
											2018-10-26 09:54:29 +02:00
										 |  |  |     memcpy(buffer, m_impl->characters(), m_impl->length()); | 
					
						
							|  |  |  |     return String(move(*impl)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | String String::substring(int start, int length) const | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-08 14:08:15 +01:00
										 |  |  |     if (!length) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |     ASSERT(m_impl); | 
					
						
							|  |  |  |     ASSERT(start + length <= m_impl->length()); | 
					
						
							|  |  |  |     // FIXME: This needs some input bounds checking.
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |     return { characters() + start, length }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StringView String::substring_view(int start, int length) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!length) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |     ASSERT(m_impl); | 
					
						
							|  |  |  |     ASSERT(start + length <= m_impl->length()); | 
					
						
							|  |  |  |     // FIXME: This needs some input bounds checking.
 | 
					
						
							|  |  |  |     return { characters() + start, length }; | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | Vector<String> String::split(const char separator) const | 
					
						
							| 
									
										
										
										
											2019-06-04 18:13:07 +10:00
										 |  |  | { | 
					
						
							|  |  |  |     return split_limit(separator, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<String> String::split_limit(const char separator, int limit) const | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     if (is_empty()) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |     Vector<String> v; | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     int substart = 0; | 
					
						
							|  |  |  |     for (int i = 0; i < length() && (v.size() + 1) != limit; ++i) { | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |         char ch = characters()[i]; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |         if (ch == separator) { | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |             int sublen = i - substart; | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |             if (sublen != 0) | 
					
						
							|  |  |  |                 v.append(substring(substart, sublen)); | 
					
						
							|  |  |  |             substart = i + 1; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     int taillen = length() - substart; | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |     if (taillen != 0) | 
					
						
							|  |  |  |         v.append(substring(substart, taillen)); | 
					
						
							| 
									
										
										
										
											2018-11-07 00:19:35 +01:00
										 |  |  |     if (characters()[length() - 1] == separator) | 
					
						
							|  |  |  |         v.append(empty()); | 
					
						
							| 
									
										
										
										
											2018-10-16 11:42:39 +02:00
										 |  |  |     return v; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | Vector<StringView> String::split_view(const char separator) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Vector<StringView> v; | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     int substart = 0; | 
					
						
							|  |  |  |     for (int i = 0; i < length(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |         char ch = characters()[i]; | 
					
						
							|  |  |  |         if (ch == separator) { | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |             int sublen = i - substart; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |             if (sublen != 0) | 
					
						
							|  |  |  |                 v.append(substring_view(substart, sublen)); | 
					
						
							|  |  |  |             substart = i + 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     int taillen = length() - substart; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |     if (taillen != 0) | 
					
						
							|  |  |  |         v.append(substring_view(substart, taillen)); | 
					
						
							|  |  |  |     if (characters()[length() - 1] == separator) | 
					
						
							| 
									
										
										
										
											2019-06-02 12:19:21 +02:00
										 |  |  |         v.append(empty()); | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |     return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  | ByteBuffer String::to_byte_buffer() const | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_impl) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2019-07-03 21:17:35 +02:00
										 |  |  |     return ByteBuffer::copy(reinterpret_cast<const u8*>(characters()), length()); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-19 01:05:59 +02:00
										 |  |  | int String::to_int(bool& ok) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-26 03:08:36 +01:00
										 |  |  |     bool negative = false; | 
					
						
							|  |  |  |     int value = 0; | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     int i = 0; | 
					
						
							| 
									
										
										
										
											2019-05-26 03:08:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-08 10:51:45 +02:00
										 |  |  |     if (is_empty()) { | 
					
						
							| 
									
										
										
										
											2019-05-26 03:08:36 +01:00
										 |  |  |         ok = false; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (characters()[0] == '-') { | 
					
						
							|  |  |  |         i++; | 
					
						
							|  |  |  |         negative = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (; i < length(); i++) { | 
					
						
							|  |  |  |         if (characters()[i] < '0' || characters()[i] > '9') { | 
					
						
							|  |  |  |             ok = false; | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value = value * 10; | 
					
						
							|  |  |  |         value += characters()[i] - '0'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ok = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return negative ? -value : value; | 
					
						
							| 
									
										
										
										
											2019-04-19 01:05:59 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | unsigned String::to_uint(bool& ok) const | 
					
						
							| 
									
										
										
										
											2018-10-31 19:49:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     unsigned value = 0; | 
					
						
							| 
									
										
										
										
											2019-06-14 06:43:56 +02:00
										 |  |  |     for (int i = 0; i < length(); ++i) { | 
					
						
							| 
									
										
										
										
											2018-10-31 19:49:22 +01:00
										 |  |  |         if (characters()[i] < '0' || characters()[i] > '9') { | 
					
						
							|  |  |  |             ok = false; | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value = value * 10; | 
					
						
							|  |  |  |         value += characters()[i] - '0'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ok = true; | 
					
						
							|  |  |  |     return value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 14:56:27 +02:00
										 |  |  | String String::number(unsigned value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return String::format("%u", value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String String::number(int value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return String::format("%d", value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 16:28:51 +01:00
										 |  |  | String String::format(const char* fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  |     va_start(ap, fmt); | 
					
						
							|  |  |  |     builder.appendvf(fmt, ap); | 
					
						
							|  |  |  |     va_end(ap); | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     return builder.to_string(); | 
					
						
							| 
									
										
										
										
											2019-01-30 16:28:51 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-04 21:53:25 +10:00
										 |  |  | bool String::starts_with(const StringView& str) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (str.is_empty()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (str.length() > length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     return !memcmp(characters(), str.characters_without_null_termination(), str.length()); | 
					
						
							| 
									
										
										
										
											2019-06-04 21:53:25 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-02 12:26:28 +02:00
										 |  |  | bool String::ends_with(const StringView& str) const | 
					
						
							| 
									
										
										
										
											2019-03-22 12:43:29 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     if (str.is_empty()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (str.length() > length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     return !memcmp(characters() + (length() - str.length()), str.characters_without_null_termination(), str.length()); | 
					
						
							| 
									
										
										
										
											2019-03-22 12:43:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-25 22:56:09 +02:00
										 |  |  | String String::repeated(char ch, int count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!count) | 
					
						
							|  |  |  |         return empty(); | 
					
						
							|  |  |  |     char* buffer; | 
					
						
							|  |  |  |     auto impl = StringImpl::create_uninitialized(count, buffer); | 
					
						
							|  |  |  |     memset(buffer, ch, count); | 
					
						
							|  |  |  |     return *impl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-02 12:26:28 +02:00
										 |  |  | bool String::matches(const StringView& mask, CaseSensitivity case_sensitivity) const | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (case_sensitivity == CaseSensitivity::CaseInsensitive) { | 
					
						
							|  |  |  |         String this_lower = this->to_lowercase(); | 
					
						
							| 
									
										
										
										
											2019-06-02 12:26:28 +02:00
										 |  |  |         String mask_lower = String(mask).to_lowercase(); | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |         return this_lower.match_helper(mask_lower); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return match_helper(mask); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-02 12:26:28 +02:00
										 |  |  | bool String::match_helper(const StringView& mask) const | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-02 12:26:28 +02:00
										 |  |  |     if (is_null()) | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char* string_ptr = characters(); | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     const char* mask_ptr = mask.characters_without_null_termination(); | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |     const char* mask_end = mask_ptr + mask.length(); | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Match string against mask directly unless we hit a *
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |     while ((*string_ptr) && (mask_ptr < mask_end) && (*mask_ptr != '*')) { | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |         if ((*mask_ptr != *string_ptr) && (*mask_ptr != '?')) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         mask_ptr++; | 
					
						
							|  |  |  |         string_ptr++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char* cp = nullptr; | 
					
						
							|  |  |  |     const char* mp = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (*string_ptr) { | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |         if ((mask_ptr < mask_end) && (*mask_ptr == '*')) { | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |             // If we have only a * left, there is no way to not match.
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |             if (++mask_ptr == mask_end) | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             mp = mask_ptr; | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |             cp = string_ptr + 1; | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |         } else if ((mask_ptr < mask_end) && ((*mask_ptr == *string_ptr) || (*mask_ptr == '?'))) { | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |             mask_ptr++; | 
					
						
							|  |  |  |             string_ptr++; | 
					
						
							| 
									
										
										
										
											2019-06-13 16:28:48 +03:00
										 |  |  |         } else if ((cp != nullptr) && (mp != nullptr)) { | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |             mask_ptr = mp; | 
					
						
							|  |  |  |             string_ptr = cp++; | 
					
						
							| 
									
										
										
										
											2019-06-13 16:28:48 +03:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Handle any trailing mask
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:27:29 +03:00
										 |  |  |     while ((mask_ptr < mask_end) && (*mask_ptr == '*')) | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  |         mask_ptr++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:28:48 +03:00
										 |  |  |     // If we 'ate' all of the mask and the string then we match.
 | 
					
						
							|  |  |  |     return (mask_ptr == mask_end) && !*string_ptr; | 
					
						
							| 
									
										
										
										
											2019-05-26 20:36:16 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } |