VirtualBox

source: vbox/trunk/src/VBox/Runtime/strformat.cpp@ 4071

Last change on this file since 4071 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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