fix build
[far2l.git] / utils / include / utils.h
blob3660a32046edfd2efb6e80bb21a8a3e4e5674546
1 #pragma once
2 #include <string>
3 #include <vector>
4 #include <cstdarg>
5 #include <sys/types.h>
6 #include <string.h>
7 #include "cctweaks.h"
8 #include "BitTwiddle.hpp"
9 #include "MatchWildcard.hpp"
10 #include "WideMB.h"
11 #include "Escaping.h"
12 #include "Environment.h"
13 #include "ErrnoSaver.hpp"
14 #include "PlatformConstants.h"
15 #include "debug.h"
16 #include "IntStrConv.h"
18 #define MAKE_STR(x) _MAKE_STR(x)
19 #define _MAKE_STR(x) #x
21 #ifdef __APPLE__
22 # define st_mtim st_mtimespec
23 # define st_ctim st_ctimespec
24 # define st_atim st_atimespec
25 #endif
27 template <class C> static size_t tzlen(const C *ptz)
29 const C *etz;
30 for (etz = ptz; *etz; ++etz);
31 return (etz - ptz);
34 template <class C> static size_t tnzlen(const C *ptz, size_t n)
36 size_t i;
37 for (i = 0; i < n && ptz[i]; ++i);
38 return i;
41 // converts given hex digit to value between 0x0 and 0xf
42 // in case of error returns 0xff
43 template <class CHAR_T>
44 unsigned char ParseHexDigit(const CHAR_T hex)
46 if (hex >= (CHAR_T)'0' && hex <= (CHAR_T)'9')
47 return hex - (CHAR_T)'0';
48 if (hex >= (CHAR_T)'a' && hex <= (CHAR_T)'f')
49 return 10 + hex - (CHAR_T)'a';
50 if (hex >= (CHAR_T)'A' && hex <= (CHAR_T)'F')
51 return 10 + hex - (CHAR_T)'A';
53 return 0xff;
56 // converts given two hex digits to value between 0x0 and 0xff
57 // in case of error returns 0
58 template <class CHAR_T>
59 unsigned char ParseHexByte(const CHAR_T *hex)
61 const unsigned char rh = ParseHexDigit(hex[0]);
62 const unsigned char rl = ParseHexDigit(hex[1]);
63 if (rh == 0xff || rl == 0xff) {
64 return 0;
66 return ((rh << 4) | rl);
70 // converts given value between 0x0 and 0xf to lowercased hex digit
71 // in case of error returns 0
72 char MakeHexDigit(const unsigned char c);
74 template <class StrT>
75 size_t StrStartsFrom(const StrT &haystack, const typename StrT::value_type needle)
77 return (!haystack.empty() && haystack.front() == needle) ? 1 : 0;
80 template <class CharT>
81 size_t StrStartsFrom(const CharT *haystack, const CharT *needle)
83 size_t i;
84 for (i = 0; needle[i]; ++i) {
85 if (haystack[i] != needle[i])
86 return 0;
88 return i;
91 template <class StrT>
92 size_t StrStartsFrom(const StrT &haystack, const typename StrT::value_type *needle)
94 size_t i;
95 for (i = 0; needle[i]; ++i) {
96 if (i >= haystack.size() || haystack[i] != needle[i])
97 return 0;
99 return i;
102 template <class StrT>
103 size_t StrEndsBy(const StrT &haystack, const typename StrT::value_type *needle)
105 const size_t l = tzlen(needle);
106 if (!l || haystack.size() < l)
107 return 0;
109 return memcmp(haystack.c_str() + haystack.size() - l, needle, l * sizeof(typename StrT::value_type)) ? 0 : l;
112 template <class StrT>
113 size_t StrEndsBy(const StrT &haystack, const typename StrT::value_type needle)
115 return !haystack.empty() && haystack.back() == needle;
119 const std::string &GetMyHome();
121 void InMyPathChanged(); // NOT thread safe, can be called only before any concurrent use of InMy...
122 std::string InMyConfig(const char *subpath = NULL, bool create_path = true);
123 std::string InMyCache(const char *subpath = NULL, bool create_path = true);
124 std::string InMyTemp(const char *subpath = NULL);
126 bool IsPathIn(const wchar_t *path, const wchar_t *root);
128 bool TranslateInstallPath_Bin2Share(std::wstring &path);
129 bool TranslateInstallPath_Bin2Share(std::string &path);
130 bool TranslateInstallPath_Lib2Share(std::wstring &path);
131 bool TranslateInstallPath_Lib2Share(std::string &path);
132 bool TranslateInstallPath_Share2Lib(std::wstring &path);
133 bool TranslateInstallPath_Share2Lib(std::string &path);
134 bool TranslateInstallPath_Bin2Lib(std::string &path);
137 // converts /some/path/to/filename.extension into form "filename@HASH"
138 // where HASH produced from path and extension and also filename has
139 // some special for ini files chars replaced by '_' and affected HASH
140 void FilePathHashSuffix(std::string &pathname);
142 void CheckedCloseFD(int &fd);
143 void CheckedCloseFDPair(int *fd);
145 void MakeFDBlocking(int fd);
146 void MakeFDNonBlocking(int fd);
147 void MakeFDCloexec(int fd);
148 void MakeFDNonCloexec(int fd);
149 void HintFDSequentialAccess(int fd);
151 size_t WriteAll(int fd, const void *data, size_t len, size_t chunk = (size_t)-1);
152 size_t ReadAll(int fd, void *data, size_t len);
153 ssize_t ReadWritePiece(int fd_src, int fd_dst);
155 bool ReadWholeFile(const char *path, std::string &result, size_t limit = (size_t)-1);
157 int pipe_cloexec(int pipedes[2]);
159 void PutZombieUnderControl(pid_t pid);
161 void AbbreviateString(std::string &path, size_t needed_length);
163 const wchar_t *FileSizeToFractionAndUnits(unsigned long long &value);
164 std::wstring FileSizeString(unsigned long long value);
165 std::wstring ThousandSeparatedString(unsigned long long value);
167 std::string StrPrintfV(const char *format, va_list args);
168 std::string FN_PRINTF_ARGS(1) StrPrintf(const char *format, ...);
170 template <class CharT>
171 std::basic_string<CharT> EnsureNoSlashAtEnd(std::basic_string<CharT> str, CharT slash = '/')
173 for (size_t p = str.size(); p && str[p - 1] == slash; ) {
174 str.resize(--p);
176 return str;
179 template <class CharT>
180 std::basic_string<CharT> EnsureNoSlashAtNestedEnd(std::basic_string<CharT> str, CharT slash = '/')
182 for (size_t p = str.size(); p > 1 && str[p - 1] == slash; ) {
183 str.resize(--p);
185 return str;
189 template <class CharT>
190 std::basic_string<CharT> EnsureSlashAtEnd(std::basic_string<CharT> str, CharT slash = '/')
192 const size_t p = str.size();
193 if (!p || str[p - 1] != slash) {
194 str+= slash;
196 return str;
199 template <class CharT>
200 std::basic_string<CharT> ExtractFilePath(std::basic_string<CharT> str, CharT slash = '/')
202 const size_t p = str.rfind(slash);
203 str.resize( (p != std::string::npos) ? p : 0);
204 return str;
208 template <class CharT>
209 std::basic_string<CharT> ExtractFileName(std::basic_string<CharT> str, CharT slash = '/')
211 const size_t p = str.rfind(slash);
212 return (p != std::string::npos) ? str.substr( p + 1, str.size() - (p + 1) ) : str;
216 template <class CharT>
217 bool CutToSlash(std::basic_string<CharT> &str, bool include = false)
219 size_t p = str.rfind('/');
220 if (p == std::string::npos)
221 return false;
223 str.resize(include ? p + 1 : p);
224 return true;
227 template <class CharT>
228 void ReplaceFileNamePart(std::basic_string<CharT> &str, const CharT *replacement)
230 if (CutToSlash(str, true)) {
231 str+= replacement;
232 } else {
233 str = replacement;
238 template <class CharT>
239 void StrExplode(std::vector<std::basic_string<CharT> > &out, const std::basic_string<CharT> &str, const CharT *divs)
241 for (size_t i = 0, j = 0; i <= str.size(); ++i) {
242 const CharT *d = divs;
243 if (i != str.size()) {
244 for (; *d && *d != str[i]; ++d);
246 if (*d) {
247 if (i > j) {
248 out.emplace_back(str.substr(j, i - j));
250 j = i + 1;
255 template <class CharT>
256 void StrTrimRight(std::basic_string<CharT> &str, const char *spaces = " \t")
258 while (!str.empty() && unsigned(str.back()) <= 0x7f && strchr(spaces, str.back()) != NULL) {
259 str.pop_back();
262 template <class CharT>
263 void StrTrimLeft(std::basic_string<CharT> &str, const char *spaces = " \t")
265 while (!str.empty() && unsigned(str[0]) <= 0x7f && strchr(spaces, str[0]) != NULL) {
266 str.erase(0, 1);
270 template <class CharT>
271 void StrTrim(std::basic_string<CharT> &str, const char *spaces = " \t")
273 StrTrimRight(str, spaces);
274 StrTrimLeft(str, spaces);
278 template <typename HaystackT, typename NeedlesT>
279 static const HaystackT *FindAnyOfChars(const HaystackT *haystack, const NeedlesT *needles)
281 for(; *haystack; ++haystack)
283 for(size_t i = 0; needles[i]; ++i)
285 if (*haystack == (HaystackT)needles[i])
286 return haystack;
289 return nullptr;
292 template <typename HaystackIT, typename NeedlesT>
293 static HaystackIT FindAnyOfChars(HaystackIT haystack, const HaystackIT haystack_end, const NeedlesT *needles)
295 for(; haystack != haystack_end; ++haystack)
297 for(size_t i = 0; needles[i]; ++i)
299 if (*haystack == (decltype(*haystack))needles[i])
300 return haystack;
303 return nullptr;
306 bool CaseIgnoreEngStrMatch(const std::string &str1, const std::string &str2);
307 bool CaseIgnoreEngStrMatch(const char *str1, const char *str2, size_t len);
308 const char *CaseIgnoreEngStrChr(const char c, const char *str, size_t len);
310 template <class STRING_T, typename ARRAY_T>
311 void StrAssignArray(STRING_T &s, const ARRAY_T &a)
313 static_assert ( sizeof(a) != sizeof(void *), "StrAssignArray should be used with arrays but not pointers");
314 s.assign(a, tnzlen(a, ARRAYSIZE(a)));
317 template <class STRING_T, typename ARRAY_T>
318 void StrAppendArray(STRING_T &s, const ARRAY_T &a)
320 static_assert ( sizeof(a) != sizeof(void *), "StrAppendArray should be used with arrays but not pointers");
321 s.append(a, tnzlen(a, ARRAYSIZE(a)));
325 template <class STRING_T, typename ARRAY_T>
326 bool StrMatchArray(STRING_T &s, const ARRAY_T &a)
328 static_assert ( sizeof(a) != sizeof(void *), "StrMatchArray should be used with arrays but not pointers");
329 const size_t l = tnzlen(a, ARRAYSIZE(a));
330 return s.size() == l && s.compare(0, std::string::npos, a, l) == 0;
333 template <typename ARRAY_T, class CHAR_T>
334 void ArrayCpyZ(ARRAY_T &dst, const CHAR_T *src)
336 static_assert ( sizeof(dst) != sizeof(void *), "ArrayCpyZ should be used with arrays but not pointers");
337 size_t i;
338 for (i = 0; src[i] && i + 1 < ARRAYSIZE(dst); ++i) {
339 dst[i] = src[i];
341 dst[i] = 0;
345 bool POpen(std::string &result, const char *command);
346 bool POpen(std::vector<std::wstring> &result, const char *command);
348 #define DBGLINE fprintf(stderr, "%d %d @%s\n", getpid(), __LINE__, __FILE__)
350 bool IsCharFullWidth(wchar_t c);
351 bool IsCharPrefix(wchar_t c);
352 bool IsCharSuffix(wchar_t c);
353 bool IsCharXxxfix(wchar_t c);
355 void FN_NORETURN FN_PRINTF_ARGS(1) ThrowPrintf(const char *format, ...); // throws std::runtime_error with formatted .what()