You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
6.4KB

  1. #pragma once
  2. #include <stdarg.h>
  3. #include <vector>
  4. #include <common.hpp>
  5. namespace rack {
  6. /** Supplemental `std::string` functions */
  7. namespace string {
  8. /** Converts a printf format string and optional arguments into a std::string.
  9. The wrapper template function below automatically converts all arguments (including format string) from `std::string` to `const char*` as needed.
  10. */
  11. __attribute__((format(printf, 1, 2)))
  12. std::string f(const char* format, ...);
  13. std::string fV(const char* format, va_list args);
  14. // Converts std::string arguments of f() to `const char*`
  15. template<typename T>
  16. T convertFArg(const T& t) {return t;}
  17. inline const char* convertFArg(const std::string& s) {return s.c_str();}
  18. template<typename... Args>
  19. std::string f(Args... args) {
  20. // Allows accessing the original f() above
  21. typedef std::string (*FType)(const char* format, ...);
  22. return FType(f)(convertFArg(args)...);
  23. }
  24. /** Replaces all characters to lowercase letters */
  25. std::string lowercase(const std::string& s);
  26. /** Replaces all characters to uppercase letters */
  27. std::string uppercase(const std::string& s);
  28. /** Removes whitespace from beginning and end of string. */
  29. std::string trim(const std::string& s);
  30. /** Truncates a string to not exceed a number of UTF-8 codepoints. */
  31. std::string truncate(const std::string& s, size_t maxCodepoints);
  32. /** Truncates the beginning of a string to not exceed a number of UTF-8 codepoints. */
  33. std::string truncatePrefix(const std::string& s, size_t maxCodepoints);
  34. /** Truncates and adds "…" to the end of a string, to not exceed a number of UTF-8 codepoints. */
  35. std::string ellipsize(const std::string& s, size_t maxCodepoints);
  36. /** Truncates and adds "…" to the beginning of a string, to not exceed a number of UTF-8 codepoints. */
  37. std::string ellipsizePrefix(const std::string& s, size_t maxCodepoints);
  38. /** Returns whether a string starts with the given substring. */
  39. bool startsWith(const std::string& str, const std::string& prefix);
  40. /** Returns whether a string ends with the given substring. */
  41. bool endsWith(const std::string& str, const std::string& suffix);
  42. /** Converts a byte array to a Base64-encoded string.
  43. https://en.wikipedia.org/wiki/Base64
  44. */
  45. std::string toBase64(const uint8_t* data, size_t dataLen);
  46. std::string toBase64(const std::vector<uint8_t>& data);
  47. /** Converts a Base64-encoded string to a byte array.
  48. Throws std::runtime_error if string is invalid.
  49. */
  50. std::vector<uint8_t> fromBase64(const std::string& str);
  51. struct CaseInsensitiveCompare {
  52. /** Returns whether `a < b` using case-insensitive lexical comparison. */
  53. bool operator()(const std::string& a, const std::string& b) const;
  54. };
  55. /** Joins an container (vector, list, etc) of std::strings with an optional separator string.
  56. */
  57. template <typename TContainer>
  58. std::string join(const TContainer& container, std::string seperator = "") {
  59. std::string s;
  60. bool first = true;
  61. for (const auto& c : container) {
  62. if (!first)
  63. s += seperator;
  64. first = false;
  65. s += c;
  66. }
  67. return s;
  68. }
  69. /** Splits a string into a vector of tokens.
  70. If `maxTokens > 0`, limits the number of tokens.
  71. Tokens do not include the separator string.
  72. Examples:
  73. split("a+b+c", "+") // {"a", "b", "c"}
  74. split("abc", "+") // {"abc"}
  75. split("a++c", "+") // {"a", "", "c"}
  76. split("", "+") // {}
  77. split("abc", "") // throws rack::Exception
  78. */
  79. std::vector<std::string> split(const std::string& s, const std::string& seperator, size_t maxTokens = 0);
  80. /** Formats a UNIX timestamp with a strftime() string. */
  81. std::string formatTime(const char* format, double timestamp);
  82. std::string formatTimeISO(double timestamp);
  83. // Unicode functions
  84. /** Converts a UTF-32 string to a UTF-8 string.
  85. Skips invalid UTF-32 codepoints (greater than 0x10FFFF).
  86. */
  87. std::string UTF32toUTF8(const std::u32string& s32);
  88. /** Converts a UTF-8 string to a UTF-32 string.
  89. Skips invalid, overlong, and surrogate pair UTF-8 sequences.
  90. */
  91. std::u32string UTF8toUTF32(const std::string& s8);
  92. /** Finds the byte index of the next codepoint in a valid UTF-8 string.
  93. i must be the start of a codepoint.
  94. */
  95. size_t UTF8NextCodepoint(const std::string& s8, size_t i);
  96. /** Finds the byte index of the previous codepoint in a valid UTF-8 string.
  97. i must be the start of a codepoint.
  98. */
  99. size_t UTF8PrevCodepoint(const std::string& s8, size_t i);
  100. #if defined ARCH_WIN
  101. /** Performs a Unicode string conversion from UTF-16 to UTF-8.
  102. These are only defined on Windows because the implementation uses Windows' API, and conversion is not needed on other OS's (since everything on Mac and Linux is UTF-8).
  103. std::string and char* variables are considered UTF-8, anywhere in the program.
  104. See https://utf8everywhere.org/ for more information about VCV Rack's philosophy on string encoding, especially section 10 for rules VCV follows for handling text on Windows.
  105. */
  106. std::string UTF16toUTF8(const std::wstring& w);
  107. std::wstring UTF8toUTF16(const std::string& s);
  108. #endif
  109. /** Structured version string, for comparison.
  110. Strings are split into parts by "." and compared lexicographically.
  111. Parts are compared as the following.
  112. If both parts can be parsed as integers (such as "10" and "2"), their integer value is compared (so "10" is greater).
  113. If one part cannot be parsed as an integer (such as "2" and "beta"), the integer part is greater ("2").
  114. If neither part can be parsed as an integer (such as "alpha" and "beta"), the parts are compared as strings in typical lexicographical order.
  115. For example, the following versions are sorted earliest to latest.
  116. 1.a.0
  117. 1.b.0
  118. 1.0.0
  119. 1.0.1
  120. 1.2.0
  121. 1.10.0
  122. 2.0.0
  123. */
  124. struct Version {
  125. std::vector<std::string> parts;
  126. Version() {}
  127. Version(const std::string& s);
  128. Version(const char* s) : Version(std::string(s)) {}
  129. operator std::string() const;
  130. /** Returns whether this version is earlier than `other`. */
  131. bool operator<(const Version& other);
  132. std::string getMajor() const {
  133. return get(parts, 0, "");
  134. }
  135. std::string getMinor() const {
  136. return get(parts, 1, "");
  137. }
  138. std::string getRevision() const {
  139. return get(parts, 2, "");
  140. }
  141. };
  142. /** Returns translation string of the current language setting from `translations/<language>.json`, or English if not found. */
  143. std::string translate(const std::string& id);
  144. /** Returns translation string of the given language, or "" if not found. */
  145. std::string translate(const std::string& id, const std::string& language);
  146. /** Returns ISO 639-1 language codes of loaded translations, sorted by name of language. */
  147. std::vector<std::string> getLanguages();
  148. void init();
  149. } // namespace string
  150. } // namespace rack