VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strformat.cpp@ 91789

Last change on this file since 91789 was 91789, checked in by vboxsync, 3 years ago

SUPDrv,IPRT,VBoxGuest: Don't export ellipsis functions from SUPDrv, as that makes switching back to the kernel stack unsafe. Exports has changes (added+removed), but not bumping major IOC version as that was done a few hours ago already and it's Sunday. bugref:10124

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 29.0 KB
Line 
1/* $Id: strformat.cpp 91789 2021-10-17 18:16:11Z vboxsync $ */
2/** @file
3 * IPRT - String Formatter.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_STRING
32#include <iprt/string.h>
33#include "internal/iprt.h"
34
35#include <iprt/assert.h>
36#ifdef IN_RING3
37# include <iprt/alloc.h>
38# include <iprt/errcore.h>
39# include <iprt/uni.h>
40# include <iprt/utf16.h>
41#endif
42#include <iprt/ctype.h>
43#include <iprt/string.h>
44#include <iprt/stdarg.h>
45#include "internal/string.h"
46
47
48/**
49 * Deals with bad pointers.
50 */
51DECLHIDDEN(size_t) rtStrFormatBadPointer(size_t cch, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, int cchWidth,
52 unsigned fFlags, void const *pvStr, char szTmp[64], const char *pszTag, int cchTag)
53{
54 static char const s_szNull[] = "<NULL>";
55 int cchStr = !pvStr ? sizeof(s_szNull) - 1 : 1 + sizeof(void *) * 2 + cchTag + 1;
56
57 if (!(fFlags & RTSTR_F_LEFT))
58 while (--cchWidth >= cchStr)
59 cch += pfnOutput(pvArgOutput, " ", 1);
60
61 cchWidth -= cchStr;
62 if (!pvStr)
63 cch += pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
64 else
65 {
66 cch += pfnOutput(pvArgOutput, "<", 1);
67 cchStr = RTStrFormatNumber(&szTmp[0], (uintptr_t)pvStr, 16, sizeof(char *) * 2, 0, RTSTR_F_ZEROPAD);
68 cch += pfnOutput(pvArgOutput, szTmp, cchStr);
69 cch += pfnOutput(pvArgOutput, pszTag, cchTag);
70 cch += pfnOutput(pvArgOutput, ">", 1);
71 }
72
73 while (--cchWidth >= 0)
74 cch += pfnOutput(pvArgOutput, " ", 1);
75 return cch;
76}
77
78
79/**
80 * Finds the length of a string up to cchMax.
81 * @returns Length.
82 * @param psz Pointer to string.
83 * @param cchMax Max length.
84 */
85static unsigned _strnlen(const char *psz, unsigned cchMax)
86{
87 const char *pszC = psz;
88
89 while (cchMax-- > 0 && *psz != '\0')
90 psz++;
91
92 return (unsigned)(psz - pszC);
93}
94
95
96/**
97 * Finds the length of a string up to cchMax.
98 * @returns Length.
99 * @param pwsz Pointer to string.
100 * @param cchMax Max length.
101 */
102static unsigned _strnlenUtf16(PCRTUTF16 pwsz, unsigned cchMax)
103{
104#ifdef IN_RING3
105 unsigned cwc = 0;
106 while (cchMax-- > 0)
107 {
108 RTUNICP cp;
109 int rc = RTUtf16GetCpEx(&pwsz, &cp);
110 AssertRC(rc);
111 if (RT_FAILURE(rc) || !cp)
112 break;
113 cwc++;
114 }
115 return cwc;
116#else /* !IN_RING3 */
117 PCRTUTF16 pwszC = pwsz;
118
119 while (cchMax-- > 0 && *pwsz != '\0')
120 pwsz++;
121
122 return (unsigned)(pwsz - pwszC);
123#endif /* !IN_RING3 */
124}
125
126
127/**
128 * Finds the length of a string up to cchMax.
129 * @returns Length.
130 * @param pusz Pointer to string.
131 * @param cchMax Max length.
132 */
133static unsigned _strnlenUni(PCRTUNICP pusz, unsigned cchMax)
134{
135 PCRTUNICP puszC = pusz;
136
137 while (cchMax-- > 0 && *pusz != '\0')
138 pusz++;
139
140 return (unsigned)(pusz - puszC);
141}
142
143
144/**
145 * Formats an integer number according to the parameters.
146 *
147 * @returns Length of the number.
148 * @param psz Pointer to output string.
149 * @param u64Value Value.
150 * @param uiBase Number representation base.
151 * @param cchWidth Width
152 * @param cchPrecision Precision.
153 * @param fFlags Flags (NTFS_*).
154 */
155RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision,
156 unsigned int fFlags)
157{
158 const char *pachDigits = "0123456789abcdef";
159 char *pszStart = psz;
160 int cchMax;
161 int cchValue;
162 int i;
163 int j;
164 char chSign;
165
166 /*
167 * Validate and adjust input...
168 */
169 Assert(uiBase >= 2 && uiBase <= 16);
170 if (fFlags & RTSTR_F_CAPITAL)
171 pachDigits = "0123456789ABCDEF";
172 if (fFlags & RTSTR_F_LEFT)
173 fFlags &= ~RTSTR_F_ZEROPAD;
174 if ( (fFlags & RTSTR_F_THOUSAND_SEP)
175 && ( uiBase != 10
176 || (fFlags & RTSTR_F_ZEROPAD))) /** @todo implement RTSTR_F_ZEROPAD + RTSTR_F_THOUSAND_SEP. */
177 fFlags &= ~RTSTR_F_THOUSAND_SEP;
178
179 /*
180 * Determine value length and sign. Converts the u64Value to unsigned.
181 */
182 cchValue = 0;
183 chSign = '\0';
184 if ((fFlags & RTSTR_F_64BIT) || (u64Value & UINT64_C(0xffffffff00000000)))
185 {
186 uint64_t u64;
187 if (!(fFlags & RTSTR_F_VALSIGNED) || !(u64Value & RT_BIT_64(63)))
188 u64 = u64Value;
189 else if (u64Value != RT_BIT_64(63))
190 {
191 chSign = '-';
192 u64 = u64Value = -(int64_t)u64Value;
193 }
194 else
195 {
196 chSign = '-';
197 u64 = u64Value = RT_BIT_64(63);
198 }
199 do
200 {
201 cchValue++;
202 u64 /= uiBase;
203 } while (u64);
204 }
205 else
206 {
207 uint32_t u32 = (uint32_t)u64Value;
208 if (!(fFlags & RTSTR_F_VALSIGNED) || !(u32 & UINT32_C(0x80000000)))
209 { /* likley */ }
210 else if (u32 != UINT32_C(0x80000000))
211 {
212 chSign = '-';
213 u64Value = u32 = -(int32_t)u32;
214 }
215 else
216 {
217 chSign = '-';
218 u64Value = u32 = UINT32_C(0x80000000);
219 }
220 do
221 {
222 cchValue++;
223 u32 /= uiBase;
224 } while (u32);
225 }
226 if (fFlags & RTSTR_F_THOUSAND_SEP)
227 {
228 if (cchValue <= 3)
229 fFlags &= ~RTSTR_F_THOUSAND_SEP;
230 else
231 cchValue += cchValue / 3 - (cchValue % 3 == 0);
232 }
233
234 /*
235 * Sign (+/-).
236 */
237 i = 0;
238 if (fFlags & RTSTR_F_VALSIGNED)
239 {
240 if (chSign != '\0')
241 psz[i++] = chSign;
242 else if (fFlags & (RTSTR_F_PLUS | RTSTR_F_BLANK))
243 psz[i++] = (char)(fFlags & RTSTR_F_PLUS ? '+' : ' ');
244 }
245
246 /*
247 * Special (0/0x).
248 */
249 if ((fFlags & RTSTR_F_SPECIAL) && (uiBase % 8) == 0)
250 {
251 psz[i++] = '0';
252 if (uiBase == 16)
253 psz[i++] = (char)(fFlags & RTSTR_F_CAPITAL ? 'X' : 'x');
254 }
255
256 /*
257 * width - only if ZEROPAD
258 */
259 cchMax = 64 - (cchValue + i + 1); /* HACK! 64 bytes seems to be the usual buffer size... */
260 cchWidth -= i + cchValue;
261 if (fFlags & RTSTR_F_ZEROPAD)
262 while (--cchWidth >= 0 && i < cchMax)
263 {
264 AssertBreak(i < cchMax);
265 psz[i++] = '0';
266 cchPrecision--;
267 }
268 else if (!(fFlags & RTSTR_F_LEFT) && cchWidth > 0)
269 {
270 AssertStmt(cchWidth < cchMax, cchWidth = cchMax - 1);
271 for (j = i - 1; j >= 0; j--)
272 psz[cchWidth + j] = psz[j];
273 for (j = 0; j < cchWidth; j++)
274 psz[j] = ' ';
275 i += cchWidth;
276 }
277
278 /*
279 * precision
280 */
281 while (--cchPrecision >= cchValue)
282 {
283 AssertBreak(i < cchMax);
284 psz[i++] = '0';
285 }
286
287 psz += i;
288
289 /*
290 * write number - not good enough but it works
291 */
292 psz += cchValue;
293 i = -1;
294 if ((fFlags & RTSTR_F_64BIT) || (u64Value & UINT64_C(0xffffffff00000000)))
295 {
296 uint64_t u64 = u64Value;
297 if (fFlags & RTSTR_F_THOUSAND_SEP)
298 {
299 do
300 {
301 if ((-i - 1) % 4 == 3)
302 psz[i--] = ' ';
303 psz[i--] = pachDigits[u64 % uiBase];
304 u64 /= uiBase;
305 } while (u64);
306 }
307 else
308 {
309 do
310 {
311 psz[i--] = pachDigits[u64 % uiBase];
312 u64 /= uiBase;
313 } while (u64);
314 }
315 }
316 else
317 {
318 uint32_t u32 = (uint32_t)u64Value;
319 if (fFlags & RTSTR_F_THOUSAND_SEP)
320 {
321 do
322 {
323 if ((-i - 1) % 4 == 3)
324 psz[i--] = ' ';
325 psz[i--] = pachDigits[u32 % uiBase];
326 u32 /= uiBase;
327 } while (u32);
328 }
329 else
330 {
331 do
332 {
333 psz[i--] = pachDigits[u32 % uiBase];
334 u32 /= uiBase;
335 } while (u32);
336 }
337 }
338
339 /*
340 * width if RTSTR_F_LEFT
341 */
342 if (fFlags & RTSTR_F_LEFT)
343 while (--cchWidth >= 0)
344 *psz++ = ' ';
345
346 *psz = '\0';
347 return (unsigned)(psz - pszStart);
348}
349RT_EXPORT_SYMBOL(RTStrFormatNumber);
350
351
352/**
353 * Partial implementation of a printf like formatter.
354 * It doesn't do everything correct, and there is no floating point support.
355 * However, it supports custom formats by the means of a format callback.
356 *
357 * @returns number of bytes formatted.
358 * @param pfnOutput Output worker.
359 * Called in two ways. Normally with a string an it's length.
360 * For termination, it's called with NULL for string, 0 for length.
361 * @param pvArgOutput Argument to the output worker.
362 * @param pfnFormat Custom format worker.
363 * @param pvArgFormat Argument to the format worker.
364 * @param pszFormat Format string.
365 * @param InArgs Argument list.
366 */
367RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat,
368 const char *pszFormat, va_list InArgs)
369{
370 char szTmp[64]; /* Worker functions assumes 64 byte buffer! Ugly but faster. */
371 va_list args;
372 size_t cch = 0;
373 const char *pszStartOutput = pszFormat;
374
375 va_copy(args, InArgs); /* make a copy so we can reference it (AMD64 / gcc). */
376
377 while (*pszFormat != '\0')
378 {
379 if (*pszFormat == '%')
380 {
381 /* output pending string. */
382 if (pszStartOutput != pszFormat)
383 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
384
385 /* skip '%' */
386 pszFormat++;
387 if (*pszFormat == '%') /* '%%'-> '%' */
388 pszStartOutput = pszFormat++;
389 else
390 {
391 unsigned int fFlags = 0;
392 int cchWidth = -1;
393 int cchPrecision = -1;
394 unsigned int uBase = 10;
395 char chArgSize;
396
397 /* flags */
398 for (;;)
399 {
400 switch (*pszFormat++)
401 {
402 case '#': fFlags |= RTSTR_F_SPECIAL; continue;
403 case '-': fFlags |= RTSTR_F_LEFT; continue;
404 case '+': fFlags |= RTSTR_F_PLUS; continue;
405 case ' ': fFlags |= RTSTR_F_BLANK; continue;
406 case '0': fFlags |= RTSTR_F_ZEROPAD; continue;
407 case '\'': fFlags |= RTSTR_F_THOUSAND_SEP; continue;
408 }
409 pszFormat--;
410 break;
411 }
412
413 /* width */
414 if (RT_C_IS_DIGIT(*pszFormat))
415 {
416 for (cchWidth = 0; RT_C_IS_DIGIT(*pszFormat); pszFormat++)
417 {
418 cchWidth *= 10;
419 cchWidth += *pszFormat - '0';
420 }
421 fFlags |= RTSTR_F_WIDTH;
422 }
423 else if (*pszFormat == '*')
424 {
425 pszFormat++;
426 cchWidth = va_arg(args, int);
427 if (cchWidth < 0)
428 {
429 cchWidth = -cchWidth;
430 fFlags |= RTSTR_F_LEFT;
431 }
432 fFlags |= RTSTR_F_WIDTH;
433 }
434
435 /* precision */
436 if (*pszFormat == '.')
437 {
438 pszFormat++;
439 if (RT_C_IS_DIGIT(*pszFormat))
440 {
441 for (cchPrecision = 0; RT_C_IS_DIGIT(*pszFormat); pszFormat++)
442 {
443 cchPrecision *= 10;
444 cchPrecision += *pszFormat - '0';
445 }
446
447 }
448 else if (*pszFormat == '*')
449 {
450 pszFormat++;
451 cchPrecision = va_arg(args, int);
452 }
453 if (cchPrecision < 0)
454 cchPrecision = 0;
455 fFlags |= RTSTR_F_PRECISION;
456 }
457
458 /*
459 * Argument size.
460 */
461 chArgSize = *pszFormat;
462 switch (chArgSize)
463 {
464 default:
465 chArgSize = 0;
466 break;
467
468 case 'z':
469 case 'L':
470 case 'j':
471 case 't':
472 pszFormat++;
473 break;
474
475 case 'l':
476 pszFormat++;
477 if (*pszFormat == 'l')
478 {
479 chArgSize = 'L';
480 pszFormat++;
481 }
482 break;
483
484 case 'h':
485 pszFormat++;
486 if (*pszFormat == 'h')
487 {
488 chArgSize = 'H';
489 pszFormat++;
490 }
491 break;
492
493 case 'I': /* Used by Win32/64 compilers. */
494 if ( pszFormat[1] == '6'
495 && pszFormat[2] == '4')
496 {
497 pszFormat += 3;
498 chArgSize = 'L';
499 }
500 else if ( pszFormat[1] == '3'
501 && pszFormat[2] == '2')
502 {
503 pszFormat += 3;
504 chArgSize = 0;
505 }
506 else
507 {
508 pszFormat += 1;
509 chArgSize = 'j';
510 }
511 break;
512
513 case 'q': /* Used on BSD platforms. */
514 pszFormat++;
515 chArgSize = 'L';
516 break;
517 }
518
519 /*
520 * The type.
521 */
522 switch (*pszFormat++)
523 {
524 /* char */
525 case 'c':
526 {
527 if (!(fFlags & RTSTR_F_LEFT))
528 while (--cchWidth > 0)
529 cch += pfnOutput(pvArgOutput, " ", 1);
530
531 szTmp[0] = (char)va_arg(args, int);
532 szTmp[1] = '\0'; /* Some output functions wants terminated strings. */
533 cch += pfnOutput(pvArgOutput, &szTmp[0], 1);
534
535 while (--cchWidth > 0)
536 cch += pfnOutput(pvArgOutput, " ", 1);
537 break;
538 }
539
540 case 'S': /* Legacy, conversion done by streams now. */
541 case 's':
542 {
543 if (chArgSize == 'l')
544 {
545 /* utf-16 -> utf-8 */
546 PCRTUTF16 pwszStr = va_arg(args, PCRTUTF16);
547 if (RT_VALID_PTR(pwszStr))
548 {
549 int cwcStr = _strnlenUtf16(pwszStr, (unsigned)cchPrecision);
550 if (!(fFlags & RTSTR_F_LEFT))
551 while (--cchWidth >= cwcStr)
552 cch += pfnOutput(pvArgOutput, " ", 1);
553 cchWidth -= cwcStr;
554 while (cwcStr-- > 0)
555 {
556/** @todo \#ifndef IN_RC*/
557#ifdef IN_RING3
558 RTUNICP Cp;
559 RTUtf16GetCpEx(&pwszStr, &Cp);
560 char *pszEnd = RTStrPutCp(szTmp, Cp);
561 *pszEnd = '\0';
562 cch += pfnOutput(pvArgOutput, szTmp, pszEnd - szTmp);
563#else
564 char ch = (char)*pwszStr++;
565 cch += pfnOutput(pvArgOutput, &ch, 1);
566#endif
567 }
568 while (--cchWidth >= 0)
569 cch += pfnOutput(pvArgOutput, " ", 1);
570 }
571 else
572 cch = rtStrFormatBadPointer(cch, pfnOutput, pvArgOutput, cchWidth, fFlags,
573 pwszStr, szTmp, RT_STR_TUPLE("!BadStrW"));
574 }
575 else if (chArgSize == 'L')
576 {
577 /* unicp -> utf8 */
578 PCRTUNICP puszStr = va_arg(args, PCRTUNICP);
579 if (RT_VALID_PTR(puszStr))
580 {
581 int cchStr = _strnlenUni(puszStr, (unsigned)cchPrecision);
582 if (!(fFlags & RTSTR_F_LEFT))
583 while (--cchWidth >= cchStr)
584 cch += pfnOutput(pvArgOutput, " ", 1);
585
586 cchWidth -= cchStr;
587 while (cchStr-- > 0)
588 {
589/** @todo \#ifndef IN_RC*/
590#ifdef IN_RING3
591 char *pszEnd = RTStrPutCp(szTmp, *puszStr++);
592 cch += pfnOutput(pvArgOutput, szTmp, pszEnd - szTmp);
593#else
594 char ch = (char)*puszStr++;
595 cch += pfnOutput(pvArgOutput, &ch, 1);
596#endif
597 }
598 while (--cchWidth >= 0)
599 cch += pfnOutput(pvArgOutput, " ", 1);
600 }
601 else
602 cch = rtStrFormatBadPointer(cch, pfnOutput, pvArgOutput, cchWidth, fFlags,
603 puszStr, szTmp, RT_STR_TUPLE("!BadStrU"));
604 }
605 else
606 {
607 const char *pszStr = va_arg(args, const char *);
608 if (RT_VALID_PTR(pszStr))
609 {
610 int cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
611 if (!(fFlags & RTSTR_F_LEFT))
612 while (--cchWidth >= cchStr)
613 cch += pfnOutput(pvArgOutput, " ", 1);
614
615 cch += pfnOutput(pvArgOutput, pszStr, cchStr);
616
617 while (--cchWidth >= cchStr)
618 cch += pfnOutput(pvArgOutput, " ", 1);
619 }
620 else
621 cch = rtStrFormatBadPointer(cch, pfnOutput, pvArgOutput, cchWidth, fFlags,
622 pszStr, szTmp, RT_STR_TUPLE("!BadStr"));
623 }
624 break;
625 }
626
627 /*-----------------*/
628 /* integer/pointer */
629 /*-----------------*/
630 case 'd':
631 case 'i':
632 case 'o':
633 case 'p':
634 case 'u':
635 case 'x':
636 case 'X':
637 {
638 int cchNum;
639 uint64_t u64Value;
640
641 switch (pszFormat[-1])
642 {
643 case 'd': /* signed decimal integer */
644 case 'i':
645 fFlags |= RTSTR_F_VALSIGNED;
646 break;
647
648 case 'o':
649 uBase = 8;
650 break;
651
652 case 'p':
653 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
654 uBase = 16;
655 if (cchWidth < 0)
656 cchWidth = sizeof(char *) * 2;
657 break;
658
659 case 'u':
660 uBase = 10;
661 break;
662
663 case 'X':
664 fFlags |= RTSTR_F_CAPITAL;
665 RT_FALL_THRU();
666 case 'x':
667 uBase = 16;
668 break;
669 }
670
671 if (pszFormat[-1] == 'p')
672 u64Value = va_arg(args, uintptr_t);
673 else if (fFlags & RTSTR_F_VALSIGNED)
674 {
675 if (chArgSize == 'L')
676 {
677 u64Value = va_arg(args, int64_t);
678 fFlags |= RTSTR_F_64BIT;
679 }
680 else if (chArgSize == 'l')
681 {
682 u64Value = va_arg(args, signed long);
683 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
684 }
685 else if (chArgSize == 'h')
686 {
687 u64Value = va_arg(args, /* signed short */ int);
688 fFlags |= RTSTR_GET_BIT_FLAG(signed short);
689 }
690 else if (chArgSize == 'H')
691 {
692 u64Value = va_arg(args, /* int8_t */ int);
693 fFlags |= RTSTR_GET_BIT_FLAG(int8_t);
694 }
695 else if (chArgSize == 'j')
696 {
697 u64Value = va_arg(args, /*intmax_t*/ int64_t);
698 fFlags |= RTSTR_F_64BIT;
699 }
700 else if (chArgSize == 'z')
701 {
702 u64Value = va_arg(args, size_t);
703 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
704 }
705 else if (chArgSize == 't')
706 {
707 u64Value = va_arg(args, ptrdiff_t);
708 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
709 }
710 else
711 {
712 u64Value = va_arg(args, signed int);
713 fFlags |= RTSTR_GET_BIT_FLAG(signed int);
714 }
715 }
716 else
717 {
718 if (chArgSize == 'L')
719 {
720 u64Value = va_arg(args, uint64_t);
721 fFlags |= RTSTR_F_64BIT;
722 }
723 else if (chArgSize == 'l')
724 {
725 u64Value = va_arg(args, unsigned long);
726 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
727 }
728 else if (chArgSize == 'h')
729 {
730 u64Value = va_arg(args, /* unsigned short */ int);
731 fFlags |= RTSTR_GET_BIT_FLAG(unsigned short);
732 }
733 else if (chArgSize == 'H')
734 {
735 u64Value = va_arg(args, /* uint8_t */ int);
736 fFlags |= RTSTR_GET_BIT_FLAG(uint8_t);
737 }
738 else if (chArgSize == 'j')
739 {
740 u64Value = va_arg(args, /*uintmax_t*/ int64_t);
741 fFlags |= RTSTR_F_64BIT;
742 }
743 else if (chArgSize == 'z')
744 {
745 u64Value = va_arg(args, size_t);
746 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
747 }
748 else if (chArgSize == 't')
749 {
750 u64Value = va_arg(args, ptrdiff_t);
751 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
752 }
753 else
754 {
755 u64Value = va_arg(args, unsigned int);
756 fFlags |= RTSTR_GET_BIT_FLAG(unsigned int);
757 }
758 }
759 cchNum = RTStrFormatNumber(&szTmp[0], u64Value, uBase, cchWidth, cchPrecision, fFlags);
760 cch += pfnOutput(pvArgOutput, &szTmp[0], cchNum);
761 break;
762 }
763
764 /*
765 * Nested extensions.
766 */
767 case 'M': /* replace the format string (not stacked yet). */
768 {
769 pszStartOutput = pszFormat = va_arg(args, const char *);
770 AssertPtr(pszStartOutput);
771 break;
772 }
773
774 case 'N': /* real nesting. */
775 {
776 const char *pszFormatNested = va_arg(args, const char *);
777 va_list *pArgsNested = va_arg(args, va_list *);
778 va_list ArgsNested;
779 va_copy(ArgsNested, *pArgsNested);
780 Assert(pszFormatNested);
781 cch += RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormatNested, ArgsNested);
782 va_end(ArgsNested);
783 break;
784 }
785
786 /*
787 * IPRT Extensions.
788 */
789 case 'R':
790 {
791 if (*pszFormat != '[')
792 {
793 pszFormat--;
794 cch += rtstrFormatRt(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
795 }
796 else
797 {
798 pszFormat--;
799 cch += rtstrFormatType(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
800 }
801 break;
802 }
803
804 /*
805 * Custom format.
806 */
807 default:
808 {
809 if (pfnFormat)
810 {
811 pszFormat--;
812 cch += pfnFormat(pvArgFormat, pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
813 }
814 break;
815 }
816 }
817 pszStartOutput = pszFormat;
818 }
819 }
820 else
821 pszFormat++;
822 }
823
824 /* output pending string. */
825 if (pszStartOutput != pszFormat)
826 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
827
828 /* terminate the output */
829 pfnOutput(pvArgOutput, NULL, 0);
830
831 return cch;
832}
833RT_EXPORT_SYMBOL(RTStrFormatV);
834
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette