StringFunctions.h#

Parent directory (strings)

Contains helper functions for std::string manipulation.

Includes#

  • algorithm

  • cctype

  • cstdarg

  • cstdio

  • cstring

  • cwchar

  • iostream

  • memory

  • string (CompileTimeHash.h)

  • vector

Included By#

Namespaces#

Functions#

Source Code#

#pragma once
#include <memory>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdarg>
#include <cstring>
#include <string>
#include <cstdio>
#include <cctype>
#include <cwchar>

namespace pvr {
namespace strings {
inline std::basic_string<wchar_t> vaFormatString(const wchar_t* const format, va_list argumentList)
{
    bool result = true;

#if defined(_WIN32)
    size_t newStringSize = (size_t)_vscwprintf(format, argumentList);
#else
    va_list argumentListCopy;

    va_copy(argumentListCopy, argumentList);
    size_t newStringSize = (size_t)vswprintf(0, 0, format, argumentListCopy);
    va_end(argumentListCopy);
#endif

    // Create a new std::string
    std::basic_string<wchar_t> newString;
    newString.resize(newStringSize + 1);

    {
#ifdef _WIN32
        if (static_cast<size_t>(_vsnwprintf_s(const_cast<wchar_t*>(newString.c_str()), newStringSize + 1, newStringSize, format, argumentList)) != newStringSize)
#else
        if (static_cast<size_t>(vswprintf(const_cast<wchar_t*>(newString.c_str()), newStringSize + 1, format, argumentList)) != newStringSize)
#endif
        {
            result = false;
        }
    }

    if (!result) { newString.resize(0); }

    return newString;
}

inline std::string createFormatted(const char* const format, ...)
{
    // initialize use of the variable argument array
    va_list vaArgs;
    va_start(vaArgs, format);

    // Acquire the size by taking a copy of the variable argument array
    va_list vaArgsCopy;
    va_copy(vaArgsCopy, vaArgs);
#if defined(_WIN32)
    const size_t iLen = (size_t)vsnprintf(nullptr, 0, format, vaArgsCopy);
#else
    const size_t iLen = (size_t)std::vsnprintf(nullptr, 0, format, vaArgsCopy);
#endif
    va_end(vaArgsCopy);

    // return a formatted string without risking memory mismanagement
    // and without assuming any compiler or platform specific behavior
    std::vector<char> zc(iLen + 1);
#if defined(_WIN32)
    vsnprintf(zc.data(), zc.size(), format, vaArgs);
#else
    std::vsnprintf(zc.data(), zc.size(), format, vaArgs);
#endif
    va_end(vaArgs);
    return std::string(zc.data(), iLen);
}

inline std::basic_string<wchar_t> createFormatted(const wchar_t* format, ...)
{
    // Calculate the length of the new std::string
    va_list argumentList;
    va_start(argumentList, format);
    std::basic_string<wchar_t> newString = strings::vaFormatString(format, argumentList);
    va_end(argumentList);
    return newString;
}

inline void ignoreWhitespace(char** pszString)
{
    while (*pszString[0] == '\t' || *pszString[0] == '\n' || *pszString[0] == '\r' || *pszString[0] == ' ') { (*pszString)++; }
}

inline char* readEOLToken(char* pToken)
{
    char* pReturn = nullptr;

    char szDelim[2] = { '\n', 0 }; // try newline
    pReturn = strtok(pToken, szDelim);
    if (pReturn == nullptr)
    {
        szDelim[0] = '\r';
        pReturn = strtok(pToken, szDelim); // try linefeed
    }
    return pReturn;
}

inline bool concatenateLinesUntil(std::string& outStr, int& line, const std::vector<std::string>& lines, uint32_t limit, const char* endStr)
{
    uint32_t i, j;
    size_t nLen;

    nLen = 0;
    for (i = static_cast<uint32_t>(line); i < limit; ++i)
    {
        if (strcmp(lines[i].c_str(), endStr) == 0) { break; }
        nLen += strlen(lines[i].c_str()) + 1;
    }
    if (i == limit) { return false; }

    if (nLen != 0u)
    {
        ++nLen;

        outStr.reserve(nLen);

        for (j = static_cast<uint32_t>(line); j < i; ++j)
        {
            outStr.append(lines[j]);
            outStr.append("\n");
        }
    }

    line = static_cast<int>(i);
    return true;
}

inline void toLower(std::string& str)
{
    std::transform(str.begin(), str.end(), str.begin(), [](char c) { return static_cast<char>(std::tolower(static_cast<int>(c))); });
}

inline std::string toLower(const std::string& str)
{
    std::string loweredString = str;
    pvr::strings::toLower(loweredString);
    return loweredString;
}

inline bool startsWith(const std::string& str, const std::string& substr)
{
    if (str.rfind(substr, 0) == 0) { return true; };
    return false;
}

inline bool endsWith(const std::string& str, const std::string& substr)
{
    if (str.length() >= substr.length()) { return (0 == str.compare(str.length() - substr.length(), substr.length(), substr)); }
    else
    {
        return false;
    }
}

inline void getFileDirectory(const std::string& filePath, std::string& outFileDir)
{
    outFileDir.clear();
    auto pos = filePath.find_last_of("/");
    if (pos == std::string::npos) { return; }
    outFileDir.assign(filePath.substr(0, pos));
}

inline void getFileNameAndExtension(const std::string& fileAndExtension, std::string& filename, std::string& extension)
{
    auto it = std::find(fileAndExtension.rbegin(), fileAndExtension.rend(), '.');
    if (it == fileAndExtension.rend())
    {
        filename = fileAndExtension;
        extension = "";
        return;
    }
    auto position = fileAndExtension.rend() - it; // rend is the position one-after the start of the std::string.
    filename.assign(fileAndExtension.begin(), fileAndExtension.begin() + position - 1);
    extension.assign(fileAndExtension.begin() + position, fileAndExtension.end());
}
} // namespace strings
} // namespace pvr