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