VirtualBox

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

Last change on this file since 26180 was 26180, checked in by vboxsync, 15 years ago

*: The rest of the %V* format specifiers are history.

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