<commit_before>/**
 * @file   StringUtils.hpp
 * @brief  String utilities prototype.
 * @author zer0
 * @date   2016-04-04
 * @date   2016-12-05 (Rename: Strings -> StringUtils)
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#define CHECK_GNUC_CXX_REGEX

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>
#include <libtbag/Type.hpp>
#include <libtbag/util/BufferInfo.hpp>

#include <cstdint>
#include <string>
#include <sstream>
#include <vector>
#include <array>
#include <regex>
#include <thread>
#include <type_traits>
#include <iterator>
#include <utility>

#define TBAG_WINDOWS_NEW_LINE  "\r\n"
#define TBAG_UNIX_NEW_LINE     "\n"

#if defined(TBAG_PLATFORM_WINDOWS)
#define TBAG_NEW_LINE TBAG_WINDOWS_NEW_LINE
#else
#define TBAG_NEW_LINE TBAG_UNIX_NEW_LINE
#endif

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace string {

TBAG_CONSTEXPR char const * const WINDOWS_NEW_LINE = TBAG_WINDOWS_NEW_LINE;
TBAG_CONSTEXPR char const * const UNIX_NEW_LINE = TBAG_UNIX_NEW_LINE;
TBAG_CONSTEXPR char const * const NEW_LINE = TBAG_NEW_LINE;

TBAG_CONSTEXPR char const CHAR_SPACE  = ' ';
TBAG_CONSTEXPR char const CHAR_TAB    = '\t';
TBAG_CONSTEXPR char const CHAR_RETURN = '\n';

template <typename T>
TBAG_CONSTEXPR T const * charOrWidechar(char const * c, wchar_t const * w);

template <>
inline TBAG_CONSTEXPR char const * charOrWidechar<char>(char const * c, wchar_t const * w)
{
    return c;
}

template <>
inline TBAG_CONSTEXPR wchar_t const * charOrWidechar<wchar_t>(char const * c, wchar_t const * w)
{
    return w;
}

#ifndef CHAR_OR_WIDECHAR
#define CHAR_OR_WIDECHAR(type, str) ::libtbag::string::charOrWidechar<type>(str, L##str)
#endif

template <typename CharT>
inline TBAG_CONSTEXPR std::size_t string_length(CharT const * text)
{
    return (text == nullptr || *text == '\0') ? 0U : 1U + string_length(text + 1U);
}

template <typename FloatingType>
std::string convertStringWithFloatingPoint(FloatingType floating, int precision = 2)
{
    static_assert(std::is_floating_point<FloatingType>::value, "Not floating point type.");

    std::stringstream ss;
    ss.setf(std::ios_base::showpoint);
    ss.setf(std::ios_base::fixed, std::ios_base::floatfield);
    ss.precision(precision);
    ss << floating;
    return ss.str();
}

enum class LineFeedStyle
{
    LFS_NONE,
    LFS_UNIX,
    LFS_WINDOWS,
    LFS_AUTO,
};

TBAG_API LineFeedStyle getLineFeedStyle(std::string const & name);
TBAG_API char const * getLineFeedStyleText(LineFeedStyle style) TBAG_NOEXCEPT;

TBAG_API std::string getLineFeed(LineFeedStyle style = LineFeedStyle::LFS_AUTO);
TBAG_API std::string getStdEndLine();
TBAG_API bool appendLineFeed(LineFeedStyle style, char * buffer, int buffer_size, int offset) TBAG_NOEXCEPT;

/**
 * Separate tokens.
 *
 * @tparam CharType    Character type.
 * @tparam StringType  std::string type (Don't change this typename).
 *
 * @param[in] source       Original string.
 * @param[in] delimiter    Delimiter string.
 * @param[in] remove_empty Remove all empty tokens.
 *
 * @return
 *  Token vector.
 */
TBAG_API std::vector<std::string> splitTokens(std::string const & source, std::string const & delimiter, bool remove_empty = true);
TBAG_API std::vector<std::string> splitUtf8Tokens(std::string const & utf8_source, std::string const & utf8_delimiter, bool remove_empty = true);

template <typename Iterator>
std::string mergeTokens(Iterator begin, Iterator end, std::string const & delimiter)
{
    if (begin == end) {
        return {};
    }
    if (begin + 1 == end) {
        return *begin;
    }
    std::stringstream ss;
    ss << *begin;
    ++begin;
    for (; begin != end; ++begin) {
        ss << delimiter << *begin;
    }
    return ss.str();
}

TBAG_API std::string mergeTokens(std::vector<std::string> const & tokens, std::string const & delimiter);
TBAG_API std::string mergeTokens(std::vector<std::string> const & tokens);
TBAG_API std::string mergeArgv(char ** argv);

/**
 * Thread ID to string.
 */
TBAG_API std::string convertStringWithThreadId(std::thread::id const & id);

TBAG_CONSTEXPR char const * const STRING_EMPTY = "";
TBAG_CONSTEXPR char const * const STRING_SPACE = " ";
TBAG_CONSTEXPR char const * const STRING_HEX_PREFIX = "0x";
TBAG_CONSTEXPR int const DEFAULT_LINE_WIDTH = 2 * 8;

/**
 * Byte array to HEX string.
 */
TBAG_API char convertHalfByteToHexChar(uint8_t half_byte);
TBAG_API std::string convertByteToHexString(uint8_t hex);
TBAG_API std::string convertByteArrayToHexString(uint8_t const * bytes, std::size_t size,
                                                 std::string const & prefix = STRING_HEX_PREFIX,
                                                 std::string const & separator = STRING_EMPTY);
TBAG_API std::string convertByteArrayToHexStringBox(uint8_t const * bytes, std::size_t size,
                                                    int line_width = DEFAULT_LINE_WIDTH,
                                                    std::string const & prefix = STRING_HEX_PREFIX,
                                                    std::string const & separator = STRING_SPACE,
                                                    std::string const & new_line = NEW_LINE);

template <typename T>
std::string convertByteVectorToHexString(std::vector<T> const & bytes,
                                         std::string const & prefix = STRING_HEX_PREFIX,
                                         std::string const & separator = STRING_EMPTY)
{
    return convertByteArrayToHexString((uint8_t const *)bytes.data(), bytes.size(), prefix, separator);
}

template <typename T>
std::string convertByteVectorToHexStringBox(std::vector<T> const & bytes, int line_width = DEFAULT_LINE_WIDTH,
                                            std::string const & prefix = STRING_HEX_PREFIX,
                                            std::string const & separator = STRING_SPACE,
                                            std::string const & new_line = NEW_LINE)
{
    return convertByteArrayToHexStringBox((uint8_t const *)bytes.data(),
                                          bytes.size(), line_width, prefix, separator, new_line);
}

TBAG_CONSTEXPR std::size_t const HEX_STRING_ADDRESS_BYTE_SIZE =
        (/*PREFIX(0x)*/2) + (sizeof(std::uint64_t) * 2/*HEX STRING ADDRESS*/) + (1/*NULL*/);
using AddressHexString = std::array<char, HEX_STRING_ADDRESS_BYTE_SIZE>;

/**
 * HEX string to Byte array.
 */
TBAG_API Err convertHexCharToHalfByte(char hex_char, uint8_t & result);
TBAG_API Err convertHexCharToByte(char high_char, char low_char, uint8_t & result);
TBAG_API Err convertHexStringToBuffer(char const * hex_string, std::size_t length, libtbag::util::Buffer & buffer);

/**
 * Address to HEX string.
 */
TBAG_API AddressHexString convertAddressToHexString(void const * address) TBAG_NOEXCEPT;
TBAG_API AddressHexString convertUnsignedIntegerToHexString(std::uint64_t value) TBAG_NOEXCEPT;
TBAG_API std::string convertAddressHexStringToString(AddressHexString const & address);
TBAG_API std::string convertAddressToString(void const * address);

/**
 * Regex based token.
 */
TBAG_API std::vector<std::string> splitMatch(std::string const & source, std::regex const & match);
TBAG_API std::vector<std::string> splitMatch(std::string const & source, std::string const & match);

// Regexp utilities.
TBAG_API std::string replaceRegex(std::string const & source, std::string const & regex, std::string const & replace);
TBAG_API std::string removeRegex(std::string const & source, std::string const & regex);

/**
 * Simple replace.
 */
TBAG_API std::string replace(std::string const & source, std::string const & find, std::string const & replace);

TBAG_API bool isMatch(std::string const & source, std::regex const & regex);
TBAG_API bool isMatch(std::string const & source, std::string const & regex);
TBAG_API bool isUtf8Match(std::string const & utf8_source, std::string const & regex);

