/* static */
RTCString
RTCString::joinEx(const RTCList<RTCString, RTCString *> &a_rList,
                  const RTCString &a_rstrPrefix /* = "" */,
                  const RTCString &a_rstrSep /* = "" */)
{
    RTCString strRet;
    if (a_rList.size() > 1)
    {
        /* calc the required size */
        size_t cbNeeded = a_rstrSep.length() * (a_rList.size() - 1) + 1;
        cbNeeded += a_rstrPrefix.length() * (a_rList.size() - 1) + 1;
        for (size_t i = 0; i < a_rList.size(); ++i)
            cbNeeded += a_rList.at(i).length();
        strRet.reserve(cbNeeded);

        /* do the appending. */
        for (size_t i = 0; i < a_rList.size() - 1; ++i)
        {
            if (a_rstrPrefix.isNotEmpty())
                strRet.append(a_rstrPrefix);
            strRet.append(a_rList.at(i));
            strRet.append(a_rstrSep);
        }
        strRet.append(a_rList.last());
    }
    /* special case: one list item. */
    else if (a_rList.size() > 0)
    {
        if (a_rstrPrefix.isNotEmpty())
            strRet.append(a_rstrPrefix);
        strRet.append(a_rList.last());
    }

    return strRet;
}
RTCString::printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars)
{
    RTCString *pThis = (RTCString *)pvArg;
    if (cbChars)
    {
        size_t cchBoth = pThis->m_cch + cbChars;
        if (cchBoth >= pThis->m_cbAllocated)
        {
            /* Double the buffer size, if it's less that _4M. Align sizes like
               for append. */
            size_t cbAlloc = RT_ALIGN_Z(pThis->m_cbAllocated, IPRT_MINISTRING_APPEND_ALIGNMENT);
            cbAlloc += RT_MIN(cbAlloc, _4M);
            if (cbAlloc <= cchBoth)
                cbAlloc = RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT);
            pThis->reserve(cbAlloc);
#ifndef RT_EXCEPTIONS_ENABLED
            AssertReleaseReturn(pThis->capacity() > cchBoth, 0);
#endif
        }

        memcpy(&pThis->m_psz[pThis->m_cch], pachChars, cbChars);
        pThis->m_cch = cchBoth;
        pThis->m_psz[cchBoth] = '\0';
    }
    return cbChars;
}
RTCString RTCString::substrCP(size_t pos /*= 0*/, size_t n /*= npos*/) const
{
    RTCString ret;

    if (n)
    {
        const char *psz;

        if ((psz = c_str()))
        {
            RTUNICP cp;

            // walk the UTF-8 characters until where the caller wants to start
            size_t i = pos;
            while (*psz && i--)
                if (RT_FAILURE(RTStrGetCpEx(&psz, &cp)))
                    return ret;     // return empty string on bad encoding

            const char *pFirst = psz;

            if (n == npos)
                // all the rest:
                ret = pFirst;
            else
            {
                i = n;
                while (*psz && i--)
                    if (RT_FAILURE(RTStrGetCpEx(&psz, &cp)))
                        return ret;     // return empty string on bad encoding

                size_t cbCopy = psz - pFirst;
                if (cbCopy)
                {
                    ret.reserve(cbCopy + 1); // may throw bad_alloc
#ifndef RT_EXCEPTIONS_ENABLED
                    AssertRelease(capacity() >= cbCopy + 1);
#endif
                    memcpy(ret.m_psz, pFirst, cbCopy);
                    ret.m_cch = cbCopy;
                    ret.m_psz[cbCopy] = '\0';
                }
            }
        }
    }

    return ret;
}