1 /* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
2 *
3 * Copyright (c) 2014-2015 Datalight, Inc.
4 * All Rights Reserved Worldwide.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; use version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /* Businesses and individuals that for commercial or other reasons cannot
21 * comply with the terms of the GPLv2 license may obtain a commercial license
22 * before incorporating Reliance Edge into proprietary software for
23 * distribution in any form. Visit http://www.datalight.com/reliance-edge for
24 * more information.
25 */
26
27 /** @file
28 * @brief Default implementations of string manipulation functions.
29 *
30 * These implementations are intended to be small and simple, and thus forego
31 * all optimizations. If the C library is available, or if there are better
32 * third-party implementations available in the system, those can be used
33 * instead by defining the appropriate macros in redconf.h.
34 *
35 * These functions are not intended to be completely 100% ANSI C compatible
36 * implementations, but rather are designed to meet the needs of Reliance Edge.
37 * The compatibility is close enough that ANSI C compatible implementations
38 * can be "dropped in" as replacements without difficulty.
39 */
40 #include <redfs.h>
41
42
43 #ifndef RedStrLenUnchecked
44 static uint32_t RedStrLenUnchecked( const char * pszStr );
45 #endif
46 #ifndef RedStrCmpUnchecked
47 static int32_t RedStrCmpUnchecked( const char * pszStr1,
48 const char * pszStr2 );
49 #endif
50 #ifndef RedStrNCmpUnchecked
51 static int32_t RedStrNCmpUnchecked( const char * pszStr1,
52 const char * pszStr2,
53 uint32_t ulLen );
54 #endif
55 #ifndef RedStrNCpyUnchecked
56 static void RedStrNCpyUnchecked( char * pszDst,
57 const char * pszSrc,
58 uint32_t ulLen );
59 #endif
60
61
62 /** @brief Determine the length (in bytes) of a null terminated string.
63 *
64 * The length does not include the null terminator byte.
65 *
66 * @param pszStr The null terminated string whose length is to be determined.
67 *
68 * @return The length of the @p pszStr string.
69 */
RedStrLen(const char * pszStr)70 uint32_t RedStrLen( const char * pszStr )
71 {
72 uint32_t ulLen;
73
74 if( pszStr == NULL )
75 {
76 REDERROR();
77 ulLen = 0U;
78 }
79 else
80 {
81 /* Cast the result to uint32_t, since RedStrLenUnchecked() might be
82 * strlen(), which returns size_t, which is possibly a 64-bit value.
83 */
84 ulLen = ( uint32_t ) RedStrLenUnchecked( pszStr );
85 }
86
87 return ulLen;
88 }
89
90
91 #ifndef RedStrLenUnchecked
92
93 /** @brief Determine the length (in bytes) of a null terminated string.
94 *
95 * @param pszStr The null terminated string whose length is to be determined.
96 *
97 * @return The length of the @p pszStr string.
98 */
RedStrLenUnchecked(const char * pszStr)99 static uint32_t RedStrLenUnchecked( const char * pszStr )
100 {
101 uint32_t ulLen = 0U;
102
103 while( pszStr[ ulLen ] != '\0' )
104 {
105 ulLen++;
106 }
107
108 return ulLen;
109 }
110 #endif /* ifndef RedStrLenUnchecked */
111
112
113 /** @brief Compare two null terminated strings.
114 *
115 * @param pszStr1 The first string to compare.
116 * @param pszStr2 The second string to compare.
117 *
118 * @return Zero if the two strings are the same, otherwise nonzero.
119 *
120 * @retval 0 @p pszStr1 and @p pszStr2 are the same.
121 * @retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
122 * values of the first differing bytes.
123 * @retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
124 * values of the first differing bytes.
125 */
RedStrCmp(const char * pszStr1,const char * pszStr2)126 int32_t RedStrCmp( const char * pszStr1,
127 const char * pszStr2 )
128 {
129 int32_t lResult;
130
131 if( ( pszStr1 == NULL ) || ( pszStr2 == NULL ) )
132 {
133 REDERROR();
134 lResult = 0;
135 }
136 else
137 {
138 lResult = RedStrCmpUnchecked( pszStr1, pszStr2 );
139 }
140
141 return lResult;
142 }
143
144
145 #ifndef RedStrCmpUnchecked
146
147 /** @brief Compare two null terminated strings.
148 *
149 * @param pszStr1 The first string to compare.
150 * @param pszStr2 The second string to compare.
151 *
152 * @return Zero if the two strings are the same, otherwise nonzero.
153 */
RedStrCmpUnchecked(const char * pszStr1,const char * pszStr2)154 static int32_t RedStrCmpUnchecked( const char * pszStr1,
155 const char * pszStr2 )
156 {
157 int32_t lResult;
158 uint32_t ulIdx = 0U;
159
160 while( ( pszStr1[ ulIdx ] == pszStr2[ ulIdx ] ) && ( pszStr1[ ulIdx ] != '\0' ) )
161 {
162 ulIdx++;
163 }
164
165 /* "The sign of a non-zero return value is determined by the sign of the
166 * difference between the values of the first pair of bytes (both
167 * interpreted as type unsigned char) that differ in the strings being
168 * compared." Use uint8_t instead of unsigned char to avoid MISRA C
169 * deviations.
170 */
171 if( ( uint8_t ) pszStr1[ ulIdx ] > ( uint8_t ) pszStr2[ ulIdx ] )
172 {
173 lResult = 1;
174 }
175 else if( ( uint8_t ) pszStr1[ ulIdx ] < ( uint8_t ) pszStr2[ ulIdx ] )
176 {
177 lResult = -1;
178 }
179 else
180 {
181 lResult = 0;
182 }
183
184 return lResult;
185 }
186 #endif /* ifndef RedStrCmpUnchecked */
187
188
189 /** @brief Compare the first @p ulLen characters of two null terminated strings.
190 *
191 * @param pszStr1 The first string to compare.
192 * @param pszStr2 The second string to compare.
193 * @param ulLen The maximum length to compare. The comparison stops when
194 * either of the strings end or when @p ulLen bytes have been
195 * compared.
196 *
197 * @return Zero if the two strings are the same, otherwise nonzero.
198 *
199 * @retval 0 @p pszStr1 and @p pszStr2 are the same.
200 * @retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
201 * values of the first differing bytes.
202 * @retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
203 * values of the first differing bytes.
204 */
RedStrNCmp(const char * pszStr1,const char * pszStr2,uint32_t ulLen)205 int32_t RedStrNCmp( const char * pszStr1,
206 const char * pszStr2,
207 uint32_t ulLen )
208 {
209 int32_t lResult;
210
211 if( ( pszStr1 == NULL ) || ( pszStr2 == NULL ) )
212 {
213 REDERROR();
214 lResult = 0;
215 }
216 else
217 {
218 lResult = RedStrNCmpUnchecked( pszStr1, pszStr2, ulLen );
219 }
220
221 return lResult;
222 }
223
224
225 #ifndef RedStrNCmpUnchecked
226
227 /** @brief Compare the first @p ulLen characters of two null terminated strings.
228 *
229 * @param pszStr1 The first string to compare.
230 * @param pszStr2 The second string to compare.
231 * @param ulLen The maximum length to compare. The comparison stops when
232 * either of the strings end or when @p ulLen bytes have been
233 * compared.
234 *
235 * @return Zero if the two strings are the same, otherwise nonzero.
236 */
RedStrNCmpUnchecked(const char * pszStr1,const char * pszStr2,uint32_t ulLen)237 static int32_t RedStrNCmpUnchecked( const char * pszStr1,
238 const char * pszStr2,
239 uint32_t ulLen )
240 {
241 int32_t lResult = 0;
242 uint32_t ulIdx;
243
244 for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
245 {
246 if( pszStr1[ ulIdx ] != pszStr2[ ulIdx ] )
247 {
248 /* "The sign of a non-zero return value is determined by the sign
249 * of the difference between the values of the first pair of bytes
250 * (both interpreted as type unsigned char) that differ in the
251 * strings being compared." Use uint8_t instead of unsigned char
252 * to avoid MISRA C deviations.
253 */
254 if( ( uint8_t ) pszStr1[ ulIdx ] > ( uint8_t ) pszStr2[ ulIdx ] )
255 {
256 lResult = 1;
257 }
258 else
259 {
260 lResult = -1;
261 }
262 }
263
264 if( ( lResult != 0 ) || ( pszStr1[ ulIdx ] == '\0' ) )
265 {
266 break;
267 }
268 }
269
270 return lResult;
271 }
272 #endif /* ifndef RedStrNCmpUnchecked */
273
274
275 /** @brief Copy a string.
276 *
277 * Copy up to @p ulLen bytes of a null-terminated string (@p pszSrc) to a
278 * destination buffer (@p pszDst). The result will not be null-terminated if
279 * @p pszSrc is longer than @p ulLen - 1 bytes.
280 *
281 * If @p pszSrc is shorter than @p ulLen - 1 bytes, the remainder of @p pszDst
282 * will be filled with null bytes.
283 *
284 * @param pszDst The destination buffer, which is at least @p ulLen bytes
285 * in size.
286 * @param pszSrc The null-terminated string to copy.
287 * @param ulLen The maximum number of characters to copy.
288 */
RedStrNCpy(char * pszDst,const char * pszSrc,uint32_t ulLen)289 void RedStrNCpy( char * pszDst,
290 const char * pszSrc,
291 uint32_t ulLen )
292 {
293 if( ( pszDst == NULL ) || ( pszSrc == NULL ) )
294 {
295 REDERROR();
296 }
297 else
298 {
299 RedStrNCpyUnchecked( pszDst, pszSrc, ulLen );
300 }
301 }
302
303
304 #ifndef RedStrNCpyUnchecked
305
306 /** @brief Copy a string.
307 *
308 * @param pszDst The destination buffer, which is at least @p ulLen bytes
309 * in size.
310 * @param pszSrc The null-terminated string to copy.
311 * @param ulLen The maximum number of characters to copy.
312 */
RedStrNCpyUnchecked(char * pszDst,const char * pszSrc,uint32_t ulLen)313 static void RedStrNCpyUnchecked( char * pszDst,
314 const char * pszSrc,
315 uint32_t ulLen )
316 {
317 uint32_t ulIdx = 0U;
318
319 while( ( ulIdx < ulLen ) && ( pszSrc[ ulIdx ] != '\0' ) )
320 {
321 pszDst[ ulIdx ] = pszSrc[ ulIdx ];
322 ulIdx++;
323 }
324
325 while( ulIdx < ulLen )
326 {
327 pszDst[ ulIdx ] = '\0';
328 ulIdx++;
329 }
330 }
331 #endif /* ifndef RedStrNCpyUnchecked */
332