/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
************************************************************************
* @file M4DPAK_CharStar.c
* @ingroup
* @brief definition of the Char Star set of functions.
* @note This file defines the Char Star set of functions.
*
************************************************************************
*/
#include "M4OSA_CharStar.h"
#include "M4OSA_Memory.h"
#include "M4OSA_Debug.h"
/* WARNING: Specific Android */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
/**
************************************************************************
* @brief This function mimics the functionality of the libc's strncpy().
* @note It copies exactly len2Copy characters from pStrIn to pStrOut,
* truncating pStrIn or adding null characters to pStrOut if
* necessary.
* - If len2Copy is less than or equal to the length of pStrIn,
* a null character is appended automatically to the copied
* string.
* - If len2Copy is greater than the length of pStrIn, pStrOut is
* padded with null characters up to length len2Copy.
* - pStrOut and pStrIn MUST NOT OVERLAP (this is NOT CHECKED).
* @param pStrOut: (OUT) Destination character string.
* @param pStrIn: (IN) Source character string.
* @param len2Copy: (IN) Maximum number of characters from pStrIn to copy.
* @return M4NO_ERROR: there is no error.
* @return M4ERR_PARAMETER: pStrIn or pStrOut is M4OSA_NULL.
************************************************************************
*/
M4OSA_ERR M4OSA_chrNCopy(M4OSA_Char* pStrOut, M4OSA_Char *pStrIn, M4OSA_UInt32 len2Copy)
{
M4OSA_TRACE1_3("M4OSA_chrNCopy\t(M4OSA_Char* %x,M4OSA_Char* %x,M4OSA_UInt32 %ld)",
pStrOut,pStrIn,len2Copy);
M4OSA_DEBUG_IF2((M4OSA_NULL == pStrOut),M4ERR_PARAMETER,
"M4OSA_chrNCopy:\tpStrOut is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL == pStrIn),M4ERR_PARAMETER,
"M4OSA_chrNCopy:\tpStrIn is M4OSA_NULL");
strncpy((char *)pStrOut, (const char *)pStrIn, (size_t)len2Copy);
if(len2Copy <= (M4OSA_UInt32)strlen((const char *)pStrIn))
{
pStrOut[len2Copy] = '\0';
}
return M4NO_ERROR;
}
/**
************************************************************************
* @brief This function returns the boolean comparison of pStrIn1 and pStrIn2.
* @note The value returned in result is M4OSA_TRUE if the string
* pointed to by pStrIn1 is strictly identical to the string pointed
* to by pStrIn2, and M4OSA_FALSE otherwise.
* @param pStrIn1: (IN) First character string.
* @param pStrIn2: (IN) Second character string.
* @param cmpResult: (OUT) Comparison result.
* @return M4NO_ERROR: there is no error.
* @return M4ERR_PARAMETER: pStrIn1 pStrIn2 or cmpResult is M4OSA_NULL.
************************************************************************
*/
M4OSA_ERR M4OSA_chrAreIdentical(M4OSA_Char* pStrIn1, M4OSA_Char* pStrIn2,
M4OSA_Bool* pResult)
{
M4OSA_UInt32 i32,len32;
M4OSA_TRACE1_3("M4OSA_chrAreIdentical\t(M4OSA_Char* %x,M4OSA_Char* %x,"
"M4OSA_Int32* %x)",pStrIn1,pStrIn2,pResult);
M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn1, M4ERR_PARAMETER,
"M4OSA_chrAreIdentical:\tpStrIn1 is M4OSA_NULL");
M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn2, M4ERR_PARAMETER,
"M4OSA_chrAreIdentical:\tpStrIn2 is M4OSA_NULL");
M4OSA_DEBUG_IF2(M4OSA_NULL == pResult, M4ERR_PARAMETER,
"M4OSA_chrAreIdentical:\tpResult is M4OSA_NULL");
len32 = (M4OSA_UInt32)strlen((const char *)pStrIn1);
if(len32 != (M4OSA_UInt32)strlen((const char *)pStrIn2))
{
*pResult = M4OSA_FALSE;
return M4NO_ERROR;
}
for(i32=0;i32<len32;i32++)
{
if(pStrIn1[i32] != pStrIn2[i32])
{
*pResult = M4OSA_FALSE;
return M4NO_ERROR;
}
}
*pResult = M4OSA_TRUE;
return M4NO_ERROR;
}
/**
************************************************************************
* @brief This function gets a M4OSA_UInt32 from string.
* @note This function converts the first set of non-whitespace
* characters of pStrIn to a M4OSA_UInt32 value pVal, assuming a
* representation in base provided by the parameter base. pStrOut is
* set to the first character of the string following the last
* character of the number that has been converted.
* - in case of a failure during the conversion, pStrOut is not
* updated, and pVal is set to null.
* - in case of negative number, pStrOut is not updated, and pVal is
* set to null.
* - in case of numerical overflow, pVal is set to M4OSA_UINT32_MAX.
* - if pStrOut is not to be used, it can be set to M4OSA_NULL.
* @param pStrIn: (IN) Character string.
* @param pVal: (OUT) read value.
* @param pStrOut: (OUT) Output character string.
* @param base: (IN) Base of the character string representation.
* @return M4NO_ERROR: there is no error.
* @return M4ERR_PARAMETER: pStrIn or pVal is M4OSA_NULL.
* @return M4ERR_CHR_CONV_FAILED: conversion failure.
* @return M4WAR_CHR_NUM_RANGE: the character string represents a number
* greater than M4OSA_UINT32_MAX.
* @return M4WAR_CHR_NEGATIVE: the character string represents a negative
* number.
************************************************************************
*/
M4OSA_ERR M4OSA_chrGetUInt32(M4OSA_Char* pStrIn,
M4OSA_UInt32* pVal,
M4OSA_Char** pStrOut,
M4OSA_chrNumBase base)
{
M4OSA_UInt32 ul;
char* pTemp;
M4OSA_TRACE1_4("M4OSA_chrGetUInt32\t(M4OSA_Char* %x, M4OSA_UInt32* %x"
"M4OSA_Char** %x,M4OSA_chrNumBase %d)",pStrIn,pVal,pStrOut,base);
M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn, M4ERR_PARAMETER,
"M4OSA_chrGetUInt32:\tpStrIn is M4OSA_NULL");
M4OSA_DEBUG_IF2(M4OSA_NULL == pVal, M4ERR_PARAMETER,
"M4OSA_chrGetUInt32:\tpVal is M4OSA_NULL");
errno = 0;
switch(base)
{
case M4OSA_kchrDec:
ul = strtoul((const char *)pStrIn, &pTemp, 10);
break;
case M4OSA_kchrHexa:
ul = strtoul((const char *)pStrIn, &pTemp,16);
break;
case M4OSA_kchrOct:
ul = strtoul((const char *)pStrIn, &pTemp,8);
break;
default:
return M4ERR_PARAMETER;
}
/* has conversion failed ? */
if((M4OSA_Char*)pTemp == pStrIn)
{
*pVal = 0;
return M4ERR_CHR_CONV_FAILED;
}
/* was the number negative ? */
if(*(pStrIn+strspn((const char *)pStrIn," \t")) == '-')
{
*pVal = 0;
return M4WAR_CHR_NEGATIVE;
}
/* has an overflow occured ? */
if(errno == ERANGE)
{
*pVal = M4OSA_UINT32_MAX;
if(M4OSA_NULL != pStrOut)
{
*pStrOut = (M4OSA_Char*)pTemp;
}
return M4WAR_CHR_NUM_RANGE;
}
/* nominal case */
*pVal = (M4OSA_UInt32)ul;
if(M4OSA_NULL != pStrOut)
{
*pStrOut = (M4OSA_Char*)pTemp;
}
return M4NO_ERROR;
}
/**
************************************************************************
* @brief This function gets a M4OSA_UInt16 from string.
* @note This function converts the first set of non-whitespace
* characters of pStrIn to a M4OSA_UInt16 value pVal, assuming a
* representation in base provided by the parameter base. pStrOut is
* set to the first character of the string following the last
* character of the number that has been converted.
* - in case of a failure during the conversion, pStrOut is not
* updated, and pVal is set to null.
* - in case of negative number, pStrOut is not updated, and pVal is
* set to null.
* - in case of numerical overflow, pVal is set to M4OSA_UINT16_MAX.
* - if pStrOut is not to be used, it can be set to M4OSA_NULL.
* @param pStrIn: (IN) Character string.
* @param pVal: (OUT) read value.
* @param pStrOut: (OUT) Output character string.
* @param base: (IN) Base of the character string representation.
* @return M4NO_ERROR: there is no error.
* @return M4ERR_PARAMETER: pStrIn or pVal is M4OSA_NULL.
* @return M4ERR_CHR_CONV_FAILED: conversion failure.
* @return M4WAR_CHR_NUM_RANGE: the character string represents a number
* greater than M4OSA_UINT16_MAX.
* @return M4WAR_CHR_NEGATIVE: the character string represents a negative
* number.
************************************************************************
*/
M4OSA_ERR M4OSA_chrGetUInt16 (M4OSA_Char* pStrIn, M4OSA_UInt16 *pVal,
M4OSA_Char** pStrOut, M4OSA_chrNumBase base)
{
M4OSA_UInt32 ul;
char* pTemp;
M4OSA_TRACE1_4("M4OSA_chrGetUInt16\t(M4OSA_Char* %x, M4OSA_UInt16* %x"
"M4OSA_Char** %x,M4OSA_chrNumBase %d)",pStrIn,pVal,pStrOut,base);
M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn,M4ERR_PARAMETER,
"M4OSA_chrGetUInt16:\tpStrIn is M4OSA_NULL");
M4OSA_DEBUG_IF2(M4OSA_NULL == pVal, M4ERR_PARAMETER,
"M4OSA_chrGetUInt16:\tpVal is M4OSA_NULL");
switch(base)
{
case M4OSA_kchrDec:
ul = strtoul((const char *)pStrIn, &pTemp,10);
break;
case M4OSA_kchrHexa:
ul = strtoul((const char *)pStrIn, &pTemp,16);
break;
case M4OSA_kchrOct:
ul = strtoul((const char *)pStrIn, &pTemp,8);
break;
default:
return M4ERR_PARAMETER;
}
/* has conversion failed ? */
if((M4OSA_Char*)pTemp == pStrIn)
{
*pVal = 0;
return M4ERR_CHR_CONV_FAILED;
}
/* was the number negative ? */
if(*(pStrIn+strspn((const char *)pStrIn," \t")) == '-')
{
*pVal = 0;
return M4WAR_CHR_NEGATIVE;
}
/* has an overflow occured ? */
if(ul>M4OSA_UINT16_MAX)
{
*pVal = M4OSA_UINT16_MAX;
if(M4OSA_NULL != pStrOut)
{
*pStrOut = (M4OSA_Char*)pTemp;
}
return M4WAR_CHR_NUM_RANGE;
}
/* nominal case */
*pVal = (M4OSA_UInt16)ul;
if(M4OSA_NULL != pStrOut)
{
*pStrOut = (M4OSA_Char*)pTemp;
}
return M4NO_ERROR;
}
M4OSA_ERR M4OSA_chrSPrintf(M4OSA_Char *pStrOut, M4OSA_UInt32 strOutMaxLen,
M4OSA_Char *format, ...)
{
va_list marker;
M4OSA_Char *pTemp;
M4OSA_Char *percentPointer;
M4OSA_Char *newFormat;
M4OSA_Int32 newFormatLength=0;
M4OSA_UInt32 count_ll = 0;
M4OSA_UInt32 count_tm = 0;
M4OSA_UInt32 count_aa = 0;
M4OSA_UInt32 count;
M4OSA_UInt32 nbChar;
M4OSA_Int32 err;
M4OSA_Char flagChar[] = "'-+ #0";
M4OSA_Char widthOrPrecisionChar[] = "*0123456789";
M4OSA_Char otherPrefixChar[] = "hlL";
M4OSA_Char conversionChar[] = "diouxXnfeEgGcCsSp%";
M4OSA_TRACE1_3("M4OSA_chrSPrintf\t(M4OSA_Char* %x, M4OSA_UInt32 %ld"
"M4OSA_Char* %x)",pStrOut,strOutMaxLen,format);
M4OSA_DEBUG_IF2(M4OSA_NULL == pStrOut, M4ERR_PARAMETER,
"M4OSA_chrSPrintf:\tpStrOut is M4OSA_NULL");
M4OSA_DEBUG_IF2(M4OSA_NULL == format, M4ERR_PARAMETER,
"M4OSA_chrSPrintf:\tformat is M4OSA_NULL");
va_start(marker,format);
/* count the number of %[flags][width][.precision]ll[conversion] */
pTemp = format;
while(*pTemp)
{
percentPointer = (M4OSA_Char *)strchr((const char *)pTemp,'%'); /* get the next percent character */
if(!percentPointer)
break; /* "This is the End", (c) J. Morrisson */
pTemp = percentPointer+1; /* span it */
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
pTemp += strspn((const char *)pTemp,(const char *)flagChar); /* span the optional flags */
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
pTemp += strspn((const char *)pTemp,(const char *)widthOrPrecisionChar); /* span the optional width */
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
if(*pTemp=='.')
{
pTemp++;
pTemp += strspn((const char *)pTemp, (const char *)widthOrPrecisionChar); /* span the optional precision */
}
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
if(strlen((const char *)pTemp)>=2)
{
if(!strncmp((const char *)pTemp,"ll",2))
{
count_ll++; /* I got ONE */
pTemp +=2; /* span the "ll" prefix */
}
else if(!strncmp((const char *)pTemp,"tm",2))
{
count_tm++;
pTemp +=2;
}
else if(!strncmp((const char *)pTemp,"aa",2))
{
count_aa++;
pTemp +=2;
}
}
pTemp += strspn((const char *)pTemp, (const char *)otherPrefixChar); /* span the other optional prefix */
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
pTemp += strspn((const char *)pTemp, (const char *)conversionChar);
if(!*pTemp)
break; /* "This is the End", (c) J. Morrisson */
}
count = count_ll + count_tm + count_aa;
if(!count)
{
err= vsnprintf((char *)pStrOut, (size_t)strOutMaxLen + 1, (const char *)format, marker);
va_end(marker);
if ((err<0) || ((M4OSA_UInt32)err>strOutMaxLen))
{
pStrOut[strOutMaxLen] = '\0';
return M4ERR_CHR_STR_OVERFLOW;
}
else
{
return M4NO_ERROR;
}
}
newFormatLength = strlen((const char *)format) + 1;
newFormatLength -= (count_ll+count_tm+count_aa);
newFormat =(M4OSA_Char*)M4OSA_32bitAlignedMalloc(newFormatLength,
M4OSA_CHARSTAR,(M4OSA_Char*)"M4OSA_chrPrintf: newFormat");
if(M4OSA_NULL == newFormat)
return M4ERR_ALLOC;
newFormat[newFormatLength-1] = '\0';
pTemp = newFormat;
/* copy format to newFormat, replacing %[flags][width][.precision]ll[conversion]
* by %[flags][width][.precision]I64[conversion] */
while(*format)
{
nbChar = strcspn((const char *)format, "%");
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar); /* copy characters before the % character */
format +=nbChar;
pTemp +=nbChar;
}
if(!*format) break;
*pTemp++ = *format++; /* copy the % character */
nbChar = strspn((const char *)format, (const char *)flagChar);
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar); /* copy the flag characters */
format +=nbChar;
pTemp +=nbChar;
}
if(!*format) break;
nbChar = strspn((const char *)format, (const char *)widthOrPrecisionChar);
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar); /* copy the width characters */
format +=nbChar;
pTemp +=nbChar;
}
if(!*format) break;
if(*format=='.')
{
*pTemp++ = *format++; /* copy the dot character */
if(!format) break;
nbChar = strspn((const char *)format, (const char *)widthOrPrecisionChar);
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar); /* copy the width characters */
format +=nbChar;
pTemp +=nbChar;
}
if(!format) break;
}
if(strlen((const char *)format)>=2)
{
if(!strncmp((const char *)format, "ll", 2))
{
*pTemp++ = 'l'; /* %l */
format +=2; /* span the "ll" prefix */
}
else if(!strncmp((const char *)format, "tm", 2))
{
*pTemp++ = 'l'; /* %l */
format +=2; /* span the "tm" prefix */
}
else if(!strncmp((const char *)format, "aa", 2))
{
*pTemp++ = 'l';
format +=2; /* span the "aa" prefix */
}
}
nbChar = strspn((const char *)format, (const char *)otherPrefixChar);
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar); /* copy the other Prefix */
format +=nbChar;
pTemp +=nbChar;
}
if(!*format) break;
nbChar = strspn((const char *)format, (const char *)conversionChar);
if(nbChar)
{
strncpy((char *)pTemp, (const char *)format, nbChar);
format += nbChar;
pTemp += nbChar;
}
if(!*format) break;
}
/* Zero terminate the format string. */
(*pTemp) = '\0';
err = vsnprintf((char *)pStrOut, (size_t)strOutMaxLen + 1, (const char *)newFormat, marker);
va_end(marker);
free(newFormat);
if ((err<0) || ((M4OSA_UInt32)err>strOutMaxLen))
{
pStrOut[strOutMaxLen] = '\0';
return M4ERR_CHR_STR_OVERFLOW;
}
else
{
return M4NO_ERROR;
}
}