/**
 * Checks whether str is a decimal digit character.
 *
 * @remarks
 *  Decimal digits are any of: 0 1 2 3 4 5 6 7 8 9
 */
TBAG_API bool isDigit(std::string const & str);
TBAG_API bool isVariableName(char c);
TBAG_API bool isVariableName(std::string const & str);

TBAG_API std::string trimLeft(std::string const & str);
TBAG_API std::string trimRight(std::string const & str);
TBAG_API std::string trim(std::string const & str);

TBAG_API bool createRandomString(char * buffer, std::size_t size);

TBAG_API std::string lower(std::string const & str);
TBAG_API std::string upper(std::string const & str);

TBAG_API void lowerSelf(std::string & str);
TBAG_API void upperSelf(std::string & str);

TBAG_CONSTEXPR char const * const TRUE_LOWER_STR1 =   "on";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR2 = "true";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR3 =   "ok";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR4 =  "yes";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR5 =    "y";

TBAG_CONSTEXPR char const * const FALSE_LOWER_STR1 =   "off";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR2 = "false";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR3 =    "no";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR4 =     "n";

TBAG_API bool toVal(std::string const & str,               bool & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,               char & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned      char & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,              short & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned     short & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,                int & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned       int & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,               long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned      long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,          long long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned long long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,              float & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,             double & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,        long double & to, std::size_t * index = nullptr, int base = 10);

template <typename T>
inline T toValue(std::string const & str, T default_value = T(), int base = 10)
{
    T result;
    if (toVal(str, result, nullptr, base)) {
        return result;
    }
    return default_value;
}

template <typename T>
inline std::string toString(T val)
{
    return std::to_string(val);
}

inline std::string toString(bool val)
{
    return std::to_string(val ? 1 : 0);
}

TBAG_API std::string toHexString(unsigned char val, bool upper = true);
TBAG_API std::string toHexString(unsigned short val, bool upper = true);
TBAG_API std::string toHexString(unsigned int val, bool upper = true);
TBAG_API std::string toHexString(unsigned long val, bool upper = true);
TBAG_API std::string toHexString(unsigned long long val, bool upper = true);

TBAG_API std::size_t toByteSize(std::string const & str);

} // namespace string

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__

<commit_msg>Create TBAG_EMPTY_STRING macro.<commit_after>/**
 * @file   StringUtils.hpp
 * @brief  String utilities prototype.
 * @author zer0
 * @date   2016-04-04
 * @date   2016-12-05 (Rename: Strings -> StringUtils)
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#define CHECK_GNUC_CXX_REGEX

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>
#include <libtbag/Type.hpp>
#include <libtbag/util/BufferInfo.hpp>

#include <cstdint>
#include <string>
#include <sstream>
#include <vector>
#include <array>
#include <regex>
#include <thread>
#include <type_traits>
#include <iterator>
#include <utility>

#define TBAG_WINDOWS_NEW_LINE  "\r\n"
#define TBAG_UNIX_NEW_LINE     "\n"

#if defined(TBAG_PLATFORM_WINDOWS)
#define TBAG_NEW_LINE TBAG_WINDOWS_NEW_LINE
#else
#define TBAG_NEW_LINE TBAG_UNIX_NEW_LINE
#endif

#define TBAG_EMPTY_STRING       ""
#define TBAG_EMPTY_STRING_WIDE  L""
#define TBAG_SPACE_STRING       " "

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace string {

TBAG_CONSTEXPR char const * const WINDOWS_NEW_LINE = TBAG_WINDOWS_NEW_LINE;
TBAG_CONSTEXPR char const * const UNIX_NEW_LINE = TBAG_UNIX_NEW_LINE;
TBAG_CONSTEXPR char const * const NEW_LINE = TBAG_NEW_LINE;

TBAG_CONSTEXPR char const CHAR_SPACE  = ' ';
TBAG_CONSTEXPR char const CHAR_TAB    = '\t';
TBAG_CONSTEXPR char const CHAR_RETURN = '\n';

template <typename T>
TBAG_CONSTEXPR T const * charOrWidechar(char const * c, wchar_t const * w);

template <>
inline TBAG_CONSTEXPR char const * charOrWidechar<char>(char const * c, wchar_t const * w)
{
    return c;
}

template <>
inline TBAG_CONSTEXPR wchar_t const * charOrWidechar<wchar_t>(char const * c, wchar_t const * w)
{
    return w;
}

#ifndef CHAR_OR_WIDECHAR
#define CHAR_OR_WIDECHAR(type, str) ::libtbag::string::charOrWidechar<type>(str, L##str)
#endif

template <typename CharT>
inline TBAG_CONSTEXPR std::size_t string_length(CharT const * text)
{
    return (text == nullptr || *text == '\0') ? 0U : 1U + string_length(text + 1U);
}

template <typename FloatingType>
std::string convertStringWithFloatingPoint(FloatingType floating, int precision = 2)
{
    static_assert(std::is_floating_point<FloatingType>::value, "Not floating point type.");

    std::stringstream ss;
    ss.setf(std::ios_base::showpoint);
    ss.setf(std::ios_base::fixed, std::ios_base::floatfield);
    ss.precision(precision);
    ss << floating;
    return ss.str();
}

enum class LineFeedStyle
{
    LFS_NONE,
    LFS_UNIX,
    LFS_WINDOWS,
    LFS_AUTO,
};

TBAG_API LineFeedStyle getLineFeedStyle(std::string const & name);
TBAG_API char const * getLineFeedStyleText(LineFeedStyle style) TBAG_NOEXCEPT;

TBAG_API std::string getLineFeed(LineFeedStyle style = LineFeedStyle::LFS_AUTO);
TBAG_API std::string getStdEndLine();
TBAG_API bool appendLineFeed(LineFeedStyle style, char * buffer, int buffer_size, int offset) TBAG_NOEXCEPT;

/**
 * Separate tokens.
 *
 * @tparam CharType    Character type.
 * @tparam StringType  std::string type (Don't change this typename).
 *
 * @param[in] source       Original string.
 * @param[in] delimiter    Delimiter string.
 * @param[in] remove_empty Remove all empty tokens.
 *
 * @return
 *  Token vector.
 */
TBAG_API std::vector<std::string> splitTokens(std::string const & source, std::string const & delimiter, bool remove_empty = true);
TBAG_API std::vector<std::string> splitUtf8Tokens(std::string const & utf8_source, std::string const & utf8_delimiter, bool remove_empty = true);

template <typename Iterator>
std::string mergeTokens(Iterator begin, Iterator end, std::string const & delimiter)
{
    if (begin == end) {
        return {};
    }
    if (begin + 1 == end) {
        return *begin;
    }
    std::stringstream ss;
    ss << *begin;
    ++begin;
    for (; begin != end; ++begin) {
        ss << delimiter << *begin;
    }
    return ss.str();
}

TBAG_API std::string mergeTokens(std::vector<std::string> const & tokens, std::string const & delimiter);
TBAG_API std::string mergeTokens(std::vector<std::string> const & tokens);
TBAG_API std::string mergeArgv(char ** argv);

/**
 * Thread ID to string.
 */
TBAG_API std::string convertStringWithThreadId(std::thread::id const & id);

TBAG_CONSTEXPR char const * const STRING_EMPTY = TBAG_EMPTY_STRING;
TBAG_CONSTEXPR char const * const STRING_SPACE = TBAG_SPACE_STRING;
TBAG_CONSTEXPR char const * const STRING_HEX_PREFIX = "0x";
TBAG_CONSTEXPR int const DEFAULT_LINE_WIDTH = 2 * 8;

/**
 * Byte array to HEX string.
 */
TBAG_API char convertHalfByteToHexChar(uint8_t half_byte);
TBAG_API std::string convertByteToHexString(uint8_t hex);
TBAG_API std::string convertByteArrayToHexString(uint8_t const * bytes, std::size_t size,
                                                 std::string const & prefix = STRING_HEX_PREFIX,
                                                 std::string const & separator = STRING_EMPTY);
TBAG_API std::string convertByteArrayToHexStringBox(uint8_t const * bytes, std::size_t size,
                                                    int line_width = DEFAULT_LINE_WIDTH,
                                                    std::string const & prefix = STRING_HEX_PREFIX,
                                                    std::string const & separator = STRING_SPACE,
                                                    std::string const & new_line = NEW_LINE);

template <typename T>
std::string convertByteVectorToHexString(std::vector<T> const & bytes,
                                         std::string const & prefix = STRING_HEX_PREFIX,
                                         std::string const & separator = STRING_EMPTY)
{
    return convertByteArrayToHexString((uint8_t const *)bytes.data(), bytes.size(), prefix, separator);
}

