1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/**
17 ************************************************************************
18 * @file         M4DPAK_CharStar.c
19 * @ingroup
20  * @brief        definition of the Char Star set of functions.
21 * @note         This file defines the Char Star set of functions.
22 *
23 ************************************************************************
24*/
25
26
27#include "M4OSA_CharStar.h"
28#include "M4OSA_Memory.h"
29#include "M4OSA_Debug.h"
30
31/* WARNING: Specific Android */
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdarg.h>
35#include <string.h>
36#include <errno.h>
37
38
39/**
40 ************************************************************************
41 * @brief      This function mimics the functionality of the libc's strncpy().
42 * @note       It copies exactly len2Copy characters from pStrIn to pStrOut,
43 *             truncating  pStrIn or adding null characters to pStrOut if
44 *             necessary.
45 *             - If len2Copy is less than or equal to the length of pStrIn,
46 *               a null character is appended automatically to the copied
47 *               string.
48 *             - If len2Copy is greater than the length of pStrIn, pStrOut is
49 *               padded with null characters up to length len2Copy.
50 *             - pStrOut and pStrIn MUST NOT OVERLAP (this is NOT CHECKED).
51 * @param      pStrOut: (OUT) Destination character string.
52 * @param      pStrIn: (IN) Source character string.
53 * @param      len2Copy: (IN) Maximum number of characters from pStrIn to copy.
54 * @return     M4NO_ERROR: there is no error.
55 * @return     M4ERR_PARAMETER: pStrIn or pStrOut is M4OSA_NULL.
56  ************************************************************************
57*/
58M4OSA_ERR M4OSA_chrNCopy(M4OSA_Char* pStrOut, M4OSA_Char   *pStrIn, M4OSA_UInt32 len2Copy)
59{
60    M4OSA_TRACE1_3("M4OSA_chrNCopy\t(M4OSA_Char* %x,M4OSA_Char* %x,M4OSA_UInt32 %ld)",
61        pStrOut,pStrIn,len2Copy);
62    M4OSA_DEBUG_IF2((M4OSA_NULL == pStrOut),M4ERR_PARAMETER,
63                            "M4OSA_chrNCopy:\tpStrOut is M4OSA_NULL");
64    M4OSA_DEBUG_IF2((M4OSA_NULL == pStrIn),M4ERR_PARAMETER,
65                            "M4OSA_chrNCopy:\tpStrIn is M4OSA_NULL");
66
67    strncpy((char *)pStrOut, (const char *)pStrIn, (size_t)len2Copy);
68    if(len2Copy <= (M4OSA_UInt32)strlen((const char *)pStrIn))
69    {
70        pStrOut[len2Copy] = '\0';
71    }
72
73    return M4NO_ERROR;
74}
75
76/**
77 ************************************************************************
78  * @brief      This function returns the boolean comparison of pStrIn1 and pStrIn2.
79 * @note       The value returned in result is M4OSA_TRUE if the string
80 *             pointed to by pStrIn1 is strictly identical to the string pointed
81 *             to by pStrIn2, and M4OSA_FALSE otherwise.
82 * @param      pStrIn1: (IN) First character string.
83 * @param      pStrIn2: (IN) Second character string.
84 * @param      cmpResult: (OUT) Comparison result.
85 * @return     M4NO_ERROR: there is no error.
86 * @return     M4ERR_PARAMETER: pStrIn1 pStrIn2 or cmpResult is M4OSA_NULL.
87  ************************************************************************
88*/
89M4OSA_ERR M4OSA_chrAreIdentical(M4OSA_Char* pStrIn1, M4OSA_Char* pStrIn2,
90                                                            M4OSA_Bool* pResult)
91{
92    M4OSA_UInt32 i32,len32;
93    M4OSA_TRACE1_3("M4OSA_chrAreIdentical\t(M4OSA_Char* %x,M4OSA_Char* %x,"
94        "M4OSA_Int32* %x)",pStrIn1,pStrIn2,pResult);
95    M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn1, M4ERR_PARAMETER,
96                               "M4OSA_chrAreIdentical:\tpStrIn1 is M4OSA_NULL");
97    M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn2, M4ERR_PARAMETER,
98                               "M4OSA_chrAreIdentical:\tpStrIn2 is M4OSA_NULL");
99    M4OSA_DEBUG_IF2(M4OSA_NULL == pResult, M4ERR_PARAMETER,
100                               "M4OSA_chrAreIdentical:\tpResult is M4OSA_NULL");
101
102    len32 = (M4OSA_UInt32)strlen((const char *)pStrIn1);
103    if(len32 != (M4OSA_UInt32)strlen((const char *)pStrIn2))
104    {
105        *pResult = M4OSA_FALSE;
106        return M4NO_ERROR;
107    }
108
109    for(i32=0;i32<len32;i32++)
110    {
111        if(pStrIn1[i32] != pStrIn2[i32])
112        {
113            *pResult = M4OSA_FALSE;
114            return M4NO_ERROR;
115        }
116    }
117
118    *pResult = M4OSA_TRUE;
119
120    return M4NO_ERROR;
121}
122
123
124/**
125 ************************************************************************
126 * @brief      This function gets a M4OSA_UInt32 from string.
127 * @note       This function converts the first set of non-whitespace
128 *             characters of pStrIn to a M4OSA_UInt32 value pVal, assuming a
129 *             representation in base provided by the parameter base. pStrOut is
130 *             set to the first character of the string following the last
131 *             character of the number that has been converted.
132 *             - in case of a failure during the conversion, pStrOut is not
133 *               updated, and pVal is set to null.
134 *             - in case of negative number, pStrOut is not updated, and pVal is
135 *               set to null.
136 *             - in case of numerical overflow, pVal is set to M4OSA_UINT32_MAX.
137 *             - if pStrOut is not to be used, it can be set to M4OSA_NULL.
138 * @param      pStrIn: (IN) Character string.
139 * @param      pVal: (OUT) read value.
140 * @param      pStrOut: (OUT) Output character string.
141 * @param      base: (IN) Base of the character string representation.
142 * @return     M4NO_ERROR: there is no error.
143 * @return     M4ERR_PARAMETER: pStrIn or pVal is M4OSA_NULL.
144 * @return     M4ERR_CHR_CONV_FAILED: conversion failure.
145 * @return     M4WAR_CHR_NUM_RANGE: the character string represents a number
146 *             greater than M4OSA_UINT32_MAX.
147 * @return     M4WAR_CHR_NEGATIVE: the character string represents a negative
148 *             number.
149 ************************************************************************
150*/
151M4OSA_ERR M4OSA_chrGetUInt32(M4OSA_Char*    pStrIn,
152                             M4OSA_UInt32*    pVal,
153                             M4OSA_Char**    pStrOut,
154                             M4OSA_chrNumBase base)
155{
156    M4OSA_UInt32 ul;
157    char*        pTemp;
158
159    M4OSA_TRACE1_4("M4OSA_chrGetUInt32\t(M4OSA_Char* %x, M4OSA_UInt32* %x"
160        "M4OSA_Char** %x,M4OSA_chrNumBase %d)",pStrIn,pVal,pStrOut,base);
161    M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn, M4ERR_PARAMETER,
162                                   "M4OSA_chrGetUInt32:\tpStrIn is M4OSA_NULL");
163    M4OSA_DEBUG_IF2(M4OSA_NULL == pVal, M4ERR_PARAMETER,
164                                     "M4OSA_chrGetUInt32:\tpVal is M4OSA_NULL");
165
166    errno = 0;
167    switch(base)
168    {
169    case M4OSA_kchrDec:
170        ul = strtoul((const char *)pStrIn, &pTemp, 10);
171        break;
172    case M4OSA_kchrHexa:
173        ul = strtoul((const char *)pStrIn, &pTemp,16);
174        break;
175    case M4OSA_kchrOct:
176        ul = strtoul((const char *)pStrIn, &pTemp,8);
177        break;
178    default:
179        return M4ERR_PARAMETER;
180    }
181
182    /* has conversion failed ? */
183    if((M4OSA_Char*)pTemp == pStrIn)
184    {
185        *pVal = 0;
186        return M4ERR_CHR_CONV_FAILED;
187    }
188
189    /* was the number negative ? */
190    if(*(pStrIn+strspn((const char *)pStrIn," \t")) == '-')
191    {
192        *pVal = 0;
193        return M4WAR_CHR_NEGATIVE;
194    }
195
196    /* has an overflow occured ? */
197    if(errno == ERANGE)
198    {
199        *pVal = M4OSA_UINT32_MAX;
200        if(M4OSA_NULL != pStrOut)
201        {
202            *pStrOut = (M4OSA_Char*)pTemp;
203        }
204        return M4WAR_CHR_NUM_RANGE;
205    }
206
207    /* nominal case */
208    *pVal = (M4OSA_UInt32)ul;
209    if(M4OSA_NULL != pStrOut)
210    {
211        *pStrOut = (M4OSA_Char*)pTemp;
212    }
213
214    return M4NO_ERROR;
215}
216
217/**
218 ************************************************************************
219 * @brief      This function gets a M4OSA_UInt16 from string.
220 * @note       This function converts the first set of non-whitespace
221 *             characters of pStrIn to a M4OSA_UInt16 value pVal, assuming a
222 *             representation in base provided by the parameter base. pStrOut is
223 *             set to the first character of the string following the last
224 *             character of the number that has been converted.
225 *             - in case of a failure during the conversion, pStrOut is not
226 *               updated, and pVal is set to null.
227 *             - in case of negative number, pStrOut is not updated, and pVal is
228 *               set to null.
229 *             - in case of numerical overflow, pVal is set to M4OSA_UINT16_MAX.
230 *             - if pStrOut is not to be used, it can be set to M4OSA_NULL.
231 * @param      pStrIn: (IN) Character string.
232 * @param      pVal: (OUT) read value.
233 * @param      pStrOut: (OUT) Output character string.
234 * @param      base: (IN) Base of the character string representation.
235 * @return     M4NO_ERROR: there is no error.
236 * @return     M4ERR_PARAMETER: pStrIn or pVal is M4OSA_NULL.
237 * @return     M4ERR_CHR_CONV_FAILED: conversion failure.
238 * @return     M4WAR_CHR_NUM_RANGE: the character string represents a number
239 *             greater than M4OSA_UINT16_MAX.
240 * @return     M4WAR_CHR_NEGATIVE: the character string represents a negative
241 *             number.
242 ************************************************************************
243*/
244M4OSA_ERR M4OSA_chrGetUInt16 (M4OSA_Char* pStrIn, M4OSA_UInt16 *pVal,
245                              M4OSA_Char** pStrOut, M4OSA_chrNumBase base)
246{
247    M4OSA_UInt32 ul;
248    char*        pTemp;
249
250    M4OSA_TRACE1_4("M4OSA_chrGetUInt16\t(M4OSA_Char* %x, M4OSA_UInt16* %x"
251        "M4OSA_Char** %x,M4OSA_chrNumBase %d)",pStrIn,pVal,pStrOut,base);
252    M4OSA_DEBUG_IF2(M4OSA_NULL == pStrIn,M4ERR_PARAMETER,
253                                   "M4OSA_chrGetUInt16:\tpStrIn is M4OSA_NULL");
254    M4OSA_DEBUG_IF2(M4OSA_NULL == pVal, M4ERR_PARAMETER,
255                                     "M4OSA_chrGetUInt16:\tpVal is M4OSA_NULL");
256
257    switch(base)
258    {
259    case M4OSA_kchrDec:
260        ul = strtoul((const char *)pStrIn, &pTemp,10);
261        break;
262    case M4OSA_kchrHexa:
263        ul = strtoul((const char *)pStrIn, &pTemp,16);
264        break;
265    case M4OSA_kchrOct:
266        ul = strtoul((const char *)pStrIn, &pTemp,8);
267        break;
268    default:
269        return M4ERR_PARAMETER;
270    }
271
272    /* has conversion failed ? */
273    if((M4OSA_Char*)pTemp == pStrIn)
274    {
275        *pVal = 0;
276        return M4ERR_CHR_CONV_FAILED;
277    }
278
279    /* was the number negative ? */
280    if(*(pStrIn+strspn((const char *)pStrIn," \t")) == '-')
281    {
282        *pVal = 0;
283        return M4WAR_CHR_NEGATIVE;
284    }
285
286    /* has an overflow occured ? */
287    if(ul>M4OSA_UINT16_MAX)
288    {
289        *pVal = M4OSA_UINT16_MAX;
290        if(M4OSA_NULL != pStrOut)
291        {
292            *pStrOut = (M4OSA_Char*)pTemp;
293        }
294        return M4WAR_CHR_NUM_RANGE;
295    }
296
297    /* nominal case */
298    *pVal = (M4OSA_UInt16)ul;
299    if(M4OSA_NULL != pStrOut)
300    {
301        *pStrOut = (M4OSA_Char*)pTemp;
302    }
303    return M4NO_ERROR;
304}
305
306M4OSA_ERR M4OSA_chrSPrintf(M4OSA_Char  *pStrOut, M4OSA_UInt32 strOutMaxLen,
307                           M4OSA_Char   *format, ...)
308{
309    va_list       marker;
310    M4OSA_Char   *pTemp;
311    M4OSA_Char   *percentPointer;
312    M4OSA_Char   *newFormat;
313    M4OSA_Int32  newFormatLength=0;
314    M4OSA_UInt32  count_ll = 0;
315    M4OSA_UInt32  count_tm = 0;
316    M4OSA_UInt32  count_aa = 0;
317    M4OSA_UInt32  count;
318    M4OSA_UInt32  nbChar;
319    M4OSA_Int32     err;
320    M4OSA_Char flagChar[]             = "'-+ #0";
321    M4OSA_Char widthOrPrecisionChar[] = "*0123456789";
322    M4OSA_Char otherPrefixChar[]      = "hlL";
323    M4OSA_Char conversionChar[]       = "diouxXnfeEgGcCsSp%";
324
325    M4OSA_TRACE1_3("M4OSA_chrSPrintf\t(M4OSA_Char* %x, M4OSA_UInt32 %ld"
326        "M4OSA_Char* %x)",pStrOut,strOutMaxLen,format);
327    M4OSA_DEBUG_IF2(M4OSA_NULL == pStrOut, M4ERR_PARAMETER,
328                                    "M4OSA_chrSPrintf:\tpStrOut is M4OSA_NULL");
329    M4OSA_DEBUG_IF2(M4OSA_NULL == format, M4ERR_PARAMETER,
330                                     "M4OSA_chrSPrintf:\tformat is M4OSA_NULL");
331
332    va_start(marker,format);
333
334    /* count the number of %[flags][width][.precision]ll[conversion] */
335    pTemp = format;
336    while(*pTemp)
337    {
338        percentPointer = (M4OSA_Char *)strchr((const char *)pTemp,'%'); /* get the next percent character */
339        if(!percentPointer)
340            break;                            /* "This is the End", (c) J. Morrisson */
341        pTemp = percentPointer+1;           /* span it */
342        if(!*pTemp)
343            break;                            /* "This is the End", (c) J. Morrisson */
344        pTemp += strspn((const char *)pTemp,(const char *)flagChar);    /* span the optional flags */
345        if(!*pTemp)
346            break;                            /* "This is the End", (c) J. Morrisson */
347        pTemp += strspn((const char *)pTemp,(const char *)widthOrPrecisionChar); /* span the optional width */
348        if(!*pTemp)
349            break;                            /* "This is the End", (c) J. Morrisson */
350        if(*pTemp=='.')
351        {
352            pTemp++;
353            pTemp += strspn((const char *)pTemp, (const char *)widthOrPrecisionChar); /* span the optional precision */
354        }
355        if(!*pTemp)
356            break;                            /* "This is the End", (c) J. Morrisson */
357        if(strlen((const char *)pTemp)>=2)
358        {
359            if(!strncmp((const char *)pTemp,"ll",2))
360            {
361                count_ll++;                 /* I got ONE */
362                pTemp +=2;                  /* span the "ll" prefix */
363            }
364            else if(!strncmp((const char *)pTemp,"tm",2))
365            {
366                count_tm++;
367                pTemp +=2;
368            }
369            else if(!strncmp((const char *)pTemp,"aa",2))
370            {
371                count_aa++;
372                pTemp +=2;
373            }
374        }
375        pTemp += strspn((const char *)pTemp, (const char *)otherPrefixChar); /* span the other optional prefix */
376        if(!*pTemp)
377            break;                        /* "This is the End", (c) J. Morrisson */
378        pTemp += strspn((const char *)pTemp, (const char *)conversionChar);
379        if(!*pTemp)
380            break;                        /* "This is the End", (c) J. Morrisson */
381    }
382
383    count = count_ll + count_tm + count_aa;
384
385    if(!count)
386    {
387        err= vsnprintf((char *)pStrOut, (size_t)strOutMaxLen + 1, (const char *)format, marker);
388        va_end(marker);
389        if ((err<0) || ((M4OSA_UInt32)err>strOutMaxLen))
390        {
391            pStrOut[strOutMaxLen] = '\0';
392            return M4ERR_CHR_STR_OVERFLOW;
393        }
394        else
395        {
396            return M4NO_ERROR;
397        }
398    }
399
400
401    newFormatLength = strlen((const char *)format) + 1;
402
403    newFormatLength -= (count_ll+count_tm+count_aa);
404
405    newFormat =(M4OSA_Char*)M4OSA_32bitAlignedMalloc(newFormatLength,
406        M4OSA_CHARSTAR,(M4OSA_Char*)"M4OSA_chrPrintf: newFormat");
407    if(M4OSA_NULL == newFormat)
408        return M4ERR_ALLOC;
409    newFormat[newFormatLength-1] = '\0';
410    pTemp = newFormat;
411
412    /* copy format to newFormat, replacing %[flags][width][.precision]ll[conversion]
413     * by %[flags][width][.precision]I64[conversion] */
414    while(*format)
415    {
416        nbChar = strcspn((const char *)format, "%");
417        if(nbChar)
418        {
419            strncpy((char *)pTemp, (const char *)format, nbChar);      /* copy characters before the % character */
420            format +=nbChar;
421            pTemp   +=nbChar;
422        }
423        if(!*format) break;
424        *pTemp++ = *format++;                 /* copy the % character */
425        nbChar = strspn((const char *)format, (const char *)flagChar);
426        if(nbChar)
427        {
428            strncpy((char *)pTemp, (const char *)format, nbChar);      /* copy the flag characters */
429            format +=nbChar;
430            pTemp   +=nbChar;
431        }
432        if(!*format) break;
433        nbChar = strspn((const char *)format, (const char *)widthOrPrecisionChar);
434        if(nbChar)
435        {
436            strncpy((char *)pTemp, (const char *)format, nbChar);      /* copy the width characters */
437            format +=nbChar;
438            pTemp   +=nbChar;
439        }
440        if(!*format) break;
441        if(*format=='.')
442        {
443            *pTemp++ = *format++;              /* copy the dot character */
444            if(!format) break;
445            nbChar = strspn((const char *)format, (const char *)widthOrPrecisionChar);
446            if(nbChar)
447            {
448                strncpy((char *)pTemp, (const char *)format, nbChar);      /* copy the width characters */
449                format +=nbChar;
450                pTemp   +=nbChar;
451            }
452            if(!format) break;
453        }
454        if(strlen((const char *)format)>=2)
455        {
456            if(!strncmp((const char *)format, "ll", 2))
457            {
458                *pTemp++ = 'l'; /* %l */
459                format +=2;                         /* span the "ll" prefix */
460            }
461            else if(!strncmp((const char *)format, "tm", 2))
462            {
463                *pTemp++ = 'l'; /* %l */
464                format +=2;                         /* span the "tm" prefix */
465            }
466            else if(!strncmp((const char *)format, "aa", 2))
467            {
468                *pTemp++ = 'l';
469                format +=2;                         /* span the "aa" prefix */
470            }
471        }
472        nbChar = strspn((const char *)format, (const char *)otherPrefixChar);
473        if(nbChar)
474        {
475            strncpy((char *)pTemp, (const char *)format, nbChar);      /* copy the other Prefix */
476            format +=nbChar;
477            pTemp   +=nbChar;
478        }
479        if(!*format) break;
480        nbChar = strspn((const char *)format, (const char *)conversionChar);
481        if(nbChar)
482        {
483            strncpy((char *)pTemp, (const char *)format, nbChar);
484            format += nbChar;
485            pTemp   += nbChar;
486        }
487        if(!*format) break;
488    }
489
490    /* Zero terminate the format string. */
491    (*pTemp) = '\0';
492
493    err = vsnprintf((char *)pStrOut, (size_t)strOutMaxLen + 1, (const char *)newFormat, marker);
494    va_end(marker);
495    free(newFormat);
496    if ((err<0) || ((M4OSA_UInt32)err>strOutMaxLen))
497    {
498        pStrOut[strOutMaxLen] = '\0';
499        return M4ERR_CHR_STR_OVERFLOW;
500    }
501    else
502    {
503        return M4NO_ERROR;
504    }
505}
506
507