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