support full-width/composite characters and true color palette in terminal (#1386)
[far2l.git] / utils / include / utils.h
blob1e2f381ff3b6c525543f1a2bb5cabc603a3780b7
1 #pragma once
2 #include <string>
3 #include <vector>
4 #include <cstdarg>
5 #include <sys/types.h>
6 #include "cctweaks.h"
7 #include "MatchWildcard.hpp"
8 #include "WideMB.h"
9 #include "Escaping.h"
10 #include "Environment.h"
11 #include "ErrnoSaver.hpp"
12 #include "PlatformConstants.h"
14 #define MAKE_STR(x) _MAKE_STR(x)
15 #define _MAKE_STR(x) #x
17 template <class C> static size_t tzlen(const C *ptz)
19 const C *etz;
20 for (etz = ptz; *etz; ++etz);
21 return (etz - ptz);
24 template <class C> static size_t tnzlen(const C *ptz, size_t n)
26 size_t i;
27 for (i = 0; i < n && ptz[i]; ++i);
28 return i;
32 unsigned long htoul(const char *str, size_t maxlen = (size_t)-1);
33 unsigned long atoul(const char *str, size_t maxlen = (size_t)-1);
35 // converts given hex digit to value between 0x0 and 0xf
36 // in case of error returns 0xff
37 template <class CHAR_T>
38 unsigned char ParseHexDigit(const CHAR_T hex)
40 if (hex >= (CHAR_T)'0' && hex <= (CHAR_T)'9')
41 return hex - (CHAR_T)'0';
42 if (hex >= (CHAR_T)'a' && hex <= (CHAR_T)'f')
43 return 10 + hex - (CHAR_T)'a';
44 if (hex >= (CHAR_T)'A' && hex <= (CHAR_T)'F')
45 return 10 + hex - (CHAR_T)'A';
47 return 0xff;
50 // converts given two hex digits to value between 0x0 and 0xff
51 // in case of error returns 0
52 template <class CHAR_T>
53 unsigned char ParseHexByte(const CHAR_T *hex)
55 const unsigned char rh = ParseHexDigit(hex[0]);
56 const unsigned char rl = ParseHexDigit(hex[1]);
57 if (rh == 0xff || rl == 0xff) {
58 return 0;
60 return ((rh << 4) | rl);
64 // converts given value between 0x0 and 0xf to lowercased hex digit
65 // in case of error returns 0
66 char MakeHexDigit(const unsigned char c);
68 template <class StrT>
69 size_t StrStartsFrom(const StrT &haystack, const typename StrT::value_type needle)
71 return (!haystack.empty() && haystack.front() == needle) ? 1 : 0;
74 template <class CharT>
75 size_t StrStartsFrom(const CharT *haystack, const CharT *needle)
77 size_t i;
78 for (i = 0; needle[i]; ++i) {
79 if (haystack[i] != needle[i])
80 return 0;
82 return i;
85 template <class StrT>
86 size_t StrStartsFrom(const StrT &haystack, const typename StrT::value_type *needle)
88 size_t i;
89 for (i = 0; needle[i]; ++i) {
90 if (i >= haystack.size() || haystack[i] != needle[i])
91 return 0;
93 return i;
96 template <class StrT>
97 size_t StrEndsBy(const StrT &haystack, const typename StrT::value_type *needle)
99 const size_t l = tzlen(needle);
100 if (!l || haystack.size() < l)
101 return 0;
103 return memcmp(haystack.c_str() + haystack.size() - l, needle, l * sizeof(typename StrT::value_type)) ? 0 : l;
107 const std::string &GetMyHome();
109 void InMyPathChanged(); // NOT thread safe, can be called only before any concurrent use of InMy...
110 std::string InMyConfig(const char *subpath = NULL, bool create_path = true);
111 std::string InMyCache(const char *subpath = NULL, bool create_path = true);
112 std::string InMyTemp(const char *subpath = NULL);
114 bool IsPathIn(const wchar_t *path, const wchar_t *root);
116 bool TranslateInstallPath_Bin2Share(std::wstring &path);
117 bool TranslateInstallPath_Bin2Share(std::string &path);
118 bool TranslateInstallPath_Lib2Share(std::wstring &path);
119 bool TranslateInstallPath_Lib2Share(std::string &path);
120 bool TranslateInstallPath_Share2Lib(std::wstring &path);
121 bool TranslateInstallPath_Share2Lib(std::string &path);
122 bool TranslateInstallPath_Bin2Lib(std::string &path);
125 // converts /some/path/to/filename.extension into form "filename@HASH"
126 // where HASH produced from path and extension and also filename has
127 // some special for ini files chars replaced by '_' and affected HASH
128 void FilePathHashSuffix(std::string &pathname);
130 void CheckedCloseFD(int &fd);
131 void CheckedCloseFDPair(int *fd);
133 size_t WriteAll(int fd, const void *data, size_t len, size_t chunk = (size_t)-1);
134 size_t ReadAll(int fd, void *data, size_t len);
135 ssize_t ReadWritePiece(int fd_src, int fd_dst);
138 int pipe_cloexec(int pipedes[2]);
140 void PutZombieUnderControl(pid_t pid);
142 void AbbreviateString(std::string &path, size_t needed_length);
144 const wchar_t *FileSizeToFractionAndUnits(unsigned long long &value);
145 std::wstring FileSizeString(unsigned long long value);
146 std::wstring ThousandSeparatedString(unsigned long long value);
148 std::string StrPrintfV(const char *format, va_list args);
149 std::string FN_PRINTF_ARGS(1) StrPrintf(const char *format, ...);
151 template <class CharT>
152 std::basic_string<CharT> EnsureNoSlashAtEnd(std::basic_string<CharT> str, CharT slash = '/')
154 for (size_t p = str.size(); p && str[p - 1] == slash; ) {
155 str.resize(--p);
157 return str;
160 template <class CharT>
161 std::basic_string<CharT> EnsureNoSlashAtNestedEnd(std::basic_string<CharT> str, CharT slash = '/')
163 for (size_t p = str.size(); p > 1 && str[p - 1] == slash; ) {
164 str.resize(--p);
166 return str;
170 template <class CharT>
171 std::basic_string<CharT> EnsureSlashAtEnd(std::basic_string<CharT> str, CharT slash = '/')
173 const size_t p = str.size();
174 if (!p || str[p - 1] != slash) {
175 str+= slash;
177 return str;
180 template <class CharT>
181 std::basic_string<CharT> ExtractFilePath(std::basic_string<CharT> str, CharT slash = '/')
183 const size_t p = str.rfind(slash);
184 str.resize( (p != std::string::npos) ? p : 0);
185 return str;
189 template <class CharT>
190 std::basic_string<CharT> ExtractFileName(std::basic_string<CharT> str, CharT slash = '/')
192 const size_t p = str.rfind(slash);
193 return (p != std::string::npos) ? str.substr( p + 1, str.size() - (p + 1) ) : str;
197 template <class CharT>
198 bool CutToSlash(std::basic_string<CharT> &str, bool include = false)
200 size_t p = str.rfind('/');
201 if (p == std::string::npos)
202 return false;
204 str.resize(include ? p + 1 : p);
205 return true;
208 template <class CharT>
209 void ReplaceFileNamePart(std::basic_string<CharT> &str, const CharT *replacement)
211 if (CutToSlash(str, true)) {
212 str+= replacement;
213 } else {
214 str = replacement;
219 template <class CharT>
220 void StrExplode(std::vector<std::basic_string<CharT> > &out, const std::basic_string<CharT> &str, const CharT *divs)
222 for (size_t i = 0, j = 0; i <= str.size(); ++i) {
223 const CharT *d = divs;
224 if (i != str.size()) {
225 for (; *d && *d != str[i]; ++d);
227 if (*d) {
228 if (i > j) {
229 out.emplace_back(str.substr(j, i - j));
231 j = i + 1;
236 template <class CharT>
237 void StrTrimRight(std::basic_string<CharT> &str, const char *spaces = " \t")
239 while (!str.empty() && unsigned(str.back()) <= 0x7f && strchr(spaces, str.back()) != NULL) {
240 str.pop_back();
243 template <class CharT>
244 void StrTrimLeft(std::basic_string<CharT> &str, const char *spaces = " \t")
246 while (!str.empty() && unsigned(str[0]) <= 0x7f && strchr(spaces, str[0]) != NULL) {
247 str.erase(0, 1);
251 template <class CharT>
252 void StrTrim(std::basic_string<CharT> &str, const char *spaces = " \t")
254 StrTrimRight(str, spaces);
255 StrTrimLeft(str, spaces);
259 template <typename HaystackT, typename NeedlesT>
260 static const HaystackT *FindAnyOfChars(const HaystackT *haystack, const NeedlesT *needles)
262 for(; *haystack; ++haystack)
264 for(size_t i = 0; needles[i]; ++i)
266 if (*haystack == (HaystackT)needles[i])
267 return haystack;
270 return nullptr;
273 template <typename HaystackIT, typename NeedlesT>
274 static HaystackIT FindAnyOfChars(HaystackIT haystack, const HaystackIT haystack_end, const NeedlesT *needles)
276 for(; haystack != haystack_end; ++haystack)
278 for(size_t i = 0; needles[i]; ++i)
280 if (*haystack == (decltype(*haystack))needles[i])
281 return haystack;
284 return nullptr;
287 bool CaseIgnoreEngStrMatch(const std::string &str1, const std::string &str2);
288 bool CaseIgnoreEngStrMatch(const char *str1, const char *str2, size_t len);
289 const char *CaseIgnoreEngStrChr(const char c, const char *str, size_t len);
292 template <class POD_T>
293 void ZeroFill(POD_T &dst)
295 static_assert ( std::is_pod<POD_T>::value, "ZeroFill should be used with POD types only");
296 static_assert ( sizeof(dst) != sizeof(void *), "ZeroFill should not be used with pointers");
297 memset(&dst, 0, sizeof(dst));
300 template <class STRING_T, typename ARRAY_T>
301 void StrAssignArray(STRING_T &s, const ARRAY_T &a)
303 static_assert ( sizeof(a) != sizeof(void *), "StrAssignArray should be used with arrays but not pointers");
304 s.assign(a, tnzlen(a, ARRAYSIZE(a)));
307 template <class STRING_T, typename ARRAY_T>
308 void StrAppendArray(STRING_T &s, const ARRAY_T &a)
310 static_assert ( sizeof(a) != sizeof(void *), "StrAppendArray should be used with arrays but not pointers");
311 s.append(a, tnzlen(a, ARRAYSIZE(a)));
315 template <class STRING_T, typename ARRAY_T>
316 bool StrMatchArray(STRING_T &s, const ARRAY_T &a)
318 static_assert ( sizeof(a) != sizeof(void *), "StrMatchArray should be used with arrays but not pointers");
319 const size_t l = tnzlen(a, ARRAYSIZE(a));
320 return s.size() == l && s.compare(0, std::string::npos, a, l) == 0;
323 template <typename ARRAY_T, class CHAR_T>
324 void ArrayCpyZ(ARRAY_T &dst, const CHAR_T *src)
326 static_assert ( sizeof(dst) != sizeof(void *), "ArrayCpyZ should be used with arrays but not pointers");
327 size_t i;
328 for (i = 0; src[i] && i + 1 < ARRAYSIZE(dst); ++i) {
329 dst[i] = src[i];
331 dst[i] = 0;
334 bool POpen(std::string &result, const char *command);
335 bool POpen(std::vector<std::wstring> &result, const char *command);
337 #define DBGLINE fprintf(stderr, "%d %d @%s\n", getpid(), __LINE__, __FILE__)
339 bool IsCharFullWidth(wchar_t c);
340 bool IsCharPrefix(wchar_t c);
341 bool IsCharSuffix(wchar_t c);
342 bool IsCharXxxfix(wchar_t c);