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