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