| /* |
| * 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; |
| } |
| } |
| |