VirtualBox

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

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

UCS2->UTF-16

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