| 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 | 54 | 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 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
|
54 | if (destination == source || num == 0) { |
| 10 | ✗ | return destination; | |
| 11 | } | ||
| 12 | 54 | FW_ASSERT(source != nullptr); | |
| 13 | 54 | FW_ASSERT(destination != nullptr); | |
| 14 | |||
| 15 | // Copying an overlapping range is undefined | ||
| 16 | 54 | FwSizeType source_len = string_length(source, num) + 1; | |
| 17 | 54 | FW_ASSERT(source + source_len <= destination || destination + num <= source); | |
| 18 | |||
| 19 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
|
54 | char* returned = strncpy(destination, source, static_cast<size_t>(num)); |
| 20 | 54 | destination[num - 1] = '\0'; | |
| 21 | 54 | return returned; | |
| 22 | } | ||
| 23 | |||
| 24 | 6 | const char* Fw::StringUtils::string_last_n(const char* source, const FwSizeType n, const FwSizeType buffer_size) { | |
| 25 | 6 | FW_ASSERT(source != nullptr); | |
| 26 | 6 | FwSizeType length = Fw::StringUtils::string_length(source, buffer_size); | |
| 27 | |||
| 28 | // Calculate start index. If string is shorter than N, keep whole string. | ||
| 29 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | return (length > n) ? source + (length - n) : source; |
| 30 | } | ||
| 31 | |||
| 32 | 109 | FwSizeType Fw::StringUtils::string_length(const CHAR* source, FwSizeType buffer_size) { | |
| 33 | 109 | FwSizeType length = 0; | |
| 34 | 109 | FW_ASSERT(source != nullptr); | |
| 35 |
2/2✓ Branch 0 taken 605 times.
✓ Branch 1 taken 6 times.
|
611 | for (length = 0; length < buffer_size; length++) { |
| 36 |
2/2✓ Branch 2 taken 103 times.
✓ Branch 3 taken 502 times.
|
605 | if (source[length] == '\0') { |
| 37 | 103 | break; | |
| 38 | } | ||
| 39 | } | ||
| 40 | 109 | return length; | |
| 41 | } | ||
| 42 | |||
| 43 | 12 | FwSignedSizeType Fw::StringUtils::substring_find(const CHAR* source_string, | |
| 44 | FwSizeType source_size, | ||
| 45 | const CHAR* sub_string, | ||
| 46 | FwSizeType sub_size) { | ||
| 47 | 12 | FW_ASSERT(source_string != nullptr); | |
| 48 | 12 | FW_ASSERT(sub_string != nullptr); | |
| 49 | |||
| 50 | // zero size sub-strings should always match, including in an empty source | ||
| 51 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
12 | if (0 == sub_size) { |
| 52 | 2 | return 0; | |
| 53 | } | ||
| 54 | |||
| 55 | // Cannot find a substring larger than the source | ||
| 56 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (source_size < sub_size) { |
| 57 | 1 | return -1; | |
| 58 | } | ||
| 59 | // Confirm that the output type can hold the range of valid results | ||
| 60 | 9 | 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 | 32 | for (FwSizeType source_index = 0; | |
| 64 |
4/4✓ Branch 0 taken 28 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 4 times.
|
60 | source_index < (source_size - sub_size + 1) && |
| 65 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | 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 42 times.
✗ Branch 1 not taken.
|
42 | for (FwSizeType sub_index = 0; sub_index < sub_size; sub_index++) { |
| 69 | // Prevent read overrun | ||
| 70 | 42 | FW_ASSERT((source_index + sub_index) < source_size); | |
| 71 | // if there is a mismatch, go to next character | ||
| 72 |
2/2✓ Branch 4 taken 23 times.
✓ Branch 5 taken 19 times.
|
42 | if (source_string[source_index + sub_index] != sub_string[sub_index]) { |
| 73 | 23 | break; | |
| 74 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14 times.
|
19 | } else if (sub_index == (sub_size - 1)) { |
| 75 | // if we matched all the way to the end of the substring | ||
| 76 | 5 | return static_cast<FwSignedSizeType>(source_index); | |
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | // if we make it here, no matches were found | ||
| 82 | 4 | 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 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
|
11 | if ((source_size > 0) && (0 == sub_size)) { |
| 96 | 1 | 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 | 1 | return static_cast<FwSignedSizeType>(match_index); | |
| 102 | } | ||
| 103 | |||
| 104 | // Cannot find a substring larger than the source | ||
| 105 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (source_size < sub_size) { |
| 106 | 1 | return -1; | |
| 107 | } | ||
| 108 | // Confirm that the output type can hold the range of valid results | ||
| 109 | 9 | 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 | 9 | const FwSizeType max_start_index = source_size - sub_size; | |
| 113 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4 times.
|
33 | for (FwSizeType ii = 0; ii <= max_start_index; ii++) { |
| 114 | 29 | const FwSizeType source_index = max_start_index - ii; | |
| 115 | |||
| 116 | // if the current character matches | ||
| 117 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | for (FwSizeType sub_index = 0; sub_index < sub_size; sub_index++) { |
| 118 | // Prevent read overrun | ||
| 119 | 43 | FW_ASSERT((source_index + sub_index) < source_size); | |
| 120 | // if there is a mismatch, go to next character | ||
| 121 |
2/2✓ Branch 4 taken 24 times.
✓ Branch 5 taken 19 times.
|
43 | if (source_string[source_index + sub_index] != sub_string[sub_index]) { |
| 122 | 24 | break; | |
| 123 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14 times.
|
19 | } else if (sub_index == (sub_size - 1)) { |
| 124 | // if we matched all the way to the end of the substring | ||
| 125 | 5 | 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 | 5 | return static_cast<FwSignedSizeType>(match_index); | |
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | // if we make it here, no matches were found | ||
| 136 | 4 | return -1; | |
| 137 | } | ||
| 138 |