From f42fca6350f9c7bb8290d8d08a3493d7e6ff4987 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Mon, 17 Apr 2017 23:12:10 +1000 Subject: [PATCH] Add more string check functions --- dqn.h | 82 +++++++++++++++++++++++++++++++++++++++++++---- dqn_unit_test.cpp | 38 ++++++++++++++++++++++ 2 files changed, 114 insertions(+), 6 deletions(-) diff --git a/dqn.h b/dqn.h index ae6c764..d06ac3e 100644 --- a/dqn.h +++ b/dqn.h @@ -355,22 +355,26 @@ DQN_FILE_SCOPE bool dqn_rect_contains_p (DqnRect rect, DqnV2 p); //////////////////////////////////////////////////////////////////////////////// // String Ops //////////////////////////////////////////////////////////////////////////////// -DQN_FILE_SCOPE char dqn_char_to_upper (char c); DQN_FILE_SCOPE char dqn_char_to_lower (char c); +DQN_FILE_SCOPE char dqn_char_to_upper (char c); DQN_FILE_SCOPE bool dqn_char_is_digit (char c); DQN_FILE_SCOPE bool dqn_char_is_alpha (char c); DQN_FILE_SCOPE bool dqn_char_is_alphanum(char c); DQN_FILE_SCOPE i32 dqn_strcmp (const char *a, const char *b); // Returns the length without the null terminator -DQN_FILE_SCOPE i32 dqn_strlen (const char *a); -DQN_FILE_SCOPE char *dqn_strncpy(char *dest, const char *src, i32 numChars); +DQN_FILE_SCOPE i32 dqn_strlen (const char *a); +DQN_FILE_SCOPE i32 dqn_strlen_delimit_with(const char *a, const char delimiter); +DQN_FILE_SCOPE char *dqn_strncpy (char *dest, const char *src, i32 numChars); #define DQN_I32_TO_STR_MAX_BUF_SIZE 11 -DQN_FILE_SCOPE bool dqn_str_reverse(char *buf, const i32 bufSize); -DQN_FILE_SCOPE i32 dqn_str_to_i32 (const char *const buf, const i32 bufSize); +DQN_FILE_SCOPE bool dqn_str_reverse (char *buf, const i32 bufSize); +DQN_FILE_SCOPE bool dqn_str_has_substring(const char *const a, const i32 lenA, + const char *const b, const i32 lenB); + +DQN_FILE_SCOPE i32 dqn_str_to_i32(const char *const buf, const i32 bufSize); // Return the len of the derived string -DQN_FILE_SCOPE i32 dqn_i32_to_str (i32 value, char *buf, i32 bufSize); +DQN_FILE_SCOPE i32 dqn_i32_to_str(i32 value, char *buf, i32 bufSize); // Both return the number of bytes read, return 0 if invalid codepoint or UTF8 DQN_FILE_SCOPE u32 dqn_ucs_to_utf8(u32 *dest, u32 character); @@ -1600,6 +1604,13 @@ DQN_FILE_SCOPE i32 dqn_strlen(const char *a) return result; } +DQN_FILE_SCOPE i32 dqn_strlen_delimit_with(const char *a, const char delimiter) +{ + i32 result = 0; + while (a && a[result] && a[result] != delimiter) result++; + return result; +} + DQN_FILE_SCOPE char *dqn_strncpy(char *dest, const char *src, i32 numChars) { if (!dest) return NULL; @@ -1626,6 +1637,65 @@ DQN_FILE_SCOPE bool dqn_str_reverse(char *buf, const i32 bufSize) return true; } +DQN_FILE_SCOPE bool dqn_str_has_substring(const char *const a, const i32 lenA, + const char *const b, const i32 lenB) +{ + if (!a || !b) return false; + if (lenA == 0 || lenB == 0) return false; + + const char *longStr, *shortStr; + i32 longLen, shortLen; + if (lenA > lenB) + { + longStr = a; + longLen = lenA; + + shortStr = b; + shortLen = lenB; + } + else + { + longStr = b; + longLen = lenB; + + shortStr = a; + shortLen = lenA; + } + + bool matchedSubstr = false; + for (i32 indexIntoLong = 0; indexIntoLong < longLen && !matchedSubstr; + indexIntoLong++) + { + // NOTE: As we scan through, if the longer string we index into becomes + // shorter than the substring we're checking then the substring is not + // contained in the long string. + i32 remainingLenInLongStr = longLen - indexIntoLong; + if (remainingLenInLongStr < shortLen) break; + + const char *longSubstr = &longStr[indexIntoLong]; + i32 index = 0; + for (;;) + { + if (dqn_char_to_lower(longSubstr[index]) == + dqn_char_to_lower(shortStr[index])) + { + index++; + if (index >= shortLen || !shortStr[index]) + { + matchedSubstr = true; + break; + } + } + else + { + break; + } + } + } + + return matchedSubstr; +} + DQN_FILE_SCOPE i32 dqn_str_to_i32(const char *const buf, const i32 bufSize) { if (!buf || bufSize == 0) return 0; diff --git a/dqn_unit_test.cpp b/dqn_unit_test.cpp index 46c66d1..d1fc9a2 100644 --- a/dqn_unit_test.cpp +++ b/dqn_unit_test.cpp @@ -27,6 +27,14 @@ void dqn_strings_test() DQN_ASSERT(dqn_char_is_alphanum(' ') == false); DQN_ASSERT(dqn_char_is_alphanum('\n') == false); + DQN_ASSERT(dqn_char_to_lower(L'A') == L'a'); + DQN_ASSERT(dqn_char_to_lower(L'a') == L'a'); + DQN_ASSERT(dqn_char_to_lower(L' ') == L' '); + + DQN_ASSERT(dqn_char_to_upper(L'A') == L'A'); + DQN_ASSERT(dqn_char_to_upper(L'a') == L'A'); + DQN_ASSERT(dqn_char_to_upper(L' ') == L' '); + printf("dqn_strings_test(): char_checks: Completed successfully\n"); } @@ -208,6 +216,36 @@ void dqn_strings_test() } } + { + + { + char *a = "Microsoft"; + char *b = "icro"; + i32 lenA = dqn_strlen(a); + i32 lenB = dqn_strlen(b); + DQN_ASSERT(dqn_str_has_substring(a, lenA, b, lenB) == true); + DQN_ASSERT(dqn_str_has_substring(a, lenA, "iro", + dqn_strlen("iro")) == false); + DQN_ASSERT(dqn_str_has_substring(b, lenB, a, lenA) == true); + DQN_ASSERT(dqn_str_has_substring("iro", dqn_strlen("iro"), a, + lenA) == false); + DQN_ASSERT(dqn_str_has_substring("", 0, "iro", 4) == false); + DQN_ASSERT(dqn_str_has_substring("", 0, "", 0) == false); + DQN_ASSERT(dqn_str_has_substring(NULL, 0, NULL, 0) == false); + } + + { + char *a = "Micro"; + char *b = "irob"; + i32 lenA = dqn_strlen(a); + i32 lenB = dqn_strlen(b); + DQN_ASSERT(dqn_str_has_substring(a, lenA, b, lenB) == false); + DQN_ASSERT(dqn_str_has_substring(b, lenB, a, lenA) == false); + } + + printf("dqn_strings_test(): str_has_substring: Completed successfully\n"); + } + // UCS <-> UTF8 Checks { // Test ascii characters