template <typename T>
std::string convertByteVectorToHexStringBox(std::vector<T> const & bytes, int line_width = DEFAULT_LINE_WIDTH,
                                            std::string const & prefix = STRING_HEX_PREFIX,
                                            std::string const & separator = STRING_SPACE,
                                            std::string const & new_line = NEW_LINE)
{
    return convertByteArrayToHexStringBox((uint8_t const *)bytes.data(),
                                          bytes.size(), line_width, prefix, separator, new_line);
}

TBAG_CONSTEXPR std::size_t const HEX_STRING_ADDRESS_BYTE_SIZE =
        (/*PREFIX(0x)*/2) + (sizeof(std::uint64_t) * 2/*HEX STRING ADDRESS*/) + (1/*NULL*/);
using AddressHexString = std::array<char, HEX_STRING_ADDRESS_BYTE_SIZE>;

/**
 * HEX string to Byte array.
 */
TBAG_API Err convertHexCharToHalfByte(char hex_char, uint8_t & result);
TBAG_API Err convertHexCharToByte(char high_char, char low_char, uint8_t & result);
TBAG_API Err convertHexStringToBuffer(char const * hex_string, std::size_t length, libtbag::util::Buffer & buffer);

/**
 * Address to HEX string.
 */
TBAG_API AddressHexString convertAddressToHexString(void const * address) TBAG_NOEXCEPT;
TBAG_API AddressHexString convertUnsignedIntegerToHexString(std::uint64_t value) TBAG_NOEXCEPT;
TBAG_API std::string convertAddressHexStringToString(AddressHexString const & address);
TBAG_API std::string convertAddressToString(void const * address);

/**
 * Regex based token.
 */
TBAG_API std::vector<std::string> splitMatch(std::string const & source, std::regex const & match);
TBAG_API std::vector<std::string> splitMatch(std::string const & source, std::string const & match);

// Regexp utilities.
TBAG_API std::string replaceRegex(std::string const & source, std::string const & regex, std::string const & replace);
TBAG_API std::string removeRegex(std::string const & source, std::string const & regex);

/**
 * Simple replace.
 */
TBAG_API std::string replace(std::string const & source, std::string const & find, std::string const & replace);

TBAG_API bool isMatch(std::string const & source, std::regex const & regex);
TBAG_API bool isMatch(std::string const & source, std::string const & regex);
TBAG_API bool isUtf8Match(std::string const & utf8_source, std::string const & regex);

/**
 * Checks whether str is a decimal digit character.
 *
 * @remarks
 *  Decimal digits are any of: 0 1 2 3 4 5 6 7 8 9
 */
TBAG_API bool isDigit(std::string const & str);
TBAG_API bool isVariableName(char c);
TBAG_API bool isVariableName(std::string const & str);

TBAG_API std::string trimLeft(std::string const & str);
TBAG_API std::string trimRight(std::string const & str);
TBAG_API std::string trim(std::string const & str);

TBAG_API bool createRandomString(char * buffer, std::size_t size);

TBAG_API std::string lower(std::string const & str);
TBAG_API std::string upper(std::string const & str);

TBAG_API void lowerSelf(std::string & str);
TBAG_API void upperSelf(std::string & str);

TBAG_CONSTEXPR char const * const TRUE_LOWER_STR1 =   "on";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR2 = "true";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR3 =   "ok";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR4 =  "yes";
TBAG_CONSTEXPR char const * const TRUE_LOWER_STR5 =    "y";

TBAG_CONSTEXPR char const * const FALSE_LOWER_STR1 =   "off";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR2 = "false";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR3 =    "no";
TBAG_CONSTEXPR char const * const FALSE_LOWER_STR4 =     "n";

TBAG_API bool toVal(std::string const & str,               bool & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,               char & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned      char & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,              short & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned     short & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,                int & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned       int & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,               long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned      long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,          long long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str, unsigned long long & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,              float & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,             double & to, std::size_t * index = nullptr, int base = 10);
TBAG_API bool toVal(std::string const & str,        long double & to, std::size_t * index = nullptr, int base = 10);

template <typename T>
inline T toValue(std::string const & str, T default_value = T(), int base = 10)
{
    T result;
    if (toVal(str, result, nullptr, base)) {
        return result;
    }
    return default_value;
}

template <typename T>
inline std::string toString(T val)
{
    return std::to_string(val);
}

inline std::string toString(bool val)
{
    return std::to_string(val ? 1 : 0);
}

TBAG_API std::string toHexString(unsigned char val, bool upper = true);
TBAG_API std::string toHexString(unsigned short val, bool upper = true);
TBAG_API std::string toHexString(unsigned int val, bool upper = true);
TBAG_API std::string toHexString(unsigned long val, bool upper = true);
TBAG_API std::string toHexString(unsigned long long val, bool upper = true);

TBAG_API std::size_t toByteSize(std::string const & str);

} // namespace string

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_STRINGUTILS_HPP__

<|endoftext|>


<commit_before>// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM

#include <stdint.h>

void f() {}

void g(int x) {}

int main(void) {
  // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
  // CHECK-NEXT: function.cpp:8: note: f() defined here
  // NOSYM: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
  // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);

  // CHECK-NOT: runtime error: call to function g
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
}
<commit_msg>[ubsan] Do not run Function/function.cpp on Darwin where -fsanitize=function is not supported.<commit_after>// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM

// -fsanitize=function is unsupported on Darwin yet.
// XFAIL: darwin

#include <stdint.h>

void f() {}

void g(int x) {}

int main(void) {
  // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
  // CHECK-NEXT: function.cpp:8: note: f() defined here
  // NOSYM: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
  // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);

  // CHECK-NOT: runtime error: call to function g
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
}
<|endoftext|>


<commit_before>#include "Sofa/Components/MeshTopologyLoader.h"
#include "Sofa/Components/Common/Vec.h"

#include <stdio.h>
#include <iostream>
#include <vector>

