VirtualBox

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

Last change on this file since 14786 was 14066, checked in by vboxsync, 16 years ago

strformat.cpp: shut up 64-bit MSC warnings. (hope this fix doesn't incur the wrath of gcc)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.2 KB
Line 
1/* $Id: strformat.cpp 14066 2008-11-10 23:33:15Z vboxsync $ */
2/** @file
3 * IPRT - String Formatter.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Defined Constants *
34*******************************************************************************/
35#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
36/*#define MAX(a, b) ((a) >= (b) ? (a) : (b))
37#define MIN(a, b) ((a) < (b) ? (a) : (b)) */
38
39
40/*******************************************************************************
41* Header Files *
42*******************************************************************************/
43#define LOG_GROUP RTLOGGROUP_STRING
44#include <iprt/string.h>
45#include <iprt/assert.h>
46#ifdef IN_RING3
47# include <iprt/alloc.h>
48# include <iprt/err.h>
49# include <iprt/uni.h>
50#endif
51#include <iprt/string.h>
52#include <iprt/stdarg.h>
53#include "internal/string.h"
54
55/* Wrappers for converting to iprt facilities. */
56#define SSToDS(ptr) ptr
57#define kASSERT Assert
58#define KENDIAN_LITTLE 1
59#define KENDIAN KENDIAN_LITTLE
60#define KSIZE size_t
61typedef struct
62{
63 uint32_t ulLo;
64 uint32_t ulHi;
65} KSIZE64;
66
67
68/*******************************************************************************
69* Internal Functions *
70*******************************************************************************/
71static unsigned _strnlen(const char *psz, unsigned cchMax);
72static unsigned _strnlenUtf16(PCRTUTF16 pwsz, unsigned cchMax);
73static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags);
74
75
76/**
77 * Finds the length of a string up to cchMax.
78 * @returns Length.
79 * @param psz Pointer to string.
80 * @param cchMax Max length.
81 */
82static unsigned _strnlen(const char *psz, unsigned cchMax)
83{
84 const char *pszC = psz;
85
86 while (cchMax-- > 0 && *psz != '\0')
87 psz++;
88
89 return (unsigned)(psz - pszC);
90}
91
92
93/**
94 * Finds the length of a string up to cchMax.
95 * @returns Length.
96 * @param pwsz Pointer to string.
97 * @param cchMax Max length.
98 */
99static unsigned _strnlenUtf16(PCRTUTF16 pwsz, unsigned cchMax)
100{
101#ifdef IN_RING3
102 unsigned cwc = 0;
103 while (cchMax-- > 0)
104 {
105 RTUNICP cp;
106 int rc = RTUtf16GetCpEx(&pwsz, &cp);
107 AssertRC(rc);
108 if (RT_FAILURE(rc) || !cp)
109 break;
110 cwc++;
111 }
112 return cwc;
113#else /* !IN_RING3 */
114 PCRTUTF16 pwszC = pwsz;
115
116 while (cchMax-- > 0 && *pwsz != '\0')
117 pwsz++;
118
119 return (unsigned)(pwsz - pwszC);
120#endif /* !IN_RING3 */
121}
122
123
124/**
125 * Finds the length of a string up to cchMax.
126 * @returns Length.
127 * @param pusz Pointer to string.
128 * @param cchMax Max length.
129 */
130static unsigned _strnlenUni(PCRTUNICP pusz, unsigned cchMax)
131{
132 PCRTUNICP puszC = pusz;
133
134 while (cchMax-- > 0 && *pusz != '\0')
135 pusz++;
136
137 return (unsigned)(pusz - puszC);
138}
139
140
141/**
142 * Formats an integer number according to the parameters.
143 *
144 * @returns Length of the formatted number.
145 * @param psz Pointer to output string buffer of sufficient size.
146 * @param u64Value Value to format.
147 * @param uiBase Number representation base.
148 * @param cchWidth Width.
149 * @param cchPrecision Precision.
150 * @param fFlags Flags (NTFS_*).
151 */
152RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags)
153{
154 return rtStrFormatNumber(psz, *(KSIZE64 *)(void *)&u64Value, uiBase, cchWidth, cchPrecision, fFlags);
155}
156
157
158
159/**
160 * Formats an integer number according to the parameters.
161 *
162 * @returns Length of the number.
163 * @param psz Pointer to output string.
164 * @param ullValue Value. Using the high part is optional.
165 * @param uiBase Number representation base.
166 * @param cchWidth Width
167 * @param cchPrecision Precision.
168 * @param fFlags Flags (NTFS_*).
169 */
170static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags)
171{
172 const char * pachDigits = "0123456789abcdef";
173 char * pszStart = psz;
174 int cchValue;
175 unsigned long ul;
176#if 0
177 unsigned long ullow;
178#endif
179 int i;
180 int j;
181
182/** @todo Formatting of 64 bit numbers is broken, fix it! */
183
184 /*
185 * Validate and addjust input...
186 */
187/** @todo r=bird: Dmitry, who is calling this code with uiBase == 0? */
188 if (uiBase == 0)
189 uiBase = 10;
190 kASSERT((uiBase >= 2 || uiBase <= 16));
191 if (fFlags & RTSTR_F_CAPITAL)
192 pachDigits = "0123456789ABCDEF";
193 if (fFlags & RTSTR_F_LEFT)
194 fFlags &= ~RTSTR_F_ZEROPAD;
195
196 /*
197 * Determin value length
198 */
199 cchValue = 0;
200 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
201 {
202 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
203 if ((fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulHi & 0x80000000))
204 u64 = -(int64_t)u64;
205 do
206 {
207 cchValue++;
208 u64 /= uiBase;
209 } while (u64);
210 }
211 else
212 {
213 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
214 do
215 {
216 cchValue++;
217 ul /= uiBase;
218 } while (ul);
219 }
220
221 /*
222 * Sign (+/-).
223 */
224 i = 0;
225 if (fFlags & RTSTR_F_VALSIGNED)
226 {
227 if ((ullValue.ulHi || (fFlags & RTSTR_F_64BIT) ? ullValue.ulHi : ullValue.ulLo) & 0x80000000)
228 {
229 ullValue.ulLo = -(int32_t)ullValue.ulLo;
230 if (ullValue.ulHi)
231 ullValue.ulHi = ~ullValue.ulHi;
232 psz[i++] = '-';
233 }
234 else if (fFlags & (RTSTR_F_PLUS | RTSTR_F_BLANK))
235 psz[i++] = (char)(fFlags & RTSTR_F_PLUS ? '+' : ' ');
236 }
237
238 /*
239 * Special (0/0x).
240 */
241 if ((fFlags & RTSTR_F_SPECIAL) && (uiBase % 8) == 0)
242 {
243 psz[i++] = '0';
244 if (uiBase == 16)
245 psz[i++] = (char)(fFlags & RTSTR_F_CAPITAL ? 'X' : 'x');
246 }
247
248 /*
249 * width - only if ZEROPAD
250 */
251 cchWidth -= i + cchValue;
252 if (fFlags & RTSTR_F_ZEROPAD)
253 while (--cchWidth >= 0)
254 {
255 psz[i++] = '0';
256 cchPrecision--;
257 }
258 else if (!(fFlags & RTSTR_F_LEFT) && cchWidth > 0)
259 {
260 for (j = i-1; j >= 0; j--)
261 psz[cchWidth + j] = psz[j];
262 for (j = 0; j < cchWidth; j++)
263 psz[j] = ' ';
264 i += cchWidth;
265 }
266 psz += i;
267
268
269 /*
270 * precision
271 */
272 while (--cchPrecision >= cchValue)
273 *psz++ = '0';
274
275 /*
276 * write number - not good enough but it works
277 */
278 psz += cchValue;
279 i = -1;
280 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
281 {
282 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
283 do
284 {
285 psz[i--] = pachDigits[u64 % uiBase];
286 u64 /= uiBase;
287 } while (u64);
288 }
289 else
290 {
291 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
292 do
293 {
294 psz[i--] = pachDigits[ul % uiBase];
295 ul /= uiBase;
296 } while (ul);
297 }
298
299
300 /*
301 * width if RTSTR_F_LEFT
302 */
303 if (fFlags & RTSTR_F_LEFT)
304 while (--cchWidth >= 0)
305 *psz++ = ' ';
306
307 *psz = '\0';
308 return (unsigned)(psz - pszStart);
309}
310
311
312/**
313 * Partial implementation of a printf like formatter.
314 * It doesn't do everything correct, and there is no floating point support.
315 * However, it supports custom formats by the means of a format callback.
316 *
317 * @returns number of bytes formatted.
318 * @param pfnOutput Output worker.
319 * Called in two ways. Normally with a string an it's length.
320 * For termination, it's called with NULL for string, 0 for length.
321 * @param pvArgOutput Argument to the output worker.
322 * @param pfnFormat Custom format worker.
323 * @param pvArgFormat Argument to the format worker.
324 * @param pszFormat Format string.
325 * @param InArgs Argument list.
326 */
327RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, va_list InArgs)
328{
329 va_list args;
330 KSIZE cch = 0;
331 const char *pszStartOutput = pszFormat;
332
333 va_copy(args, InArgs); /* make a copy so we can reference it (AMD64 / gcc). */
334
335 while (*pszFormat != '\0')
336 {
337 if (*pszFormat == '%')
338 {
339 /* output pending string. */
340 if (pszStartOutput != pszFormat)
341 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
342
343 /* skip '%' */
344 pszFormat++;
345 if (*pszFormat == '%') /* '%%'-> '%' */
346 pszStartOutput = pszFormat++;
347 else
348 {
349 unsigned int fFlags = 0;
350 int cchWidth = -1;
351 int cchPrecision = -1;
352 unsigned int uBase = 10;
353 char chArgSize;
354
355 /* flags */
356 for (;;)
357 {
358 switch (*pszFormat++)
359 {
360 case '#': fFlags |= RTSTR_F_SPECIAL; continue;
361 case '-': fFlags |= RTSTR_F_LEFT; continue;
362 case '+': fFlags |= RTSTR_F_PLUS; continue;
363 case ' ': fFlags |= RTSTR_F_BLANK; continue;
364 case '0': fFlags |= RTSTR_F_ZEROPAD; continue;
365 }
366 pszFormat--;
367 break;
368 }
369
370 /* width */
371 if (ISDIGIT(*pszFormat))
372 {
373 for (cchWidth = 0; ISDIGIT(*pszFormat); pszFormat++)
374 {
375 cchWidth *= 10;
376 cchWidth += *pszFormat - '0';
377 }
378 fFlags |= RTSTR_F_WIDTH;
379 }
380 else if (*pszFormat == '*')
381 {
382 pszFormat++;
383 cchWidth = va_arg(args, int);
384 if (cchWidth < 0)
385 {
386 cchWidth = -cchWidth;
387 fFlags |= RTSTR_F_LEFT;
388 }
389 fFlags |= RTSTR_F_WIDTH;
390 }
391
392 /* precision */
393 if (*pszFormat == '.')
394 {
395 pszFormat++;
396 if (ISDIGIT(*pszFormat))
397 {
398 for (cchPrecision = 0; ISDIGIT(*pszFormat); pszFormat++)
399 {
400 cchPrecision *= 10;
401 cchPrecision += *pszFormat - '0';
402 }
403
404 }
405 else if (*pszFormat == '*')
406 {
407 pszFormat++;
408 cchPrecision = va_arg(args, int);
409 }
410 if (cchPrecision < 0)
411 cchPrecision = 0;
412 fFlags |= RTSTR_F_PRECISION;
413 }
414
415 /* argsize */
416 chArgSize = *pszFormat;
417 if (chArgSize != 'l' && chArgSize != 'L' && chArgSize != 'h' && chArgSize != 'j' && chArgSize != 'z' && chArgSize != 't')
418 chArgSize = 0;
419 else
420 {
421 pszFormat++;
422 if (*pszFormat == 'l' && chArgSize == 'l')
423 {
424 chArgSize = 'L';
425 pszFormat++;
426 }
427 else if (*pszFormat == 'h' && chArgSize == 'h')
428 {
429 chArgSize = 'H';
430 pszFormat++;
431 }
432 }
433
434 /*
435 * The type.
436 */
437 switch (*pszFormat++)
438 {
439 /* char */
440 case 'c':
441 {
442 char ch;
443
444 if (!(fFlags & RTSTR_F_LEFT))
445 while (--cchWidth > 0)
446 cch += pfnOutput(pvArgOutput, " ", 1);
447
448 ch = (char)va_arg(args, int);
449 cch += pfnOutput(pvArgOutput, SSToDS(&ch), 1);
450
451 while (--cchWidth > 0)
452 cch += pfnOutput(pvArgOutput, " ", 1);
453 break;
454 }
455
456#ifndef IN_RING3
457 case 'S': /* Unicode string as current code page -> Unicode as UTF-8 in GC/R0. */
458 chArgSize = 'l';
459 /* fall thru */
460#endif
461 case 's': /* Unicode string as utf8 */
462 {
463 if (chArgSize == 'l')
464 {
465 /* utf-16 -> utf-8 */
466 int cchStr;
467 PCRTUTF16 pwszStr = va_arg(args, PRTUTF16);
468
469 if (!VALID_PTR(pwszStr))
470 {
471 static RTUTF16 s_wszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
472 pwszStr = s_wszNull;
473 }
474 cchStr = _strnlenUtf16(pwszStr, (unsigned)cchPrecision);
475 if (!(fFlags & RTSTR_F_LEFT))
476 while (--cchWidth >= cchStr)
477 cch += pfnOutput(pvArgOutput, " ", 1);
478 cchWidth -= cchStr;
479 while (cchStr-- > 0)
480 {
481#ifdef IN_RING3
482 RTUNICP Cp;
483 RTUtf16GetCpEx(&pwszStr, &Cp);
484 char szUtf8[8]; /* Cp=0x7fffffff -> 6 bytes. */
485 char *pszEnd = RTStrPutCp(szUtf8, Cp);
486 cch += pfnOutput(pvArgOutput, szUtf8, pszEnd - szUtf8);
487#else
488 char ch = (char)*pwszStr++;
489 cch += pfnOutput(pvArgOutput, &ch, 1);
490#endif
491 }
492 while (--cchWidth >= 0)
493 cch += pfnOutput(pvArgOutput, " ", 1);
494 }
495 else if (chArgSize == 'L')
496 {
497 /* unicp -> utf8 */
498 int cchStr;
499 PCRTUNICP puszStr = va_arg(args, PCRTUNICP);
500
501 if (!VALID_PTR(puszStr))
502 {
503 static RTUNICP s_uszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
504 puszStr = s_uszNull;
505 }
506 cchStr = _strnlenUni(puszStr, (unsigned)cchPrecision);
507 if (!(fFlags & RTSTR_F_LEFT))
508 while (--cchWidth >= cchStr)
509 cch += pfnOutput(pvArgOutput, " ", 1);
510
511 cchWidth -= cchStr;
512 while (cchStr-- > 0)
513 {
514#ifdef IN_RING3
515 char szUtf8[8]; /* Cp=0x7fffffff -> 6 bytes. */
516 char *pszEnd = RTStrPutCp(szUtf8, *puszStr++);
517 cch += pfnOutput(pvArgOutput, szUtf8, pszEnd - szUtf8);
518#else
519 char ch = (char)*puszStr++;
520 cch += pfnOutput(pvArgOutput, &ch, 1);
521#endif
522 }
523 while (--cchWidth >= 0)
524 cch += pfnOutput(pvArgOutput, " ", 1);
525 }
526 else
527 {
528 int cchStr;
529 const char *pszStr = va_arg(args, char*);
530
531 if (!VALID_PTR(pszStr))
532 pszStr = "<NULL>";
533 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
534 if (!(fFlags & RTSTR_F_LEFT))
535 while (--cchWidth >= cchStr)
536 cch += pfnOutput(pvArgOutput, " ", 1);
537
538 cch += pfnOutput(pvArgOutput, pszStr, cchStr);
539
540 while (--cchWidth >= cchStr)
541 cch += pfnOutput(pvArgOutput, " ", 1);
542 }
543 break;
544 }
545
546#ifdef IN_RING3
547 case 'S': /* Unicode string as current code page. */
548 {
549 if (chArgSize == 'l')
550 {
551 /* UTF-16 */
552 int cchStr;
553 PCRTUTF16 pwsz2Str = va_arg(args, PRTUTF16);
554 if (!VALID_PTR(pwsz2Str))
555 {
556 static RTUTF16 s_wsz2Null[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
557 pwsz2Str = s_wsz2Null;
558 }
559
560 cchStr = _strnlenUtf16(pwsz2Str, (unsigned)cchPrecision);
561 if (!(fFlags & RTSTR_F_LEFT))
562 while (--cchWidth >= cchStr)
563 cch += pfnOutput(pvArgOutput, " ", 1);
564
565 if (cchStr)
566 {
567 /* allocate temporary buffer. */
568 PRTUTF16 pwsz2Tmp = (PRTUTF16)RTMemTmpAlloc((cchStr + 1) * sizeof(RTUTF16));
569 memcpy(pwsz2Tmp, pwsz2Str, cchStr * sizeof(RTUTF16));
570 pwsz2Tmp[cchStr] = '\0';
571
572 char *pszUtf8;
573 int rc = RTUtf16ToUtf8(pwsz2Tmp, &pszUtf8);
574 if (RT_SUCCESS(rc))
575 {
576 char *pszCurCp;
577 rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszUtf8);
578 if (RT_SUCCESS(rc))
579 {
580 cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
581 RTStrFree(pszCurCp);
582 }
583 RTStrFree(pszUtf8);
584 }
585 if (RT_FAILURE(rc))
586 while (cchStr-- > 0)
587 cch += pfnOutput(pvArgOutput, "\x7f", 1);
588 RTMemTmpFree(pwsz2Tmp);
589 }
590
591 while (--cchWidth >= cchStr)
592 cch += pfnOutput(pvArgOutput, " ", 1);
593 }
594 else if (chArgSize == 'L')
595 {
596 /* UCS-32 */
597 AssertMsgFailed(("Not implemented yet\n"));
598 }
599 else
600 {
601 /* UTF-8 */
602 int cchStr;
603 const char *pszStr = va_arg(args, char *);
604
605 if (!VALID_PTR(pszStr))
606 pszStr = "<NULL>";
607 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
608 if (!(fFlags & RTSTR_F_LEFT))
609 while (--cchWidth >= cchStr)
610 cch += pfnOutput(pvArgOutput, " ", 1);
611
612 if (cchStr)
613 {
614 /* allocate temporary buffer. */
615 char *pszTmp = (char *)RTMemTmpAlloc(cchStr + 1);
616 memcpy(pszTmp, pszStr, cchStr);
617 pszTmp[cchStr] = '\0';
618
619 char *pszCurCp;
620 int rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszTmp);
621 if (RT_SUCCESS(rc))
622 {
623 cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
624 RTStrFree(pszCurCp);
625 }
626 else
627 while (cchStr-- > 0)
628 cch += pfnOutput(pvArgOutput, "\x7f", 1);
629 RTMemTmpFree(pszTmp);
630 }
631
632 while (--cchWidth >= cchStr)
633 cch += pfnOutput(pvArgOutput, " ", 1);
634 }
635 break;
636 }
637#endif
638
639
640 /*-----------------*/
641 /* integer/pointer */
642 /*-----------------*/
643 case 'd':
644 case 'i':
645 case 'o':
646 case 'p':
647 case 'u':
648 case 'x':
649 case 'X':
650 {
651 char achNum[64]; /* FIXME */
652 int cchNum;
653 uint64_t u64Value;
654
655 switch (pszFormat[-1])
656 {
657 case 'd': /* signed decimal integer */
658 case 'i':
659 fFlags |= RTSTR_F_VALSIGNED;
660 break;
661
662 case 'o':
663 uBase = 8;
664 break;
665
666 case 'p':
667 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
668 uBase = 16;
669 if (cchWidth < 0)
670 cchWidth = sizeof(char *) * 2;
671 break;
672
673 case 'u':
674 uBase = 10;
675 break;
676
677 case 'X':
678 fFlags |= RTSTR_F_CAPITAL;
679 case 'x':
680 uBase = 16;
681 break;
682 }
683
684 if (pszFormat[-1] == 'p')
685 u64Value = va_arg(args, uintptr_t);
686 else if (fFlags & RTSTR_F_VALSIGNED)
687 {
688 if (chArgSize == 'L')
689 {
690 u64Value = va_arg(args, int64_t);
691 fFlags |= RTSTR_F_64BIT;
692 }
693 else if (chArgSize == 'l')
694 {
695 u64Value = va_arg(args, signed long);
696 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
697 }
698 else if (chArgSize == 'h')
699 {
700 u64Value = va_arg(args, /* signed short */ int);
701 fFlags |= RTSTR_GET_BIT_FLAG(signed short);
702 }
703 else if (chArgSize == 'H')
704 {
705 u64Value = va_arg(args, /* int8_t */ int);
706 fFlags |= RTSTR_GET_BIT_FLAG(int8_t);
707 }
708 else if (chArgSize == 'j')
709 {
710 u64Value = va_arg(args, /*intmax_t*/ int64_t);
711 fFlags |= RTSTR_F_64BIT;
712 }
713 else if (chArgSize == 'z')
714 {
715 u64Value = va_arg(args, size_t);
716 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
717 }
718 else if (chArgSize == 't')
719 {
720 u64Value = va_arg(args, ptrdiff_t);
721 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
722 }
723 else
724 {
725 u64Value = va_arg(args, signed int);
726 fFlags |= RTSTR_GET_BIT_FLAG(signed int);
727 }
728 }
729 else
730 {
731 if (chArgSize == 'L')
732 {
733 u64Value = va_arg(args, uint64_t);
734 fFlags |= RTSTR_F_64BIT;
735 }
736 else if (chArgSize == 'l')
737 {
738 u64Value = va_arg(args, unsigned long);
739 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
740 }
741 else if (chArgSize == 'h')
742 {
743 u64Value = va_arg(args, /* unsigned short */ int);
744 fFlags |= RTSTR_GET_BIT_FLAG(unsigned short);
745 }
746 else if (chArgSize == 'H')
747 {
748 u64Value = va_arg(args, /* uint8_t */ int);
749 fFlags |= RTSTR_GET_BIT_FLAG(uint8_t);
750 }
751 else if (chArgSize == 'j')
752 {
753 u64Value = va_arg(args, /*uintmax_t*/ int64_t);
754 fFlags |= RTSTR_F_64BIT;
755 }
756 else if (chArgSize == 'z')
757 {
758 u64Value = va_arg(args, size_t);
759 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
760 }
761 else if (chArgSize == 't')
762 {
763 u64Value = va_arg(args, ptrdiff_t);
764 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
765 }
766 else
767 {
768 u64Value = va_arg(args, unsigned int);
769 fFlags |= RTSTR_GET_BIT_FLAG(unsigned int);
770 }
771 }
772 cchNum = RTStrFormatNumber((char *)SSToDS(&achNum), u64Value, uBase, cchWidth, cchPrecision, fFlags);
773 cch += pfnOutput(pvArgOutput, (char *)SSToDS(&achNum), cchNum);
774 break;
775 }
776
777 /*
778 * Nested extensions.
779 */
780 case 'M': /* replace the format string (not stacked yet). */
781 {
782 pszStartOutput = pszFormat = va_arg(args, const char *);
783 AssertPtr(pszStartOutput);
784 break;
785 }
786
787 case 'N': /* real nesting. */
788 {
789 const char *pszFormatNested = va_arg(args, const char *);
790 va_list *pArgsNested = va_arg(args, va_list *);
791 va_list ArgsNested;
792 va_copy(ArgsNested, *pArgsNested);
793 Assert(pszFormatNested);
794 cch += RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormatNested, ArgsNested);
795 break;
796 }
797
798 /*
799 * IPRT Extensions.
800 */
801 case 'R':
802 {
803 if (*pszFormat != '[')
804 {
805 pszFormat--;
806 cch += rtstrFormatRt(pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
807 }
808 else
809 {
810 pszFormat--;
811 cch += rtstrFormatType(pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
812 }
813 break;
814 }
815
816#ifdef RT_WITH_VBOX
817 /*
818 * VBox extensions.
819 */
820 case 'V':
821 {
822 pszFormat--;
823 cch += rtstrFormatVBox(pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
824 break;
825 }
826#endif
827
828 /*
829 * Custom format.
830 */
831 default:
832 {
833 if (pfnFormat)
834 {
835 pszFormat--;
836 cch += pfnFormat(pvArgFormat, pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
837 }
838 break;
839 }
840 }
841 pszStartOutput = pszFormat;
842 }
843 }
844 else
845 pszFormat++;
846 }
847
848 /* output pending string. */
849 if (pszStartOutput != pszFormat)
850 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
851
852 /* terminate the output */
853 pfnOutput(pvArgOutput, NULL, 0);
854
855 return cch;
856}
857
858
859/**
860 * Partial implementation of a printf like formatter.
861 * It doesn't do everything correct, and there is no floating point support.
862 * However, it supports custom formats by the means of a format callback.
863 *
864 * @returns number of bytes formatted.
865 * @param pfnOutput Output worker.
866 * Called in two ways. Normally with a string an it's length.
867 * For termination, it's called with NULL for string, 0 for length.
868 * @param pvArgOutput Argument to the output worker.
869 * @param pfnFormat Custom format worker.
870 * @param pvArgFormat Argument to the format worker.
871 * @param pszFormat Format string.
872 * @param ... Argument list.
873 */
874RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, ...)
875{
876 size_t cch;
877 va_list args;
878 va_start(args, pszFormat);
879 cch = RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormat, args);
880 va_end(args);
881 return cch;
882}
883
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