You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
10 KiB
C
332 lines
10 KiB
C
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
|
|
*
|
|
* Copyright (c) 2014-2015 Datalight, Inc.
|
|
* All Rights Reserved Worldwide.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; use version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
/* Businesses and individuals that for commercial or other reasons cannot
|
|
* comply with the terms of the GPLv2 license may obtain a commercial license
|
|
* before incorporating Reliance Edge into proprietary software for
|
|
* distribution in any form. Visit http://www.datalight.com/reliance-edge for
|
|
* more information.
|
|
*/
|
|
|
|
/** @file
|
|
* @brief Default implementations of string manipulation functions.
|
|
*
|
|
* These implementations are intended to be small and simple, and thus forego
|
|
* all optimizations. If the C library is available, or if there are better
|
|
* third-party implementations available in the system, those can be used
|
|
* instead by defining the appropriate macros in redconf.h.
|
|
*
|
|
* These functions are not intended to be completely 100% ANSI C compatible
|
|
* implementations, but rather are designed to meet the needs of Reliance Edge.
|
|
* The compatibility is close enough that ANSI C compatible implementations
|
|
* can be "dropped in" as replacements without difficulty.
|
|
*/
|
|
#include <redfs.h>
|
|
|
|
|
|
#ifndef RedStrLenUnchecked
|
|
static uint32_t RedStrLenUnchecked( const char * pszStr );
|
|
#endif
|
|
#ifndef RedStrCmpUnchecked
|
|
static int32_t RedStrCmpUnchecked( const char * pszStr1,
|
|
const char * pszStr2 );
|
|
#endif
|
|
#ifndef RedStrNCmpUnchecked
|
|
static int32_t RedStrNCmpUnchecked( const char * pszStr1,
|
|
const char * pszStr2,
|
|
uint32_t ulLen );
|
|
#endif
|
|
#ifndef RedStrNCpyUnchecked
|
|
static void RedStrNCpyUnchecked( char * pszDst,
|
|
const char * pszSrc,
|
|
uint32_t ulLen );
|
|
#endif
|
|
|
|
|
|
/** @brief Determine the length (in bytes) of a null terminated string.
|
|
*
|
|
* The length does not include the null terminator byte.
|
|
*
|
|
* @param pszStr The null terminated string whose length is to be determined.
|
|
*
|
|
* @return The length of the @p pszStr string.
|
|
*/
|
|
uint32_t RedStrLen( const char * pszStr )
|
|
{
|
|
uint32_t ulLen;
|
|
|
|
if( pszStr == NULL )
|
|
{
|
|
REDERROR();
|
|
ulLen = 0U;
|
|
}
|
|
else
|
|
{
|
|
/* Cast the result to uint32_t, since RedStrLenUnchecked() might be
|
|
* strlen(), which returns size_t, which is possibly a 64-bit value.
|
|
*/
|
|
ulLen = ( uint32_t ) RedStrLenUnchecked( pszStr );
|
|
}
|
|
|
|
return ulLen;
|
|
}
|
|
|
|
|
|
#ifndef RedStrLenUnchecked
|
|
|
|
/** @brief Determine the length (in bytes) of a null terminated string.
|
|
*
|
|
* @param pszStr The null terminated string whose length is to be determined.
|
|
*
|
|
* @return The length of the @p pszStr string.
|
|
*/
|
|
static uint32_t RedStrLenUnchecked( const char * pszStr )
|
|
{
|
|
uint32_t ulLen = 0U;
|
|
|
|
while( pszStr[ ulLen ] != '\0' )
|
|
{
|
|
ulLen++;
|
|
}
|
|
|
|
return ulLen;
|
|
}
|
|
#endif /* ifndef RedStrLenUnchecked */
|
|
|
|
|
|
/** @brief Compare two null terminated strings.
|
|
*
|
|
* @param pszStr1 The first string to compare.
|
|
* @param pszStr2 The second string to compare.
|
|
*
|
|
* @return Zero if the two strings are the same, otherwise nonzero.
|
|
*
|
|
* @retval 0 @p pszStr1 and @p pszStr2 are the same.
|
|
* @retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
|
|
* values of the first differing bytes.
|
|
* @retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
|
|
* values of the first differing bytes.
|
|
*/
|
|
int32_t RedStrCmp( const char * pszStr1,
|
|
const char * pszStr2 )
|
|
{
|
|
int32_t lResult;
|
|
|
|
if( ( pszStr1 == NULL ) || ( pszStr2 == NULL ) )
|
|
{
|
|
REDERROR();
|
|
lResult = 0;
|
|
}
|
|
else
|
|
{
|
|
lResult = RedStrCmpUnchecked( pszStr1, pszStr2 );
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
#ifndef RedStrCmpUnchecked
|
|
|
|
/** @brief Compare two null terminated strings.
|
|
*
|
|
* @param pszStr1 The first string to compare.
|
|
* @param pszStr2 The second string to compare.
|
|
*
|
|
* @return Zero if the two strings are the same, otherwise nonzero.
|
|
*/
|
|
static int32_t RedStrCmpUnchecked( const char * pszStr1,
|
|
const char * pszStr2 )
|
|
{
|
|
int32_t lResult;
|
|
uint32_t ulIdx = 0U;
|
|
|
|
while( ( pszStr1[ ulIdx ] == pszStr2[ ulIdx ] ) && ( pszStr1[ ulIdx ] != '\0' ) )
|
|
{
|
|
ulIdx++;
|
|
}
|
|
|
|
/* "The sign of a non-zero return value is determined by the sign of the
|
|
* difference between the values of the first pair of bytes (both
|
|
* interpreted as type unsigned char) that differ in the strings being
|
|
* compared." Use uint8_t instead of unsigned char to avoid MISRA C
|
|
* deviations.
|
|
*/
|
|
if( ( uint8_t ) pszStr1[ ulIdx ] > ( uint8_t ) pszStr2[ ulIdx ] )
|
|
{
|
|
lResult = 1;
|
|
}
|
|
else if( ( uint8_t ) pszStr1[ ulIdx ] < ( uint8_t ) pszStr2[ ulIdx ] )
|
|
{
|
|
lResult = -1;
|
|
}
|
|
else
|
|
{
|
|
lResult = 0;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
#endif /* ifndef RedStrCmpUnchecked */
|
|
|
|
|
|
/** @brief Compare the first @p ulLen characters of two null terminated strings.
|
|
*
|
|
* @param pszStr1 The first string to compare.
|
|
* @param pszStr2 The second string to compare.
|
|
* @param ulLen The maximum length to compare. The comparison stops when
|
|
* either of the strings end or when @p ulLen bytes have been
|
|
* compared.
|
|
*
|
|
* @return Zero if the two strings are the same, otherwise nonzero.
|
|
*
|
|
* @retval 0 @p pszStr1 and @p pszStr2 are the same.
|
|
* @retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
|
|
* values of the first differing bytes.
|
|
* @retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
|
|
* values of the first differing bytes.
|
|
*/
|
|
int32_t RedStrNCmp( const char * pszStr1,
|
|
const char * pszStr2,
|
|
uint32_t ulLen )
|
|
{
|
|
int32_t lResult;
|
|
|
|
if( ( pszStr1 == NULL ) || ( pszStr2 == NULL ) )
|
|
{
|
|
REDERROR();
|
|
lResult = 0;
|
|
}
|
|
else
|
|
{
|
|
lResult = RedStrNCmpUnchecked( pszStr1, pszStr2, ulLen );
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
#ifndef RedStrNCmpUnchecked
|
|
|
|
/** @brief Compare the first @p ulLen characters of two null terminated strings.
|
|
*
|
|
* @param pszStr1 The first string to compare.
|
|
* @param pszStr2 The second string to compare.
|
|
* @param ulLen The maximum length to compare. The comparison stops when
|
|
* either of the strings end or when @p ulLen bytes have been
|
|
* compared.
|
|
*
|
|
* @return Zero if the two strings are the same, otherwise nonzero.
|
|
*/
|
|
static int32_t RedStrNCmpUnchecked( const char * pszStr1,
|
|
const char * pszStr2,
|
|
uint32_t ulLen )
|
|
{
|
|
int32_t lResult = 0;
|
|
uint32_t ulIdx;
|
|
|
|
for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
|
|
{
|
|
if( pszStr1[ ulIdx ] != pszStr2[ ulIdx ] )
|
|
{
|
|
/* "The sign of a non-zero return value is determined by the sign
|
|
* of the difference between the values of the first pair of bytes
|
|
* (both interpreted as type unsigned char) that differ in the
|
|
* strings being compared." Use uint8_t instead of unsigned char
|
|
* to avoid MISRA C deviations.
|
|
*/
|
|
if( ( uint8_t ) pszStr1[ ulIdx ] > ( uint8_t ) pszStr2[ ulIdx ] )
|
|
{
|
|
lResult = 1;
|
|
}
|
|
else
|
|
{
|
|
lResult = -1;
|
|
}
|
|
}
|
|
|
|
if( ( lResult != 0 ) || ( pszStr1[ ulIdx ] == '\0' ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
#endif /* ifndef RedStrNCmpUnchecked */
|
|
|
|
|
|
/** @brief Copy a string.
|
|
*
|
|
* Copy up to @p ulLen bytes of a null-terminated string (@p pszSrc) to a
|
|
* destination buffer (@p pszDst). The result will not be null-terminated if
|
|
* @p pszSrc is longer than @p ulLen - 1 bytes.
|
|
*
|
|
* If @p pszSrc is shorter than @p ulLen - 1 bytes, the remainder of @p pszDst
|
|
* will be filled with null bytes.
|
|
*
|
|
* @param pszDst The destination buffer, which is at least @p ulLen bytes
|
|
* in size.
|
|
* @param pszSrc The null-terminated string to copy.
|
|
* @param ulLen The maximum number of characters to copy.
|
|
*/
|
|
void RedStrNCpy( char * pszDst,
|
|
const char * pszSrc,
|
|
uint32_t ulLen )
|
|
{
|
|
if( ( pszDst == NULL ) || ( pszSrc == NULL ) )
|
|
{
|
|
REDERROR();
|
|
}
|
|
else
|
|
{
|
|
RedStrNCpyUnchecked( pszDst, pszSrc, ulLen );
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef RedStrNCpyUnchecked
|
|
|
|
/** @brief Copy a string.
|
|
*
|
|
* @param pszDst The destination buffer, which is at least @p ulLen bytes
|
|
* in size.
|
|
* @param pszSrc The null-terminated string to copy.
|
|
* @param ulLen The maximum number of characters to copy.
|
|
*/
|
|
static void RedStrNCpyUnchecked( char * pszDst,
|
|
const char * pszSrc,
|
|
uint32_t ulLen )
|
|
{
|
|
uint32_t ulIdx = 0U;
|
|
|
|
while( ( ulIdx < ulLen ) && ( pszSrc[ ulIdx ] != '\0' ) )
|
|
{
|
|
pszDst[ ulIdx ] = pszSrc[ ulIdx ];
|
|
ulIdx++;
|
|
}
|
|
|
|
while( ulIdx < ulLen )
|
|
{
|
|
pszDst[ ulIdx ] = '\0';
|
|
ulIdx++;
|
|
}
|
|
}
|
|
#endif /* ifndef RedStrNCpyUnchecked */
|