namespace Sofa
{

namespace Components
{

using namespace Common;

static void skipToEOL(FILE* f)
{
    int	ch;
    while ((ch = fgetc(f)) != EOF && ch != '\n');
}

static bool readLine(char* buf, int size, FILE* f)
{
    buf[0] = '\0';
    if (fgets(buf, size, f) == NULL)
        return false;
    if ((int)strlen(buf)==size-1 && buf[size-1] != '\n')
        skipToEOL(f);
    return true;
}

bool MeshTopologyLoader::load(const char *filename)
{
    char cmd[1024];
    FILE* file;
    int npoints = 0;
    int nlines = 0;
    int ntris = 0;
    int nquads = 0;
    int ntetras = 0;
    int ncubes = 0;

    if ((file = fopen(filename, "r")) == NULL)
    {
        std::cout << "ERROR: cannot read file '" << filename << "'. Exiting..." << std::endl;
        return false;
    }
    // Check first line
    if (!readLine(cmd, sizeof(cmd), file))
    {
        fclose(file);
        return false;
    }
    std::cout << cmd << std::endl;
    if (!strncmp(cmd,"$NOD",4)) // Gmsh format
    {
        std::cout << "Loading Gmsh topology '" << filename << "'" << std::endl;
        fscanf(file, "%d\n", &npoints);
        setNbPoints(npoints);
        std::vector<int> pmap;
        for (int i=0; i<npoints; ++i)
        {
            int index = i;
            double x,y,z;
            fscanf(file, "%d %lf %lf %lf\n", &index, &x, &y, &z);
            addPoint(x, y, z);
            if ((int)pmap.size() <= index) pmap.resize(index+1);
            pmap[index] = i;
        }

        readLine(cmd, sizeof(cmd), file);
        //std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ENDNOD",7))
        {
            std::cerr << "'$ENDNOD' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }

        readLine(cmd, sizeof(cmd), file);
        //std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ELM",4))
        {
            std::cerr << "'$ELM' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }

        int nelems = 0;
        fscanf(file, "%d\n", &nelems);

        for (int i=0; i<nelems; ++i)
        {
            int index, etype, rphys, relem, nnodes;
            fscanf(file, "%d %d %d %d %d", &index, &etype, &rphys, &relem, &nnodes);
            std::vector<int> nodes;
            nodes.resize(nnodes);
            for (int n=0; n<nnodes; ++n)
            {
                int t = 0;
                fscanf(file, "%d",&t);
                nodes[n] = (((unsigned int)t)<pmap.size())?pmap[t]:0;
            }
            switch (etype)
            {
            case 1: // Line
                if (nnodes == 2)
                {
                    addLine(nodes[0], nodes[1]);
                    ++nlines;
                }
                break;
            case 2: // Triangle
                if (nnodes == 3)
                {
                    addTriangle(nodes[0], nodes[1], nodes[2]);
                    ++ntris;
                }
                break;
            case 3: // Quad
                if (nnodes == 4)
                {
                    addQuad(nodes[0], nodes[1], nodes[2], nodes[3]);
                    ++nquads;
                }
                break;
            case 4: // Tetra
                if (nnodes == 4)
                {
                    addTetra(nodes[0], nodes[1], nodes[2], nodes[3]);
                    ++ntetras;
                }
                break;
            case 5: // Hexa
                if (nnodes == 8)
                {
                    addCube(nodes[0], nodes[1], nodes[2], nodes[3],
                            nodes[4], nodes[5], nodes[6], nodes[7]);
                    ++ncubes;
                }
                break;
            }
            skipToEOL(file);
        }
        readLine(cmd, sizeof(cmd), file);
        std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ENDELM",7))
        {
            std::cerr << "'$ENDELM' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }
    }
    else if (!strncmp(cmd,"Xsp 3.0",7))
    {
        int totalNumMasses;
        int totalNumSprings;

        //		skipToEOL(file);

        // then find out number of masses and springs
        if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"numm"))
        {
            fscanf(file, "%d", &totalNumMasses);
            setNbPoints(totalNumMasses);
        }
        if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"nums"))
        {
            fscanf(file, "%d", &totalNumSprings);
            setNbLines(totalNumSprings);
//		setNumSprings(totalNumSprings);
        }

        std::cout << "Model contains "<< totalNumMasses <<" masses and "<< totalNumSprings <<" springs"<<std::endl;

        while (fscanf(file, "%s", cmd) != EOF)
        {
            if (!strcmp(cmd,"mass"))
            {
                int index;
                char location;
                double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
                bool fixed=false;
                fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
                        &index, &location,
                        &px, &py, &pz, &vx, &vy, &vz,
                        &mass, &elastic);

                if (mass < 0)
                {
                    // fixed point initialization
                    mass = -mass;
                    fixed = true;
                }
                addPoint(px,py,pz);
            }
            else if (!strcmp(cmd,"lspg"))	// linear springs connector
            {
                int	index;
                int m1,m2;
                double ks=0.0,kd=0.0,initpos=-1;
                fscanf(file, "%d %d %d %lf %lf %lf\n", &index,
                        &m1,&m2,&ks,&kd,&initpos);
                --m1;
                --m2;

                addLine(m1,m2);
            }
            else if (!strcmp(cmd,"grav"))
            {
                double gx,gy,gz;
                fscanf(file, "%lf %lf %lf\n", &gx, &gy, &gz);
            }
            else if (!strcmp(cmd,"visc"))
            {
                double viscosity;
                fscanf(file, "%lf\n", &viscosity);
            }
            else if (!strcmp(cmd,"step"))
            {
                //fscanf(file, "%lf\n", &(MSparams.default_dt));
                skipToEOL(file);
            }
            else if (!strcmp(cmd,"frce"))
            {
                skipToEOL(file);
            }
            else if (cmd[0] == '#')	// it's a comment
            {
                skipToEOL(file);
            }
            else		// it's an unknown keyword
            {
                printf("%s: Unknown MassSpring keyword: %s\n", filename, cmd);
                skipToEOL(file);
            }
        }
        fclose(file);
    }
    else
    {
        std::cout << "Loading mesh topology '" << filename << "'" << std::endl;
        while (fscanf(file, "%s", cmd) != EOF)
        {
            if (!strcmp(cmd,"line"))
            {
                int p1,p2;
                fscanf(file, "%d %d\n",
                        &p1, &p2);
                addLine(p1, p2);
                ++nlines;
            }
            else if (!strcmp(cmd,"triangle"))
            {
                int p1,p2,p3;
                fscanf(file, "%d %d %d\n",
                        &p1, &p2, &p3);
                addTriangle(p1, p2, p3);
                ++ntris;
            }
            else if (!strcmp(cmd,"quad"))
            {
                int p1,p2,p3,p4;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                addQuad(p1, p2, p3, p4);
                ++nquads;
            }
            else if (!strcmp(cmd,"tetra"))
            {
                int p1,p2,p3,p4;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                addTetra(p1, p2, p3, p4);
                ++ntetras;
            }
            else if (!strcmp(cmd,"cube"))
            {
                int p1,p2,p3,p4,p5,p6,p7,p8;
                fscanf(file, "%d %d %d %d %d %d %d %d\n",
                        &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8);
                addCube(p1, p2, p3, p4, p5, p6, p7, p8);
                ++ncubes;
            }
            else if (!strcmp(cmd,"point"))
            {
                double px,py,pz;
                fscanf(file, "%lf %lf %lf\n",
                        &px, &py, &pz);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"v"))
            {
                double px,py,pz;
                fscanf(file, "%lf %lf %lf\n",
                        &px, &py, &pz);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"f"))
            {
                int p1,p2,p3,p4=0;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                if (p4)
                {
                    addQuad(p1-1, p2-1, p3-1, p4-1);
                    ++nquads;
                }
                else
                {
                    addTriangle(p1-1, p2-1, p3-1);
                    ++ntris;
                }
            }
            else if (!strcmp(cmd,"mass"))
            {
                int index;
                char location;
                double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
                fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
                        &index, &location,
                        &px, &py, &pz, &vx, &vy, &vz,
                        &mass, &elastic);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"lspg"))
            {
                int	index;
                int m1,m2;
                double ks=0.0,kd=0.0,initpos=-1;
                fscanf(file, "%d %d %d %lf %lf %lf\n", &index,
                        &m1,&m2,&ks,&kd,&initpos);
                --m1;
                --m2;
                addLine(m1,m2);
                ++nlines;
            }
            else if (cmd[0] == '#')	// it's a comment
            {
                skipToEOL(file);
            }
            else		// it's an unknown keyword
            {
                printf("%s: Unknown Mesh keyword: %s\n", filename, cmd);
                skipToEOL(file);
                return false;
            }
        }
    }
    std::cout << "Loading topology complete:";
    if (npoints>0) std::cout << ' ' << npoints << " points";
    if (nlines>0)  std::cout << ' ' << nlines  << " lines";
    if (ntris>0)   std::cout << ' ' << ntris   << " triangles";
    if (nquads>0)  std::cout << ' ' << nquads  << " quads";
    if (ntetras>0) std::cout << ' ' << ntetras << " tetrahedra";
    if (ncubes>0)  std::cout << ' ' << ncubes  << " cubes";
    std::cout << std::endl;
    fclose(file);
    return true;
}

} // namespace Components

} // namespace Sofa
<commit_msg>r718/sofa-dev : bug corrected<commit_after>#include "Sofa/Components/MeshTopologyLoader.h"
#include "Sofa/Components/Common/Vec.h"

#include <stdio.h>
#include <iostream>
#include <vector>

