1 #ifndef _META_H
2 #define _META_H
3
4 #include "config.h"
5
6 #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE < 200112L)
7 #undef _POSIX_C_SOURCE
8 #endif
9 #ifndef _POSIX_C_SOURCE
10 #define _POSIX_C_SOURCE 200112L
11 #endif
12
13 #include <string>
14 #include <map>
15 #include <set>
16 #include <vector>
17 #include <deque>
18 #include <limits>
19 #include <cstdio>
20 #include <ctime>
21 #include <cstring>
22 #include <functional>
23
24 #include <fcntl.h>
25 #include <pthread.h>
26 #include <strings.h>
27 #include <cstdlib>
28 #include <errno.h>
29
30 #define EXTREME_MEMORY_SAVING false
31
32
33 #ifdef _MSC_VER
34 #define __func__ __FUNCTION__
35 #endif
36
37 #if __GNUC__ == 4 && __GNUC_MINOR__ < 8 && !defined(__clang__)
38 #define COMPATGCC47
39 #define EMPLACE_PAIR_COMPAT(M,K,V) if((M).find(K) == (M).end()) (M).insert(std::make_pair(K,V))
40 #else
41 #define EMPLACE_PAIR_COMPAT(M,K,V) (M).emplace(K,V)
42 #endif
43
44 // little STFU helper
45 #if __GNUC__ >= 7
46 #define __just_fall_through [[fallthrough]]
47 #else
48 #define __just_fall_through
49 #endif
50
51 namespace acng
52 {
53
54 class acbuf;
55
56 typedef std::string mstring;
57 typedef const std::string cmstring;
58
59 typedef std::pair<mstring, mstring> tStrPair;
60 typedef std::vector<mstring> tStrVec;
61 typedef std::set<mstring> tStrSet;
62 typedef std::deque<mstring> tStrDeq;
63 typedef mstring::size_type tStrPos;
64 const static tStrPos stmiss(cmstring::npos);
65 typedef unsigned short USHORT;
66 typedef unsigned char UCHAR;
67 typedef const char * LPCSTR;
68 typedef std::pair<LPCSTR, size_t> tPtrLen;
69 #define citer const_iterator
70
71 #define CPATHSEPUNX '/'
72 #define SZPATHSEPUNIX "/"
73 #define CPATHSEPWIN '\\'
74 #define SZPATHSEPWIN "\\"
75 extern cmstring sPathSep, sPathSepUnix, sDefPortHTTP, sDefPortHTTPS, hendl;
76
77 extern cmstring FAKEDATEMARK;
78
79 #ifdef WINDOWS
80 #define WIN32
81 #define SZPATHSEP SZPATHSEPWIN
82 #define CPATHSEP CPATHSEPWIN
83 #define szNEWLINE "\r\n"
84 #else
85 #define SZPATHSEP SZPATHSEPUNIX
86 #define CPATHSEP CPATHSEPUNX
87 #define szNEWLINE "\n"
88 #endif
89
90 // some alternative versions of these flags
91
92 #ifndef O_NONBLOCK
93 #ifdef NOBLOCK
94 #define O_NONBLOCK NOBLOCK
95 #else
96 #ifdef O_NDELAY
97 #define O_NONBLOCK O_NDELAY
98 #endif
99 #endif
100 #endif
101
102 #ifndef O_NONBLOCK
103 #error "Unknown how to configure non-blocking mode (O_NONBLOCK) on this system"
104 #endif
105
106 //#define PATHSEP "/"
107 int getUUID();
108
109 #define SPACECHARS " \f\n\r\t\v"
110
111 #ifdef COMPATGCC47
112 class tStrMap : public std::map<mstring, mstring>
113 {
114 public:
emplace(cmstring & key,cmstring & value)115 void emplace(cmstring& key, cmstring& value)
116 {
117 EMPLACE_PAIR_COMPAT(*this, key, value);
118 }
119 };
120 #else
121 typedef std::map<mstring, mstring> tStrMap;
122 #endif
123
124 inline void trimFront(mstring &s, LPCSTR junk=SPACECHARS)
125 {
126 mstring::size_type pos = s.find_first_not_of(junk);
127 if(pos != 0)
128 s.erase(0, pos);
129 }
130
131 inline void trimBack(mstring &s, LPCSTR junk=SPACECHARS)
132 {
133 mstring::size_type pos = s.find_last_not_of(junk);
134 s.erase(pos+1);
135 }
136
137 inline void trimString(mstring &s, LPCSTR junk=SPACECHARS)
138 {
139 trimBack(s, junk);
140 trimFront(s, junk);
141 }
142
143 #define trimLine(x) { trimFront(x); trimBack(x); }
144
145 #define startsWith(where, what) (0==(where).compare(0, (what).size(), (what)))
146 #define endsWith(where, what) ((where).size()>=(what).size() && \
147 0==(where).compare((where).size()-(what).size(), (what).size(), (what)))
148 #define startsWithSz(where, what) (0==(where).compare(0, sizeof((what))-1, (what)))
149 #define endsWithSzAr(where, what) ((where).size()>=(sizeof((what))-1) && \
150 0==(where).compare((where).size()-(sizeof((what))-1), (sizeof((what))-1), (what)))
151 #define stripSuffix(where, what) if(endsWithSzAr(where, what)) where.erase(where.size()-sizeof(what)+1);
152 #define stripPrefixChars(where, what) where.erase(0, where.find_first_not_of(what))
153
154 #define setIfNotEmpty(where, cand) { if(where.empty() && !cand.empty()) where = cand; }
155 #define setIfNotEmpty2(where, cand, alt) { if(where.empty()) { if(!cand.empty()) where = cand; else where = alt; } }
156
157 mstring GetBaseName(cmstring &in);
158 mstring GetDirPart(cmstring &in);
159 tStrPair SplitDirPath(cmstring& in);
160
161 LPCSTR GetTypeSuffix(cmstring& s);
162
163 void trimProto(mstring & sUri);
164 tStrPos findHostStart(const mstring & sUri);
165
166 #ifndef _countof
167 #define _countof(x) sizeof(x)/sizeof(x[0])
168 #endif
169
170 #define WITHLEN(x) x, (_countof(x)-1)
171 #define MAKE_PTR_0_LEN(x) x, 0, (_countof(x)-1)
172
173 // there is memchr and strpbrk but nothing like the last one acting on specified RAW memory range
mempbrk(LPCSTR membuf,char const * const needles,size_t len)174 static inline LPCSTR mempbrk (LPCSTR membuf, char const * const needles, size_t len)
175 {
176 for(LPCSTR pWhere=membuf ; pWhere<membuf+len ; pWhere++)
177 for(LPCSTR pWhat=needles; *pWhat ; pWhat++)
178 if(*pWhat==*pWhere)
179 return pWhere;
180 return nullptr;
181 }
182
183 // Sometimes I miss Perl...
184 tStrVec::size_type Tokenize(cmstring &in, const char* sep, tStrVec & out, bool bAppend=false, mstring::size_type nStartOffset=0);
185 /*inline void Join(mstring &out, const mstring & sep, const tStrVec & tokens)
186 {out.clear(); if(tokens.empty()) return; for(const auto& tok: tokens)out+=(sep + tok);}
187 */
188 void StrSubst(mstring &contents, const mstring &from, const mstring &to, tStrPos start=0);
189
190 // TODO: __attribute__((externally_visible))
191 bool ParseKeyValLine(const mstring & sIn, mstring & sOutKey, mstring & sOutVal);
192 #define keyEq(a, b) (0 == strcasecmp((a), (b).c_str()))
193
194 extern cmstring PROT_PFX_HTTPS, PROT_PFX_HTTP;
195
196 class tHttpUrl
197 {
198
199 private:
200 mstring sPort;
201
202 public:
203 bool SetHttpUrl(cmstring &uri, bool unescape = true);
204 mstring ToURI(bool bEscaped) const;
205 mstring sHost, sPath, sUserPass;
206
207 bool bSSL=false;
GetProtoPrefix()208 inline cmstring & GetProtoPrefix() const
209 {
210 return bSSL ? PROT_PFX_HTTPS : PROT_PFX_HTTP;
211 }
212
213 tHttpUrl & operator=(const tHttpUrl &a)
214 {
215 sHost = a.sHost;
216 sPort = a.sPort;
217 sPath = a.sPath;
218 sUserPass = a.sUserPass;
219 bSSL = a.bSSL;
220 return *this;
221 }
222 bool operator==(const tHttpUrl &a) const
223 {
224 return a.sHost == sHost && a.sPort == sPort && a.sPath == sPath
225 && a.sUserPass == sUserPass && a.bSSL == bSSL;
226 }
227 ;bool operator!=(const tHttpUrl &a) const
228 {
229 return !(a == *this);
230 }
clear()231 inline void clear()
232 {
233 sHost.clear();
234 sPort.clear();
235 sPath.clear();
236 sUserPass.clear();
237 bSSL = false;
238 }
GetDefaultPortForProto()239 inline cmstring& GetDefaultPortForProto() const {
240 return bSSL ? sDefPortHTTPS : sDefPortHTTP;
241 }
GetPort()242 inline cmstring& GetPort() const { return !sPort.empty() ? sPort : GetDefaultPortForProto(); }
243
tHttpUrl(cmstring & host,cmstring & port,bool ssl)244 inline tHttpUrl(cmstring &host, cmstring& port, bool ssl) :
245 sPort(port), sHost(host), bSSL(ssl)
246 {
247 }
248 inline tHttpUrl() =default;
249 // evil method that should only be called for specific purposes in certain locations
NormalizePath()250 tHttpUrl* NormalizePath() { StrSubst(sPath, "//", "/"); return this; }
251 };
252
253 #define POKE(x) for(;;) { ssize_t n=write(x, "", 1); if(n>0 || (EAGAIN!=errno && EINTR!=errno)) break; }
254
255 #define MIN_VAL(x) (std::numeric_limits< x >::min())
256 #define MAX_VAL(x) (std::numeric_limits< x >::max())
257
258 void appendLong(mstring &s, long val);
259
260 mstring BytesToHexString(const uint8_t b[], unsigned short binLength);
261 bool CsAsciiToBin(LPCSTR a, uint8_t b[], unsigned short binLength);
262
263 typedef const unsigned char CUCHAR;
264 bool CsEqual(LPCSTR a, uint8_t b[], unsigned short binLength);
265
266 #if SIZEOF_LONG == 8
267 // _FILE_OFFSET_BITS mostly irrelevant. But if it's set, watch out for user's "experiments".
268 #if _FILE_OFFSET_BITS == 32
269 #error Unsupported: _FILE_OFFSET_BITS == 32 with large long size
270 #else
271 #define OFF_T_FMT "%" PRId64
272 #endif
273
274 #else // not a 64bit arch?
275
276 #if 64 == _FILE_OFFSET_BITS
277 #define OFF_T_FMT "%" PRId64
278 #endif
279
280 #if 32 == _FILE_OFFSET_BITS
281 #define OFF_T_FMT "%" PRId32
282 #endif
283
284 #endif // !64bit arch
285
286 #ifndef OFF_T_FMT // either set above or let the os/compiler deal with the mess
287 #define OFF_T_FMT "%ld"
288 #endif
289
290 // let the compiler optimize and keep best variant
291 off_t atoofft(LPCSTR p);
292
atoofft(LPCSTR p,off_t nDefVal)293 inline off_t atoofft(LPCSTR p, off_t nDefVal)
294 {
295 return p ? atoofft(p) : nDefVal;
296 }
297
298 mstring offttosH(off_t n);
299 mstring offttosHdotted(off_t n);
300 tStrDeq ExpandFilePattern(cmstring& pattern, bool bSorted=false, bool bQuiet=false);
301
302 //void MakeAbsolutePath(mstring &dirToFix, const mstring &reldir);
303
304
305 mstring UrlEscape(cmstring &s);
306 void UrlEscapeAppend(cmstring &s, mstring &sTarget);
307 bool UrlUnescapeAppend(cmstring &from, mstring & to);
308 // Decode with result as return value, no error reporting
309 mstring UrlUnescape(cmstring &from);
310 mstring DosEscape(cmstring &s);
311 // just the bare minimum to make sure the string does not break HTML formating
312 mstring html_sanitize(cmstring& in);
313
314 mstring UserinfoEscape(cmstring &s);
315
316 #define pathTidy(s) { if(startsWithSz(s, "." SZPATHSEP)) s.erase(0, 2); tStrPos n(0); \
317 for(n=0;stmiss!=n;) { n=s.find(SZPATHSEP SZPATHSEP, n); if(stmiss!=n) s.erase(n, 1);}; \
318 for(n=0;stmiss!=n;) { n=s.find(SZPATHSEP "." SZPATHSEP, n); if(stmiss!=n) s.erase(n, 2);}; }
319
320 // appears in the STL container?
321 #define ContHas(stlcont, needle) ((stlcont).find(needle) != (stlcont).end())
322 #define ContHasLinear(stlcont, needle) ((stlcont).end() != (std::find((stlcont).begin(), (stlcont).end(), needle)))
323
324 #define StrHas(haystack, needle) (haystack.find(needle) != stmiss)
325 #define StrHasFrom(haystack, needle, startpos) (haystack.find(needle, startpos) != stmiss)
326 #define StrEraseEnd(s,len) (s).erase((s).size() - len)
327
328 off_t GetFileSize(cmstring & path, off_t defret);
329
330 mstring offttos(off_t n);
331 mstring ltos(long n);
332 mstring offttosH(off_t n);
333
334 //template<typename charp>
335 off_t strsizeToOfft(const char *sizeString); // XXX: if needed... charp sizeString, charp *next)
336
337
338 void replaceChars(mstring &s, LPCSTR szBadChars, char goodChar);
339
340 extern cmstring sEmptyString;
341
342 //! iterator-like helper for string splitting, for convenient use with for-loops
343 // Works exactly once!
344 class tSplitWalk
345 {
346 cmstring &s;
347 mutable mstring::size_type start, len, oob;
348 LPCSTR m_seps;
349
350 public:
351 inline tSplitWalk(cmstring *line, LPCSTR separators=SPACECHARS, unsigned begin=0)
352 : s(*line), start(begin), len(stmiss), oob(line->size()), m_seps(separators) {}
Next()353 inline bool Next() const
354 {
355 if(len != stmiss) // not initial state, find the next position
356 start = start + len + 1;
357
358 if(start>=oob)
359 return false;
360
361 start = s.find_first_not_of(m_seps, start);
362
363 if(start<oob)
364 {
365 len = s.find_first_of(m_seps, start);
366 len = (len == stmiss) ? oob-start : len-start;
367 }
368 else if (len != stmiss) // not initial state, end reached
369 return false;
370 else if(s.empty()) // initial state, no parts
371 return false;
372 else // initial state, use the whole string
373 {
374 start = 0;
375 len = oob;
376 }
377
378 return true;
379 }
str()380 inline mstring str() const { return s.substr(start, len); }
mstring()381 inline operator mstring() const { return str(); }
remainder()382 inline LPCSTR remainder() const { return s.c_str() + start; }
383
384 struct iterator
385 {
386 tSplitWalk* _walker = nullptr;
387 // default is end sentinel
388 bool bEol = true;
iteratoriterator389 iterator() {}
iteratoriterator390 iterator(tSplitWalk& walker) : _walker(&walker) { bEol = !walker.Next(); }
391 // just good enough for basic iteration and end detection
392 bool operator==(const iterator& other) const { return (bEol && other.bEol); }
393 bool operator!=(const iterator& other) const { return !(other == *this); }
394 iterator operator++() { bEol = !_walker->Next(); return *this; }
395 std::string operator*() { return _walker->str(); }
396 };
begin()397 iterator begin() {return iterator(*this); }
end()398 iterator end() { return iterator(); }
399 };
400
401 //bool CreateDetachedThread(void *(*threadfunc)(void *));
402
403 void DelTree(cmstring &what);
404
405 bool IsAbsolute(cmstring &dirToFix);
406
407 mstring unEscape(cmstring &s);
408
409 std::string BytesToHexString(const uint8_t sum[], unsigned short lengthBin);
410 //bool HexToString(const char *a, mstring& ret);
411 bool Hex2buf(const char *a, size_t len, acbuf& ret);
412
413 // STFU helpers, (void) casts are not effective for certain functions
ignore_value(int i)414 static inline void ignore_value (int i) { (void) i; }
ignore_ptr(void * p)415 static inline void ignore_ptr (void* p) { (void) p; }
416
GetTime()417 static inline time_t GetTime()
418 {
419 return ::time(0);
420 }
421
422 static const time_t END_OF_TIME(MAX_VAL(time_t)-2);
423
424 unsigned FormatTime(char *buf, size_t bufLen, const time_t cur);
425
426 struct tCurrentTime
427 {
428 char buf[30];
429 unsigned len;
tCurrentTimetCurrentTime430 inline tCurrentTime() { len=FormatTime(buf, sizeof(buf), time(nullptr)); }
mstringtCurrentTime431 inline operator mstring() { return mstring(buf, len); }
432 };
433
434 // represents a boolean value like a normal bool but also carries additional data
435 template <typename Textra, Textra defval>
436 struct extended_bool
437 {
438 bool value;
439 Textra xdata;
440 inline operator bool() { return value; }
valueextended_bool441 inline extended_bool(bool val, Textra xtra = defval) : value(val), xdata(xtra) {};
442 };
443
444 void DelTree(cmstring &what);
445
446 struct tErrnoFmter: public mstring
447 {
448 tErrnoFmter(LPCSTR prefix = nullptr);
449 };
450
451 mstring EncodeBase64Auth(cmstring &sPwdString);
452 mstring EncodeBase64(LPCSTR data, unsigned len);
453
454 #if defined(HAVE_SSL) || defined(HAVE_TOMCRYPT)
455 #define HAVE_DECB64
456 bool DecodeBase64(LPCSTR pAscii, size_t len, acbuf& binData);
457 #endif
458
459 typedef std::deque<std::pair<std::string, std::string>> tLPS;
460
461 #ifdef __GNUC__
462 #define AC_LIKELY(x) __builtin_expect(!!(x), true)
463 #define AC_UNLIKELY(x) __builtin_expect(!!(x), false)
464 #else
465 #define AC_LIKELY(x) x
466 #define AC_UNLIKELY(x) x
467 #endif
468
469 // shortcut for the non-invasive lookup and copy of stuff from maps
470 #define ifThereStoreThere(x,y,z) { auto itFind = (x).find(y); if(itFind != (x).end()) z = itFind->second; }
471 #define ifThereStoreThereAndBreak(x,y,z) { auto itFind = (x).find(y); if(itFind != (x).end()) { z = itFind->second; break; } }
472
473 bool scaseequals(cmstring& a, cmstring& b);
474
475 // dirty little RAII helper
476 struct tDtorEx {
477 std::function<void(void)> _action;
tDtorExtDtorEx478 inline tDtorEx(decltype(_action) action) : _action(action) {}
~tDtorExtDtorEx479 inline ~tDtorEx() { _action(); }
480 };
481
482 // from bgtask.cc
483 cmstring GetFooter();
484
485 template<typename T>
pairSum(const std::pair<T,T> & a,const std::pair<T,T> & b)486 std::pair<T,T> pairSum(const std::pair<T,T>& a, const std::pair<T,T>& b)
487 {
488 return std::pair<T,T>(a.first+b.first, a.second + b.second);
489 }
490
491 }
492
493 #endif // _META_H
494
495