Files
zTC1/mico-os/libraries/utilities/StringUtils.c
2025-03-11 15:54:45 +08:00

1357 lines
41 KiB
C

/**
******************************************************************************
* @file StringUtils.c
* @author William Xu
* @version V1.0.0
* @date 05-May-2014
* @brief This file contains function for manipulating strings..
******************************************************************************
*
* The MIT License
* Copyright (c) 2014 MXCHIP Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#include "StringUtils.h"
#include "debug.h"
#include <stddef.h>
#include <stdarg.h>
#ifndef MIN
extern int MIN (/*@sef@*/ int x, /*@sef@*/ int y); /* LINT : This tells lint that the parameter must be side-effect free. i.e. evaluation does not change any values (since it is being evaulated more than once */
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif /* ifndef MIN */
#ifndef MAX
extern int MAX (/*@sef@*/ int x, /*@sef@*/ int y); /* LINT : This tells lint that the parameter must be side-effect free. i.e. evaluation does not change any values (since it is being evaulated more than once */
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif /* ifndef MAX */
#define IS_AF(c) ((c >= 'A') && (c <= 'F'))
#define IS_af(c) ((c >= 'a') && (c <= 'f'))
#define IS_09(c) ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c) IS_09(c)
#define CONVERTDEC(c) (c - '0')
#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))
//===========================================================================================================================
// formatMACAddr
//
// Add ":" to every two character
//===========================================================================================================================
void formatMACAddr(char *destAddr, char *srcAddr)
{
sprintf((char *)destAddr, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",\
toupper(*(char *)srcAddr),toupper(*((char *)(srcAddr)+1)),\
toupper(*((char *)(srcAddr)+2)),toupper(*((char *)(srcAddr)+3)),\
toupper(*((char *)(srcAddr)+4)),toupper(*((char *)(srcAddr)+5)),\
toupper(*((char *)(srcAddr)+6)),toupper(*((char *)(srcAddr)+7)),\
toupper(*((char *)(srcAddr)+8)),toupper(*((char *)(srcAddr)+9)),\
toupper(*((char *)(srcAddr)+10)),toupper(*((char *)(srcAddr)+11)));
}
//===========================================================================================================================
// __strdup
//
// Alloc a new memory and store the input content
//===========================================================================================================================
char *__strdup(const char *src)
{
int len;
char *dst;
if (src == NULL)
return NULL;
if (src[0] == 0)
return NULL;
len = strlen(src) + 1;
dst = (char*)malloc(len);
if (dst)
memcpy(dst, src, len);
return dst;
}
char *__strdup_trans_dot(char *src)
{
char *dst, *dstTemp;
char *srcTemp = src;
uint32_t newLen = strlen(src)+1;
while(*srcTemp!= 0) {
if (*srcTemp == '.')
newLen++;
srcTemp++;
}
dst = malloc(newLen);
dstTemp = dst;
srcTemp = src;
while(*srcTemp!= 0) {
if (*srcTemp == '.') {
*dstTemp++ = '/';
*dstTemp++ = '.';
srcTemp++;
} else {
*dstTemp++ = *srcTemp++;
}
}
*dstTemp = 0x0;
return dst;
}
/***
*strnlen - return the length of a null-terminated string
*
*Purpose:
* Finds the length in bytes of the given string, not including
* the final null character. Only the first maxsize characters
* are inspected: if the null character is not found, maxsize is
* returned.
*
*Entry:
* const char * str - string whose length is to be computed
* size_t maxsize
*
*Exit:
* Length of the string "str", exclusive of the final null byte, or
* maxsize if the null character is not found.
*
*Exceptions:
*
*******************************************************************************/
#if defined (__CC_ARM)
size_t strnlen(const char *str, size_t maxsize)
{
size_t n;
/* Note that we do not check if s == NULL, because we do not
* return errno_t...
*/
for (n = 0; n < maxsize && *str; n++, str++)
;
return n;
}
#endif
void Int2Str(uint8_t* str, int32_t intnum)
{
uint32_t i, Div = 1000000000, j = 0, Status = 0;
for (i = 0; i < 10; i++)
{
str[j++] = (intnum / Div) + 48;
intnum = intnum % Div;
Div /= 10;
if ((str[j-1] == '0') & (Status == 0))
{
j = 0;
}
else
{
Status++;
}
}
}
uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum)
{
uint32_t i = 0, res = 0;
uint32_t val = 0;
if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X'))
{
if (inputstr[2] == '\0')
{
return 0;
}
for (i = 2; i < 11; i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1; */
res = 1;
break;
}
if (ISVALIDHEX(inputstr[i]))
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
/* Return 0, Invalid input */
res = 0;
break;
}
}
/* Over 8 digit hex --invalid */
if (i >= 11)
{
res = 0;
}
}
else /* max 10-digit decimal input */
{
for (i = 0;i < 11;i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1 */
res = 1;
break;
}
else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0))
{
val = val << 10;
*intnum = val;
res = 1;
break;
}
else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0))
{
val = val << 20;
*intnum = val;
res = 1;
break;
}
else if (ISVALIDDEC(inputstr[i]))
{
val = val * 10 + CONVERTDEC(inputstr[i]);
}
else
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* Over 10 digit decimal --invalid */
if (i >= 11)
{
res = 0;
}
}
return res;
}
unsigned int str2hex(unsigned char *ibuf, unsigned char *obuf,
unsigned int olen)
{
unsigned int i; /* loop iteration variable */
unsigned int j = 0; /* current character */
unsigned int by = 0; /* byte value for conversion */
unsigned char ch; /* current character */
unsigned int len = strlen((char *)ibuf);
/* process the list of characaters */
for (i = 0; i < len; i++) {
if (i == (2 * olen)) {
// truncated it.
return j + 1;
}
ch = ibuf[i];
/* do the conversion */
if (ch >= '0' && ch <= '9')
by = (by << 4) + ch - '0';
else if (ch >= 'A' && ch <= 'F')
by = (by << 4) + ch - 'A' + 10;
else if (ch >= 'a' && ch <= 'f')
by = (by << 4) + ch - 'a' + 10;
else { /* error if not hexadecimal */
return 0;
}
/* store a byte for each pair of hexadecimal digits */
if (i & 1) {
j = ((i + 1) / 2) - 1;
obuf[j] = by & 0xff;
}
}
return j + 1;
}
//===========================================================================================================================
// TextToHardwareAddress
//
// Parses hardware address text (e.g. AA:BB:CC:00:11:22:33:44 for Fibre Channel) into an n-byte array.
// Segments can be separated by a colon ':', dash '-', or a space ' '. Segments do not need zero padding
// (e.g. "0:1:2:3:4:5:6:7" is equivalent to "00:01:02:03:04:05:06:07").
//===========================================================================================================================
OSStatus TextToHardwareAddress( const void *inText, size_t inTextSize, size_t inAddrSize, void *outAddr )
{
OSStatus err;
const char * src;
const char * end;
int i;
int x;
char c;
uint8_t * dst;
if( inTextSize == kSizeCString ) inTextSize = strlen( (const char *) inText );
src = (const char *) inText;
end = src + inTextSize;
dst = (uint8_t *) outAddr;
while( inAddrSize-- > 0 )
{
x = 0;
i = 0;
while( ( i < 2 ) && ( src < end ) )
{
c = *src++;
if( isdigit_safe( c ) ) { x = ( x * 16 ) + ( c - '0' ); ++i; }
else if( isxdigit_safe( c ) ) { x = ( x * 16 ) + 10 + ( tolower_safe( c ) - 'a' ); ++i; }
else if( ( i != 0 ) || ( ( c != ':' ) && ( c != '-' ) && ( c != ' ' ) ) ) break;
}
if( i == 0 )
{
err = kMalformedErr;
goto exit;
}
require_action( (( x >= 0x00 ) && ( x <= 0xFF )), exit, err = kRangeErr );
if( dst ) *dst++ = (uint8_t) x;
}
err = kNoErr;
exit:
return err;
}
char* DataToHexString( const uint8_t *inBuf, size_t inBufLen )
{
char* buf_str = NULL;
char* buf_ptr;
require_quiet(inBuf, error);
require_quiet(inBufLen > 0, error);
buf_str = (char*) malloc (2*inBufLen + 1);
require(buf_str, error);
buf_ptr = buf_str;
uint32_t i;
for (i = 0; i < inBufLen; i++) buf_ptr += sprintf(buf_ptr, "%02X", inBuf[i]);
*buf_ptr = '\0';
return buf_str;
error:
if ( buf_str ) free( buf_str );
return NULL;
}
char* DataToHexStringWithSpaces( const uint8_t *inBuf, size_t inBufLen )
{
char* buf_str = NULL;
char* buf_ptr = NULL;
require_quiet(inBuf, error);
require_quiet(inBufLen > 0, error);
buf_str = (char*) malloc (3*inBufLen + 1);
require(buf_str, error);
buf_ptr = buf_str;
uint32_t i;
for (i = 0; i < inBufLen; i++) buf_ptr += sprintf(buf_ptr, "%02X ", inBuf[i]);
*buf_ptr = '\0';
return buf_str;
error:
if ( buf_str ) free( buf_str );
return NULL;
}
char* DataToHexStringWithColons( const uint8_t *inBuf, size_t inBufLen )
{
char* buf_str = NULL;
char* buf_ptr = NULL;
require_quiet(inBuf, error);
require_quiet(inBufLen > 0, error);
buf_str = (char*) malloc (3*inBufLen + 1);
require(buf_str, error);
buf_ptr = buf_str;
uint32_t i;
for (i = 0; i < inBufLen; i++)
{
if ( i == inBufLen - 1 )
buf_ptr += sprintf(buf_ptr, "%02X", inBuf[i]);
else
buf_ptr += sprintf(buf_ptr, "%02X:", inBuf[i]);
}
*buf_ptr = '\0';
return buf_str;
error:
if ( buf_str ) free( buf_str );
return NULL;
}
char* DataToCString( const uint8_t *inBuf, size_t inBufLen )
{
char* cString = NULL;
require_quiet(inBuf, error);
require_quiet(inBufLen > 0, error);
cString = (char*) malloc( inBufLen + 1 );
require(cString, error);
memcpy( cString, inBuf, inBufLen );
*(cString + inBufLen ) = '\0';
return cString;
error:
if ( cString ) free( cString );
return NULL;
}
//===========================================================================================================================
// strnicmp
//
// Like the ANSI C strncmp routine, but performs a case-insensitive compare.
//===========================================================================================================================
int strnicmp( const char *inS1, const char *inS2, size_t inMax )
{
const char * end;
int c1;
int c2;
end = inS1 + inMax;
while( inS1 < end )
{
c1 = tolower( *( (const unsigned char *) inS1 ) );
c2 = tolower( *( (const unsigned char *) inS2 ) );
if( c1 < c2 ) return( -1 );
if( c1 > c2 ) return( 1 );
if( c1 == '\0' ) break;
++inS1;
++inS2;
}
return( 0 );
}
//===========================================================================================================================
// strnicmpx
//
// Like the ANSI C strncmp routine, but case-insensitive and requires all characters in s1 match all characters in s2.
//===========================================================================================================================
int strnicmpx( const void *inS1, size_t inN, const char *inS2 )
{
const unsigned char * s1;
const unsigned char * s2;
int c1;
int c2;
s1 = (const unsigned char *) inS1;
s2 = (const unsigned char *) inS2;
while( inN-- > 0 )
{
c1 = tolower( *s1 );
c2 = tolower( *s2 );
if( c1 < c2 ) return( -1 );
if( c1 > c2 ) return( 1 );
if( c2 == 0 ) return( 0 );
++s1;
++s2;
}
if( *s2 != 0 ) return( -1 );
return( 0 );
}
//===========================================================================================================================
// VSNScanF - va_list version of SNScanF.
//===========================================================================================================================
int VSNScanF( const void *inString, size_t inSize, const char *inFormat, va_list inArgs )
{
int matched;
const unsigned char * src;
const unsigned char * end;
const unsigned char * fmt;
const unsigned char * old;
const unsigned char * setStart;
const unsigned char * setEnd;
const unsigned char * set;
int notSet;
int suppress;
int alt;
int storePtr;
int fieldWidth;
int sizeModifier;
unsigned char * s;
int * i;
int base;
int negative;
unsigned char c;
int64_t x;
int v;
void * p;
const unsigned char ** ptrArg;
size_t * sizeArg;
size_t len;
if( inSize == kSizeCString ) inSize = strlen( (const char *) inString );
src = (const unsigned char *) inString;
end = src + inSize;
fmt = (const unsigned char *) inFormat;
matched = 0;
for( ;; )
{
// Skip whitespace. 1 or more whitespace in the format matches 0 or more whitepsace in the string.
if( isspace( *fmt ) )
{
++fmt;
while( isspace( *fmt ) ) ++fmt;
while( ( src < end ) && isspace( *src ) ) ++src;
}
if( *fmt == '\0' ) break;
// If it's not a conversion, it must match exactly. Otherwise, move onto conversion handling.
if( *fmt != '%' )
{
if( src >= end ) break;
if( *fmt++ != *src++ ) break;
continue;
}
++fmt;
// Flags
suppress = 0;
alt = 0;
storePtr = 0;
for( ;; )
{
c = *fmt;
if( c == '*' ) suppress = 1;
else if( c == '#' ) alt += 1;
else if( c == '&' ) storePtr = 1;
else break;
++fmt;
}
// Field width. If none, use INT_MAX to simplify no-width vs width cases.
if( isdigit( *fmt ) )
{
fieldWidth = 0;
do
{
fieldWidth = ( fieldWidth * 10 ) + ( *fmt++ - '0' );
} while( isdigit( *fmt ) );
}
else if( *fmt == '.' )
{
++fmt;
fieldWidth = va_arg( inArgs, int );
if( fieldWidth < 0 ) goto exit;
}
else
{
fieldWidth = INT_MAX;
}
// Size modifier. Note: converts double-char (e.g. hh) into unique char (e.g. H) for easier processing.
c = *fmt;
switch( c )
{
case 'h':
if( *( ++fmt ) == 'h' ) { sizeModifier = 'H'; ++fmt; } // hh for char * / unsigned char *
else sizeModifier = 'h'; // h for short * / unsigned short *
break;
case 'l':
if( *( ++fmt ) == 'l' ) { sizeModifier = 'L'; ++fmt; } // ll for long long * / unsigned long long *
else sizeModifier = 'l'; // l for long * / unsigned long *
break;
case 'j': // j for intmax_t * / uintmax_t *
case 'z': // z for size_t *
case 't': // t for ptrdiff_t *
sizeModifier = c;
++fmt;
break;
default:
sizeModifier = 0;
break;
}
if( *fmt == '\0' ) break;
// Conversions
switch( *fmt++ )
{
case 'd': // %d: Signed decimal integer.
base = 10;
break;
case 'u': // %u: Unsigned decimal integer.
base = 10;
break;
case 'p': // %x/%X/%p: Hexidecimal integer.
if( sizeModifier == 0 ) sizeModifier = 'p';
case 'x':
case 'X':
base = 16;
break;
case 'o': // %o: Octal integer.
base = 8;
break;
case 'i': // %i: Integer using an optional prefix to determine the base (e.g. 10, 0xA, 012, 0b1010 for decimal 10).
base = 0;
break;
case 'b': // %b: Binary integer.
base = 2;
break;
case 'c': // %c: 1 or more characters.
if( sizeModifier != 0 ) goto exit;
if( storePtr )
{
len = (size_t)( end - src );
if( len > (size_t) fieldWidth )
{
len = (size_t) fieldWidth;
}
if( suppress ) { src += len; continue; }
ptrArg = va_arg( inArgs, const unsigned char ** );
if( ptrArg ) *ptrArg = src;
sizeArg = va_arg( inArgs, size_t * );
if( sizeArg ) *sizeArg = len;
src += len;
}
else
{
if( fieldWidth == INT_MAX ) fieldWidth = 1;
if( ( end - src ) < fieldWidth ) goto exit;
if( suppress ) { src += fieldWidth; continue; }
s = va_arg( inArgs, unsigned char * );
if( !s ) goto exit;
while( fieldWidth-- > 0 ) *s++ = *src++;
}
++matched;
continue;
case 's': // %s: string of non-whitespace characters with a null terminator.
if( sizeModifier != 0 ) goto exit;
// Skip leading white space first since fieldWidth does not include leading whitespace.
while( ( src < end ) && isspace( *src ) ) ++src;
if( !alt && ( ( src >= end ) || ( *src == '\0' ) ) ) goto exit;
// Copy the string until a null terminator, whitespace, or the max fieldWidth is hit.
if( suppress )
{
while( ( src < end ) && ( *src != '\0' ) && !isspace( *src ) && ( fieldWidth-- > 0 ) ) ++src;
}
else if( storePtr )
{
old = src;
while( ( src < end ) && ( *src != '\0' ) && !isspace( *src ) && ( fieldWidth-- > 0 ) ) ++src;
ptrArg = va_arg( inArgs, const unsigned char ** );
if( ptrArg ) *ptrArg = old;
sizeArg = va_arg( inArgs, size_t * );
if( sizeArg ) *sizeArg = (size_t)( src - old );
++matched;
}
else
{
s = va_arg( inArgs, unsigned char * );
if( !s ) goto exit;
while( ( src < end ) && ( *src != '\0' ) && !isspace( *src ) && ( fieldWidth-- > 0 ) ) *s++ = *src++;
*s = '\0';
++matched;
}
continue;
case '[': // %[: Match a scanset (set between brackets or the compliment set if it starts with ^).
if( sizeModifier != 0 ) goto exit;
notSet = ( *fmt == '^' ); // A scanlist starting with ^ matches all characters not in the scanlist.
if( notSet ) ++fmt;
setStart = fmt;
if( *fmt == ']' ) ++fmt; // A scanlist (after a potential ^) starting with ] includes ] in the set.
// Find the end of the scanlist.
while( ( *fmt != '\0' ) && ( *fmt != ']' ) ) ++fmt;
if( *fmt == '\0' ) goto exit;
setEnd = fmt++;
// Parse until a mismatch, null terminator, or the max fieldWidth is hit.
old = src;
if( notSet )
{
while( ( src < end ) && ( *src != '\0' ) && ( fieldWidth-- > 0 ) )
{
c = *src;
for( set = setStart; ( set < setEnd ) && ( *set != c ); ++set ) {}
if( set < setEnd ) break;
++src;
}
}
else
{
while( ( src < end ) && ( *src != '\0' ) && ( fieldWidth-- > 0 ) )
{
c = *src;
for( set = setStart; ( set < setEnd ) && ( *set != c ); ++set ) {}
if( set >= setEnd ) break;
++src;
}
}
if( ( old == src ) && !alt ) goto exit;
if( !suppress )
{
if( storePtr )
{
ptrArg = va_arg( inArgs, const unsigned char ** );
if( ptrArg ) *ptrArg = old;
sizeArg = va_arg( inArgs, size_t * );
if( sizeArg ) *sizeArg = (size_t)( src - old );
}
else
{
s = va_arg( inArgs, unsigned char * );
if( !s ) goto exit;
while( old < src ) *s++ = *old++;
*s = '\0';
}
++matched;
}
continue;
case '%': // %%: Match a literal % character.
if( sizeModifier != 0 ) goto exit;
if( fieldWidth != INT_MAX ) goto exit;
if( suppress ) goto exit;
if( src >= end ) goto exit;
if( *src++ != '%' ) goto exit;
continue;
case 'n': // %n: Return the number of characters read so far.
if( sizeModifier != 0 ) goto exit;
if( fieldWidth != INT_MAX ) goto exit;
if( suppress ) goto exit;
i = va_arg( inArgs, int * );
if( !i ) goto exit;
*i = (int)( src - ( (const unsigned char *) inString ) );
continue;
default: // Unknown conversion.
goto exit;
}
// Number conversion. Skip leading white space since number conversions ignore leading white space.
while( ( src < end ) && isspace( *src ) ) ++src;
// Handle +/- prefix for negative/positive (even for unsigned numbers).
negative = 0;
if( ( ( end - src ) > 1 ) && ( fieldWidth > 0 ) )
{
if( src[ 0 ] == '-' )
{
negative = 1;
++src;
--fieldWidth;
}
else if( src[ 0 ] == '+' )
{
++src;
--fieldWidth;
}
}
// Detect the base for base 0 and skip valid prefixes.
old = src;
if( base == 0 )
{
if( ( ( end - src ) > 2 ) && ( fieldWidth >= 2 ) &&
( src[ 0 ] == '0' ) && ( tolower( src[ 1 ] ) == 'x' ) && isxdigit( src[ 2 ] ) )
{
base = 16;
src += 2;
fieldWidth -= 2;
}
else if( ( ( end - src ) > 2 ) && ( fieldWidth >= 2 ) &&
( src[ 0 ] == '0' ) && ( tolower( src[ 1 ] ) == 'b' ) &&
( ( src[ 2 ] == '0' ) || ( src[ 2 ] == '1' ) ) )
{
base = 2;
src += 2;
fieldWidth -= 2;
}
else if( ( ( end - src ) > 1 ) && ( fieldWidth >= 1 ) &&
( src[ 0 ] == '0' ) && ( src[ 1 ] >= '0' ) && ( src[ 1 ] <= '7' ) )
{
base = 8;
src += 1;
fieldWidth -= 1;
}
else
{
base = 10;
}
}
else if( ( base == 16 ) && ( ( end - src ) >= 2 ) && ( fieldWidth >= 2 ) &&
( src[ 0 ] == '0' ) && ( tolower( src[ 1 ] ) == 'x' ) )
{
src += 2;
fieldWidth -= 2;
}
else if( ( base == 2 ) && ( ( end - src ) >= 2 ) && ( fieldWidth >= 2 ) &&
( src[ 0 ] == '0' ) && ( tolower( src[ 1 ] ) == 'b' ) )
{
src += 2;
fieldWidth -= 2;
}
// Convert the string to a number.
x = 0;
while( ( src < end ) && ( fieldWidth-- > 0 ) )
{
c = *src;
if( isdigit( c ) ) v = c - '0';
else if( isxdigit( c ) ) v = 10 + ( tolower( c ) - 'a' );
else break;
if( v >= base ) break;
x = ( x * base ) + v;
++src;
}
if( src == old ) goto exit;
if( suppress ) continue;
if( negative ) x = -x;
// Store the result.
p = va_arg( inArgs, void * );
if( !p ) goto exit;
switch( sizeModifier )
{
case 0: *( (int *) p ) = (int) x; break;
case 'l': *( (long *) p ) = (long) x; break;
case 'H': *( (char *) p ) = (char) x; break;
case 'h': *( (short *) p ) = (short) x; break;
case 'L': *( (int64_t *) p ) = x; break;
case 'j': *( (intmax_t *) p ) = (intmax_t) x; break;
case 'z': *( (size_t *) p ) = (size_t) x; break;
case 't': *( (ptrdiff_t *) p ) = (ptrdiff_t) x; break;
case 'p': *( (void **) p ) = (void *)( (uintptr_t) x ); break;
default: // Unknown size modifier.
goto exit;
}
++matched;
}
exit:
return( matched );
}
//===========================================================================================================================
// strnicmp_suffix
//
// Like strnicmp routine, but only returns 0 if the entire suffix matches.
//===========================================================================================================================
int strnicmp_suffix( const void *inStr, size_t inMaxLen, const char *inSuffix )
{
const char * stringPtr;
size_t stringLen;
size_t suffixLen;
stringPtr = (const char *) inStr;
stringLen = strnlen( stringPtr, inMaxLen );
suffixLen = strlen( inSuffix );
if( suffixLen <= stringLen )
{
return( strnicmpx( stringPtr + ( stringLen - suffixLen ), suffixLen, inSuffix ) );
}
return( -1 );
}
//===========================================================================================================================
// strnstr_suffix
//
// Like the ANSI C strstr routine, but performs a case-insensitive compare.
//===========================================================================================================================
char * strnstr_suffix( const char *inStr, size_t inMaxLen, const char *inSuffix)
{
size_t stringLen;
size_t suffixLen;
char * instr_tmp;
char * inSuffix_tmp;
size_t i;
char * ret;
suffixLen = strlen( inSuffix );
stringLen = strnlen( inStr, inMaxLen );
instr_tmp = calloc(stringLen+1, 1);
inSuffix_tmp = calloc(suffixLen+1, 1);
for(i=0; i<stringLen; i++)
instr_tmp[i] = tolower(inStr[i]);
for(i=0; i<suffixLen; i++)
inSuffix_tmp[i] = tolower(inSuffix[i]);
if( suffixLen <= stringLen ){
ret = strstr( instr_tmp, inSuffix_tmp );
if(ret != NULL)
ret = (char *)(inStr+(ret-instr_tmp));
}
else
ret = NULL;
free(instr_tmp);
free(inSuffix_tmp);
return ret;
}
//#ifndef __GNUC__
void *memmem(void *start, unsigned int s_len, void *find, unsigned int f_len)
{
char *p, *q;
unsigned int len;
p = start, q = find;
len = 0;
while((p - (char *)start + f_len) <= s_len){
while(*p++ == *q++){
len++;
if(len == f_len)
return(p - f_len);
};
q = find;
len = 0;
};
return(NULL);
}
//#endif
static uint8_t string_to_generic( const char* string, uint8_t str_length, uint32_t* value_out, uint8_t is_unsigned, uint8_t is_hex )
{
uint8_t nibble;
uint8_t characters_processed = 0;
if ( string == NULL )
{
return 0;
}
*value_out = 0;
while ( ( characters_processed != str_length ) &&
( 0 == hexchar_to_nibble( *string, &nibble ) ) &&
( ( is_hex != 0 ) || ( nibble < 10 ) )
)
{
if ( is_hex != 0 )
{
if ( ( ( *value_out > ( 0x7fffffff >> 4 ) ) && ( is_unsigned == 0 ) ) ||
( *value_out > ( 0xffffffff >> 4 ) )
)
{
break;
}
*value_out = ( *value_out << 4 ) + nibble;
}
else
{
if ( ( ( *value_out > ( 0x7fffffff / 10 ) ) && ( is_unsigned == 0 ) ) ||
( *value_out > ( 0xffffffff / 10 ) )
)
{
break;
}
*value_out = ( *value_out * 10 ) + nibble;
}
string++;
characters_processed++;
}
return characters_processed;
}
/*!
******************************************************************************
* Convert a decimal or hexidecimal string to an integer.
*
* @param[in] str The string containing the value.
*
* @return The value represented by the string.
*/
uint32_t generic_string_to_unsigned( const char* str )
{
uint32_t val = 0;
uint8_t is_hex = 0;
if ( strncmp( str, "0x", 2 ) == 0 )
{
is_hex = 1;
str += 2;
}
string_to_unsigned( str, (uint8_t)strlen(str), &val, is_hex );
return val;
}
/**
* Converts a decimal/hexidecimal string (with optional sign) to a signed long int
* Better than strtol or atol or atoi because the return value indicates if an error occurred
*
* @param string[in] : The string buffer to be converted
* @param str_length[in] : The maximum number of characters to process in the string buffer
* @param value_out[out] : The unsigned in that will receive value of the the decimal string
* @param is_hex[in] : 0 = Decimal string, 1 = Hexidecimal string
*
* @return the number of characters successfully converted (including sign). i.e. 0 = error
*
*/
uint8_t string_to_signed( const char* string, uint8_t str_length, int32_t* value_out, uint8_t is_hex )
{
uint8_t characters_processed = 0;
uint8_t retval;
char first_char;
if ( string == NULL )
{
return 0;
}
first_char = *string;
if ( ( first_char == '-' ) || ( *string == '+' ) )
{
characters_processed++;
string++;
str_length--;
}
retval = string_to_generic( string, str_length, (uint32_t*)value_out, 0, is_hex );
if ( retval == 0 )
{
return 0;
}
if ( first_char == '-' )
{
*value_out = -(*value_out);
}
return (uint8_t) ( characters_processed + retval );
}
/**
* Converts a decimal/hexidecimal string to an unsigned long int
* Better than strtol or atol or atoi because the return value indicates if an error occurred
*
* @param string[in] : The string buffer to be converted
* @param str_length[in] : The maximum number of characters to process in the string buffer
* @param value_out[out] : The unsigned in that will receive value of the the decimal string
* @param is_hex[in] : 0 = Decimal string, 1 = Hexidecimal string
*
* @return the number of characters successfully converted. i.e. 0 = error
*
*/
uint8_t string_to_unsigned( const char* string, uint8_t str_length, uint32_t* value_out, uint8_t is_hex )
{
return string_to_generic( string, str_length, value_out, 1, is_hex );
}
/**
* Converts a unsigned long int to a decimal string
*
* @param value[in] : The unsigned long to be converted
* @param output[out] : The buffer which will receive the decimal string
* @param min_length[in] : the minimum number of characters to output (zero padding will apply if required).
* @param max_length[in] : the maximum number of characters to output (up to 10 ). There must be space for terminating NULL.
*
* @note: A terminating NULL is added. Wnsure that there is space in the buffer for this.
*
* @return the number of characters returned (excluding terminating null)
*
*/
uint8_t unsigned_to_decimal_string( uint32_t value, char* output, uint8_t min_length, uint8_t max_length )
{
uint8_t digits_left;
char buffer[ 10 ] = "0000000000";
max_length = (uint8_t) MIN( max_length, sizeof( buffer ) );
digits_left = max_length;
while ( ( value != 0 ) && ( digits_left != 0 ) )
{
--digits_left;
buffer[ digits_left ] = (char) (( value % 10 ) + '0');
value = value / 10;
}
digits_left = (uint8_t) MIN( ( max_length - min_length ), digits_left );
memcpy( output, &buffer[ digits_left ], (size_t)( max_length - digits_left ) );
/* Add terminating null */
output[( max_length - digits_left )] = '\x00';
return (uint8_t) ( max_length - digits_left );
}
/**
* Converts a signed long int to a decimal string
*
* @param value[in] : The signed long to be converted
* @param output[out] : The buffer which will receive the decimal string
* @param min_length[in] : the minimum number of characters to output (zero padding will apply if required)
* @param max_length[in] : the maximum number of characters to output (up to 10 ). There must be space for terminating NULL.
*
* @note: A terminating NULL is added. Wnsure that there is space in the buffer for this.
*
* @return the number of characters returned.
*
*/
uint8_t signed_to_decimal_string( int32_t value, char* output, uint8_t min_length, uint8_t max_length )
{
uint8_t retval = 0;
if ( ( value < 0 ) && ( max_length > 0 ) )
{
*output = '-';
output++;
max_length--;
value = -value;
retval++;
}
retval = (uint8_t) ( retval + unsigned_to_decimal_string( (uint32_t)value, output, min_length, max_length ) );
return retval;
}
/**
* Converts a unsigned long int to a hexidecimal string
*
* @param value[in] : The unsigned long to be converted
* @param output[out] : The buffer which will receive the hexidecimal string
* @param min_length[in] : the minimum number of characters to output (zero padding will apply if required)
* @param max_length[in] : the maximum number of characters to output (up to 8 ) There must be space for terminating NULL.
*
* @note: A terminating NULL is added. Wnsure that there is space in the buffer for this.
* @note: No leading '0x' is added.
*
* @return the number of characters returned.
*
*/
uint8_t unsigned_to_hex_string( uint32_t value, char* output, uint8_t min_length, uint8_t max_length )
{
uint8_t digits_left;
char buffer[ 8 ] = "00000000";
max_length = (uint8_t) MIN( max_length, sizeof( buffer ) );
digits_left = max_length;
while ( ( value != 0 ) && ( digits_left != 0 ) )
{
--digits_left;
buffer[ digits_left ] = nibble_to_hexchar( value & 0x0000000F );
value = value >> 4;
}
digits_left = (uint8_t) MIN( ( max_length - min_length ), digits_left );
memcpy( output, &buffer[ digits_left ], (size_t)( max_length - digits_left ) );
/* Add terminating null */
output[( max_length - digits_left )] = '\x00';
return (uint8_t) ( max_length - digits_left );
}
int is_digit_str( const char* str )
{
int res = 0;
int i = 0;
if ( str != NULL )
{
i = (int)strlen(str);
res = 1;
while ( i > 0 )
{
if ( !IS_09(*str) )
{
res = 0;
break;
}
str++;
i--;
}
}
return res;
}
uint8_t match_string_with_wildcard_pattern( const char* string, uint32_t length, const char* pattern )
{
uint32_t current_string_length = length;
uint32_t temp_string_length = 0;
char* current_string = (char*)string;
char* current_pattern = (char*)pattern;
char* temp_string = NULL;
char* temp_pattern = NULL;
/* Iterate through string and pattern until '*' is found */
while ( ( current_string_length != 0 ) && ( *current_pattern != '*' ) )
{
/* Current pattern is not equal current string and current pattern isn't a wildcard character */
if ( ( *current_pattern != *current_string ) && ( *current_pattern != '?' ) )
{
return 0;
}
current_pattern++;
current_string++;
current_string_length--;
}
/* '*' is detected in pattern. Consume string until matching pattern is found */
while ( current_string_length != 0 )
{
switch ( *current_pattern )
{
case '*':
if ( *(++current_pattern) == '\0' )
{
/* Last character in the pattern is '*'. Return successful */
return 1;
}
/* Store temp variables for starting another matching iteration when non-matching character is found. */
temp_pattern = current_pattern;
temp_string_length = current_string_length - 1;
temp_string = current_string + 1;
break;
case '?':
current_pattern++;
current_string++;
current_string_length--;
break;
default:
if ( *current_pattern == *current_string )
{
current_pattern++;
current_string++;
current_string_length--;
}
else
{
current_pattern = temp_pattern;
current_string = temp_string++;
current_string_length = temp_string_length--;
}
break;
}
}
while ( *current_pattern == '*' )
{
current_pattern++;
}
return ( *current_pattern == '\0' );
}
/*
******************************************************************************
* Length limited version of strstr. Ported from bcmutils.c
*
* @param arg The string to be searched.
* @param arg The length of the string to be searched.
* @param arg The string to be found.
* @param arg The length of the string to be found.
*
* @return pointer to the found string if search successful, otherwise NULL
*/
char* strnstr(const char *s, uint16_t s_len, const char *substr, uint16_t substr_len)
{
for (; s_len >= substr_len; s++, s_len--)
{
if (strncmp(s, substr, substr_len) == 0)
{
return (char*)s;
}
}
return NULL;
}