VirtualBox

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

最後變更 在這個檔案從8147是 7422,由 vboxsync 提交於 17 年 前

Another silly _strnlenUtf16 regression.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette