VirtualBox

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

Last change on this file since 977 was 628, checked in by vboxsync, 18 years ago

Implement log flag usecrlf, which translates LF line ending to CR/LF.
Activate it by default for Windows builds, only for release log so far.
Also fixed a couple of typos in comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.4 KB
Line 
1/* $Id: strformat.cpp 628 2007-02-05 11:59:58Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - String Formatter.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Defined Constants *
25*******************************************************************************/
26#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
27/*#define MAX(a, b) ((a) >= (b) ? (a) : (b))
28#define MIN(a, b) ((a) < (b) ? (a) : (b)) */
29
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP RTLOGGROUP_STRING
35#include <iprt/string.h>
36#include <iprt/assert.h>
37#ifdef IN_RING3
38#include <iprt/alloc.h>
39#include <iprt/err.h>
40#endif
41#include <iprt/string.h>
42#include <iprt/stdarg.h>
43#include "internal/string.h"
44
45/* Wrappers for converting to iprt facilities. */
46#define SSToDS(ptr) ptr
47#define kASSERT Assert
48#define KENDIAN_LITTLE 1
49#define KENDIAN KENDIAN_LITTLE
50#define KSIZE size_t
51typedef struct
52{
53 uint32_t ulLo;
54 uint32_t ulHi;
55} KSIZE64;
56
57
58/*******************************************************************************
59* Internal Functions *
60*******************************************************************************/
61static unsigned _strnlen(const char *psz, unsigned cchMax);
62static unsigned _strnlenUCS2(PCRTUCS2 pucs, unsigned cchMax);
63static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags);
64
65
66/**
67 * Finds the length of a string up to cchMax.
68 * @returns Length.
69 * @param psz Pointer to string.
70 * @param cchMax Max length.
71 */
72static unsigned _strnlen(const char *psz, unsigned cchMax)
73{
74 const char *pszC = psz;
75
76 while (cchMax-- > 0 && *psz != '\0')
77 psz++;
78
79 return psz - pszC;
80}
81
82
83/**
84 * Finds the length of a string up to cchMax.
85 * @returns Length.
86 * @param pucs Pointer to string.
87 * @param cchMax Max length.
88 */
89static unsigned _strnlenUCS2(PCRTUCS2 pucs, unsigned cchMax)
90{
91 PCRTUCS2 pucsC = pucs;
92
93 while (cchMax-- > 0 && *pucs != '\0')
94 pucs++;
95
96 return pucs - pucsC;
97}
98
99
100/**
101 * Finds the length of a string up to cchMax.
102 * @returns Length.
103 * @param pusz Pointer to string.
104 * @param cchMax Max length.
105 */
106static unsigned _strnlenUni(PCRTUNICP pusz, unsigned cchMax)
107{
108 PCRTUNICP puszC = pusz;
109
110 while (cchMax-- > 0 && *pusz != '\0')
111 pusz++;
112
113 return pusz - puszC;
114}
115
116
117/**
118 * Formats an integer number according to the parameters.
119 *
120 * @returns Length of the formatted number.
121 * @param psz Pointer to output string buffer of sufficient size.
122 * @param u64Value Value to format.
123 * @param uiBase Number representation base.
124 * @param cchWidth Width.
125 * @param cchPrecision Precision.
126 * @param fFlags Flags (NTFS_*).
127 */
128RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags)
129{
130 return rtStrFormatNumber(psz, *(KSIZE64 *)(void *)&u64Value, uiBase, cchWidth, cchPrecision, fFlags);
131}
132
133
134
135/**
136 * Formats an integer number according to the parameters.
137 *
138 * @returns Length of the number.
139 * @param psz Pointer to output string.
140 * @param ullValue Value. Using the high part is optional.
141 * @param uiBase Number representation base.
142 * @param cchWidth Width
143 * @param cchPrecision Precision.
144 * @param fFlags Flags (NTFS_*).
145 */
146static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags)
147{
148 char * pachDigits = "0123456789abcdef";
149 char * pszStart = psz;
150 int cchValue;
151 unsigned long ul;
152#if 0
153 unsigned long ullow;
154#endif
155 int i;
156 int j;
157
158/** @todo Formatting of 64 bit numbers is broken, fix it! */
159
160 /*
161 * Validate and addjust input...
162 */
163 kASSERT((uiBase >= 2 || uiBase <= 16));
164 if (fFlags & RTSTR_F_CAPITAL)
165 pachDigits = "0123456789ABCDEF";
166 if (fFlags & RTSTR_F_LEFT)
167 fFlags &= ~RTSTR_F_ZEROPAD;
168
169 /*
170 * Determin value length
171 */
172 cchValue = 0;
173 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
174 {
175 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
176 if ((fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulHi & 0x80000000))
177 u64 = -(int64_t)u64;
178 do
179 {
180 cchValue++;
181 u64 /= uiBase;
182 } while (u64);
183 }
184 else
185 {
186 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
187 do
188 {
189 cchValue++;
190 ul /= uiBase;
191 } while (ul);
192 }
193
194 /*
195 * Sign (+/-).
196 */
197 i = 0;
198 if (fFlags & RTSTR_F_VALSIGNED)
199 {
200 if ((ullValue.ulHi || (fFlags & RTSTR_F_64BIT) ? ullValue.ulHi : ullValue.ulLo) & 0x80000000)
201 {
202 ullValue.ulLo = -(int32_t)ullValue.ulLo;
203 if (ullValue.ulHi)
204 ullValue.ulHi = ~ullValue.ulHi;
205 psz[i++] = '-';
206 }
207 else if (fFlags & (RTSTR_F_PLUS | RTSTR_F_BLANK))
208 psz[i++] = (char)(fFlags & RTSTR_F_PLUS ? '+' : ' ');
209 }
210
211 /*
212 * Special (0/0x).
213 */
214 if (fFlags & RTSTR_F_SPECIAL && (uiBase % 8) == 0)
215 {
216 psz[i++] = '0';
217 if (uiBase == 16)
218 psz[i++] = (char)(fFlags & RTSTR_F_CAPITAL ? 'X' : 'x');
219 }
220
221 /*
222 * width - only if ZEROPAD
223 */
224 cchWidth -= i + cchValue;
225 if (fFlags & RTSTR_F_ZEROPAD)
226 while (--cchWidth >= 0)
227 {
228 psz[i++] = '0';
229 cchPrecision--;
230 }
231 else if (!(fFlags & RTSTR_F_LEFT) && cchWidth > 0)
232 {
233 for (j = i-1; j >= 0; j--)
234 psz[cchWidth + j] = psz[j];
235 for (j = 0; j < cchWidth; j++)
236 psz[j] = ' ';
237 i += cchWidth;
238 }
239 psz += i;
240
241
242 /*
243 * precision
244 */
245 while (--cchPrecision >= cchValue)
246 *psz++ = '0';
247
248 /*
249 * write number - not good enough but it works
250 */
251 psz += cchValue;
252 i = -1;
253 if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
254 {
255 uint64_t u64 = *(uint64_t *)(void *)&ullValue;
256 do
257 {
258 psz[i--] = pachDigits[u64 % uiBase];
259 u64 /= uiBase;
260 } while (u64);
261 }
262 else
263 {
264 ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
265 do
266 {
267 psz[i--] = pachDigits[ul % uiBase];
268 ul /= uiBase;
269 } while (ul);
270 }
271
272
273 /*
274 * width if RTSTR_F_LEFT
275 */
276 if (fFlags & RTSTR_F_LEFT)
277 while (--cchWidth >= 0)
278 *psz++ = ' ';
279
280 *psz = '\0';
281 return psz - pszStart;
282}
283
284
285/**
286 * Partial implementation of a printf like formatter.
287 * It doesn't do everything correct, and there is no floating point support.
288 * However, it supports custom formats by the means of a format callback.
289 *
290 * @returns number of bytes formatted.
291 * @param pfnOutput Output worker.
292 * Called in two ways. Normally with a string an it's length.
293 * For termination, it's called with NULL for string, 0 for length.
294 * @param pvArgOutput Argument to the output worker.
295 * @param pfnFormat Custom format worker.
296 * @param pvArgFormat Argument to the format worker.
297 * @param pszFormat Format string.
298 * @param InArgs Argument list.
299 */
300RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, va_list InArgs)
301{
302 /* make a copy so we can reference it (AMD64 / gcc). */
303 va_list args;
304 va_copy(args, InArgs);
305
306 KSIZE cch = 0;
307 const char *pszStartOutput = pszFormat;
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 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 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