]>
git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - ubuntu/vbox/vboxguest/common/string/strformat.c
1 /* $Id: strformat.cpp $ */
3 * IPRT - String Formatter.
7 * Copyright (C) 2006-2016 Oracle Corporation
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.
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.
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.
28 /*********************************************************************************************************************************
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)) */
36 /*********************************************************************************************************************************
38 *********************************************************************************************************************************/
39 #define LOG_GROUP RTLOGGROUP_STRING
40 #include <iprt/string.h>
41 #include "internal/iprt.h"
43 #include <iprt/assert.h>
45 # include <iprt/alloc.h>
46 # include <iprt/err.h>
47 # include <iprt/uni.h>
49 #include <iprt/string.h>
50 #include <iprt/stdarg.h>
51 #include "internal/string.h"
53 /* Wrappers for converting to iprt facilities. */
54 #define SSToDS(ptr) ptr
55 #define kASSERT Assert
56 #define KENDIAN_LITTLE 1
57 #define KENDIAN KENDIAN_LITTLE
66 /*********************************************************************************************************************************
67 * Internal Functions *
68 *********************************************************************************************************************************/
69 static unsigned _strnlen(const char *psz
, unsigned cchMax
);
70 static unsigned _strnlenUtf16(PCRTUTF16 pwsz
, unsigned cchMax
);
71 static int rtStrFormatNumber(char *psz
, KSIZE64 ullValue
, unsigned int uiBase
, signed int cchWidth
, signed int cchPrecision
, unsigned int fFlags
);
75 * Finds the length of a string up to cchMax.
77 * @param psz Pointer to string.
78 * @param cchMax Max length.
80 static unsigned _strnlen(const char *psz
, unsigned cchMax
)
82 const char *pszC
= psz
;
84 while (cchMax
-- > 0 && *psz
!= '\0')
87 return (unsigned)(psz
- pszC
);
92 * Finds the length of a string up to cchMax.
94 * @param pwsz Pointer to string.
95 * @param cchMax Max length.
97 static unsigned _strnlenUtf16(PCRTUTF16 pwsz
, unsigned cchMax
)
104 int rc
= RTUtf16GetCpEx(&pwsz
, &cp
);
106 if (RT_FAILURE(rc
) || !cp
)
111 #else /* !IN_RING3 */
112 PCRTUTF16 pwszC
= pwsz
;
114 while (cchMax
-- > 0 && *pwsz
!= '\0')
117 return (unsigned)(pwsz
- pwszC
);
118 #endif /* !IN_RING3 */
123 * Finds the length of a string up to cchMax.
125 * @param pusz Pointer to string.
126 * @param cchMax Max length.
128 static unsigned _strnlenUni(PCRTUNICP pusz
, unsigned cchMax
)
130 PCRTUNICP puszC
= pusz
;
132 while (cchMax
-- > 0 && *pusz
!= '\0')
135 return (unsigned)(pusz
- puszC
);
140 * Formats an integer number according to the parameters.
142 * @returns Length of the formatted number.
143 * @param psz Pointer to output string buffer of sufficient size.
144 * @param u64Value Value to format.
145 * @param uiBase Number representation base.
146 * @param cchWidth Width.
147 * @param cchPrecision Precision.
148 * @param fFlags Flags (NTFS_*).
150 RTDECL(int) RTStrFormatNumber(char *psz
, uint64_t u64Value
, unsigned int uiBase
, signed int cchWidth
, signed int cchPrecision
,
153 return rtStrFormatNumber(psz
, *(KSIZE64
*)(void *)&u64Value
, uiBase
, cchWidth
, cchPrecision
, fFlags
);
155 RT_EXPORT_SYMBOL(RTStrFormatNumber
);
160 * Formats an integer number according to the parameters.
162 * @returns Length of the number.
163 * @param psz Pointer to output string.
164 * @param ullValue Value. Using the high part is optional.
165 * @param uiBase Number representation base.
166 * @param cchWidth Width
167 * @param cchPrecision Precision.
168 * @param fFlags Flags (NTFS_*).
170 static int rtStrFormatNumber(char *psz
, KSIZE64 ullValue
, unsigned int uiBase
, signed int cchWidth
, signed int cchPrecision
,
173 const char *pachDigits
= "0123456789abcdef";
174 char *pszStart
= psz
;
182 * Validate and adjust input...
184 Assert(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 if ( (fFlags
& RTSTR_F_THOUSAND_SEP
)
191 || (fFlags
& RTSTR_F_ZEROPAD
))) /** @todo implement RTSTR_F_ZEROPAD + RTSTR_F_THOUSAND_SEP. */
192 fFlags
&= ~RTSTR_F_THOUSAND_SEP
;
195 * Determine value length
198 if (ullValue
.ulHi
|| (fFlags
& RTSTR_F_64BIT
))
200 uint64_t u64
= *(uint64_t *)(void *)&ullValue
;
201 if ((fFlags
& RTSTR_F_VALSIGNED
) && (ullValue
.ulHi
& 0x80000000))
211 ul
= (fFlags
& RTSTR_F_VALSIGNED
) && (ullValue
.ulLo
& 0x80000000) ? -(int32_t)ullValue
.ulLo
: ullValue
.ulLo
;
218 if (fFlags
& RTSTR_F_THOUSAND_SEP
)
221 fFlags
&= ~RTSTR_F_THOUSAND_SEP
;
223 cchValue
+= cchValue
/ 3 - (cchValue
% 3 == 0);
230 if (fFlags
& RTSTR_F_VALSIGNED
)
232 if ((ullValue
.ulHi
|| (fFlags
& RTSTR_F_64BIT
) ? ullValue
.ulHi
: ullValue
.ulLo
) & 0x80000000)
234 ullValue
.ulLo
= -(int32_t)ullValue
.ulLo
;
236 ullValue
.ulHi
= ~ullValue
.ulHi
;
239 else if (fFlags
& (RTSTR_F_PLUS
| RTSTR_F_BLANK
))
240 psz
[i
++] = (char)(fFlags
& RTSTR_F_PLUS
? '+' : ' ');
246 if ((fFlags
& RTSTR_F_SPECIAL
) && (uiBase
% 8) == 0)
250 psz
[i
++] = (char)(fFlags
& RTSTR_F_CAPITAL
? 'X' : 'x');
254 * width - only if ZEROPAD
256 cchMax
= 64 - (cchValue
+ i
+ 1); /* HACK! 64 bytes seems to be the usual buffer size... */
257 cchWidth
-= i
+ cchValue
;
258 if (fFlags
& RTSTR_F_ZEROPAD
)
259 while (--cchWidth
>= 0 && i
< cchMax
)
261 AssertBreak(i
< cchMax
);
265 else if (!(fFlags
& RTSTR_F_LEFT
) && cchWidth
> 0)
267 AssertStmt(cchWidth
< cchMax
, cchWidth
= cchMax
- 1);
268 for (j
= i
- 1; j
>= 0; j
--)
269 psz
[cchWidth
+ j
] = psz
[j
];
270 for (j
= 0; j
< cchWidth
; j
++)
278 while (--cchPrecision
>= cchValue
)
280 AssertBreak(i
< cchMax
);
287 * write number - not good enough but it works
291 if (ullValue
.ulHi
|| (fFlags
& RTSTR_F_64BIT
))
293 uint64_t u64
= *(uint64_t *)(void *)&ullValue
;
294 if (fFlags
& RTSTR_F_THOUSAND_SEP
)
298 if ((-i
- 1) % 4 == 3)
300 psz
[i
--] = pachDigits
[u64
% uiBase
];
308 psz
[i
--] = pachDigits
[u64
% uiBase
];
315 ul
= (fFlags
& RTSTR_F_VALSIGNED
) && (ullValue
.ulLo
& 0x80000000) ? -(int32_t)ullValue
.ulLo
: ullValue
.ulLo
;
316 if (fFlags
& RTSTR_F_THOUSAND_SEP
)
320 if ((-i
- 1) % 4 == 3)
322 psz
[i
--] = pachDigits
[ul
% uiBase
];
330 psz
[i
--] = pachDigits
[ul
% uiBase
];
337 * width if RTSTR_F_LEFT
339 if (fFlags
& RTSTR_F_LEFT
)
340 while (--cchWidth
>= 0)
344 return (unsigned)(psz
- pszStart
);
349 * Partial implementation of a printf like formatter.
350 * It doesn't do everything correct, and there is no floating point support.
351 * However, it supports custom formats by the means of a format callback.
353 * @returns number of bytes formatted.
354 * @param pfnOutput Output worker.
355 * Called in two ways. Normally with a string an it's length.
356 * For termination, it's called with NULL for string, 0 for length.
357 * @param pvArgOutput Argument to the output worker.
358 * @param pfnFormat Custom format worker.
359 * @param pvArgFormat Argument to the format worker.
360 * @param pszFormat Format string.
361 * @param InArgs Argument list.
363 RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput
, void *pvArgOutput
, PFNSTRFORMAT pfnFormat
, void *pvArgFormat
,
364 const char *pszFormat
, va_list InArgs
)
366 char szTmp
[64]; /* Worker functions assumes 64 byte buffer! Ugly but faster. */
369 const char *pszStartOutput
= pszFormat
;
371 va_copy(args
, InArgs
); /* make a copy so we can reference it (AMD64 / gcc). */
373 while (*pszFormat
!= '\0')
375 if (*pszFormat
== '%')
377 /* output pending string. */
378 if (pszStartOutput
!= pszFormat
)
379 cch
+= pfnOutput(pvArgOutput
, pszStartOutput
, pszFormat
- pszStartOutput
);
383 if (*pszFormat
== '%') /* '%%'-> '%' */
384 pszStartOutput
= pszFormat
++;
387 unsigned int fFlags
= 0;
389 int cchPrecision
= -1;
390 unsigned int uBase
= 10;
396 switch (*pszFormat
++)
398 case '#': fFlags
|= RTSTR_F_SPECIAL
; continue;
399 case '-': fFlags
|= RTSTR_F_LEFT
; continue;
400 case '+': fFlags
|= RTSTR_F_PLUS
; continue;
401 case ' ': fFlags
|= RTSTR_F_BLANK
; continue;
402 case '0': fFlags
|= RTSTR_F_ZEROPAD
; continue;
403 case '\'': fFlags
|= RTSTR_F_THOUSAND_SEP
; continue;
410 if (ISDIGIT(*pszFormat
))
412 for (cchWidth
= 0; ISDIGIT(*pszFormat
); pszFormat
++)
415 cchWidth
+= *pszFormat
- '0';
417 fFlags
|= RTSTR_F_WIDTH
;
419 else if (*pszFormat
== '*')
422 cchWidth
= va_arg(args
, int);
425 cchWidth
= -cchWidth
;
426 fFlags
|= RTSTR_F_LEFT
;
428 fFlags
|= RTSTR_F_WIDTH
;
432 if (*pszFormat
== '.')
435 if (ISDIGIT(*pszFormat
))
437 for (cchPrecision
= 0; ISDIGIT(*pszFormat
); pszFormat
++)
440 cchPrecision
+= *pszFormat
- '0';
444 else if (*pszFormat
== '*')
447 cchPrecision
= va_arg(args
, int);
449 if (cchPrecision
< 0)
451 fFlags
|= RTSTR_F_PRECISION
;
457 chArgSize
= *pszFormat
;
473 if (*pszFormat
== 'l')
482 if (*pszFormat
== 'h')
489 case 'I': /* Used by Win32/64 compilers. */
490 if ( pszFormat
[1] == '6'
491 && pszFormat
[2] == '4')
496 else if ( pszFormat
[1] == '3'
497 && pszFormat
[2] == '2')
509 case 'q': /* Used on BSD platforms. */
518 switch (*pszFormat
++)
523 if (!(fFlags
& RTSTR_F_LEFT
))
524 while (--cchWidth
> 0)
525 cch
+= pfnOutput(pvArgOutput
, " ", 1);
527 szTmp
[0] = (char)va_arg(args
, int);
528 szTmp
[1] = '\0'; /* Some output functions wants terminated strings. */
529 cch
+= pfnOutput(pvArgOutput
, SSToDS(&szTmp
[0]), 1);
531 while (--cchWidth
> 0)
532 cch
+= pfnOutput(pvArgOutput
, " ", 1);
536 case 'S': /* Legacy, conversion done by streams now. */
539 if (chArgSize
== 'l')
541 /* utf-16 -> utf-8 */
543 PCRTUTF16 pwszStr
= va_arg(args
, PRTUTF16
);
545 if (!VALID_PTR(pwszStr
))
547 static RTUTF16 s_wszNull
[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
550 cchStr
= _strnlenUtf16(pwszStr
, (unsigned)cchPrecision
);
551 if (!(fFlags
& RTSTR_F_LEFT
))
552 while (--cchWidth
>= cchStr
)
553 cch
+= pfnOutput(pvArgOutput
, " ", 1);
557 /** @todo \#ifndef IN_RC*/
560 RTUtf16GetCpEx(&pwszStr
, &Cp
);
561 char *pszEnd
= RTStrPutCp(szTmp
, Cp
);
563 cch
+= pfnOutput(pvArgOutput
, szTmp
, pszEnd
- szTmp
);
565 char ch
= (char)*pwszStr
++;
566 cch
+= pfnOutput(pvArgOutput
, &ch
, 1);
569 while (--cchWidth
>= 0)
570 cch
+= pfnOutput(pvArgOutput
, " ", 1);
572 else if (chArgSize
== 'L')
576 PCRTUNICP puszStr
= va_arg(args
, PCRTUNICP
);
578 if (!VALID_PTR(puszStr
))
580 static RTUNICP s_uszNull
[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
583 cchStr
= _strnlenUni(puszStr
, (unsigned)cchPrecision
);
584 if (!(fFlags
& RTSTR_F_LEFT
))
585 while (--cchWidth
>= cchStr
)
586 cch
+= pfnOutput(pvArgOutput
, " ", 1);
591 /** @todo \#ifndef IN_RC*/
593 char *pszEnd
= RTStrPutCp(szTmp
, *puszStr
++);
594 cch
+= pfnOutput(pvArgOutput
, szTmp
, pszEnd
- szTmp
);
596 char ch
= (char)*puszStr
++;
597 cch
+= pfnOutput(pvArgOutput
, &ch
, 1);
600 while (--cchWidth
>= 0)
601 cch
+= pfnOutput(pvArgOutput
, " ", 1);
606 const char *pszStr
= va_arg(args
, char*);
608 if (!VALID_PTR(pszStr
))
610 cchStr
= _strnlen(pszStr
, (unsigned)cchPrecision
);
611 if (!(fFlags
& RTSTR_F_LEFT
))
612 while (--cchWidth
>= cchStr
)
613 cch
+= pfnOutput(pvArgOutput
, " ", 1);
615 cch
+= pfnOutput(pvArgOutput
, pszStr
, cchStr
);
617 while (--cchWidth
>= cchStr
)
618 cch
+= pfnOutput(pvArgOutput
, " ", 1);
623 /*-----------------*/
624 /* integer/pointer */
625 /*-----------------*/
637 switch (pszFormat
[-1])
639 case 'd': /* signed decimal integer */
641 fFlags
|= RTSTR_F_VALSIGNED
;
649 fFlags
|= RTSTR_F_ZEROPAD
; /* Note not standard behaviour (but I like it this way!) */
652 cchWidth
= sizeof(char *) * 2;
660 fFlags
|= RTSTR_F_CAPITAL
;
666 if (pszFormat
[-1] == 'p')
667 u64Value
= va_arg(args
, uintptr_t);
668 else if (fFlags
& RTSTR_F_VALSIGNED
)
670 if (chArgSize
== 'L')
672 u64Value
= va_arg(args
, int64_t);
673 fFlags
|= RTSTR_F_64BIT
;
675 else if (chArgSize
== 'l')
677 u64Value
= va_arg(args
, signed long);
678 fFlags
|= RTSTR_GET_BIT_FLAG(unsigned long);
680 else if (chArgSize
== 'h')
682 u64Value
= va_arg(args
, /* signed short */ int);
683 fFlags
|= RTSTR_GET_BIT_FLAG(signed short);
685 else if (chArgSize
== 'H')
687 u64Value
= va_arg(args
, /* int8_t */ int);
688 fFlags
|= RTSTR_GET_BIT_FLAG(int8_t);
690 else if (chArgSize
== 'j')
692 u64Value
= va_arg(args
, /*intmax_t*/ int64_t);
693 fFlags
|= RTSTR_F_64BIT
;
695 else if (chArgSize
== 'z')
697 u64Value
= va_arg(args
, size_t);
698 fFlags
|= RTSTR_GET_BIT_FLAG(size_t);
700 else if (chArgSize
== 't')
702 u64Value
= va_arg(args
, ptrdiff_t);
703 fFlags
|= RTSTR_GET_BIT_FLAG(ptrdiff_t);
707 u64Value
= va_arg(args
, signed int);
708 fFlags
|= RTSTR_GET_BIT_FLAG(signed int);
713 if (chArgSize
== 'L')
715 u64Value
= va_arg(args
, uint64_t);
716 fFlags
|= RTSTR_F_64BIT
;
718 else if (chArgSize
== 'l')
720 u64Value
= va_arg(args
, unsigned long);
721 fFlags
|= RTSTR_GET_BIT_FLAG(unsigned long);
723 else if (chArgSize
== 'h')
725 u64Value
= va_arg(args
, /* unsigned short */ int);
726 fFlags
|= RTSTR_GET_BIT_FLAG(unsigned short);
728 else if (chArgSize
== 'H')
730 u64Value
= va_arg(args
, /* uint8_t */ int);
731 fFlags
|= RTSTR_GET_BIT_FLAG(uint8_t);
733 else if (chArgSize
== 'j')
735 u64Value
= va_arg(args
, /*uintmax_t*/ int64_t);
736 fFlags
|= RTSTR_F_64BIT
;
738 else if (chArgSize
== 'z')
740 u64Value
= va_arg(args
, size_t);
741 fFlags
|= RTSTR_GET_BIT_FLAG(size_t);
743 else if (chArgSize
== 't')
745 u64Value
= va_arg(args
, ptrdiff_t);
746 fFlags
|= RTSTR_GET_BIT_FLAG(ptrdiff_t);
750 u64Value
= va_arg(args
, unsigned int);
751 fFlags
|= RTSTR_GET_BIT_FLAG(unsigned int);
754 cchNum
= RTStrFormatNumber((char *)SSToDS(&szTmp
), u64Value
, uBase
, cchWidth
, cchPrecision
, fFlags
);
755 cch
+= pfnOutput(pvArgOutput
, (char *)SSToDS(&szTmp
), cchNum
);
762 case 'M': /* replace the format string (not stacked yet). */
764 pszStartOutput
= pszFormat
= va_arg(args
, const char *);
765 AssertPtr(pszStartOutput
);
769 case 'N': /* real nesting. */
771 const char *pszFormatNested
= va_arg(args
, const char *);
772 va_list *pArgsNested
= va_arg(args
, va_list *);
774 va_copy(ArgsNested
, *pArgsNested
);
775 Assert(pszFormatNested
);
776 cch
+= RTStrFormatV(pfnOutput
, pvArgOutput
, pfnFormat
, pvArgFormat
, pszFormatNested
, ArgsNested
);
786 if (*pszFormat
!= '[')
789 cch
+= rtstrFormatRt(pfnOutput
, pvArgOutput
, &pszFormat
, &args
, cchWidth
, cchPrecision
, fFlags
, chArgSize
);
794 cch
+= rtstrFormatType(pfnOutput
, pvArgOutput
, &pszFormat
, &args
, cchWidth
, cchPrecision
, fFlags
, chArgSize
);
807 cch
+= pfnFormat(pvArgFormat
, pfnOutput
, pvArgOutput
, &pszFormat
, &args
, cchWidth
, cchPrecision
, fFlags
, chArgSize
);
812 pszStartOutput
= pszFormat
;
819 /* output pending string. */
820 if (pszStartOutput
!= pszFormat
)
821 cch
+= pfnOutput(pvArgOutput
, pszStartOutput
, pszFormat
- pszStartOutput
);
823 /* terminate the output */
824 pfnOutput(pvArgOutput
, NULL
, 0);
828 RT_EXPORT_SYMBOL(RTStrFormatV
);
832 * Partial implementation of a printf like formatter.
833 * It doesn't do everything correct, and there is no floating point support.
834 * However, it supports custom formats by the means of a format callback.
836 * @returns number of bytes formatted.
837 * @param pfnOutput Output worker.
838 * Called in two ways. Normally with a string an it's length.
839 * For termination, it's called with NULL for string, 0 for length.
840 * @param pvArgOutput Argument to the output worker.
841 * @param pfnFormat Custom format worker.
842 * @param pvArgFormat Argument to the format worker.
843 * @param pszFormat Format string.
844 * @param ... Argument list.
846 RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput
, void *pvArgOutput
, PFNSTRFORMAT pfnFormat
, void *pvArgFormat
, const char *pszFormat
, ...)
850 va_start(args
, pszFormat
);
851 cch
= RTStrFormatV(pfnOutput
, pvArgOutput
, pfnFormat
, pvArgFormat
, pszFormat
, args
);
855 RT_EXPORT_SYMBOL(RTStrFormat
);