xref: /aosp_15_r20/external/fastrpc/src/std_strlprintf.c (revision 418b791d679beb2078b579a3b6936cf330c41799)
1*418b791dSBob Badour /*
2*418b791dSBob Badour  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3*418b791dSBob Badour  *
4*418b791dSBob Badour  * Redistribution and use in source and binary forms, with or without
5*418b791dSBob Badour  * modification, are permitted provided that the following conditions are
6*418b791dSBob Badour  * met:
7*418b791dSBob Badour  *    * Redistributions of source code must retain the above copyright
8*418b791dSBob Badour  *      notice, this list of conditions and the following disclaimer.
9*418b791dSBob Badour  *    * Redistributions in binary form must reproduce the above
10*418b791dSBob Badour  *      copyright notice, this list of conditions and the following
11*418b791dSBob Badour  *      disclaimer in the documentation and/or other materials provided
12*418b791dSBob Badour  *      with the distribution.
13*418b791dSBob Badour  *    * Neither the name of The Linux Foundation nor the names of its
14*418b791dSBob Badour  *      contributors may be used to endorse or promote products derived
15*418b791dSBob Badour  *      from this software without specific prior written permission.
16*418b791dSBob Badour  *
17*418b791dSBob Badour  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18*418b791dSBob Badour  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*418b791dSBob Badour  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20*418b791dSBob Badour  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21*418b791dSBob Badour  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*418b791dSBob Badour  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*418b791dSBob Badour  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24*418b791dSBob Badour  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25*418b791dSBob Badour  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26*418b791dSBob Badour  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*418b791dSBob Badour  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*418b791dSBob Badour  */
29*418b791dSBob Badour 
30*418b791dSBob Badour #include "AEEstd.h"
31*418b791dSBob Badour #include "AEEBufBound.h"
32*418b791dSBob Badour #include "AEEsmath.h"
33*418b791dSBob Badour #include "AEEStdErr.h"
34*418b791dSBob Badour #include "std_dtoa.h"
35*418b791dSBob Badour //#include "math.h"
36*418b791dSBob Badour 
37*418b791dSBob Badour //==============================================================================
38*418b791dSBob Badour //   Macro definitions
39*418b791dSBob Badour //==============================================================================
40*418b791dSBob Badour 
41*418b791dSBob Badour #define  ISDIGIT(c)              ( (c) >= '0' && (c) <= '9')
42*418b791dSBob Badour #define  TOLOWER(c)              ( (c) | 32 )   // works only for letters
43*418b791dSBob Badour #define  FAILED(b)               ( (b) != AEE_SUCCESS ? TRUE : FALSE )
44*418b791dSBob Badour #define  CLEANUP_ON_ERROR(b,l)   if( FAILED( b ) ) { goto l; }
45*418b791dSBob Badour #define  ROUND(d, p)             fp_round( d, p )
46*418b791dSBob Badour #define  FP_POW_10(n)            fp_pow_10(n)
47*418b791dSBob Badour 
48*418b791dSBob Badour //==============================================================================
49*418b791dSBob Badour //   Type definitions
50*418b791dSBob Badour //==============================================================================
51*418b791dSBob Badour 
52*418b791dSBob Badour 
53*418b791dSBob Badour // Formatting flags
54*418b791dSBob Badour 
55*418b791dSBob Badour #define FF_PLUS     1    // '+'
56*418b791dSBob Badour #define FF_MINUS    2    // '-'
57*418b791dSBob Badour #define FF_POUND    4    // '#'
58*418b791dSBob Badour #define FF_BLANK    8    // ' '
59*418b791dSBob Badour #define FF_ZERO    16    // '0'
60*418b791dSBob Badour 
61*418b791dSBob Badour typedef struct {
62*418b791dSBob Badour 
63*418b791dSBob Badour    // Parsed values (from "%..." expression)
64*418b791dSBob Badour 
65*418b791dSBob Badour    int      flags;          // FF_PLUS, FF_MINUS, etc.
66*418b791dSBob Badour    char     cType;          // d, s, c, x, X, etc.
67*418b791dSBob Badour    int32    nWidth;         // number preceding '.' : controls padding
68*418b791dSBob Badour    int32    nPrecision;     // number following '.'  (-1 if not given)
69*418b791dSBob Badour 
70*418b791dSBob Badour    // Computed values
71*418b791dSBob Badour 
72*418b791dSBob Badour    const char *  pszStr;         // string holding prefix + value
73*418b791dSBob Badour    int           nPrefix;        // # of numeric prefix bytes in pszStr[]
74*418b791dSBob Badour    int           nLen;           // length of string (after prefix)
75*418b791dSBob Badour    int           nNumWidth;      // minimum numeric value size (pad with '0')
76*418b791dSBob Badour 
77*418b791dSBob Badour } FieldFormat;
78*418b791dSBob Badour 
79*418b791dSBob Badour typedef int (*pfnFormatFloat)(FieldFormat* me, double dNumber, char* pcBuffer);
80*418b791dSBob Badour 
81*418b791dSBob Badour //==============================================================================
82*418b791dSBob Badour //   Function definitions
83*418b791dSBob Badour //==============================================================================
84*418b791dSBob Badour 
85*418b791dSBob Badour // Read an unsigned decimal integer
86*418b791dSBob Badour //
ScanDecimal(const char ** ppsz)87*418b791dSBob Badour static int ScanDecimal(const char **ppsz)
88*418b791dSBob Badour {
89*418b791dSBob Badour    int n = 0;
90*418b791dSBob Badour    const char *psz;
91*418b791dSBob Badour 
92*418b791dSBob Badour    for (psz = *ppsz; ISDIGIT(*psz); ++psz) {
93*418b791dSBob Badour       n = n*10 + (int) (*psz - '0');
94*418b791dSBob Badour    }
95*418b791dSBob Badour    *ppsz = psz;
96*418b791dSBob Badour    return n;
97*418b791dSBob Badour }
98*418b791dSBob Badour 
99*418b791dSBob Badour 
100*418b791dSBob Badour #define FORMATNUMBER_SIZE   24   // octal: 22 + '0' + null ;  decimal: 20 + sign + null
101*418b791dSBob Badour 
102*418b791dSBob Badour 
103*418b791dSBob Badour // Convert number to string, setting computed fields in FieldFormat.
104*418b791dSBob Badour //
105*418b791dSBob Badour //  pcBuf[] must have room for at least FORMATNUMBER_SIZE characters
106*418b791dSBob Badour //  return value: length of string.
107*418b791dSBob Badour //
108*418b791dSBob Badour static __inline void
FormatNumber(FieldFormat * me,char pcBuf[FORMATNUMBER_SIZE],uint64 uNum64)109*418b791dSBob Badour FormatNumber(FieldFormat *me, char pcBuf[FORMATNUMBER_SIZE], uint64 uNum64)
110*418b791dSBob Badour {
111*418b791dSBob Badour    char cType = me->cType;
112*418b791dSBob Badour    const char *cpszDigits;
113*418b791dSBob Badour    char *pc = pcBuf;
114*418b791dSBob Badour    int nBase;
115*418b791dSBob Badour    char *pcRev;
116*418b791dSBob Badour 
117*418b791dSBob Badour    if (cType == 'p') {
118*418b791dSBob Badour       cType = 'X';
119*418b791dSBob Badour       me->nPrecision = 8;
120*418b791dSBob Badour    }
121*418b791dSBob Badour 
122*418b791dSBob Badour    if (me->nPrecision >= 0) {
123*418b791dSBob Badour       me->nNumWidth = me->nPrecision;
124*418b791dSBob Badour       // Odd thing: '0' flag is ignored for numbers when precision is
125*418b791dSBob Badour       // specified.
126*418b791dSBob Badour       me->flags &= ~FF_ZERO;
127*418b791dSBob Badour    } else {
128*418b791dSBob Badour       me->nNumWidth = 1;
129*418b791dSBob Badour    }
130*418b791dSBob Badour 
131*418b791dSBob Badour    // Output prefix
132*418b791dSBob Badour 
133*418b791dSBob Badour    if (( 'd' == cType || 'i' == cType)) {
134*418b791dSBob Badour       if ((int64)uNum64 < 0) {
135*418b791dSBob Badour          *pc++ = '-';
136*418b791dSBob Badour          uNum64 = (uint64)-(int64)uNum64;
137*418b791dSBob Badour       } else if (me->flags & FF_PLUS) {
138*418b791dSBob Badour          *pc++ = '+';
139*418b791dSBob Badour       } else if (me->flags & FF_BLANK) {
140*418b791dSBob Badour          *pc++ = ' ';
141*418b791dSBob Badour       }
142*418b791dSBob Badour    }
143*418b791dSBob Badour 
144*418b791dSBob Badour    if ((me->flags & FF_POUND) && 0 != uNum64) {
145*418b791dSBob Badour       if ('x' == TOLOWER(cType)) {
146*418b791dSBob Badour          *pc++ = '0';
147*418b791dSBob Badour          *pc++ = cType;
148*418b791dSBob Badour       } else if ('o' == cType) {
149*418b791dSBob Badour          *pc++ = '0';
150*418b791dSBob Badour          // Odd thing about libc printf: "0" prefix counts as part of minimum
151*418b791dSBob Badour          // width, but "0x" prefix does not.
152*418b791dSBob Badour          --me->nNumWidth;
153*418b791dSBob Badour       }
154*418b791dSBob Badour    }
155*418b791dSBob Badour    me->nPrefix = pc - pcBuf;
156*418b791dSBob Badour 
157*418b791dSBob Badour    // Output unsigned numeric value
158*418b791dSBob Badour 
159*418b791dSBob Badour    nBase = ('o' == cType          ? 8 :
160*418b791dSBob Badour             'x' == TOLOWER(cType) ? 16 :
161*418b791dSBob Badour             10);
162*418b791dSBob Badour    cpszDigits = ((cType == 'X') ? "0123456789ABCDEF"
163*418b791dSBob Badour                                 : "0123456789abcdef");
164*418b791dSBob Badour 
165*418b791dSBob Badour    pcRev = pc;
166*418b791dSBob Badour 
167*418b791dSBob Badour    while (uNum64) {
168*418b791dSBob Badour       *pc++ = cpszDigits[uNum64 % (unsigned)nBase];
169*418b791dSBob Badour       uNum64 /= (unsigned)nBase;
170*418b791dSBob Badour    }
171*418b791dSBob Badour 
172*418b791dSBob Badour    *pc = '\0';
173*418b791dSBob Badour 
174*418b791dSBob Badour    me->pszStr = pcBuf;
175*418b791dSBob Badour    me->nLen = pc - pcRev;
176*418b791dSBob Badour 
177*418b791dSBob Badour    // Reverse string
178*418b791dSBob Badour 
179*418b791dSBob Badour    --pc;
180*418b791dSBob Badour    for (; pcRev < pc; ++pcRev, --pc) {
181*418b791dSBob Badour       char c = *pc;
182*418b791dSBob Badour       *pc = *pcRev;
183*418b791dSBob Badour       *pcRev = c;
184*418b791dSBob Badour    }
185*418b791dSBob Badour }
186*418b791dSBob Badour 
187*418b791dSBob Badour //
188*418b791dSBob Badour // This function converts the input floating point number dNumber to an
189*418b791dSBob Badour // ASCII string using either %f or %F formatting. This functions assumes
190*418b791dSBob Badour // that dNumer is a valid floating point number (i.e., dNumber is NOT
191*418b791dSBob Badour // +/-INF or NaN). The size of the output buffer pcBuffer should be at
192*418b791dSBob Badour // least STD_DTOA_FORMAT_FLOAT_SIZE.
193*418b791dSBob Badour //
ConvertFloat(FieldFormat * me,double dNumber,char * pcBuffer,int nBufSize)194*418b791dSBob Badour static int ConvertFloat(FieldFormat* me, double dNumber, char* pcBuffer,
195*418b791dSBob Badour                         int nBufSize)
196*418b791dSBob Badour {
197*418b791dSBob Badour    int nError = AEE_SUCCESS;
198*418b791dSBob Badour    int32 nPrecision = 0;
199*418b791dSBob Badour    int nIndex = 0;
200*418b791dSBob Badour    BufBound OutBuf;
201*418b791dSBob Badour    char szIntegerPart[STD_DTOA_FORMAT_INTEGER_SIZE] = {0};
202*418b791dSBob Badour    char szFractionPart[STD_DTOA_FORMAT_FRACTION_SIZE] = {0};
203*418b791dSBob Badour    int nExponent = 0;
204*418b791dSBob Badour    char cType = TOLOWER(me->cType);
205*418b791dSBob Badour 
206*418b791dSBob Badour    // Set the precision for conversion
207*418b791dSBob Badour    nPrecision = me->nPrecision;
208*418b791dSBob Badour    if (nPrecision < 0) {
209*418b791dSBob Badour       // No precision was specified, set it to the default value if the
210*418b791dSBob Badour       // format specifier is not %a
211*418b791dSBob Badour       if (cType != 'a') {
212*418b791dSBob Badour          nPrecision = STD_DTOA_DEFAULT_FLOAT_PRECISION;
213*418b791dSBob Badour       }
214*418b791dSBob Badour    }
215*418b791dSBob Badour    else if ((0 == nPrecision) && ('g' == cType)) {
216*418b791dSBob Badour       nPrecision = 1;
217*418b791dSBob Badour    }
218*418b791dSBob Badour 
219*418b791dSBob Badour    if (cType != 'a') {
220*418b791dSBob Badour       // For %g, check whether to use %e of %f formatting style.
221*418b791dSBob Badour       // Also, set the precision value accordingly since in this case the user
222*418b791dSBob Badour       // specified value is really the number of significant digits.
223*418b791dSBob Badour       // These next few steps should be skipped if the input number is 0.
224*418b791dSBob Badour       if (dNumber != 0.0) {
225*418b791dSBob Badour          nExponent = fp_log_10(dNumber);
226*418b791dSBob Badour          if ('g' == cType) {
227*418b791dSBob Badour             if ((nExponent < -4) || (nExponent >= nPrecision)) {
228*418b791dSBob Badour                cType = 'e';
229*418b791dSBob Badour                nPrecision = nPrecision - 1;
230*418b791dSBob Badour             }
231*418b791dSBob Badour             else {
232*418b791dSBob Badour                cType = 'f';
233*418b791dSBob Badour                nPrecision = nPrecision - nExponent - 1;
234*418b791dSBob Badour             }
235*418b791dSBob Badour          }
236*418b791dSBob Badour 
237*418b791dSBob Badour          // For %e, convert the number to the form d.ddd
238*418b791dSBob Badour          if ('e' == cType) {
239*418b791dSBob Badour             dNumber = dNumber / FP_POW_10(nExponent);
240*418b791dSBob Badour          }
241*418b791dSBob Badour 
242*418b791dSBob Badour          // Now, round the number to the specified precision
243*418b791dSBob Badour          dNumber = ROUND(dNumber, nPrecision);
244*418b791dSBob Badour 
245*418b791dSBob Badour          // For %e, the rounding operation may have resulted in a number dd.ddd
246*418b791dSBob Badour          // Reconvert it to the form d.ddd
247*418b791dSBob Badour          if (('e' == cType) && ((dNumber >= 10.0) || (dNumber <= -10.0))) {
248*418b791dSBob Badour             dNumber = dNumber / 10.0;
249*418b791dSBob Badour             nExponent++;
250*418b791dSBob Badour          }
251*418b791dSBob Badour       }
252*418b791dSBob Badour 
253*418b791dSBob Badour       // Convert the decmial number to string
254*418b791dSBob Badour       nError = std_dtoa_decimal(dNumber, nPrecision, szIntegerPart, szFractionPart);
255*418b791dSBob Badour       CLEANUP_ON_ERROR(nError, bail);
256*418b791dSBob Badour    }
257*418b791dSBob Badour    else
258*418b791dSBob Badour    {
259*418b791dSBob Badour       // Conver the hex floating point number to string
260*418b791dSBob Badour       nError = std_dtoa_hex(dNumber, nPrecision, me->cType, szIntegerPart,
261*418b791dSBob Badour                             szFractionPart, &nExponent);
262*418b791dSBob Badour       CLEANUP_ON_ERROR(nError, bail);
263*418b791dSBob Badour    }
264*418b791dSBob Badour 
265*418b791dSBob Badour 
266*418b791dSBob Badour    //
267*418b791dSBob Badour    // Write the output as per the specified format.
268*418b791dSBob Badour    // First: Check for any prefixes that need to be added to the output.
269*418b791dSBob Badour    // The only possible prefixes are '-', '+' or ' '. The following rules
270*418b791dSBob Badour    // are applicable:
271*418b791dSBob Badour    // 1. One and only one prefix will be applicable at any time.
272*418b791dSBob Badour    // 2. If the number is negative, then '+' and ' ' are not applicable.
273*418b791dSBob Badour    // 3. For positive numbers, the prefix '+' takes precedence over ' '.
274*418b791dSBob Badour    //
275*418b791dSBob Badour    // In addition, we were dealing with a hex floating point number (%a),
276*418b791dSBob Badour    // then we need to write of the 0x prefix.
277*418b791dSBob Badour    //
278*418b791dSBob Badour    BufBound_Init(&OutBuf, pcBuffer, nBufSize);
279*418b791dSBob Badour    if (dNumber < 0.0) {
280*418b791dSBob Badour       // The '-' sign would have already been added to the szIntegerPart by
281*418b791dSBob Badour       // the conversion function.
282*418b791dSBob Badour       me->nPrefix = 1;
283*418b791dSBob Badour    }
284*418b791dSBob Badour    if (dNumber >= 0.0){
285*418b791dSBob Badour       if (me->flags & FF_PLUS) {
286*418b791dSBob Badour          BufBound_Putc(&OutBuf, '+');
287*418b791dSBob Badour          me->nPrefix = 1;
288*418b791dSBob Badour       }
289*418b791dSBob Badour       else if(me->flags & FF_BLANK) {
290*418b791dSBob Badour          BufBound_Putc(&OutBuf, ' ');
291*418b791dSBob Badour          me->nPrefix = 1;
292*418b791dSBob Badour       }
293*418b791dSBob Badour    }
294*418b791dSBob Badour 
295*418b791dSBob Badour    // For %a, write out the 0x prefix
296*418b791dSBob Badour    if ('a' == cType) {
297*418b791dSBob Badour       BufBound_Putc(&OutBuf, '0');
298*418b791dSBob Badour       BufBound_Putc(&OutBuf, ('a' == me->cType) ? 'x' : 'X');
299*418b791dSBob Badour       me->nPrefix += 2;
300*418b791dSBob Badour    }
301*418b791dSBob Badour 
302*418b791dSBob Badour    // Second: Write the integer part
303*418b791dSBob Badour    BufBound_Puts(&OutBuf, szIntegerPart);
304*418b791dSBob Badour 
305*418b791dSBob Badour    // Third: Write the decimal point followed by the fraction part.
306*418b791dSBob Badour    // For %g, we need to truncate the trailing zeros in the fraction.
307*418b791dSBob Badour    // Skip this if the '#' flag is specified
308*418b791dSBob Badour    if (!(me->flags & FF_POUND) && ('g' == TOLOWER(me->cType))) {
309*418b791dSBob Badour       for (nIndex = std_strlen(szFractionPart) - 1;
310*418b791dSBob Badour            (nIndex >= 0) && (szFractionPart[nIndex] == '0'); nIndex--) {
311*418b791dSBob Badour          szFractionPart[nIndex] = '\0';
312*418b791dSBob Badour       }
313*418b791dSBob Badour    }
314*418b791dSBob Badour 
315*418b791dSBob Badour    // The decimal point is specified only if there are some decimal digits.
316*418b791dSBob Badour    // However, if the '#' format specifier is present then the decimal point
317*418b791dSBob Badour    // will be present.
318*418b791dSBob Badour    if ((me->flags & FF_POUND) || (*szFractionPart != 0)) {
319*418b791dSBob Badour       BufBound_Putc(&OutBuf, '.');
320*418b791dSBob Badour 
321*418b791dSBob Badour       // Write the fraction part
322*418b791dSBob Badour       BufBound_Puts(&OutBuf, szFractionPart);
323*418b791dSBob Badour    }
324*418b791dSBob Badour 
325*418b791dSBob Badour    // For %e and %a, write out the exponent
326*418b791dSBob Badour    if (('e' == cType) || ('a' == cType)) {
327*418b791dSBob Badour       char* pcExpStart = NULL;
328*418b791dSBob Badour       char* pcExpEnd = NULL;
329*418b791dSBob Badour       char cTemp = 0;
330*418b791dSBob Badour 
331*418b791dSBob Badour       if ('a' == me->cType) {
332*418b791dSBob Badour          BufBound_Putc(&OutBuf, 'p');
333*418b791dSBob Badour       }
334*418b791dSBob Badour       else if ('A' == me->cType) {
335*418b791dSBob Badour          BufBound_Putc(&OutBuf, 'P');
336*418b791dSBob Badour       }
337*418b791dSBob Badour       else if (('e' == me->cType) || ('g' == me->cType)) {
338*418b791dSBob Badour          BufBound_Putc(&OutBuf, 'e');
339*418b791dSBob Badour       }
340*418b791dSBob Badour       else {
341*418b791dSBob Badour          BufBound_Putc(&OutBuf, 'E');
342*418b791dSBob Badour       }
343*418b791dSBob Badour 
344*418b791dSBob Badour       // Write the exponent sign
345*418b791dSBob Badour       if (nExponent < 0) {
346*418b791dSBob Badour          BufBound_Putc(&OutBuf, '-');
347*418b791dSBob Badour          nExponent = -nExponent;
348*418b791dSBob Badour       }
349*418b791dSBob Badour       else {
350*418b791dSBob Badour          BufBound_Putc(&OutBuf, '+');
351*418b791dSBob Badour       }
352*418b791dSBob Badour 
353*418b791dSBob Badour       // Write out the exponent.
354*418b791dSBob Badour       // For %e, the exponent should at least be two digits.
355*418b791dSBob Badour       // The exponent to be written will be at most 4 digits as any
356*418b791dSBob Badour       // overflow would have been take care of by now.
357*418b791dSBob Badour       if (BufBound_Left(&OutBuf) >= 4) {
358*418b791dSBob Badour          if ('e' == cType) {
359*418b791dSBob Badour             if (nExponent < 10) {
360*418b791dSBob Badour                BufBound_Putc(&OutBuf, '0');
361*418b791dSBob Badour             }
362*418b791dSBob Badour          }
363*418b791dSBob Badour 
364*418b791dSBob Badour          pcExpStart = OutBuf.pcWrite;
365*418b791dSBob Badour          do {
366*418b791dSBob Badour             BufBound_Putc(&OutBuf, '0' + (nExponent % 10));
367*418b791dSBob Badour             nExponent /= 10;
368*418b791dSBob Badour          } while (nExponent);
369*418b791dSBob Badour          pcExpEnd = OutBuf.pcWrite - 1;
370*418b791dSBob Badour 
371*418b791dSBob Badour          // Reverse the exponent
372*418b791dSBob Badour          for (; pcExpStart < pcExpEnd; pcExpStart++, pcExpEnd--) {
373*418b791dSBob Badour             cTemp = *pcExpStart;
374*418b791dSBob Badour             *pcExpStart = *pcExpEnd;
375*418b791dSBob Badour             *pcExpEnd = cTemp;
376*418b791dSBob Badour          }
377*418b791dSBob Badour       }
378*418b791dSBob Badour    }
379*418b791dSBob Badour 
380*418b791dSBob Badour    // Null-terminate the string
381*418b791dSBob Badour    BufBound_ForceNullTerm(&OutBuf);
382*418b791dSBob Badour 
383*418b791dSBob Badour    // Set the output parameters
384*418b791dSBob Badour    // We do not care if there was enough space in the output buffer or not.
385*418b791dSBob Badour    // The output would be truncated to a maximum length of
386*418b791dSBob Badour    // STD_DTOA_FORMAT_FLOAT_SIZE.
387*418b791dSBob Badour    me->pszStr = OutBuf.pcBuf;
388*418b791dSBob Badour    me->nLen = BufBound_ReallyWrote(&OutBuf) - me->nPrefix - 1;
389*418b791dSBob Badour 
390*418b791dSBob Badour bail:
391*418b791dSBob Badour 
392*418b791dSBob Badour    return nError;
393*418b791dSBob Badour }
394*418b791dSBob Badour 
395*418b791dSBob Badour //
396*418b791dSBob Badour // This is a wrapper function that converts an input floating point number
397*418b791dSBob Badour // to a string based on a given format specifier %e, %f or %g. It first checks
398*418b791dSBob Badour // if the specified number is a valid floating point number before calling
399*418b791dSBob Badour // the function that does the conversion.
400*418b791dSBob Badour //
401*418b791dSBob Badour // The size of the output buffer pcBuffer should be at least STD_DTOA_FORMAT_FLOAT_SIZE.
402*418b791dSBob Badour //
FormatFloat(FieldFormat * me,double dNumber,char pcBuffer[STD_DTOA_FORMAT_FLOAT_SIZE])403*418b791dSBob Badour static int FormatFloat(FieldFormat* me, double dNumber,
404*418b791dSBob Badour                        char pcBuffer[STD_DTOA_FORMAT_FLOAT_SIZE])
405*418b791dSBob Badour {
406*418b791dSBob Badour    int nError = AEE_SUCCESS;
407*418b791dSBob Badour    FloatingPointType NumberType = FP_TYPE_UNKOWN;
408*418b791dSBob Badour 
409*418b791dSBob Badour    // Check for error conditions
410*418b791dSBob Badour    if (NULL == pcBuffer) {
411*418b791dSBob Badour       nError = AEE_EBADPARM;
412*418b791dSBob Badour       goto bail;
413*418b791dSBob Badour    }
414*418b791dSBob Badour 
415*418b791dSBob Badour    // Initialize the output params first
416*418b791dSBob Badour    me->nLen = 0;
417*418b791dSBob Badour    me->nPrefix = 0;
418*418b791dSBob Badour 
419*418b791dSBob Badour    // Check for special cases such as NaN and Infinity
420*418b791dSBob Badour    nError = fp_check_special_cases(dNumber, &NumberType);
421*418b791dSBob Badour    CLEANUP_ON_ERROR(nError, bail);
422*418b791dSBob Badour 
423*418b791dSBob Badour    switch(NumberType) {
424*418b791dSBob Badour 	  case FP_TYPE_NEGATIVE_INF:
425*418b791dSBob Badour 
426*418b791dSBob Badour 		 if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) {
427*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_UPPER_CASE,
428*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
429*418b791dSBob Badour 		 }
430*418b791dSBob Badour 		 else {
431*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_LOWER_CASE,
432*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
433*418b791dSBob Badour 		 }
434*418b791dSBob Badour 
435*418b791dSBob Badour 		 // Don't pad with 0's
436*418b791dSBob Badour 		 me->flags &= ~FF_ZERO;
437*418b791dSBob Badour 
438*418b791dSBob Badour 		 break;
439*418b791dSBob Badour 
440*418b791dSBob Badour 	  case FP_TYPE_POSITIVE_INF:
441*418b791dSBob Badour 
442*418b791dSBob Badour 		 if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) {
443*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_UPPER_CASE,
444*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
445*418b791dSBob Badour 		 }
446*418b791dSBob Badour 		 else {
447*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_LOWER_CASE,
448*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
449*418b791dSBob Badour 		 }
450*418b791dSBob Badour 
451*418b791dSBob Badour 		 // Don't pad with 0's
452*418b791dSBob Badour 		 me->flags &= ~FF_ZERO;
453*418b791dSBob Badour 
454*418b791dSBob Badour 		 break;
455*418b791dSBob Badour 
456*418b791dSBob Badour 	  case FP_TYPE_NAN:
457*418b791dSBob Badour 
458*418b791dSBob Badour 		 if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) {
459*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_UPPER_CASE,
460*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
461*418b791dSBob Badour 		 }
462*418b791dSBob Badour 		 else
463*418b791dSBob Badour 		 {
464*418b791dSBob Badour 			me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_LOWER_CASE,
465*418b791dSBob Badour 								   STD_DTOA_FORMAT_FLOAT_SIZE);
466*418b791dSBob Badour 		 }
467*418b791dSBob Badour 
468*418b791dSBob Badour 		 // Don't pad with 0's
469*418b791dSBob Badour 		 me->flags &= ~FF_ZERO;
470*418b791dSBob Badour 
471*418b791dSBob Badour 		 break;
472*418b791dSBob Badour 
473*418b791dSBob Badour 	  case FP_TYPE_GENERAL:
474*418b791dSBob Badour 
475*418b791dSBob Badour 		 nError = ConvertFloat(me, dNumber, pcBuffer,
476*418b791dSBob Badour                                STD_DTOA_FORMAT_FLOAT_SIZE);
477*418b791dSBob Badour 		 CLEANUP_ON_ERROR(nError, bail);
478*418b791dSBob Badour 
479*418b791dSBob Badour 		 break;
480*418b791dSBob Badour 
481*418b791dSBob Badour 	  default:
482*418b791dSBob Badour 
483*418b791dSBob Badour 		 // This should only happen if this function has been modified
484*418b791dSBob Badour 		 // to support other special cases and this block has not been
485*418b791dSBob Badour 		 // updated.
486*418b791dSBob Badour 		 nError = AEE_EFAILED;
487*418b791dSBob Badour 		 goto bail;
488*418b791dSBob Badour    }
489*418b791dSBob Badour 
490*418b791dSBob Badour    // Set the output parameters
491*418b791dSBob Badour    me->pszStr = pcBuffer;
492*418b791dSBob Badour 
493*418b791dSBob Badour 
494*418b791dSBob Badour bail:
495*418b791dSBob Badour 
496*418b791dSBob Badour    return nError;
497*418b791dSBob Badour }
498*418b791dSBob Badour 
std_strlprintf_inner(char * pszDest,int nDestSize,const char * cpszFmt,AEEVaList args,pfnFormatFloat pfnFormatFloatFunc)499*418b791dSBob Badour static int std_strlprintf_inner(char *pszDest, int nDestSize,
500*418b791dSBob Badour                                 const char *cpszFmt, AEEVaList args,
501*418b791dSBob Badour                                 pfnFormatFloat pfnFormatFloatFunc)
502*418b791dSBob Badour {
503*418b791dSBob Badour    BufBound bb;
504*418b791dSBob Badour    const char *pcIn = cpszFmt;
505*418b791dSBob Badour 
506*418b791dSBob Badour    BufBound_Init(&bb, pszDest, nDestSize);
507*418b791dSBob Badour 
508*418b791dSBob Badour    for (;;) {
509*418b791dSBob Badour       FieldFormat ff;
510*418b791dSBob Badour       const char *pcEsc;
511*418b791dSBob Badour       char achBuf[FORMATNUMBER_SIZE];
512*418b791dSBob Badour       char achBuf2[STD_DTOA_FORMAT_FLOAT_SIZE];
513*418b791dSBob Badour       char cType;
514*418b791dSBob Badour       boolean bLong = 0;
515*418b791dSBob Badour 
516*418b791dSBob Badour       pcEsc = std_strchrend(pcIn, '%');
517*418b791dSBob Badour       BufBound_Write(&bb, pcIn, pcEsc-pcIn);
518*418b791dSBob Badour 
519*418b791dSBob Badour       if (0 == *pcEsc) {
520*418b791dSBob Badour          break;
521*418b791dSBob Badour       }
522*418b791dSBob Badour       pcIn = pcEsc+1;
523*418b791dSBob Badour 
524*418b791dSBob Badour       //----------------------------------------------------
525*418b791dSBob Badour       // Consume "%..." specifiers:
526*418b791dSBob Badour       //
527*418b791dSBob Badour       //   %[FLAGS] [WIDTH] [.PRECISION] [{h | l | I64 | L}]
528*418b791dSBob Badour       //----------------------------------------------------
529*418b791dSBob Badour 
530*418b791dSBob Badour       std_memset(&ff, 0, sizeof(FieldFormat));
531*418b791dSBob Badour       ff.nPrecision = -1;
532*418b791dSBob Badour 
533*418b791dSBob Badour       // Consume all flags
534*418b791dSBob Badour       for (;;) {
535*418b791dSBob Badour          int f;
536*418b791dSBob Badour 
537*418b791dSBob Badour          f = (('+' == *pcIn) ? FF_PLUS  :
538*418b791dSBob Badour               ('-' == *pcIn) ? FF_MINUS :
539*418b791dSBob Badour               ('#' == *pcIn) ? FF_POUND :
540*418b791dSBob Badour               (' ' == *pcIn) ? FF_BLANK :
541*418b791dSBob Badour               ('0' == *pcIn) ? FF_ZERO  : 0);
542*418b791dSBob Badour 
543*418b791dSBob Badour          if (0 == f) {
544*418b791dSBob Badour             break;
545*418b791dSBob Badour          }
546*418b791dSBob Badour 
547*418b791dSBob Badour          ff.flags |= f;
548*418b791dSBob Badour          ++pcIn;
549*418b791dSBob Badour       }
550*418b791dSBob Badour 
551*418b791dSBob Badour       // Consume width
552*418b791dSBob Badour       if ('*' == *pcIn) {
553*418b791dSBob Badour          AEEVA_ARG(args, ff.nWidth, int32);
554*418b791dSBob Badour          pcIn++;
555*418b791dSBob Badour       } else {
556*418b791dSBob Badour          ff.nWidth = ScanDecimal(&pcIn);
557*418b791dSBob Badour       }
558*418b791dSBob Badour       if ((ff.flags & FF_MINUS) && ff.nWidth > 0) {
559*418b791dSBob Badour          ff.nWidth = -ff.nWidth;
560*418b791dSBob Badour       }
561*418b791dSBob Badour 
562*418b791dSBob Badour       // Consume precision
563*418b791dSBob Badour       if ('.' == *pcIn) {
564*418b791dSBob Badour          pcIn++;
565*418b791dSBob Badour          if ('*' == *pcIn) { // Can be *... (given in int * param)
566*418b791dSBob Badour             AEEVA_ARG(args, ff.nPrecision, int32);
567*418b791dSBob Badour             pcIn++;
568*418b791dSBob Badour          } else {
569*418b791dSBob Badour             ff.nPrecision = ScanDecimal(&pcIn);
570*418b791dSBob Badour          }
571*418b791dSBob Badour       }
572*418b791dSBob Badour 
573*418b791dSBob Badour       // Consume size designator
574*418b791dSBob Badour       {
575*418b791dSBob Badour          static const struct {
576*418b791dSBob Badour             char    szPre[3];
577*418b791dSBob Badour             boolean b64;
578*418b791dSBob Badour          } a[] = {
579*418b791dSBob Badour             { "l",  0, },
580*418b791dSBob Badour             { "ll", 1, },
581*418b791dSBob Badour             { "L",  1, },
582*418b791dSBob Badour             { "j",  1, },
583*418b791dSBob Badour             { "h",  0, },
584*418b791dSBob Badour             { "hh", 0, },
585*418b791dSBob Badour             { "z",  0 }
586*418b791dSBob Badour          };
587*418b791dSBob Badour 
588*418b791dSBob Badour          int n = STD_ARRAY_SIZE(a);
589*418b791dSBob Badour 
590*418b791dSBob Badour          while (--n >= 0) {
591*418b791dSBob Badour             const char *psz = std_strbegins(pcIn, a[n].szPre);
592*418b791dSBob Badour             if ((const char*)0 != psz) {
593*418b791dSBob Badour                pcIn = psz;
594*418b791dSBob Badour                bLong = a[n].b64;
595*418b791dSBob Badour                break;
596*418b791dSBob Badour             }
597*418b791dSBob Badour          }
598*418b791dSBob Badour       }
599*418b791dSBob Badour 
600*418b791dSBob Badour       //----------------------------------------------------
601*418b791dSBob Badour       //
602*418b791dSBob Badour       // Format output values
603*418b791dSBob Badour       //
604*418b791dSBob Badour       //----------------------------------------------------
605*418b791dSBob Badour 
606*418b791dSBob Badour       ff.cType = cType = *pcIn++;
607*418b791dSBob Badour 
608*418b791dSBob Badour       if ('s' == cType) {
609*418b791dSBob Badour 
610*418b791dSBob Badour          // String
611*418b791dSBob Badour          char *psz;
612*418b791dSBob Badour 
613*418b791dSBob Badour          AEEVA_ARG(args, psz, char*);
614*418b791dSBob Badour          ff.pszStr = psz;
615*418b791dSBob Badour          ff.nLen = std_strlen(psz);
616*418b791dSBob Badour          if (ff.nPrecision >= 0 && ff.nPrecision < ff.nLen) {
617*418b791dSBob Badour             ff.nLen = ff.nPrecision;
618*418b791dSBob Badour          }
619*418b791dSBob Badour 
620*418b791dSBob Badour       } else if ('c' == cType) {
621*418b791dSBob Badour 
622*418b791dSBob Badour          // char
623*418b791dSBob Badour          AEEVA_ARG(args, achBuf[0], int);
624*418b791dSBob Badour          achBuf[1] = '\0';
625*418b791dSBob Badour          ff.pszStr = achBuf;
626*418b791dSBob Badour          ff.nLen = 1;
627*418b791dSBob Badour 
628*418b791dSBob Badour       } else if ('u' == cType ||
629*418b791dSBob Badour                  'o' == cType ||
630*418b791dSBob Badour                  'd' == cType ||
631*418b791dSBob Badour                  'i' == cType ||
632*418b791dSBob Badour                  'p' == cType ||
633*418b791dSBob Badour                  'x' == TOLOWER(cType) ) {
634*418b791dSBob Badour 
635*418b791dSBob Badour          // int
636*418b791dSBob Badour          uint64 uArg64;
637*418b791dSBob Badour 
638*418b791dSBob Badour          if (bLong) {
639*418b791dSBob Badour             AEEVA_ARG(args, uArg64, int64);  // See how much room needed
640*418b791dSBob Badour          } else {
641*418b791dSBob Badour             uint32 uArg32;
642*418b791dSBob Badour             AEEVA_ARG(args, uArg32, int32);  // See how much room needed
643*418b791dSBob Badour             uArg64 = uArg32;
644*418b791dSBob Badour             if ('d' == cType || 'i' == cType) {
645*418b791dSBob Badour                uArg64 = (uint64)(int64)(int32)uArg32;
646*418b791dSBob Badour             }
647*418b791dSBob Badour          }
648*418b791dSBob Badour 
649*418b791dSBob Badour          FormatNumber(&ff, achBuf, uArg64);
650*418b791dSBob Badour 
651*418b791dSBob Badour       } else if (pfnFormatFloatFunc &&
652*418b791dSBob Badour                  ('e' == TOLOWER(cType) ||
653*418b791dSBob Badour                   'f' == TOLOWER(cType) ||
654*418b791dSBob Badour                   'g' == TOLOWER(cType) ||
655*418b791dSBob Badour                   'a' == TOLOWER(cType))) {
656*418b791dSBob Badour 
657*418b791dSBob Badour          // float
658*418b791dSBob Badour             int nError = AEE_SUCCESS;
659*418b791dSBob Badour             double dNumber;
660*418b791dSBob Badour 
661*418b791dSBob Badour             AEEVA_ARG(args, dNumber, double);
662*418b791dSBob Badour             nError = pfnFormatFloatFunc(&ff, dNumber, achBuf2);
663*418b791dSBob Badour             if (FAILED(nError)) {
664*418b791dSBob Badour                continue;
665*418b791dSBob Badour             }
666*418b791dSBob Badour 
667*418b791dSBob Badour       } else if ('\0' == cType) {
668*418b791dSBob Badour 
669*418b791dSBob Badour          // premature end
670*418b791dSBob Badour          break;
671*418b791dSBob Badour 
672*418b791dSBob Badour       } else {
673*418b791dSBob Badour          // Unknown type
674*418b791dSBob Badour          BufBound_Putc(&bb, cType);
675*418b791dSBob Badour          continue;
676*418b791dSBob Badour       }
677*418b791dSBob Badour 
678*418b791dSBob Badour       // FieldFormat computed variables + nWidth controls output
679*418b791dSBob Badour 
680*418b791dSBob Badour       if (ff.flags & FF_ZERO) {
681*418b791dSBob Badour          ff.nNumWidth = ff.nWidth - ff.nPrefix;
682*418b791dSBob Badour       }
683*418b791dSBob Badour 
684*418b791dSBob Badour       {
685*418b791dSBob Badour          int nLen1 = ff.nLen;
686*418b791dSBob Badour          int nLen2 = STD_MAX(ff.nNumWidth, nLen1) + ff.nPrefix;
687*418b791dSBob Badour 
688*418b791dSBob Badour          // Putnc() safely ignores negative sizes
689*418b791dSBob Badour          BufBound_Putnc(&bb, ' ', smath_Sub(ff.nWidth,nLen2));
690*418b791dSBob Badour          BufBound_Write(&bb, ff.pszStr, ff.nPrefix);
691*418b791dSBob Badour          BufBound_Putnc(&bb, '0', smath_Sub(ff.nNumWidth, nLen1));
692*418b791dSBob Badour          BufBound_Write(&bb, ff.pszStr+ff.nPrefix, nLen1);
693*418b791dSBob Badour          BufBound_Putnc(&bb, ' ', smath_Sub(-nLen2, ff.nWidth));
694*418b791dSBob Badour       }
695*418b791dSBob Badour    }
696*418b791dSBob Badour 
697*418b791dSBob Badour    AEEVA_END(args);
698*418b791dSBob Badour 
699*418b791dSBob Badour    BufBound_ForceNullTerm(&bb);
700*418b791dSBob Badour 
701*418b791dSBob Badour    /* Return number of bytes required regardless if buffer bound was reached */
702*418b791dSBob Badour 
703*418b791dSBob Badour    /* Note that we subtract 1 because the NUL byte which was added in
704*418b791dSBob Badour       BufBound_ForceNullTerm() is counted as a written byte; the semantics
705*418b791dSBob Badour       of both the ...printf() functions and the strl...() functions call for
706*418b791dSBob Badour       the NUL byte to be excluded from the count. */
707*418b791dSBob Badour 
708*418b791dSBob Badour    return BufBound_Wrote(&bb)-1;
709*418b791dSBob Badour }
710*418b791dSBob Badour 
std_vstrlprintf(char * pszDest,int nDestSize,const char * cpszFmt,AEEVaList args)711*418b791dSBob Badour int std_vstrlprintf(char *pszDest, int nDestSize,
712*418b791dSBob Badour                     const char *cpszFmt,
713*418b791dSBob Badour                     AEEVaList args)
714*418b791dSBob Badour {
715*418b791dSBob Badour    return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, NULL);
716*418b791dSBob Badour }
717*418b791dSBob Badour 
std_vsnprintf(char * pszDest,int nDestSize,const char * cpszFmt,AEEVaList args)718*418b791dSBob Badour int std_vsnprintf(char *pszDest, int nDestSize,
719*418b791dSBob Badour                   const char *cpszFmt,
720*418b791dSBob Badour                   AEEVaList args)
721*418b791dSBob Badour /*
722*418b791dSBob Badour    Same as std_vstrlprintf with the additional support of floating point
723*418b791dSBob Badour    conversion specifiers - %e, %f, %g and %a
724*418b791dSBob Badour */
725*418b791dSBob Badour {
726*418b791dSBob Badour    return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, FormatFloat);
727*418b791dSBob Badour }
728*418b791dSBob Badour 
std_strlprintf(char * pszDest,int nDestSize,const char * pszFmt,...)729*418b791dSBob Badour int std_strlprintf(char *pszDest, int nDestSize, const char *pszFmt, ...)
730*418b791dSBob Badour {
731*418b791dSBob Badour    int nRet;
732*418b791dSBob Badour    AEEVaList args;
733*418b791dSBob Badour 
734*418b791dSBob Badour    AEEVA_START(args, pszFmt);
735*418b791dSBob Badour 
736*418b791dSBob Badour    nRet = std_vstrlprintf(pszDest, nDestSize, pszFmt, args);
737*418b791dSBob Badour 
738*418b791dSBob Badour    AEEVA_END(args);
739*418b791dSBob Badour 
740*418b791dSBob Badour    return nRet;
741*418b791dSBob Badour }
742*418b791dSBob Badour 
std_snprintf(char * pszDest,int nDestSize,const char * pszFmt,...)743*418b791dSBob Badour int std_snprintf(char *pszDest, int nDestSize, const char *pszFmt, ...)
744*418b791dSBob Badour /*
745*418b791dSBob Badour    Same as std_strlprintf with the additional support of floating point
746*418b791dSBob Badour    conversion specifiers - %e, %f, %g and %a
747*418b791dSBob Badour */
748*418b791dSBob Badour {
749*418b791dSBob Badour    int nRet;
750*418b791dSBob Badour    AEEVaList args;
751*418b791dSBob Badour 
752*418b791dSBob Badour    AEEVA_START(args, pszFmt);
753*418b791dSBob Badour 
754*418b791dSBob Badour    nRet = std_vsnprintf(pszDest, nDestSize, pszFmt, args);
755*418b791dSBob Badour 
756*418b791dSBob Badour    AEEVA_END(args);
757*418b791dSBob Badour 
758*418b791dSBob Badour    return nRet;
759*418b791dSBob Badour }
760