1 
2 /* Web Polygraph       http://www.web-polygraph.org/
3  * Copyright 2003-2011 The Measurement Factory
4  * Licensed under the Apache License, Version 2.0 */
5 
6 #include "xstd/xstd.h"
7 
8 #include <limits>
9 #include <limits.h>
10 #include <ctype.h>
11 #include <fstream>
12 
13 #include "xstd/h/math.h"
14 #include "xstd/h/string.h"
15 #include "xstd/h/iostream.h"
16 #include "xstd/h/sys/types.h"
17 #include "xstd/h/sys/resource.h"
18 #include "xstd/Time.h"
19 
20 // see SSI_FD_NEWMAX below
21 #ifdef HAVE_SYS_SYSINFO_H
22 #include <sys/sysinfo.h>
23 #endif
24 
25 #include "xstd/Assert.h"
26 #include "xstd/gadgets.h"
27 
28 
29 // try "ceil(700/0.7)" to see why xceil is needed
30 // also useful as "xceil(m1*m2, 1)" because "ceil(10*~0.9)" == 10 on Linux
xceil(double nom,double denom)31 double xceil(double nom, double denom) {
32 #if HAVE_CEILF
33 	return (double)ceilf((float)(nom/denom));
34 #else
35 	const double cex = ceil(nom/denom);
36 	const double cm1 = cex-1;
37 	const double cp1 = cex+1;
38 
39 	const double dm1 = Abs(nom - cm1*denom);
40 	const double dex = Abs(nom - cex*denom);
41 	const double dp1 = Abs(nom - cp1*denom);
42 
43 	if (dm1 <= dex && nom <= cm1*denom )
44 		return dm1 <= dp1 || !(nom <= cp1*denom) ? cm1 : cp1;
45 	else
46 		return dex <= dp1 || !(nom <= cp1*denom) ? cex : cp1;
47 #endif
48 }
49 
XGCD(int a,int b)50 int XGCD(int a, int b) {
51 	return b ? XGCD(b, a % b) : a;
52 }
53 
54 // strNstr(), sort of
StrBoundStr(const char * s,const char * embed,const char * eos)55 const char *StrBoundStr(const char *s, const char *embed, const char *eos) {
56 	if (!Should(embed))
57 		return 0;
58 	if (!*embed)
59 		return 0; // or s?
60 
61 	const char head = *embed++; // skip first char
62 	const int tailLen = strlen(embed);
63 	// find first character first
64 	while (const char *p = StrBoundChr(s, head, eos)) {
65 		const char *tail = p + 1;
66 		if (eos - tail >= tailLen && strncmp(tail, embed, tailLen) == 0)
67 			return p;
68 		s = tail;
69 	}
70 	return 0;
71 }
72 
73 // strNchr(), sort of
StrBoundChr(const char * s,char c,const char * eos)74 const char *StrBoundChr(const char *s, char c, const char *eos) {
75 	while (s < eos) {
76 		if (*s == c)
77 			return s;
78 		else
79 			++s;
80 	}
81 	return 0;
82 }
83 
84 // find char from end of string
StrBoundRChr(const char * s,char c,const char * eos)85 const char *StrBoundRChr(const char *s, char c, const char *eos) {
86 	while (s < eos--) {
87 		if (*eos == c)
88 			return eos;
89 	}
90 	return 0;
91 }
92 
93 // finds next space char
StrBoundSpace(const char * s,const char * eos)94 const char *StrBoundSpace(const char *s, const char *eos) {
95 	while (s < eos) {
96 		if (isspace(*s))
97 			return s;
98 		else
99 			++s;
100 	}
101 	return 0;
102 }
103 
StrBoundAfterSpace(const char * s,const char * eos)104 const char *StrBoundAfterSpace(const char *s, const char *eos) {
105 	while (s < eos && !isspace(*s))
106 		s++;
107 	while (s < eos && isspace(*s))
108 		s++;
109 	return s < eos ? s : 0;
110 }
111 
StrNotSpace(const char * s)112 const char *StrNotSpace(const char *s) {
113 	while (*s) {
114 		if (!isspace(*s))
115 			return s;
116 		++s;
117 	}
118 	return 0;
119 }
120 
isInt(const char * s,int & i,const char ** p,int base)121 bool isInt(const char *s, int &i, const char **p, int base) {
122 	const int min = std::numeric_limits<int>::min();
123 	const int max = std::numeric_limits<int>::max();
124 	int64_t i64;
125 	if (isInt64(s, i64, p, base) && Should(min <= i64 && i64 <= max)) {
126 		i = static_cast<int>(i64);
127 		return true;
128 	}
129 	return false;
130 }
131 
isInt64(const char * s,int64_t & i,const char ** p,int base)132 bool isInt64(const char *s, int64_t &i, const char **p, int base) {
133 	if (s) {
134 		char *ptr = 0;
135 		const int64_t h = strtoll(s, &ptr, base);
136 		if (ptr != s && ptr) {
137 			i = h;
138 			if (p) *p = ptr;
139 			return true;
140 		}
141 	}
142 	return false;
143 }
144 
isNum(const char * s,double & d,const char ** p)145 bool isNum(const char *s, double &d, const char **p) {
146 	if (s) {
147 		char *ptr = 0;
148 		const double h = strtod(s, &ptr);
149 		if (ptr != s) {
150 			d = h;
151 			if (p) *p = ptr;
152 			return true;
153 		}
154 	}
155 	return false;
156 }
157 
isDbl(const char * s,double & d,const char ** p)158 bool isDbl(const char *s, double &d, const char **p) {
159 	double dd;
160 	const char *pp;
161 	if (!isNum(s, dd, &pp))
162 		return false;
163 
164 	Assert(pp);
165 
166 	// check that it is not an integer (has '.' or 'e')
167 	const char *h = strchr(s, '.');
168 	bool dbl = h && h < pp;
169 	if (!dbl) {
170 		h = strchr(s, 'e');
171 		dbl = h && h < pp;
172 	}
173 
174 	if (dbl) {
175 		d = dd;
176 		if (p) *p = pp;
177 	}
178 	return dbl;
179 }
180 
xatoi(const char * s,int def)181 int xatoi(const char *s, int def) {
182 	isInt(s, def);
183 	return def;
184 }
185 
redirectOutput(const char * fname)186 void redirectOutput(const char *fname) {
187 	if (Should(fname)) {
188 		ofstream *f = new ofstream(fname);
189 		cout.rdbuf(f->rdbuf());
190 		cerr.rdbuf(f->rdbuf());
191 		clog.rdbuf(f->rdbuf());
192 	}
193 }
194 
configureStream(ostream & os,int prec)195 void configureStream(ostream &os, int prec) {
196 	os.precision(prec);
197 	os.setf(ios::fixed, ios::floatfield);
198 	os.setf(ios::showpoint, ios::basefield);
199 }
200 
201 // XXX: move into a separate file
202 static bool base64_initialized = false;
203 static int base64_value[256];
204 const char base64_code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
205 	"abcdefghijklmnopqrstuvwxyz0123456789+/";
206 
207 static
base64_init()208 void base64_init() {
209 	const int count = (int)(sizeof(base64_value)/sizeof(*base64_value));
210 	{for (int i = 0; i < count; ++i)
211 		base64_value[i] = -1;
212 	}
213 
214 	{for (int i = 0; i < 64; i++)
215 		base64_value[(int) base64_code[i]] = i;
216 	}
217 	base64_value[(int)'='] = 0;
218 
219 	base64_initialized = true;
220 }
221 
222 // XXX: should check for garbage at the end of inBuf if we ran out of outBuf
DecodeBase64(const char * inBuf,int inLen,char * outBuf,int outLen)223 int DecodeBase64(const char *inBuf, int inLen, char *outBuf, int outLen) {
224 	Assert(inBuf && outBuf);
225 
226 	if (!base64_initialized)
227 		base64_init();
228 
229 	int c = 0;
230 	long val = 0;
231 	int outPos = 0;
232 	for (int inPos = 0; inPos < inLen && outPos < outLen; ++inPos) {
233 		unsigned int k = ((unsigned int) (unsigned char) inBuf[inPos]) % 256;
234 		if (base64_value[k] < 0)
235 			continue;
236 		val <<= 6;
237 		val += base64_value[k];
238 		if (++c < 4)
239 			continue;
240 
241 		if (outPos < outLen)
242 			outBuf[outPos++] = val >> 16;         // High 8 bits
243 		if (outPos < outLen)
244 			outBuf[outPos++] = (val >> 8) & 0xff; // Mid 8 bits
245 		if (outPos < outLen)
246 			outBuf[outPos++] = val & 0xff;        // Low 8 bits
247 		val = c = 0;
248 	}
249 	return outPos;
250 }
251 
252 
253 // adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
PrintBase64(ostream & os,const char * buf,int len)254 ostream &PrintBase64(ostream &os, const char *buf, int len) {
255 	Assert(buf);
256 
257 	if (!base64_initialized)
258 		base64_init();
259 
260 	int bits = 0;
261 	int char_count = 0;
262 	while (len--) {
263 		const int c = (unsigned char)*buf++;
264 		bits += c;
265 		char_count++;
266 		if (char_count == 3) {
267 			os
268 				<< base64_code[bits >> 18]
269 				<< base64_code[(bits >> 12) & 0x3f]
270 				<< base64_code[(bits >> 6) & 0x3f]
271 				<< base64_code[bits & 0x3f];
272 			bits = 0;
273 			char_count = 0;
274 		} else {
275 			bits <<= 8;
276 		}
277 	}
278 
279 	if (char_count) {
280 		bits <<= 16 - (8 * char_count);
281 		os << base64_code[bits >> 18] << base64_code[(bits >> 12) & 0x3f];
282 		if (char_count == 1)
283 			os.write("==", 2);
284 		else
285 			os << base64_code[(bits >> 6) & 0x3f] << '=';
286 	}
287 	return os;
288 }
289 
290 
291 #ifdef HAVE_GETRLIMIT
292 
293 static
rlimit2int(rlim_t rl)294 int rlimit2int(rlim_t rl) {
295 #ifdef RLIM_INFINITY
296 	if (rl == RLIM_INFINITY) {
297 #ifdef __APPLE__
298 		// On Mac OS X setrlimit(2) does not accept RLIM_INFINITY or
299 		// INT_MAX values. This causes assertion when FileScanner sets
300 		// max FD to hard limit. See compatibility section in
301 		// getrlimit(2).
302 		return OPEN_MAX;
303 #else
304 		return INT_MAX;
305 #endif
306 	}
307 #endif
308 	// rlim_t can be unsigned so we are trying to avoid comparisons
309 	// that generate warnings and casting that changes signs
310 	if (!rl)
311 		return 0;
312 	if (rl <= 0)
313 		return -1;
314 	Should(rl <= ((rlim_t)INT_MAX));
315 	return MiniMax(0, (int)rl, INT_MAX);
316 }
317 
GetCurFD()318 int GetCurFD() {
319 	struct rlimit rl;
320 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
321 		return -1;
322 	return rlimit2int(rl.rlim_cur);
323 }
324 
GetMaxFD()325 int GetMaxFD() {
326 	// True64 requires this to by-pass 4K hard limit
327 #ifdef SSI_FD_NEWMAX
328 	static bool beenThere = false;
329 	if (!beenThere) {
330 		Should(setsysinfo(SSI_FD_NEWMAX, 0, 0, 0, 1) == 0);
331 		beenThere = true;
332 	}
333 #endif
334 	struct rlimit rl;
335 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
336 		return -1;
337 	return rlimit2int(rl.rlim_max);
338 }
339 
SetMaxFD(int maxFD)340 int SetMaxFD(int maxFD) {
341 	struct rlimit rl;
342 	rl.rlim_max = Min(maxFD, GetMaxFD());
343 	rl.rlim_cur = rl.rlim_max;
344 	if (rl.rlim_cur > 0)
345 		Assert(setrlimit(RLIMIT_NOFILE, &rl) >= 0);
346 	return rlimit2int(rl.rlim_cur);
347 }
348 
349 #else /* HAVE_GETRLIMIT */
350 
GetCurFD()351 int GetCurFD() { return -1; }
GetMaxFD()352 int GetMaxFD() { return 0xFFFF; }
SetMaxFD(int maxFD)353 int SetMaxFD(int maxFD) { return maxFD; }
354 
355 #endif /* HAVE_GETRLIMIT */
356