/* ----> 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 | |
/** @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 | |
/** @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 | |
/** @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 | |