| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "StringUtils.hpp" | ||
| 2 | #include <Fw/Types/Assert.hpp> | ||
| 3 | #include <Fw/Types/ExternalString.hpp> | ||
| 4 | #include <cstring> | ||
| 5 | #include <limits> | ||
| 6 | |||
| 7 | 3058 | char* Fw::StringUtils::string_copy(char* destination, const char* source, FwSizeType num) { | |
| 8 | // Handle self-copy and 0 bytes copy | ||
| 9 |
2/4✓ Branch 0 taken 3058 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3058 times.
|
3058 | if (destination == source || num == 0) { |
| 10 | ✗ | return destination; | |
| 11 | } | ||
| 12 | 3058 | FW_ASSERT(source != nullptr); | |
| 13 | 3058 | FW_ASSERT(destination != nullptr); | |
| 14 | |||
| 15 | // Copying an overlapping range is undefined | ||
| 16 | 3058 | FwSizeType source_len = string_length(source, num) + 1; | |
| 17 | 3058 | FW_ASSERT(source + source_len <= destination || destination + num <= source); | |
| 18 | |||
| 19 | 3057 | char* returned = strncpy(destination, source, static_cast<size_t>(num)); | |
| 20 | 3057 | destination[num - 1] = '\0'; | |
| 21 | 3057 | return returned; | |
| 22 | } | ||
| 23 | |||
| 24 | ✗ | const char* Fw::StringUtils::string_last_n(const char* source, const FwSizeType n, const FwSizeType buffer_size) { | |
| 25 | ✗ | FW_ASSERT(source != nullptr); | |
| 26 | ✗ | FwSizeType length = Fw::StringUtils::string_length(source, buffer_size); | |
| 27 | |||
| 28 | // Calculate start index. If string is shorter than N, keep whole string. | ||
| 29 | ✗ | return (length > n) ? source + (length - n) : source; | |
| 30 | } | ||
| 31 | |||
| 32 | 14132 | FwSizeType Fw::StringUtils::string_length(const CHAR* source, FwSizeType buffer_size) { | |
| 33 | 14132 | FwSizeType length = 0; | |
| 34 | 14132 | FW_ASSERT(source != nullptr); | |
| 35 |
2/2✓ Branch 0 taken 334356 times.
✓ Branch 1 taken 37 times.
|
334393 | for (length = 0; length < buffer_size; length++) { |
| 36 |
2/2✓ Branch 0 taken 14095 times.
✓ Branch 1 taken 320261 times.
|
334356 | if (source[length] == '\0') { |
| 37 | 14095 | break; | |
| 38 | } | ||
| 39 | } | ||
| 40 | 14132 | return length; | |
| 41 | } | ||
| 42 | |||
| 43 | 3 | FwSignedSizeType Fw::StringUtils::substring_find(const CHAR* source_string, | |
| 44 | FwSizeType source_size, | ||
| 45 | const CHAR* sub_string, | ||
| 46 | FwSizeType sub_size) { | ||
| 47 | 3 | FW_ASSERT(source_string != nullptr); | |
| 48 | 3 | FW_ASSERT(sub_string != nullptr); | |
| 49 | |||
| 50 | // zero size sub-strings should always match, including in an empty source | ||
| 51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (0 == sub_size) { |
| 52 | ✗ | return 0; | |
| 53 | } | ||
| 54 | |||
| 55 | // Cannot find a substring larger than the source | ||
| 56 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (source_size < sub_size) { |
| 57 | ✗ | return -1; | |
| 58 | } | ||
| 59 | // Confirm that the output type can hold the range of valid results | ||
| 60 | 3 | FW_ASSERT(source_size - sub_size <= static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max())); | |
| 61 | |||
| 62 | // Loop from zero to source_size - sub_size (inclusive) | ||
| 63 | 3 | for (FwSizeType source_index = 0; | |
| 64 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | source_index < (source_size - sub_size + 1) && |
| 65 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | source_index < static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()); |
| 66 | source_index++) { | ||
| 67 | // if the current character matches | ||
| 68 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | for (FwSizeType sub_index = 0; sub_index < sub_size; sub_index++) { |
| 69 | // Prevent read overrun | ||
| 70 | 21 | FW_ASSERT((source_index + sub_index) < source_size); | |
| 71 | // if there is a mismatch, go to next character | ||
| 72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (source_string[source_index + sub_index] != sub_string[sub_index]) { |
| 73 | ✗ | break; | |
| 74 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
|
21 | } else if (sub_index == (sub_size - 1)) { |
| 75 | // if we matched all the way to the end of the substring | ||
| 76 | 3 | return static_cast<FwSignedSizeType>(source_index); | |
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | // if we make it here, no matches were found | ||
| 82 | ✗ | return -1; | |
| 83 | } | ||
| 84 | |||
| 85 | 11 | FwSignedSizeType Fw::StringUtils::substring_find_last(const CHAR* source_string, | |
| 86 | FwSizeType source_size, | ||
| 87 | const CHAR* sub_string, | ||
| 88 | FwSizeType sub_size) { | ||
| 89 | 11 | FW_ASSERT(source_string != nullptr); | |
| 90 | 11 | FW_ASSERT(sub_string != nullptr); | |
| 91 | |||
| 92 | 11 | FwSizeType match_index = 0; | |
| 93 | |||
| 94 | // zero size sub-strings should always match | ||
| 95 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if ((source_size > 0) && (0 == sub_size)) { |
| 96 | ✗ | match_index = source_size - 1; | |
| 97 | |||
| 98 | // Ensure we can represent the match_index in a signed num | ||
| 99 | FW_ASSERT(static_cast<FwSizeType>(static_cast<FwSignedSizeType>(match_index)) == match_index); | ||
| 100 | |||
| 101 | ✗ | return static_cast<FwSignedSizeType>(match_index); | |
| 102 | } | ||
| 103 | |||
| 104 | // Cannot find a substring larger than the source | ||
| 105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (source_size < sub_size) { |
| 106 | ✗ | return -1; | |
| 107 | } | ||
| 108 | // Confirm that the output type can hold the range of valid results | ||
| 109 | 11 | FW_ASSERT(source_size - sub_size <= static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max())); | |
| 110 | |||
| 111 | // Loop from source_size - sub_size to zero (inclusive) | ||
| 112 | 11 | const FwSizeType max_start_index = source_size - sub_size; | |
| 113 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 1 times.
|
124 | for (FwSizeType ii = 0; ii <= max_start_index; ii++) { |
| 114 | 123 | const FwSizeType source_index = max_start_index - ii; | |
| 115 | |||
| 116 | // if the current character matches | ||
| 117 |
1/2✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
|
145 | for (FwSizeType sub_index = 0; sub_index < sub_size; sub_index++) { |
| 118 | // Prevent read overrun | ||
| 119 | 145 | FW_ASSERT((source_index + sub_index) < source_size); | |
| 120 | // if there is a mismatch, go to next character | ||
| 121 |
2/2✓ Branch 0 taken 113 times.
✓ Branch 1 taken 32 times.
|
145 | if (source_string[source_index + sub_index] != sub_string[sub_index]) { |
| 122 | 113 | break; | |
| 123 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 22 times.
|
32 | } else if (sub_index == (sub_size - 1)) { |
| 124 | // if we matched all the way to the end of the substring | ||
| 125 | 10 | match_index = source_index; | |
| 126 | |||
| 127 | // Ensure the result converts properly | ||
| 128 | FW_ASSERT(static_cast<FwSizeType>(static_cast<FwSignedSizeType>(match_index)) == match_index); | ||
| 129 | |||
| 130 | 10 | return static_cast<FwSignedSizeType>(match_index); | |
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | // if we make it here, no matches were found | ||
| 136 | 1 | return -1; | |
| 137 | } | ||
| 138 |