namespace Sofa
{

namespace Components
{

using namespace Common;

static void skipToEOL(FILE* f)
{
    int	ch;
    while ((ch = fgetc(f)) != EOF && ch != '\n');
}

static bool readLine(char* buf, int size, FILE* f)
{
    buf[0] = '\0';
    if (fgets(buf, size, f) == NULL)
        return false;
    if ((int)strlen(buf)==size-1 && buf[size-1] != '\n')
        skipToEOL(f);
    return true;
}

bool MeshTopologyLoader::load(const char *filename)
{
    char cmd[1024];
    FILE* file;
    int npoints = 0;
    int nlines = 0;
    int ntris = 0;
    int nquads = 0;
    int ntetras = 0;
    int ncubes = 0;

    if ((file = fopen(filename, "r")) == NULL)
    {
        std::cout << "ERROR: cannot read file '" << filename << "'. Exiting..." << std::endl;
        return false;
    }
    // Check first line
    if (!readLine(cmd, sizeof(cmd), file))
    {
        fclose(file);
        return false;
    }
    std::cout << cmd << std::endl;
    if (!strncmp(cmd,"$NOD",4)) // Gmsh format
    {
        std::cout << "Loading Gmsh topology '" << filename << "'" << std::endl;
        fscanf(file, "%d\n", &npoints);
        setNbPoints(npoints);
        std::vector<int> pmap;
        for (int i=0; i<npoints; ++i)
        {
            int index = i;
            double x,y,z;
            fscanf(file, "%d %lf %lf %lf\n", &index, &x, &y, &z);
            addPoint(x, y, z);
            if ((int)pmap.size() <= index) pmap.resize(index+1);
            pmap[index] = i;
        }

        readLine(cmd, sizeof(cmd), file);
        //std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ENDNOD",7))
        {
            std::cerr << "'$ENDNOD' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }

        readLine(cmd, sizeof(cmd), file);
        //std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ELM",4))
        {
            std::cerr << "'$ELM' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }

        int nelems = 0;
        fscanf(file, "%d\n", &nelems);

        for (int i=0; i<nelems; ++i)
        {
            int index, etype, rphys, relem, nnodes;
            fscanf(file, "%d %d %d %d %d", &index, &etype, &rphys, &relem, &nnodes);
            std::vector<int> nodes;
            nodes.resize(nnodes);
            for (int n=0; n<nnodes; ++n)
            {
                int t = 0;
                fscanf(file, "%d",&t);
                nodes[n] = (((unsigned int)t)<pmap.size())?pmap[t]:0;
            }
            switch (etype)
            {
            case 1: // Line
                if (nnodes == 2)
                {
                    addLine(nodes[0], nodes[1]);
                    ++nlines;
                }
                break;
            case 2: // Triangle
                if (nnodes == 3)
                {
                    addTriangle(nodes[0], nodes[1], nodes[2]);
                    ++ntris;
                }
                break;
            case 3: // Quad
                if (nnodes == 4)
                {
                    addQuad(nodes[0], nodes[1], nodes[2], nodes[3]);
                    ++nquads;
                }
                break;
            case 4: // Tetra
                if (nnodes == 4)
                {
                    addTetra(nodes[0], nodes[1], nodes[2], nodes[3]);
                    ++ntetras;
                }
                break;
            case 5: // Hexa
                if (nnodes == 8)
                {
                    addCube(nodes[0], nodes[1], nodes[2], nodes[3],
                            nodes[4], nodes[5], nodes[6], nodes[7]);
                    ++ncubes;
                }
                break;
            }
            skipToEOL(file);
        }
        readLine(cmd, sizeof(cmd), file);
        std::cout << cmd << std::endl;
        if (strncmp(cmd,"$ENDELM",7))
        {
            std::cerr << "'$ENDELM' expected, found '" << cmd << "'" << std::endl;
            fclose(file);
            return false;
        }
    }
    else if (!strncmp(cmd,"Xsp 3.0",7))
    {
        int totalNumMasses;
        int totalNumSprings;

        //		skipToEOL(file);

        // then find out number of masses and springs
        if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"numm"))
        {
            fscanf(file, "%d", &totalNumMasses);
            setNbPoints(totalNumMasses);
            npoints=totalNumMasses;
        }
        if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"nums"))
        {
            fscanf(file, "%d", &totalNumSprings);
            setNbLines(totalNumSprings);
            nlines=totalNumSprings;
            //		setNumSprings(totalNumSprings);
        }

        //std::cout << "Model contains "<< totalNumMasses <<" masses and "<< totalNumSprings <<" springs"<<std::endl;

        while (fscanf(file, "%s", cmd) != EOF)
        {
            if (!strcmp(cmd,"mass"))
            {
                int index;
                char location;
                double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
                bool fixed=false;
                fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
                        &index, &location,
                        &px, &py, &pz, &vx, &vy, &vz,
                        &mass, &elastic);

                if (mass < 0)
                {
                    // fixed point initialization
                    mass = -mass;
                    fixed = true;
                }
                addPoint(px,py,pz);
            }
            else if (!strcmp(cmd,"lspg"))	// linear springs connector
            {
                int	index;
                int m1,m2;
                double ks=0.0,kd=0.0,initpos=-1;
                fscanf(file, "%d %d %d %lf %lf %lf\n", &index,
                        &m1,&m2,&ks,&kd,&initpos);
                --m1;
                --m2;

                addLine(m1,m2);
            }
            else if (!strcmp(cmd,"grav"))
            {
                double gx,gy,gz;
                fscanf(file, "%lf %lf %lf\n", &gx, &gy, &gz);
            }
            else if (!strcmp(cmd,"visc"))
            {
                double viscosity;
                fscanf(file, "%lf\n", &viscosity);
            }
            else if (!strcmp(cmd,"step"))
            {
                //fscanf(file, "%lf\n", &(MSparams.default_dt));
                skipToEOL(file);
            }
            else if (!strcmp(cmd,"frce"))
            {
                skipToEOL(file);
            }
            else if (cmd[0] == '#')	// it's a comment
            {
                skipToEOL(file);
            }
            else		// it's an unknown keyword
            {
                printf("%s: Unknown MassSpring keyword: %s\n", filename, cmd);
                skipToEOL(file);
            }
        }
    }
    else
    {
        std::cout << "Loading mesh topology '" << filename << "'" << std::endl;
        while (fscanf(file, "%s", cmd) != EOF)
        {
            if (!strcmp(cmd,"line"))
            {
                int p1,p2;
                fscanf(file, "%d %d\n",
                        &p1, &p2);
                addLine(p1, p2);
                ++nlines;
            }
            else if (!strcmp(cmd,"triangle"))
            {
                int p1,p2,p3;
                fscanf(file, "%d %d %d\n",
                        &p1, &p2, &p3);
                addTriangle(p1, p2, p3);
                ++ntris;
            }
            else if (!strcmp(cmd,"quad"))
            {
                int p1,p2,p3,p4;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                addQuad(p1, p2, p3, p4);
                ++nquads;
            }
            else if (!strcmp(cmd,"tetra"))
            {
                int p1,p2,p3,p4;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                addTetra(p1, p2, p3, p4);
                ++ntetras;
            }
            else if (!strcmp(cmd,"cube"))
            {
                int p1,p2,p3,p4,p5,p6,p7,p8;
                fscanf(file, "%d %d %d %d %d %d %d %d\n",
                        &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8);
                addCube(p1, p2, p3, p4, p5, p6, p7, p8);
                ++ncubes;
            }
            else if (!strcmp(cmd,"point"))
            {
                double px,py,pz;
                fscanf(file, "%lf %lf %lf\n",
                        &px, &py, &pz);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"v"))
            {
                double px,py,pz;
                fscanf(file, "%lf %lf %lf\n",
                        &px, &py, &pz);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"f"))
            {
                int p1,p2,p3,p4=0;
                fscanf(file, "%d %d %d %d\n",
                        &p1, &p2, &p3, &p4);
                if (p4)
                {
                    addQuad(p1-1, p2-1, p3-1, p4-1);
                    ++nquads;
                }
                else
                {
                    addTriangle(p1-1, p2-1, p3-1);
                    ++ntris;
                }
            }
            else if (!strcmp(cmd,"mass"))
            {
                int index;
                char location;
                double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
                fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
                        &index, &location,
                        &px, &py, &pz, &vx, &vy, &vz,
                        &mass, &elastic);
                addPoint(px, py, pz);
                ++npoints;
            }
            else if (!strcmp(cmd,"lspg"))
            {
                int	index;
                int m1,m2;
                double ks=0.0,kd=0.0,initpos=-1;
                fscanf(file, "%d %d %d %lf %lf %lf\n", &index,
                        &m1,&m2,&ks,&kd,&initpos);
                --m1;
                --m2;
                addLine(m1,m2);
                ++nlines;
            }
            else if (cmd[0] == '#')	// it's a comment
            {
                skipToEOL(file);
            }
            else		// it's an unknown keyword
            {
                printf("%s: Unknown Mesh keyword: %s\n", filename, cmd);
                skipToEOL(file);
                return false;
            }
        }
    }
    std::cout << "Loading topology complete:";
    if (npoints>0) std::cout << ' ' << npoints << " points";
    if (nlines>0)  std::cout << ' ' << nlines  << " lines";
    if (ntris>0)   std::cout << ' ' << ntris   << " triangles";
    if (nquads>0)  std::cout << ' ' << nquads  << " quads";
    if (ntetras>0) std::cout << ' ' << ntetras << " tetrahedra";
    if (ncubes>0)  std::cout << ' ' << ncubes  << " cubes";
    std::cout << std::endl;
    fclose(file);
    return true;
}

} // namespace Components

} // namespace Sofa
<|endoftext|>


<commit_before>/*
   Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LGPL.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

   Alternatively, this file is available under the Mozilla Public License
   Version 1.1.  You may obtain a copy of the License at
   http://www.mozilla.org/MPL/
*/

#include "arguments.h"
#include "connectaddress.h"
#include "eventdispatcher.h"
#include "imessagereceiver.h"
#include "message.h"
#include "pendingreply.h"
#include "connection.h"

#include "../testutil.h"

#include <iostream>
#include <string>

static void addressMessageToBus(Message *msg)
{
    msg->setType(Message::MethodCallMessage);
    msg->setDestination("org.freedesktop.DBus");
    msg->setInterface("org.freedesktop.DBus");
    msg->setPath("/org/freedesktop/DBus");
}

