diff options
Diffstat (limited to 'src/VBox/Runtime/common/string/straprintf.cpp')
-rw-r--r-- | src/VBox/Runtime/common/string/straprintf.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/string/straprintf.cpp b/src/VBox/Runtime/common/string/straprintf.cpp new file mode 100644 index 00000000..59c12d67 --- /dev/null +++ b/src/VBox/Runtime/common/string/straprintf.cpp @@ -0,0 +1,197 @@ +/* $Id: straprintf.cpp $ */ +/** @file + * IPRT - Allocating String Formatters. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/string.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/alloc.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** strallocoutput() argument structure. */ +typedef struct STRALLOCARG +{ + /** Pointer to current buffer position. */ + char *psz; + /** Number of bytes left in the buffer - not including the trailing zero. */ + size_t cch; + /** Pointer to the start of the buffer. */ + char *pszBuffer; + /** The number of bytes in the buffer. */ + size_t cchBuffer; + /** Set if the buffer was allocated using RTMemRealloc(). If clear + * pszBuffer points to the initial stack buffer. */ + bool fAllocated; + /** Allocation tag used for statistics and such. */ + const char *pszTag; +} STRALLOCARG; +/** Pointer to a strallocoutput() argument structure. */ +typedef STRALLOCARG *PSTRALLOCARG; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +static DECLCALLBACK(size_t) strallocoutput(void *pvArg, const char *pachChars, size_t cbChars); + + +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg Pointer to a STRBUFARG structure. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +static DECLCALLBACK(size_t) strallocoutput(void *pvArg, const char *pachChars, size_t cbChars) +{ + PSTRALLOCARG pArg = (PSTRALLOCARG)pvArg; + if (pArg->psz) + { + /* + * The fast path + */ + if (cbChars <= pArg->cch) + { + if (cbChars) + { + memcpy(pArg->psz, pachChars, cbChars); + pArg->cch -= cbChars; + pArg->psz += cbChars; + } + *pArg->psz = '\0'; + return cbChars; + } + + /* + * Need to (re)allocate the buffer. + */ + size_t cbAdded = RT_MIN(pArg->cchBuffer, _1M); + if (cbAdded <= cbChars) + cbAdded = RT_ALIGN_Z(cbChars, _4K); + if (cbAdded <= _1G) + { + char *pszBuffer = (char *)RTMemReallocTag(pArg->fAllocated ? pArg->pszBuffer : NULL, + cbAdded + pArg->cchBuffer, pArg->pszTag); + if (pszBuffer) + { + size_t off = pArg->psz - pArg->pszBuffer; + if (!pArg->fAllocated) + { + memcpy(pszBuffer, pArg->pszBuffer, off); + pArg->fAllocated = true; + } + + pArg->pszBuffer = pszBuffer; + pArg->cchBuffer += cbAdded; + pArg->psz = pszBuffer + off; + pArg->cch += cbAdded; + + if (cbChars) + { + memcpy(pArg->psz, pachChars, cbChars); + pArg->cch -= cbChars; + pArg->psz += cbChars; + } + *pArg->psz = '\0'; + return cbChars; + } + /* else allocation failure */ + } + /* else wrap around */ + + /* failure */ + pArg->psz = NULL; + } + return 0; +} + + +RTDECL(int) RTStrAPrintfVTag(char **ppszBuffer, const char *pszFormat, va_list args, const char *pszTag) +{ +#ifdef IN_RING3 + char szBuf[2048]; +#else + char szBuf[256]; +#endif + STRALLOCARG Arg; + Arg.fAllocated = false; + Arg.cchBuffer = sizeof(szBuf); + Arg.pszBuffer = szBuf; + Arg.cch = sizeof(szBuf) - 1; + Arg.psz = szBuf; + Arg.pszTag = pszTag; + szBuf[0] = '\0'; + int cbRet = (int)RTStrFormatV(strallocoutput, &Arg, NULL, NULL, pszFormat, args); + if (Arg.psz) + { + if (!Arg.fAllocated) + { + /* duplicate the string in szBuf */ + Assert(Arg.pszBuffer == szBuf); + char *psz = (char *)RTMemAllocTag(cbRet + 1, pszTag); + if (psz) + memcpy(psz, szBuf, cbRet + 1); + *ppszBuffer = psz; + } + else + { + /* adjust the allocated buffer */ + char *psz = (char *)RTMemReallocTag(Arg.pszBuffer, cbRet + 1, pszTag); + *ppszBuffer = psz ? psz : Arg.pszBuffer; + } + } + else + { + /* allocation error */ + *ppszBuffer = NULL; + cbRet = -1; + + /* free any allocated buffer */ + if (Arg.fAllocated) + RTMemFree(Arg.pszBuffer); + } + + return cbRet; +} +RT_EXPORT_SYMBOL(RTStrAPrintfVTag); + + +RTDECL(char *) RTStrAPrintf2VTag(const char *pszFormat, va_list args, const char *pszTag) +{ + char *pszBuffer; + RTStrAPrintfVTag(&pszBuffer, pszFormat, args, pszTag); + return pszBuffer; +} +RT_EXPORT_SYMBOL(RTStrAPrintf2VTag); + |