330 lines
9.4 KiB
C
330 lines
9.4 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
|
||
|
|
||
|
|
||
|
/** @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
|
||
|
|