class ReplyCheck : public IMessageReceiver
{
public:
    EventDispatcher *m_eventDispatcher;
    void handlePendingReplyFinished(PendingReply *pr) override
    {
        pr->dumpState();
        std::cout << "got it!\n" << pr->reply()->arguments().prettyPrint();
        TEST(pr->isFinished());
        TEST(!pr->isError());

        // This is really a different test, it used to reproduce a memory leak under Valgrind
        Message reply = pr->takeReply();

        m_eventDispatcher->interrupt();
    }
};

static void testBusAddress(bool waitForConnected)
{
    EventDispatcher eventDispatcher;
    Connection conn(&eventDispatcher, ConnectAddress::StandardBus::Session);

    Message msg;
    addressMessageToBus(&msg);
    msg.setMethod("RequestName");

    Arguments::Writer writer;
    writer.writeString("Bana.nana"); // requested name
    writer.writeUint32(4); // TODO proper enum or so: 4 == DBUS_NAME_FLAG_DO_NOT_QUEUE
    msg.setArguments(writer.finish());

    if (waitForConnected) {
        // finish creating the connection
        while (conn.uniqueName().empty()) {
            eventDispatcher.poll();
        }
    }

    PendingReply busNameReply = conn.send(std::move(msg));
    ReplyCheck replyCheck;
    replyCheck.m_eventDispatcher = &eventDispatcher;
    busNameReply.setReceiver(&replyCheck);

    while (eventDispatcher.poll()) {
    }
}

class TimeoutCheck : public IMessageReceiver
{
public:
    EventDispatcher *m_eventDispatcher;
    void handlePendingReplyFinished(PendingReply *reply) override
    {
        TEST(reply->isFinished());
        TEST(!reply->hasNonErrorReply());
        TEST(reply->error().code() == Error::Timeout);
        std::cout << "We HAVE timed out.\n";
        m_eventDispatcher->interrupt();
    }
};

static void testTimeout()
{
    EventDispatcher eventDispatcher;
    Connection conn(&eventDispatcher, ConnectAddress::StandardBus::Session);

    // finish creating the connection; we need to know our own name so we can send the message to
    // ourself so we can make sure that there will be no reply :)
    while (conn.uniqueName().empty()) {
        eventDispatcher.poll();
    }

    Message msg = Message::createCall("/some/dummy/path/lol", "dummy_interface", "non_existent_method");
    msg.setDestination(conn.uniqueName());

    PendingReply neverGonnaGetReply = conn.send(std::move(msg), 200);
    TimeoutCheck timeoutCheck;
    timeoutCheck.m_eventDispatcher = &eventDispatcher;
    neverGonnaGetReply.setReceiver(&timeoutCheck);

    while (eventDispatcher.poll()) {
    }
}

int main(int, char *[])
{
    testBusAddress(false);
    testBusAddress(true);
    testTimeout();
    // TODO testBadCall
    std::cout << "Passed!\n";
}
<commit_msg>Make this dummy interface name valid according to spec<commit_after>/*
   Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LGPL.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

   Alternatively, this file is available under the Mozilla Public License
   Version 1.1.  You may obtain a copy of the License at
   http://www.mozilla.org/MPL/
*/

#include "arguments.h"
#include "connectaddress.h"
#include "eventdispatcher.h"
#include "imessagereceiver.h"
#include "message.h"
#include "pendingreply.h"
#include "connection.h"

#include "../testutil.h"

#include <iostream>
#include <string>

static void addressMessageToBus(Message *msg)
{
    msg->setType(Message::MethodCallMessage);
    msg->setDestination("org.freedesktop.DBus");
    msg->setInterface("org.freedesktop.DBus");
    msg->setPath("/org/freedesktop/DBus");
}

class ReplyCheck : public IMessageReceiver
{
public:
    EventDispatcher *m_eventDispatcher;
    void handlePendingReplyFinished(PendingReply *pr) override
    {
        pr->dumpState();
        std::cout << "got it!\n" << pr->reply()->arguments().prettyPrint();
        TEST(pr->isFinished());
        TEST(!pr->isError());

        // This is really a different test, it used to reproduce a memory leak under Valgrind
        Message reply = pr->takeReply();

        m_eventDispatcher->interrupt();
    }
};

static void testBusAddress(bool waitForConnected)
{
    EventDispatcher eventDispatcher;
    Connection conn(&eventDispatcher, ConnectAddress::StandardBus::Session);

    Message msg;
    addressMessageToBus(&msg);
    msg.setMethod("RequestName");

    Arguments::Writer writer;
    writer.writeString("Bana.nana"); // requested name
    writer.writeUint32(4); // TODO proper enum or so: 4 == DBUS_NAME_FLAG_DO_NOT_QUEUE
    msg.setArguments(writer.finish());

    if (waitForConnected) {
        // finish creating the connection
        while (conn.uniqueName().empty()) {
            eventDispatcher.poll();
        }
    }

    PendingReply busNameReply = conn.send(std::move(msg));
    ReplyCheck replyCheck;
    replyCheck.m_eventDispatcher = &eventDispatcher;
    busNameReply.setReceiver(&replyCheck);

    while (eventDispatcher.poll()) {
    }
}

class TimeoutCheck : public IMessageReceiver
{
public:
    EventDispatcher *m_eventDispatcher;
    void handlePendingReplyFinished(PendingReply *reply) override
    {
        TEST(reply->isFinished());
        TEST(!reply->hasNonErrorReply());
        TEST(reply->error().code() == Error::Timeout);
        std::cout << "We HAVE timed out.\n";
        m_eventDispatcher->interrupt();
    }
};

static void testTimeout()
{
    EventDispatcher eventDispatcher;
    Connection conn(&eventDispatcher, ConnectAddress::StandardBus::Session);

    // finish creating the connection; we need to know our own name so we can send the message to
    // ourself so we can make sure that there will be no reply :)
    while (conn.uniqueName().empty()) {
        eventDispatcher.poll();
    }

    Message msg = Message::createCall("/some/dummy/path", "org.no_interface", "non_existent_method");
    msg.setDestination(conn.uniqueName());

    PendingReply neverGonnaGetReply = conn.send(std::move(msg), 200);
    TimeoutCheck timeoutCheck;
    timeoutCheck.m_eventDispatcher = &eventDispatcher;
    neverGonnaGetReply.setReceiver(&timeoutCheck);

    while (eventDispatcher.poll()) {
    }
}

