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