VirtualBox

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

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

C-ify some files in the runtime for building them inside Linux kernel modules

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.3 KB
Line 
1/* $Id: strformat.cpp 4694 2007-09-11 10:14:54Z 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/** @todo r=bird: Dmitry, who is calling this code with uiBase == 0? */
160 if (uiBase == 0)
161 uiBase = 10;
162 kASSERT((uiBase >= 2 || uiBase <= 16));
163 if (fFlags & RTSTR_F_CAPITAL)
164 pachDigits = "0123456789ABCDEF";
165 if (fFlags & RTSTR_F_LEFT)
166 fFlags &= ~RTSTR_F_ZEROPAD;
167
168 /*
169 * Determin value length
170 */
171 cchValue = 0;
172 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
173 {
174 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
175 if ((fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulHi & 0x80000000))
176 u64 = -(int64_t)u64;
177 do
178 {
179 cchValue++;
180 u64 /= uiBase;
181 } while (u64);
182 }
183 else
184 {
185 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
186 do
187 {
188 cchValue++;
189 ul /= uiBase;
190 } while (ul);
191 }
192
193 /*
194 * Sign (+/-).
195 */
196 i = 0;
197 if (fFlags & RTSTR_F_VALSIGNED)
198 {
199 if ((ullValue.ulHi || (fFlags & RTSTR_F_64BIT) ? ullValue.ulHi : ullValue.ulLo) & 0x80000000)
200 {
201 ullValue.ulLo = -(int32_t)ullValue.ulLo;
202 if (ullValue.ulHi)
203 ullValue.ulHi = ~ullValue.ulHi;
204 psz[i++] = '-';
205 }
206 else if (fFlags & (RTSTR_F_PLUS | RTSTR_F_BLANK))
207 psz[i++] = (char)(fFlags & RTSTR_F_PLUS ? '+' : ' ');
208 }
209
210 /*
211 * Special (0/0x).
212 */
213 if (fFlags & RTSTR_F_SPECIAL && (uiBase % 8) == 0)
214 {
215 psz[i++] = '0';
216 if (uiBase == 16)
217 psz[i++] = (char)(fFlags & RTSTR_F_CAPITAL ? 'X' : 'x');
218 }
219
220 /*
221 * width - only if ZEROPAD
222 */
223 cchWidth -= i + cchValue;
224 if (fFlags & RTSTR_F_ZEROPAD)
225 while (--cchWidth >= 0)
226 {
227 psz[i++] = '0';
228 cchPrecision--;
229 }
230 else if (!(fFlags & RTSTR_F_LEFT) && cchWidth > 0)
231 {
232 for (j = i-1; j >= 0; j--)
233 psz[cchWidth + j] = psz[j];
234 for (j = 0; j < cchWidth; j++)
235 psz[j] = ' ';
236 i += cchWidth;
237 }
238 psz += i;
239
240
241 /*
242 * precision
243 */
244 while (--cchPrecision >= cchValue)
245 *psz++ = '0';
246
247 /*
248 * write number - not good enough but it works
249 */
250 psz += cchValue;
251 i = -1;
252 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
253 {
254 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
255 do
256 {
257 psz[i--] = pachDigits[u64 % uiBase];
258 u64 /= uiBase;
259 } while (u64);
260 }
261 else
262 {
263 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
264 do
265 {
266 psz[i--] = pachDigits[ul % uiBase];
267 ul /= uiBase;
268 } while (ul);
269 }
270
271
272 /*
273 * width if RTSTR_F_LEFT
274 */
275 if (fFlags & RTSTR_F_LEFT)
276 while (--cchWidth >= 0)
277 *psz++ = ' ';
278
279 *psz = '\0';
280 return psz - pszStart;
281}
282
283
284/**
285 * Partial implementation of a printf like formatter.
286 * It doesn't do everything correct, and there is no floating point support.
287 * However, it supports custom formats by the means of a format callback.
288 *
289 * @returns number of bytes formatted.
290 * @param pfnOutput Output worker.
291 * Called in two ways. Normally with a string an it's length.
292 * For termination, it's called with NULL for string, 0 for length.
293 * @param pvArgOutput Argument to the output worker.
294 * @param pfnFormat Custom format worker.
295 * @param pvArgFormat Argument to the format worker.
296 * @param pszFormat Format string.
297 * @param InArgs Argument list.
298 */
299RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, va_list InArgs)
300{
301 /* make a copy so we can reference it (AMD64 / gcc). */
302 va_list args;
303 KSIZE cch = 0;
304 const char *pszStartOutput = pszFormat;
305
306 va_copy(args, InArgs);
307
308 while (*pszFormat != '\0')
309 {
310 if (*pszFormat == '%')
311 {
312 /* output pending string. */
313 if (pszStartOutput != pszFormat)
314 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
315
316 /* skip '%' */
317 pszFormat++;
318 if (*pszFormat == '%') /* '%%'-> '%' */
319 pszStartOutput = pszFormat++;
320 else
321 {
322 unsigned int fFlags = 0;
323 int cchWidth = -1;
324 int cchPrecision = -1;
325 unsigned int uBase = 10;
326 char chArgSize;
327
328 /* flags */
329 for (;;)
330 {
331 switch (*pszFormat++)
332 {
333 case '#': fFlags |= RTSTR_F_SPECIAL; continue;
334 case '-': fFlags |= RTSTR_F_LEFT; continue;
335 case '+': fFlags |= RTSTR_F_PLUS; continue;
336 case ' ': fFlags |= RTSTR_F_BLANK; continue;
337 case '0': fFlags |= RTSTR_F_ZEROPAD; continue;
338 }
339 pszFormat--;
340 break;
341 }
342
343 /* width */
344 if (ISDIGIT(*pszFormat))
345 {
346 for (cchWidth = 0; ISDIGIT(*pszFormat); pszFormat++)
347 {
348 cchWidth *= 10;
349 cchWidth += *pszFormat - '0';
350 }
351 fFlags |= RTSTR_F_WIDTH;
352 }
353 else if (*pszFormat == '*')
354 {
355 pszFormat++;
356 cchWidth = va_arg(args, int);
357 if (cchWidth < 0)
358 {
359 cchWidth = -cchWidth;
360 fFlags |= RTSTR_F_LEFT;
361 }
362 fFlags |= RTSTR_F_WIDTH;
363 }
364
365 /* precision */
366 if (*pszFormat == '.')
367 {
368 pszFormat++;
369 if (ISDIGIT(*pszFormat))
370 {
371 for (cchPrecision = 0; ISDIGIT(*pszFormat); pszFormat++)
372 {
373 cchPrecision *= 10;
374 cchPrecision += *pszFormat - '0';
375 }
376
377 }
378 else if (*pszFormat == '*')
379 {
380 pszFormat++;
381 cchPrecision = va_arg(args, int);
382 }
383 if (cchPrecision < 0)
384 cchPrecision = 0;
385 fFlags |= RTSTR_F_PRECISION;
386 }
387
388 /* argsize */
389 chArgSize = *pszFormat;
390 if (chArgSize != 'l' && chArgSize != 'L' && chArgSize != 'h' && chArgSize != 'j' && chArgSize != 'z' && chArgSize != 't')
391 chArgSize = 0;
392 else
393 {
394 pszFormat++;
395 if (*pszFormat == 'l' && chArgSize == 'l')
396 {
397 chArgSize = 'L';
398 pszFormat++;
399 }
400 else if (*pszFormat == 'h' && chArgSize == 'h')
401 {
402 chArgSize = 'H';
403 pszFormat++;
404 }
405 }
406
407 /*
408 * The type.
409 */
410 switch (*pszFormat++)
411 {
412 /* char */
413 case 'c':
414 {
415 char ch;
416
417 if (!(fFlags & RTSTR_F_LEFT))
418 while (--cchWidth > 0)
419 cch += pfnOutput(pvArgOutput, " ", 1);
420
421 ch = (char)va_arg(args, int);
422 cch += pfnOutput(pvArgOutput, SSToDS(&ch), 1);
423
424 while (--cchWidth > 0)
425 cch += pfnOutput(pvArgOutput, " ", 1);
426 break;
427 }
428
429#ifndef IN_RING3
430 case 'S': /* Unicode string as current code page. */
431 chArgSize = 'l';
432 /* fall thru */
433#endif
434 case 's': /* Unicode string as utf8 */
435 {
436 if (chArgSize == 'l')
437 {
438 /* ucs2 -> utf8 */
439 int cchStr;
440 PCRTUTF16 pwszStr = va_arg(args, PRTUTF16);
441
442 if (!VALID_PTR(pwszStr))
443 {
444 static RTUTF16 s_wszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
445 pwszStr = s_wszNull;
446 }
447 cchStr = _strnlenUCS2(pwszStr, (unsigned)cchPrecision);
448 if (!(fFlags & RTSTR_F_LEFT))
449 while (--cchWidth >= cchStr)
450 cch += pfnOutput(pvArgOutput, " ", 1);
451 while (cchStr-- > 0)
452 {
453#ifdef IN_RING3
454 RTUNICP Cp;
455 RTUtf16GetCpEx(&pwszStr, &Cp);
456 char szUtf8[8]; /* Cp=0x7fffffff -> 6 bytes. */
457 char *pszEnd = RTStrPutCp(szUtf8, Cp);
458 cch += pfnOutput(pvArgOutput, szUtf8, pszEnd - szUtf8);
459#else
460 char ch = (char)*pwszStr++;
461 cch += pfnOutput(pvArgOutput, &ch, 1);
462#endif
463 }
464 while (--cchWidth >= cchStr)
465 cch += pfnOutput(pvArgOutput, " ", 1);
466 }
467 else if (chArgSize == 'L')
468 {
469 /* unicp -> utf8 */
470 int cchStr;
471 PCRTUNICP puszStr = va_arg(args, PCRTUNICP);
472
473 if (!VALID_PTR(puszStr))
474 {
475 static RTUNICP uszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
476 puszStr = uszNull;
477 }
478 cchStr = _strnlenUni(puszStr, (unsigned)cchPrecision);
479 if (!(fFlags & RTSTR_F_LEFT))
480 while (--cchWidth >= cchStr)
481 cch += pfnOutput(pvArgOutput, " ", 1);
482
483 while (cchStr-- > 0)
484 {
485#ifdef IN_RING3
486 char szUtf8[8]; /* Cp=0x7fffffff -> 6 bytes. */
487 char *pszEnd = RTStrPutCp(szUtf8, *puszStr++);
488 cch += pfnOutput(pvArgOutput, szUtf8, pszEnd - szUtf8);
489#else
490 char ch = (char)*puszStr++;
491 cch += pfnOutput(pvArgOutput, &ch, 1);
492#endif
493 }
494 while (--cchWidth >= cchStr)
495 cch += pfnOutput(pvArgOutput, " ", 1);
496 }
497 else
498 {
499 int cchStr;
500 const char *pszStr = va_arg(args, char*);
501
502 if (!VALID_PTR(pszStr))
503 pszStr = "<NULL>";
504 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
505 if (!(fFlags & RTSTR_F_LEFT))
506 while (--cchWidth >= cchStr)
507 cch += pfnOutput(pvArgOutput, " ", 1);
508
509 cch += pfnOutput(pvArgOutput, pszStr, cchStr);
510
511 while (--cchWidth >= cchStr)
512 cch += pfnOutput(pvArgOutput, " ", 1);
513 }
514 break;
515 }
516
517#ifdef IN_RING3
518 case 'S': /* Unicode string as current code page. */
519 {
520 if (chArgSize == 'l')
521 {
522 int cchStr;
523 PCRTUCS2 pucs2Str = va_arg(args, PRTUCS2);
524 if (!VALID_PTR(pucs2Str))
525 {
526 static RTUCS2 ucs2Null[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
527 pucs2Str = ucs2Null;
528 }
529
530 cchStr = _strnlenUCS2(pucs2Str, (unsigned)cchPrecision);
531 if (!(fFlags & RTSTR_F_LEFT))
532 while (--cchWidth >= cchStr)
533 cch += pfnOutput(pvArgOutput, " ", 1);
534
535 if (cchStr)
536 {
537 /* allocate temporary buffer. */
538 PRTUCS2 pucs2Tmp = (PRTUCS2)RTMemAlloc((cchStr + 1) * sizeof(RTUCS2));
539 memcpy(pucs2Tmp, pucs2Str, cchStr * sizeof(RTUCS2));
540 pucs2Tmp[cchStr] = '\0';
541
542 char *pszUtf8;
543 int rc = RTStrUcs2ToUtf8(&pszUtf8, pucs2Tmp);
544 if (RT_SUCCESS(rc))
545 {
546 char *pszCurCp;
547 rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszUtf8);
548 if (RT_SUCCESS(rc))
549 {
550 cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
551 RTStrFree(pszCurCp);
552 }
553 RTStrFree(pszUtf8);
554 }
555 if (RT_FAILURE(rc))
556 while (cchStr-- > 0)
557 cch += pfnOutput(pvArgOutput, "\x7f", 1);
558 RTMemFree(pucs2Tmp);
559 }
560
561 while (--cchWidth >= cchStr)
562 cch += pfnOutput(pvArgOutput, " ", 1);
563 }
564 else if (chArgSize == 'L')
565 {
566 AssertMsgFailed(("Not implemented yet\n"));
567 }
568 else
569 {
570 int cchStr;
571 const char *pszStr = va_arg(args, char*);
572
573 if (!VALID_PTR(pszStr))
574 pszStr = "<NULL>";
575 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
576 if (!(fFlags & RTSTR_F_LEFT))
577 while (--cchWidth >= cchStr)
578 cch += pfnOutput(pvArgOutput, " ", 1);
579
580 if (cchStr)
581 {
582 /* allocate temporary buffer. */
583 char *pszTmp = (char *)RTMemAlloc(cchStr + 1);
584 memcpy(pszTmp, pszStr, cchStr);
585 pszTmp[cchStr] = '\0';
586
587 char *pszCurCp;
588 int rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszTmp);
589 if (RT_SUCCESS(rc))
590 {
591 cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
592 RTStrFree(pszCurCp);
593 }
594 else
595 while (cchStr-- > 0)
596 cch += pfnOutput(pvArgOutput, "\x7f", 1);
597 RTMemFree(pszTmp);
598 }
599
600 while (--cchWidth >= cchStr)
601 cch += pfnOutput(pvArgOutput, " ", 1);
602 }
603 break;
604 }
605#endif
606
607
608 /*-----------------*/
609 /* integer/pointer */
610 /*-----------------*/
611 case 'd':
612 case 'i':
613 case 'o':
614 case 'p':
615 case 'u':
616 case 'x':
617 case 'X':
618 {
619 char achNum[64]; /* FIXME */
620 int cchNum;
621 uint64_t u64Value;
622
623 switch (pszFormat[-1])
624 {
625 case 'd': /* signed decimal integer */
626 case 'i':
627 fFlags |= RTSTR_F_VALSIGNED;
628 break;
629
630 case 'o':
631 uBase = 8;
632 break;
633
634 case 'p':
635 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
636 uBase = 16;
637 if (cchWidth < 0)
638 cchWidth = sizeof(char *) * 2;
639 break;
640
641 case 'u':
642 uBase = 10;
643 break;
644
645 case 'X':
646 fFlags |= RTSTR_F_CAPITAL;
647 case 'x':
648 uBase = 16;
649 break;
650 }
651
652 if (pszFormat[-1] == 'p')
653 u64Value = va_arg(args, uintptr_t);
654 else if (fFlags & RTSTR_F_VALSIGNED)
655 {
656 if (chArgSize == 'L')
657 {
658 u64Value = va_arg(args, int64_t);
659 fFlags |= RTSTR_F_64BIT;
660 }
661 else if (chArgSize == 'l')
662 {
663 u64Value = va_arg(args, signed long);
664 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
665 }
666 else if (chArgSize == 'h')
667 {
668 u64Value = va_arg(args, /* signed short */ int);
669 fFlags |= RTSTR_GET_BIT_FLAG(signed short);
670 }
671 else if (chArgSize == 'H')
672 {
673 u64Value = va_arg(args, /* int8_t */ int);
674 fFlags |= RTSTR_GET_BIT_FLAG(int8_t);
675 }
676 else if (chArgSize == 'j')
677 {
678 u64Value = va_arg(args, /*intmax_t*/ int64_t);
679 fFlags |= RTSTR_F_64BIT;
680 }
681 else if (chArgSize == 'z')
682 {
683 u64Value = va_arg(args, size_t);
684 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
685 }
686 else if (chArgSize == 't')
687 {
688 u64Value = va_arg(args, ptrdiff_t);
689 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
690 }
691 else
692 {
693 u64Value = va_arg(args, signed int);
694 fFlags |= RTSTR_GET_BIT_FLAG(signed int);
695 }
696 }
697 else
698 {
699 if (chArgSize == 'L')
700 {
701 u64Value = va_arg(args, uint64_t);
702 fFlags |= RTSTR_F_64BIT;
703 }
704 else if (chArgSize == 'l')
705 {
706 u64Value = va_arg(args, unsigned long);
707 fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
708 }
709 else if (chArgSize == 'h')
710 {
711 u64Value = va_arg(args, /* unsigned short */ int);
712 fFlags |= RTSTR_GET_BIT_FLAG(unsigned short);
713 }
714 else if (chArgSize == 'H')
715 {
716 u64Value = va_arg(args, /* uint8_t */ int);
717 fFlags |= RTSTR_GET_BIT_FLAG(uint8_t);
718 }
719 else if (chArgSize == 'j')
720 {
721 u64Value = va_arg(args, /*uintmax_t*/ int64_t);
722 fFlags |= RTSTR_F_64BIT;
723 }
724 else if (chArgSize == 'z')
725 {
726 u64Value = va_arg(args, size_t);
727 fFlags |= RTSTR_GET_BIT_FLAG(size_t);
728 }
729 else if (chArgSize == 't')
730 {
731 u64Value = va_arg(args, ptrdiff_t);
732 fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
733 }
734 else
735 {
736 u64Value = va_arg(args, unsigned int);
737 fFlags |= RTSTR_GET_BIT_FLAG(unsigned int);
738 }
739 }
740 cchNum = RTStrFormatNumber((char *)SSToDS(&achNum), u64Value, uBase, cchWidth, cchPrecision, fFlags);
741 cch += pfnOutput(pvArgOutput, (char *)SSToDS(&achNum), cchNum);
742 break;
743 }
744
745 /*
746 * Nested extension.
747 */
748 case 'N':
749 {
750 const char *pszFormatNested = va_arg(args, const char *);
751 va_list *pArgsNested = va_arg(args, va_list *);
752 va_list ArgsNested;
753 va_copy(ArgsNested, *pArgsNested);
754 Assert(pszFormatNested);
755 cch += RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormatNested, ArgsNested);
756 break;
757 }
758
759 /*
760 * innotek Portable Runtime Extensions.
761 */
762 case 'R':
763 {
764 pszFormat--;
765 cch += rtstrFormatRt(pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
766 break;
767 }
768
769#ifdef RT_WITH_VBOX
770 /*
771 * VBox extensions.
772 */
773 case 'V':
774 {
775 pszFormat--;
776 cch += rtstrFormatVBox(pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
777 break;
778 }
779#endif
780
781 /*
782 * Custom format.
783 */
784 default:
785 {
786 if (pfnFormat)
787 {
788 pszFormat--;
789 cch += pfnFormat(pvArgFormat, pfnOutput, pvArgOutput, &pszFormat, &args, cchPrecision, cchWidth, fFlags, chArgSize);
790 }
791 break;
792 }
793 }
794 pszStartOutput = pszFormat;
795 }
796 }
797 else
798 pszFormat++;
799 }
800
801 /* output pending string. */
802 if (pszStartOutput != pszFormat)
803 cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
804
805 /* terminate the output */
806 pfnOutput(pvArgOutput, NULL, 0);
807
808 return cch;
809}
810
811
812/**
813 * Partial implementation of a printf like formatter.
814 * It doesn't do everything correct, and there is no floating point support.
815 * However, it supports custom formats by the means of a format callback.
816 *
817 * @returns number of bytes formatted.
818 * @param pfnOutput Output worker.
819 * Called in two ways. Normally with a string an it's length.
820 * For termination, it's called with NULL for string, 0 for length.
821 * @param pvArgOutput Argument to the output worker.
822 * @param pfnFormat Custom format worker.
823 * @param pvArgFormat Argument to the format worker.
824 * @param pszFormat Format string.
825 * @param ... Argument list.
826 */
827RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, ...)
828{
829 size_t cch;
830 va_list args;
831 va_start(args, pszFormat);
832 cch = RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormat, args);
833 va_end(args);
834 return cch;
835}
836
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