int main(int, char *[])
{
    testBusAddress(false);
    testBusAddress(true);
    testTimeout();
    // TODO testBadCall
    std::cout << "Passed!\n";
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2014  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "xrandr.h"
#include <QProcess>
#include <QDebug>
#include <QRegExp>
#include <QObject>
#include <QDir>
#include <QVector>

static QByteArray indentString(QByteArray line) {
  QByteArray s;
  int length = line.size();
  char ch;
  for(int indent=0; indent < length; indent++ ) {
    ch = line[indent];
    if( ch == ' ' || ch == '\t' )
      s.append(ch);
    else
      break;
  }
  return s;
}

static int indentLevel(QByteArray line) {
  int indent = 0;
  while(indent < line.size() && ( line[indent] == ' ' || line[indent] == '\t' ) )
    ++indent;
  return indent;
}

// new parsing code using xrandr --verbose
QList<MonitorInfo*> XRandRBackend::getMonitorsInfo() {
  QList<MonitorInfo*> monitors;
  // execute xrandr command and read its output
  QProcess process;
  // set locale to "C" guarantee English output of xrandr
  process.processEnvironment().insert("LC_ALL", "c");
  process.start("xrandr --verbose");
  process.waitForFinished(-1);
  if(process.exitCode() != 0)
    return monitors;
  QList<QByteArray> lines = process.readAllStandardOutput().split('\n');
  // start parsing the output
  QRegExp regMonitorLine("([\\w-]+) +connected +(primary)? *(\\d+x\\d+\\+(\\d+)\\+(\\d+))?.*");
  QRegExp regModeLine("\\s+(\\d+x\\d+).*");
  QRegExp regRateLine("\\s+([vh]):.* clock\\s+([\\d.]+).?Hz.*");
  QRegExp regKeyValue("\\s*(\\w[\\w ]*)\\s*:\\s*(\\S.*)?");

  bool hasError = false;
  MonitorInfo* monitor = NULL;
  QList<QByteArray>::iterator it = lines.begin();
  bool readingModes = false;
  // currently, we only support one X screen, that is screen 0
  while(it != lines.end() && !hasError) {
    QByteArray& line = *it;
    if(!monitor) {
      if(regMonitorLine.exactMatch(line)) {
        // format: VGA-0 connected 1280x1024+1024+0 (0x55) normal...
        monitor = new MonitorInfo();
        monitor->name = regMonitorLine.cap(1);
        if(regMonitorLine.cap(2) == "primary") { // is primary monitor
          monitor->primaryOk = true;
        }
        if(!regMonitorLine.cap(3).isEmpty()) // mode+xpos+ypos
          monitor->enabledOk = true;
        monitor->xPos = regMonitorLine.cap(4).toInt();
        monitor->yPos = regMonitorLine.cap(5).toInt();
      }
    }
    else { // reading properties of this monitor
      if(regModeLine.exactMatch(line)) { // this is a mode line
        // sample: 1280x1024 (0x55) 108.000MHz +HSync +VSync *current +preferred
        readingModes = true;
        QString mode = regModeLine.cap(1);
        QString rate;
        bool isCurrent = line.contains("current");
        bool isPreferred = line.contains("preferred");
        ++it;
        while(it != lines.end()) {
          line = *it;
          if(regRateLine.exactMatch(line)) {
            // sample:
            //        h: width  1280 start 1328 end 1440 total 1688 skew    0 clock  63.98KHz
            //        v: height 1024 start 1025 end 1028 total 1066           clock  60.02Hz
            if(regRateLine.cap(1) == QLatin1String("v"))
              rate = regRateLine.cap(2);
            ++it;
          }
          else {
            --it;
            break; // rate lines ended for this mode
          }
        }
        if(!mode.isEmpty() && !rate.isEmpty()) {
          if(!monitor->modes.contains(mode))
            monitor->modes.append(mode);
          if(!monitor->modeLines.contains(mode))
            monitor->modeLines[mode] = QStringList();
          monitor->modeLines[mode].append(rate);
          if(isPreferred) {
            monitor->preferredMode = mode;
            monitor->preferredRate = rate;
          }
          if(isCurrent) {
            monitor->currentMode = mode;
            monitor->currentRate = rate;
          }
        }
      }
      else { // this is not a mode line, read other properties
        if(readingModes) {
          // mode lines ended, so the whole monitor info is read
          monitors.append(monitor);
          monitor = NULL;
          readingModes = false;
          continue;
        }

        if(regKeyValue.exactMatch(line)) { // format: <key>: <value>
          QString key = regKeyValue.cap(1);
          QString value = regKeyValue.cap(2);
          QByteArray lineStringStart = indentString(line);
          int propertyIndentLevel = indentLevel(line);
          ++it;
          while( it != lines.end() ) {
            QByteArray& line = *it;
            int actualIndentLevel = indentLevel(line);
            if( actualIndentLevel>propertyIndentLevel && line.startsWith(lineStringStart) ) {
              value += "\n" + line.trimmed();
              ++it;
            } else
              break;
          }
          qDebug() << key << "=" << value;
          if(key == "Gamma") {
            monitor->gamma = value;
          }
          else if(key == "Brightness") {
            monitor->brightness = value;
          }
          else if(key == "EDID") {
            monitor->edid = value ;
            // Get vendor
            QString hex = value.replace("\n","").replace(" ","").toLower();
            int vendorPosStart = hex.indexOf("fc00");
            if(vendorPosStart>0) {
            int vendorPosEnd = hex.indexOf("00", vendorPosStart+4);
              QString vendorHex = hex.mid(vendorPosStart+4, vendorPosEnd-vendorPosStart-4);
              QByteArray vendor = QByteArray::fromHex(vendorHex.toLocal8Bit()).trimmed();
              // qDebug() << "Vendor:" << vendorHex << "VendorHex" << vendor ;
              monitor->vendor = vendor;
            }
          }
          continue;
        } // End format: <key>: <value>
        else { // this line is not key:value
        }
      }
    }
    if( it != lines.end() ) ++it;
  }

  if(monitor) // this should not happen unless a parsing error happens
    delete monitor;

  resolvePositions(monitors);

  return monitors;
}

bool XRandRBackend::setMonitorsSettings(const QList<MonitorSettings*> monitors) {
  QString cmd = getCommand(monitors);
  QProcess process;
  process.start(cmd);
  process.waitForFinished();
  return process.exitCode() == 0;
}

QString XRandRBackend::getCommand(const QList<MonitorSettings*> monitors)  {
  QMap<MonitorSettings::Position, QString> positions;

  positions[MonitorSettings::Left] = "--left-of";
  positions[MonitorSettings::Right] = "--right-of";
  positions[MonitorSettings::Above] = "--above";
  positions[MonitorSettings::Bellow] = "--below";

  QByteArray cmd = "xrandr";

  foreach(MonitorSettings * monitor, monitors) {
    cmd += " --output ";
    cmd.append(monitor->name);
    cmd.append(' ');

    // if the monitor is turned on
    if(monitor->enabledOk) {
      QString sel_res = monitor->currentMode;
      QString sel_rate = monitor->currentRate;

      if(sel_res == QObject::tr("Auto"))   // auto resolution
        cmd.append("--auto");
      else {
        cmd.append("--mode ");
        cmd.append(sel_res);
        if(sel_rate != QObject::tr("Auto")) {  // not auto refresh rate
          cmd.append(" --rate ");
          cmd.append(sel_rate);
        }
      }
      if(monitor->position != MonitorSettings::None) {
        cmd.append(" ");
        cmd.append(positions[monitor->position]);
        cmd.append(" ");
        cmd.append(monitor->positionRelativeToOutput);
      }
      if(monitor->primaryOk)
        cmd.append(" --primary");
      cmd.append(" --brightness ");
      cmd.append(monitor->brightness);
      cmd.append(" --gamma ");
      cmd.append(monitor->gamma);
    }
    else    // turn off
      cmd.append("--off");
  }

  qDebug() << "cmd:" << cmd;
  return cmd;
}

// resolve the position relationship among the montors
void XRandRBackend::resolvePositions(QList< MonitorInfo* >& monitors) {
  Q_FOREACH(MonitorInfo * monitor, monitors) {
    MonitorSettings::Position pos;
    MonitorInfo* neighbor = findAdjacentMonitor(monitors, monitor, pos);
    if(neighbor) {
      monitor->position = pos;
      monitor->positionRelativeToOutput = neighbor->name;
    }
  }
}

MonitorInfo* XRandRBackend::findAdjacentMonitor(QList< MonitorInfo* >& monitors, MonitorInfo* monitor, MonitorSettings::Position& pos) {
  MonitorInfo* neighbor = NULL;
  QRect monitorRect = monitor->geometry();
  pos = MonitorSettings::None;
  Q_FOREACH(MonitorInfo * mon, monitors) {
    if(mon == monitor || mon->positionRelativeToOutput == monitor->name)
      continue;
    QRect neighborRect = mon->geometry();
    if(monitorRect.top() == neighborRect.top()) {
      if((monitorRect.right() + 1) == neighborRect.left()) { // monitor is at left of neighbor
        pos = MonitorSettings::Left;
        neighbor = mon;
        break;
      }
      else if(monitorRect.left() == (neighborRect.right() + 1)) { // monitor is at right of neighbor
        pos = MonitorSettings::Right;
        neighbor = mon;
        break;
      }
    }
    if(monitorRect.left() == neighborRect.left()) {
      if((monitorRect.bottom() + 1) == neighborRect.top()) { // monitor is above neighbor
        pos = MonitorSettings::Above;
        neighbor = mon;
        break;
      }
      else if(monitorRect.top() == (neighborRect.bottom() + 1)) { // monitor is below neighbor
        pos = MonitorSettings::Bellow;
        neighbor = mon;
        break;
      }
    }
  }
  return neighbor;
}
<commit_msg>Fixed: Restore position of monitor when user cancels settings.<commit_after>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2014  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "xrandr.h"
#include <QProcess>
#include <QDebug>
#include <QRegExp>
#include <QObject>
#include <QDir>
#include <QVector>

static QByteArray indentString(QByteArray line) {
  QByteArray s;
  int length = line.size();
  char ch;
  for(int indent=0; indent < length; indent++ ) {
    ch = line[indent];
    if( ch == ' ' || ch == '\t' )
      s.append(ch);
    else
      break;
  }
  return s;
}

static int indentLevel(QByteArray line) {
  int indent = 0;
  while(indent < line.size() && ( line[indent] == ' ' || line[indent] == '\t' ) )
    ++indent;
  return indent;
}

// new parsing code using xrandr --verbose
QList<MonitorInfo*> XRandRBackend::getMonitorsInfo() {
  QList<MonitorInfo*> monitors;
  // execute xrandr command and read its output
  QProcess process;
  // set locale to "C" guarantee English output of xrandr
  process.processEnvironment().insert("LC_ALL", "c");
  process.start("xrandr --verbose");
  process.waitForFinished(-1);
  if(process.exitCode() != 0)
    return monitors;
  QList<QByteArray> lines = process.readAllStandardOutput().split('\n');
  // start parsing the output
  QRegExp regMonitorLine("([\\w-]+) +connected +(primary)? *(\\d+x\\d+\\+(\\d+)\\+(\\d+))?.*");
  QRegExp regModeLine("\\s+(\\d+x\\d+).*");
  QRegExp regRateLine("\\s+([vh]):.* clock\\s+([\\d.]+).?Hz.*");
  QRegExp regKeyValue("\\s*(\\w[\\w ]*)\\s*:\\s*(\\S.*)?");

  bool hasError = false;
  MonitorInfo* monitor = NULL;
  QList<QByteArray>::iterator it = lines.begin();
  bool readingModes = false;
  // currently, we only support one X screen, that is screen 0
  while(it != lines.end() && !hasError) {
    QByteArray& line = *it;
    if(!monitor) {
      if(regMonitorLine.exactMatch(line)) {
        // format: VGA-0 connected 1280x1024+1024+0 (0x55) normal...
        monitor = new MonitorInfo();
        monitor->name = regMonitorLine.cap(1);
        if(regMonitorLine.cap(2) == "primary") { // is primary monitor
          monitor->primaryOk = true;
        }
        if(!regMonitorLine.cap(3).isEmpty()) // mode+xpos+ypos
          monitor->enabledOk = true;
        monitor->xPos = regMonitorLine.cap(4).toInt();
        monitor->yPos = regMonitorLine.cap(5).toInt();
      }
    }
    else { // reading properties of this monitor
      if(regModeLine.exactMatch(line)) { // this is a mode line
        // sample: 1280x1024 (0x55) 108.000MHz +HSync +VSync *current +preferred
        readingModes = true;
        QString mode = regModeLine.cap(1);
        QString rate;
        bool isCurrent = line.contains("current");
        bool isPreferred = line.contains("preferred");
        ++it;
        while(it != lines.end()) {
          line = *it;
          if(regRateLine.exactMatch(line)) {
            // sample:
            //        h: width  1280 start 1328 end 1440 total 1688 skew    0 clock  63.98KHz
            //        v: height 1024 start 1025 end 1028 total 1066           clock  60.02Hz
            if(regRateLine.cap(1) == QLatin1String("v"))
              rate = regRateLine.cap(2);
            ++it;
          }
          else {
            --it;
            break; // rate lines ended for this mode
          }
        }
        if(!mode.isEmpty() && !rate.isEmpty()) {
          if(!monitor->modes.contains(mode))
            monitor->modes.append(mode);
          if(!monitor->modeLines.contains(mode))
            monitor->modeLines[mode] = QStringList();
          monitor->modeLines[mode].append(rate);
          if(isPreferred) {
            monitor->preferredMode = mode;
            monitor->preferredRate = rate;
          }
          if(isCurrent) {
            monitor->currentMode = mode;
            monitor->currentRate = rate;
          }
        }
      }
      else { // this is not a mode line, read other properties
        if(readingModes) {
          // mode lines ended, so the whole monitor info is read
          monitors.append(monitor);
          monitor = NULL;
          readingModes = false;
          continue;
        }

        if(regKeyValue.exactMatch(line)) { // format: <key>: <value>
          QString key = regKeyValue.cap(1);
          QString value = regKeyValue.cap(2);
          QByteArray lineStringStart = indentString(line);
          int propertyIndentLevel = indentLevel(line);
          ++it;
          while( it != lines.end() ) {
            QByteArray& line = *it;
            int actualIndentLevel = indentLevel(line);
            if( actualIndentLevel>propertyIndentLevel && line.startsWith(lineStringStart) ) {
              value += "\n" + line.trimmed();
              ++it;
            } else
              break;
          }
          qDebug() << key << "=" << value;
          if(key == "Gamma") {
            monitor->gamma = value;
          }
          else if(key == "Brightness") {
            monitor->brightness = value;
          }
          else if(key == "EDID") {
            monitor->edid = value ;
            // Get vendor
            QString hex = value.replace("\n","").replace(" ","").toLower();
            int vendorPosStart = hex.indexOf("fc00");
            if(vendorPosStart>0) {
            int vendorPosEnd = hex.indexOf("00", vendorPosStart+4);
              QString vendorHex = hex.mid(vendorPosStart+4, vendorPosEnd-vendorPosStart-4);
              QByteArray vendor = QByteArray::fromHex(vendorHex.toLocal8Bit()).trimmed();
              // qDebug() << "Vendor:" << vendorHex << "VendorHex" << vendor ;
              monitor->vendor = vendor;
            }
          }
          continue;
        } // End format: <key>: <value>
        else { // this line is not key:value
        }
      }
    }
    if( it != lines.end() ) ++it;
  }

  if(monitor) // this should not happen unless a parsing error happens
    delete monitor;

  resolvePositions(monitors);

  return monitors;
}

bool XRandRBackend::setMonitorsSettings(const QList<MonitorSettings*> monitors) {
  QString cmd = getCommand(monitors);
  QProcess process;
  process.start(cmd);
  process.waitForFinished();
  return process.exitCode() == 0;
}

QString XRandRBackend::getCommand(const QList<MonitorSettings*> monitors)  {
  QMap<MonitorSettings::Position, QString> positions;

  positions[MonitorSettings::Left] = "--left-of";
  positions[MonitorSettings::Right] = "--right-of";
  positions[MonitorSettings::Above] = "--above";
  positions[MonitorSettings::Bellow] = "--below";

  QByteArray cmd = "xrandr";

  foreach(MonitorSettings * monitor, monitors) {
    cmd += " --output ";
    cmd.append(monitor->name);
    cmd.append(' ');

    // if the monitor is turned on
    if(monitor->enabledOk) {
      QString sel_res = monitor->currentMode;
      QString sel_rate = monitor->currentRate;

      if(sel_res == QObject::tr("Auto"))   // auto resolution
        cmd.append("--auto");
      else {
        cmd.append("--mode ");
        cmd.append(sel_res);
        if(sel_rate != QObject::tr("Auto")) {  // not auto refresh rate
          cmd.append(" --rate ");
          cmd.append(sel_rate);
        }
      }
      if(monitor->position != MonitorSettings::None) {
        cmd.append(" ");
        cmd.append(positions[monitor->position]);
        cmd.append(" ");
        cmd.append(monitor->positionRelativeToOutput);
      } else
          cmd.append(" --pos 0x0");
      if(monitor->primaryOk)
        cmd.append(" --primary");
      cmd.append(" --brightness ");
      cmd.append(monitor->brightness);
      cmd.append(" --gamma ");
      cmd.append(monitor->gamma);
    }
    else    // turn off
      cmd.append("--off");
  }

  qDebug() << "cmd:" << cmd;
  return cmd;
}

// resolve the position relationship among the montors
void XRandRBackend::resolvePositions(QList< MonitorInfo* >& monitors) {
  Q_FOREACH(MonitorInfo * monitor, monitors) {
    MonitorSettings::Position pos;
    MonitorInfo* neighbor = findAdjacentMonitor(monitors, monitor, pos);
    if(neighbor) {
      monitor->position = pos;
      monitor->positionRelativeToOutput = neighbor->name;
    }
  }
}

MonitorInfo* XRandRBackend::findAdjacentMonitor(QList< MonitorInfo* >& monitors, MonitorInfo* monitor, MonitorSettings::Position& pos) {
  MonitorInfo* neighbor = NULL;
  QRect monitorRect = monitor->geometry();
  pos = MonitorSettings::None;
  Q_FOREACH(MonitorInfo * mon, monitors) {
    if(mon == monitor || mon->positionRelativeToOutput == monitor->name)
      continue;
    QRect neighborRect = mon->geometry();
    if(monitorRect.top() == neighborRect.top()) {
      if((monitorRect.right() + 1) == neighborRect.left()) { // monitor is at left of neighbor
        pos = MonitorSettings::Left;
        neighbor = mon;
        break;
      }
      else if(monitorRect.left() == (neighborRect.right() + 1)) { // monitor is at right of neighbor
        pos = MonitorSettings::Right;
        neighbor = mon;
        break;
      }
    }
    if(monitorRect.left() == neighborRect.left()) {
      if((monitorRect.bottom() + 1) == neighborRect.top()) { // monitor is above neighbor
        pos = MonitorSettings::Above;
        neighbor = mon;
        break;
      }
      else if(monitorRect.top() == (neighborRect.bottom() + 1)) { // monitor is below neighbor
        pos = MonitorSettings::Bellow;
        neighbor = mon;
        break;
      }
    }
  }
  return neighbor;
}
<|endoftext|>