mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-10-16 01:37:45 -04:00
* Use new version of CI-CD Actions, checkout@v3 instead of checkout@v2 on all jobs * Use cSpell spell check, and use ubuntu-20.04 for formatting check * Add in bot formatting action * Update freertos_demo.yml and freertos_plus_demo.yml files to increase github log readability * Add in a Qemu demo onto the workflows.
475 lines
13 KiB
C
475 lines
13 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 Implements utilities that convert strings to numbers.
|
|
*/
|
|
#include <redfs.h>
|
|
#include <redtestutils.h>
|
|
|
|
|
|
#define ISHEXDIGITU( c ) ( ( ( c ) >= 'A' ) && ( ( c ) <= 'F' ) )
|
|
#define ISHEXDIGITL( c ) ( ( ( c ) >= 'a' ) && ( ( c ) <= 'f' ) )
|
|
#define ISHEXDIGIT( c ) ( ISHEXDIGITL( c ) || ISHEXDIGITU( c ) )
|
|
|
|
|
|
/** @brief Converts an ASCII number into an int32_t.
|
|
*
|
|
* Converts all decimal digit numbers up to the end of the string or to the
|
|
* first non-numerical character.
|
|
*
|
|
* @note This function does *not* ignore leading white space.
|
|
*
|
|
* @param pszNum Pointer to a constant array of characters.
|
|
*
|
|
* @return The integer represented in the string.
|
|
*/
|
|
int32_t RedAtoI( const char * pszNum )
|
|
{
|
|
int32_t lValue = 0;
|
|
int32_t lNegative = 1;
|
|
uint32_t ulIdx = 0U;
|
|
|
|
if( pszNum[ ulIdx ] == '+' )
|
|
{
|
|
ulIdx++;
|
|
}
|
|
else if( pszNum[ ulIdx ] == '-' )
|
|
{
|
|
ulIdx++;
|
|
lNegative = -1;
|
|
}
|
|
else
|
|
{
|
|
/* No sign, implicitly positive.
|
|
*/
|
|
}
|
|
|
|
while( ISDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
lValue *= 10;
|
|
lValue += pszNum[ ulIdx ] - '0';
|
|
ulIdx++;
|
|
}
|
|
|
|
lValue *= lNegative;
|
|
|
|
return lValue;
|
|
}
|
|
|
|
|
|
/** @brief Convert a hexadecimal ASCII number into a uint32_t value.
|
|
*
|
|
* The function processes all hex digits up to a NUL-terminator, or to the
|
|
* first non-hex character. Only hexadecimal digits are processed, so leading
|
|
* white space, or a leading "0x" prefix are not allowed.
|
|
*
|
|
* If pszNum points to an empty string (points to a NUL), this function will
|
|
* return NULL, and the value at *pulNum will not be modified.
|
|
*
|
|
* @note This function does not check for overflow. If there are more
|
|
* significant digits than can be represented in a uint32_t variable, the
|
|
* output is unspecified.
|
|
*
|
|
* @param pszNum A pointer to a constant array of hex characters.
|
|
* @param pulNum A pointer to the location in which to store the uint32_t
|
|
* result. Upon return, this value will be modified ONLY if
|
|
* the function succeeds and the returned pointer is valid (not
|
|
* NULL).
|
|
*
|
|
* @return A pointer to the byte following the converted number or NULL to
|
|
* indicate failure.
|
|
*/
|
|
const char * RedHtoUL( const char * pszNum,
|
|
uint32_t * pulNum )
|
|
{
|
|
uint64_t ullValue;
|
|
const char * pszReturn;
|
|
|
|
pszReturn = RedHtoULL( pszNum, &ullValue );
|
|
|
|
if( pszReturn != NULL )
|
|
{
|
|
if( ullValue < UINT32_MAX )
|
|
{
|
|
*pulNum = ( uint32_t ) ullValue;
|
|
}
|
|
else
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|
|
|
|
|
|
/** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.
|
|
*
|
|
* The function processes all hex digits up to a NUL-terminator, or to the
|
|
* first non-hex character. Only hexadecimal digits are processed, so leading
|
|
* white space, or a leading "0x" prefix are not allowed.
|
|
*
|
|
* If pszNum points to an empty string (points to a NUL), this function will
|
|
* return NULL, and the value at *pulNum will not be modified.
|
|
*
|
|
* @note This function does not check for overflow. If there are more
|
|
* significant digits than can be represented in a uint64_t variable, the
|
|
* output is unspecified.
|
|
*
|
|
* @param pszNum A pointer to a constant array of hex characters.
|
|
* @param pullNum A pointer to the location in which to store the uint64_t
|
|
* result. Upon return, this value will be modified ONLY if
|
|
* the function succeeds and the returned pointer is valid (not
|
|
* NULL).
|
|
*
|
|
* @return A pointer to the byte following the converted number, or NULL to
|
|
* indicate failure.
|
|
*/
|
|
const char * RedHtoULL( const char * pszNum,
|
|
uint64_t * pullNum )
|
|
{
|
|
uint64_t ullValue = 0U;
|
|
const char * pszReturn = NULL;
|
|
uint32_t ulIdx = 0U;
|
|
|
|
REDASSERT( pszNum != NULL );
|
|
REDASSERT( pullNum != NULL );
|
|
|
|
while( pszNum[ ulIdx ] != '\0' )
|
|
{
|
|
char cDigit = pszNum[ ulIdx ];
|
|
|
|
if( ISDIGIT( cDigit ) )
|
|
{
|
|
cDigit -= '0';
|
|
}
|
|
else if( ISHEXDIGITU( cDigit ) )
|
|
{
|
|
cDigit -= ( 'A' - 10 );
|
|
}
|
|
else if( ISHEXDIGITL( cDigit ) )
|
|
{
|
|
cDigit -= ( 'a' - 10 );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
REDASSERT( ( ullValue & UINT64_SUFFIX( 0xF000000000000000 ) ) == 0U );
|
|
|
|
ullValue <<= 4U;
|
|
ullValue += cDigit;
|
|
|
|
ulIdx++;
|
|
pszReturn = &pszNum[ ulIdx ];
|
|
}
|
|
|
|
/* Modify the number returned only if we found one or more valid hex
|
|
* digits.
|
|
*/
|
|
if( pszReturn != NULL )
|
|
{
|
|
*pullNum = ullValue;
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|
|
|
|
|
|
/** @brief Convert the ASCII number to a uint32_t value.
|
|
*
|
|
* The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
|
|
* they may be upper or lower case. The conversion process will stop with the
|
|
* first non hex or decimal digit.
|
|
*
|
|
* If the number is negative (the first character is a '-' sign), the value
|
|
* will be range checked and returned as the equivalent unsigned value.
|
|
*
|
|
* @note This function will NOT fail for numbers which exceed the size of a
|
|
* uint32_t value.
|
|
*
|
|
* @param pszNum A pointer to the ASCII number to convert
|
|
* @param pulNum A pointer to the uint32_t location to store the result.
|
|
* This value will be modified on return only if the function
|
|
* succeeds and the returned pointer is valid (not NULL).
|
|
*
|
|
* @return A pointer to the byte following the converted number, or NULL to
|
|
* indicate failure.
|
|
*/
|
|
const char * RedNtoUL( const char * pszNum,
|
|
uint32_t * pulNum )
|
|
{
|
|
bool fNegative = false;
|
|
uint32_t ulIdx = 0U;
|
|
const char * pszReturn;
|
|
|
|
REDASSERT( pszNum != NULL );
|
|
REDASSERT( pulNum != NULL );
|
|
|
|
if( pszNum[ ulIdx ] == '-' )
|
|
{
|
|
fNegative = true;
|
|
ulIdx++;
|
|
}
|
|
|
|
/* Hex numbers must be prefixed with '0x'.
|
|
*/
|
|
if( ( pszNum[ ulIdx ] == '0' ) && ( ( pszNum[ ulIdx + 1U ] == 'x' ) || ( pszNum[ ulIdx + 1U ] == 'X' ) ) )
|
|
{
|
|
ulIdx += 2U;
|
|
|
|
if( ISDIGIT( pszNum[ ulIdx ] ) || ISHEXDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
pszReturn = RedHtoUL( &pszNum[ ulIdx ], pulNum );
|
|
}
|
|
else
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
}
|
|
else if( ISDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
uint32_t ulTemp;
|
|
|
|
ulTemp = RedAtoI( &pszNum[ ulIdx ] );
|
|
|
|
while( ISDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
ulIdx++;
|
|
}
|
|
|
|
if( fNegative )
|
|
{
|
|
/* Fail if the number is out of range.
|
|
*/
|
|
if( ulTemp > INT32_MAX )
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
*pulNum = -( ( int32_t ) ulTemp );
|
|
pszReturn = &pszNum[ ulIdx ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pulNum = ulTemp;
|
|
pszReturn = &pszNum[ ulIdx ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Return an error if there is not at least one hex or decimal digit.
|
|
*/
|
|
pszReturn = NULL;
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|
|
|
|
|
|
/** @brief Convert the ASCII number pointed to by pszNum to a uint64_t value.
|
|
*
|
|
* The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
|
|
* they may be upper or lower case. The conversion process will stop with the
|
|
* first non hex or decimal digit.
|
|
*
|
|
* If the number is negative (the first character is a '-' sign), the value
|
|
* will be range checked and returned as the equivalent unsigned value.
|
|
*
|
|
* @param pszNum A pointer to the ASCII number to convert.
|
|
* @param pullNum A pointer to the uint64_t location to store the result.
|
|
* This value will be modified on return only if the function
|
|
* succeeds and the returned pointer is valid (not NULL).
|
|
*
|
|
* @return A pointer to the byte following the converted number, or NULL to
|
|
* indicate failure.
|
|
*/
|
|
const char * RedNtoULL( const char * pszNum,
|
|
uint64_t * pullNum )
|
|
{
|
|
bool fNegative = false;
|
|
uint32_t ulIdx = 0U;
|
|
const char * pszReturn;
|
|
|
|
REDASSERT( pszNum != NULL );
|
|
REDASSERT( pullNum != NULL );
|
|
|
|
if( pszNum[ ulIdx ] == '-' )
|
|
{
|
|
fNegative = true;
|
|
ulIdx++;
|
|
}
|
|
|
|
/* Hex numbers must be prefixed with '0x'.
|
|
*/
|
|
if( ( pszNum[ ulIdx ] == '0' ) && ( ( pszNum[ ulIdx + 1U ] == 'x' ) || ( pszNum[ ulIdx + 1U ] == 'X' ) ) )
|
|
{
|
|
ulIdx += 2U;
|
|
|
|
if( ISDIGIT( pszNum[ ulIdx ] ) || ISHEXDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
pszReturn = RedHtoULL( &pszNum[ ulIdx ], pullNum );
|
|
}
|
|
else
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
}
|
|
else if( ISDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
uint64_t ullTemp = 0U;
|
|
|
|
while( ISDIGIT( pszNum[ ulIdx ] ) )
|
|
{
|
|
ullTemp *= 10U;
|
|
ullTemp += pszNum[ ulIdx ] - '0';
|
|
ulIdx++;
|
|
}
|
|
|
|
if( fNegative )
|
|
{
|
|
/* Fail if the number is out of range.
|
|
*/
|
|
if( ullTemp > INT64_MAX )
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
*pullNum = ( uint64_t ) ( -( ( int64_t ) ullTemp ) );
|
|
pszReturn = &pszNum[ ulIdx ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pullNum = ullTemp;
|
|
pszReturn = &pszNum[ ulIdx ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Return an error if there is not at least one hex or decimal digit.
|
|
*/
|
|
pszReturn = NULL;
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|
|
|
|
|
|
/** @brief Convert an ASCII hex or decimal number, which may may have a "B",
|
|
* "KB", or "MB" suffix (case insensitive), to a binary value.
|
|
*
|
|
* Hex numbers must be prefixed with "0x".
|
|
*
|
|
* @note If there is no postfix, KB is assumed!
|
|
*
|
|
* May fail due to bad formatting or overflow.
|
|
*
|
|
* @param pszNum A pointer to the ASCII number to convert.
|
|
* @param pulResult A pointer to a uint32_t in which to place the result.
|
|
*
|
|
* @return A pointer to the byte following the string, or NULL to indicate an
|
|
* error. In the event of an error, *pulResult will not be modified.
|
|
*/
|
|
const char * RedSizeToUL( const char * pszNum,
|
|
uint32_t * pulResult )
|
|
{
|
|
uint32_t ulResult;
|
|
const char * pszSuffix;
|
|
const char * pszReturn;
|
|
uint32_t ulIdx = 0U;
|
|
|
|
REDASSERT( pszNum != NULL );
|
|
REDASSERT( pulResult != NULL );
|
|
|
|
/* Do the basic hex/decimal conversion
|
|
*/
|
|
pszSuffix = RedNtoUL( pszNum, &ulResult );
|
|
|
|
if( pszSuffix != NULL )
|
|
{
|
|
if( ( pszSuffix[ ulIdx ] == 'B' ) || ( pszSuffix[ ulIdx ] == 'b' ) )
|
|
{
|
|
ulIdx++;
|
|
pszReturn = &pszSuffix[ ulIdx ];
|
|
}
|
|
else if( ( ( pszSuffix[ ulIdx ] == 'M' ) || ( pszSuffix[ ulIdx ] == 'm' ) ) &&
|
|
( ( pszSuffix[ ulIdx + 1U ] == 'B' ) || ( pszSuffix[ ulIdx + 1U ] == 'b' ) ) )
|
|
{
|
|
ulIdx += 2U;
|
|
|
|
if( ulResult > ( UINT32_MAX / ( 1024U * 1024U ) ) )
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
ulResult *= 1024U * 1024U;
|
|
pszReturn = &pszSuffix[ ulIdx ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The number is either postfixed with "KB" or something
|
|
* else (we don't care), but we must increment the pointer
|
|
* if it is something recognize.
|
|
*/
|
|
if( ( ( pszSuffix[ ulIdx ] == 'K' ) || ( pszSuffix[ ulIdx ] == 'k' ) ) &&
|
|
( ( pszSuffix[ ulIdx + 1U ] == 'B' ) || ( pszSuffix[ ulIdx + 1U ] == 'b' ) ) )
|
|
{
|
|
ulIdx += 2U;
|
|
}
|
|
|
|
/* "B" or "MB" were not specified, so it must be "KB"
|
|
*/
|
|
if( ulResult > ( UINT32_MAX / 1024U ) )
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
ulResult *= 1024UL;
|
|
pszReturn = &pszSuffix[ ulIdx ];
|
|
}
|
|
}
|
|
|
|
if( pszReturn != NULL )
|
|
{
|
|
*pulResult = ulResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszReturn = NULL;
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|