GCC Code Coverage Report


Directory: Fw/Types/
File: StringUtils.cpp
Date: 2026-09-03 21:15:04
Exec Total Coverage
Lines: 59 60 98.3%
Functions: 5 5 100.0%
Branches: 37 44 84.1%

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