1 #include <time.h>
2 #include <stdarg.h>
3 #include <sys/stat.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <string>
8 #include <vector>
9 #include <set>
10 #include <map>
11 #include <signal.h>
12 #include <float.h>
13 
14 #ifdef _MSC_VER
15 #include <crtdbg.h>
16 #include <process.h>
17 #include <windows.h>
18 #include <psapi.h>
19 #include <io.h>
20 #else
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #endif
28 
29 #include "myutils.h"
30 
31 const char *SVN_VERSION =
32 #include "svnversion.h"
33 ;
34 
35 #define	TEST_UTILS			0
36 
37 using namespace std;
38 
39 const unsigned MY_IO_BUFSIZ = 32000;
40 const unsigned MAX_FORMATTED_STRING_LENGTH = 64000;
41 
42 static char *g_IOBuffers[256];
43 static time_t g_StartTime = time(0);
44 static vector<string> g_Argv;
45 static double g_PeakMemUseBytes;
46 
47 #if	TEST_UTILS
TestUtils()48 void TestUtils()
49 	{
50 	const int C = 100000000;
51 	for (int i = 0; i < C; ++i)
52 		ProgressStep(i, C, "something or other");
53 
54 	Progress("\n");
55 	Progress("Longer message\r");
56 	Sleep(1000);
57 	Progress("Short\r");
58 	Sleep(1000);
59 	Progress("And longer again\r");
60 	Sleep(1000);
61 	Progress("Shrt\n");
62 	Sleep(1000);
63 	const unsigned N = 10;
64 	unsigned M = 10;
65 	for (unsigned i = 0; i < N; ++i)
66 		{
67 		ProgressStep(i, N, "Allocating 1MB blocks");
68 		for (unsigned j = 0; j < M; ++j)
69 			{
70 			ProgressStep(j, M, "Inner loop");
71 			malloc(100000);
72 			Sleep(500);
73 			}
74 		}
75 	}
76 #endif // TEST_UTILS
77 
AllocBuffer(FILE * f)78 static void AllocBuffer(FILE *f)
79 	{
80 	int fd = fileno(f);
81 	if (fd < 0 || fd >= 256)
82 		return;
83 	if (g_IOBuffers[fd] == 0)
84 		g_IOBuffers[fd] = myalloc(char, MY_IO_BUFSIZ);
85 	setvbuf(f, g_IOBuffers[fd], _IOFBF, MY_IO_BUFSIZ);
86 	}
87 
FreeBuffer(FILE * f)88 static void FreeBuffer(FILE *f)
89 	{
90 	int fd = fileno(f);
91 	if (fd < 0 || fd >= 256)
92 		return;
93 	if (g_IOBuffers[fd] == 0)
94 		return;
95 	myfree(g_IOBuffers[fd]);
96 	g_IOBuffers[fd] = 0;
97 	}
98 
GetElapsedSecs()99 unsigned GetElapsedSecs()
100 	{
101 	return (unsigned) (time(0) - g_StartTime);
102 	}
103 
104 static unsigned g_NewCalls;
105 static unsigned g_FreeCalls;
106 static double g_InitialMemUseBytes;
107 static double g_TotalAllocBytes;
108 static double g_TotalFreeBytes;
109 static double g_NetBytes;
110 static double g_MaxNetBytes;
111 
LogAllocStats()112 void LogAllocStats()
113 	{
114 	Log("\n");
115 	Log("       Allocs  %u\n", g_NewCalls);
116 	Log("        Frees  %u\n", g_FreeCalls);
117 	Log("Initial alloc  %s\n", MemBytesToStr(g_InitialMemUseBytes));
118 	Log("  Total alloc  %s\n", MemBytesToStr(g_TotalAllocBytes));
119 	Log("   Total free  %s\n", MemBytesToStr(g_TotalFreeBytes));
120 	Log("    Net bytes  %s\n", MemBytesToStr(g_NetBytes));
121 	Log("Max net bytes  %s\n", MemBytesToStr(g_MaxNetBytes));
122 	Log("   Peak total  %s\n", MemBytesToStr(g_MaxNetBytes + g_InitialMemUseBytes));
123 	}
124 
StdioFileExists(const string & FileName)125 bool StdioFileExists(const string &FileName)
126 	{
127 	struct stat SD;
128 	int i = stat(FileName.c_str(), &SD);
129 	return i == 0;
130 	}
131 
myassertfail(const char * Exp,const char * File,unsigned Line)132 void myassertfail(const char *Exp, const char *File, unsigned Line)
133 	{
134 	Die("%s(%u) assert failed: %s", File, Line, Exp);
135 	}
136 
myisatty(int fd)137 bool myisatty(int fd)
138 	{
139 	return isatty(fd) != 0;
140 	}
141 
142 #ifdef _MSC_VER
143 #include <io.h>
fseeko(FILE * stream,off_t offset,int whence)144 int fseeko(FILE *stream, off_t offset, int whence)
145 	{
146 	off_t FilePos = _fseeki64(stream, offset, whence);
147 	return (FilePos == -1L) ? -1 : 0;
148 	}
149 #define ftello(fm) (off_t) _ftelli64(fm)
150 #endif
151 
LogStdioFileState(FILE * f)152 void LogStdioFileState(FILE *f)
153 	{
154 	unsigned long tellpos = (unsigned long) ftello(f);
155 	long fseek_pos = fseek(f, 0, SEEK_CUR);
156 	int fd = fileno(f);
157 	Log("FILE *     %p\n", f);
158 	Log("fileno     %d\n", fd);
159 	Log("feof       %d\n", feof(f));
160 	Log("ferror     %d\n", ferror(f));
161 	Log("ftell      %ld\n", tellpos);
162 	Log("fseek      %ld\n", fseek_pos);
163 #if	!defined(_GNU_SOURCE) && !defined(__APPLE_CC__)
164 	fpos_t fpos;
165 	int fgetpos_retval = fgetpos(f, &fpos);
166 	Log("fpos       %ld (retval %d)\n", (long) fpos, fgetpos_retval);
167 //	Log("eof        %d\n", _eof(fd));
168 #endif
169 #ifdef _MSC_VER
170 	__int64 pos64 = _ftelli64(f);
171 	Log("_ftelli64  %lld\n", pos64);
172 #endif
173 	}
174 
OpenStdioFile(const string & FileName)175 FILE *OpenStdioFile(const string &FileName)
176 	{
177 	const char *Mode = "rb";
178 	FILE *f = fopen(FileName.c_str(), Mode);
179 	if (f == 0)
180 		{
181 		if (errno == EFBIG)
182 			{
183 			if (sizeof(off_t) == 4)
184 				Die("File too big, off_t is 32 bits, recompile needed");
185 			else
186 				Die("Cannot open '%s', file too big (off_t=%u bits)",
187 				  FileName.c_str(), sizeof(off_t)*8);
188 			}
189 		Die("Cannot open %s, errno=%d %s",
190 		  FileName.c_str(), errno, strerror(errno));
191 		}
192 	AllocBuffer(f);
193 	return f;
194 	}
195 
CreateStdioFile(const string & FileName)196 FILE *CreateStdioFile(const string &FileName)
197 	{
198 	FILE *f = fopen(FileName.c_str(), "wb+");
199 	if (0 == f)
200 		Die("Cannot create %s, errno=%d %s",
201 		  FileName.c_str(), errno, strerror(errno));
202 	AllocBuffer(f);
203 	return f;
204 	}
205 
SetStdioFilePos(FILE * f,off_t Pos)206 void SetStdioFilePos(FILE *f, off_t Pos)
207 	{
208 	if (0 == f)
209 		Die("SetStdioFilePos failed, f=NULL");
210 	int Ok = fseeko(f, Pos, SEEK_SET);
211 	off_t NewPos = ftello(f);
212 	if (Ok != 0 || Pos != NewPos)
213 		{
214 		LogStdioFileState(f);
215 		Die("SetStdioFilePos(%d) failed, Ok=%d NewPos=%d",
216 		  (int) Pos, Ok, (int) NewPos);
217 		}
218 	}
219 
ReadStdioFile(FILE * f,off_t Pos,void * Buffer,unsigned Bytes)220 void ReadStdioFile(FILE *f, off_t Pos, void *Buffer, unsigned Bytes)
221 	{
222 	if (0 == f)
223 		Die("ReadStdioFile failed, f=NULL");
224 	SetStdioFilePos(f, Pos);
225 	unsigned BytesRead = fread(Buffer, 1, Bytes, f);
226 	if (BytesRead != Bytes)
227 		{
228 		LogStdioFileState(f);
229 		Die("ReadStdioFile failed, attempted %d bytes, read %d bytes, errno=%d",
230 		  (int) Bytes, (int) BytesRead, errno);
231 		}
232 	}
233 
ReadStdioFile(FILE * f,void * Buffer,unsigned Bytes)234 void ReadStdioFile(FILE *f, void *Buffer, unsigned Bytes)
235 	{
236 	if (0 == f)
237 		Die("ReadStdioFile failed, f=NULL");
238 	unsigned BytesRead = fread(Buffer, 1, Bytes, f);
239 	if (BytesRead != Bytes)
240 		{
241 		LogStdioFileState(f);
242 		Die("ReadStdioFile failed, attempted %d bytes, read %d bytes, errno=%d",
243 		  (int) Bytes, (int) BytesRead, errno);
244 		}
245 	}
246 
247 // Return values from functions like lseek, ftell, fgetpos are
248 // "undefined" for files that cannot seek. Attempt to detect
249 // whether a file can seek by checking for error returns.
CanSetStdioFilePos(FILE * f)250 bool CanSetStdioFilePos(FILE *f)
251 	{
252 // Common special cases
253 	if (f == stdin || f == stdout || f == stderr)
254 		return false;
255 
256 	fpos_t CurrPos;
257 	int ok1 = fgetpos(f, &CurrPos);
258 	if (ok1 < 0)
259 		return false;
260 	int ok2 = fseek(f, 0, SEEK_END);
261 	if (ok2 < 0)
262 		return false;
263 	fpos_t EndPos;
264 	int ok3 = fgetpos(f, &EndPos);
265 	int ok4 = fsetpos(f, &CurrPos);
266 	if (!ok3 || !ok4)
267 		return false;
268 	return true;
269 	}
270 
ReadAllStdioFile(FILE * f,unsigned & FileSize)271 byte *ReadAllStdioFile(FILE *f, unsigned &FileSize)
272 	{
273 	const unsigned BUFF_SIZE = 1024*1024;
274 
275 	if (CanSetStdioFilePos(f))
276 		{
277 		off_t Pos = GetStdioFilePos(f);
278 		off_t FileSize = GetStdioFileSize(f);
279 		if (FileSize > UINT_MAX)
280 			Die("ReadAllStdioFile: file size > UINT_MAX");
281 		SetStdioFilePos(f, 0);
282 		byte *Buffer = myalloc(byte, unsigned(FileSize));
283 		ReadStdioFile(f, Buffer, unsigned(FileSize));
284 		SetStdioFilePos(f, Pos);
285 		FileSize = unsigned(FileSize);
286 		return Buffer;
287 		}
288 
289 // Can't seek, read one buffer at a time.
290 	FileSize = 0;
291 
292 // Just to initialize so that first call to realloc works.
293 	byte *Buffer = (byte *) malloc(4);
294 	if (Buffer == 0)
295 		Die("ReadAllStdioFile, out of memory");
296 	for (;;)
297 		{
298 		Buffer = (byte *) realloc(Buffer, FileSize + BUFF_SIZE);
299 		unsigned BytesRead = fread(Buffer + FileSize, 1, BUFF_SIZE, f);
300 		FileSize += BytesRead;
301 		if (BytesRead < BUFF_SIZE)
302 			{
303 			Buffer = (byte *) realloc(Buffer, FileSize);
304 			return Buffer;
305 			}
306 		}
307 	}
308 
ReadAllStdioFile(const std::string & FileName,off_t & FileSize)309 byte *ReadAllStdioFile(const std::string &FileName, off_t &FileSize)
310 	{
311 #if	WIN32
312 	FILE *f = OpenStdioFile(FileName);
313 	FileSize = GetStdioFileSize(f);
314 	CloseStdioFile(f);
315 
316 	HANDLE h = CreateFile(FileName.c_str(), GENERIC_READ, FILE_SHARE_READ,
317 	  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
318 	if (h == INVALID_HANDLE_VALUE)
319 		Die("ReadAllStdioFile:Open(%s) failed", FileName.c_str());
320 
321 	unsigned uFileSize = (unsigned) FileSize;
322 	if ((off_t) uFileSize != FileSize)
323 		Die("File too big (%.1f Gb): %s", double(FileSize)/1e9, FileName.c_str());
324 
325 	byte *Buffer = myalloc(byte, uFileSize);
326 	DWORD BytesRead;
327 	ReadFile(h, Buffer, uFileSize, &BytesRead, NULL);
328 	if (FileSize != BytesRead)
329 		Die("ReadAllStdioFile:Error reading %s, attempted %u got %u",
330 		  FileName.c_str(), FileSize, (unsigned) BytesRead);
331 
332 	CloseHandle(h);
333 	return Buffer;
334 #else
335 	int h = open(FileName.c_str(), O_RDONLY);
336 	if (h < 0)
337 		Die("ReadAllStdioFile:Cannot open %s", FileName.c_str());
338 	FileSize = lseek(h, 0, SEEK_END);
339 	if (FileSize == (off_t) (-1))
340 		Die("ReadAllStdioFile:Error seeking %s", FileName.c_str());
341 	// byte *Buffer = myalloc<byte>(FileSize);
342 	size_t stBytes = (size_t) FileSize;
343 	if ((off_t) stBytes != FileSize)
344 		Die("ReadAllStdioFile: off_t overflow");
345 	byte *Buffer = (byte *) malloc(stBytes);
346 	if (Buffer == 0)
347 		Die("ReadAllStdioFile: failed to allocate %s", MemBytesToStr(stBytes));
348 	lseek(h, 0, SEEK_SET);
349 	size_t n = read(h, Buffer, stBytes);
350 	if (n != FileSize)
351 		Die("ReadAllStdioFile, Error reading %s, attempted %g got %g",
352 		  FileName.c_str(), (double) FileSize, (double) n);
353 	close(h);
354 	return Buffer;
355 #endif
356 	}
357 
WriteStdioFile(FILE * f,off_t Pos,const void * Buffer,unsigned Bytes)358 void WriteStdioFile(FILE *f, off_t Pos, const void *Buffer, unsigned Bytes)
359 	{
360 	if (0 == f)
361 		Die("WriteStdioFile failed, f=NULL");
362 	SetStdioFilePos(f, Pos);
363 	unsigned BytesWritten = fwrite(Buffer, 1, Bytes, f);
364 	if (BytesWritten != Bytes)
365 		{
366 		LogStdioFileState(f);
367 		Die("WriteStdioFile failed, attempted %d bytes, wrote %d bytes, errno=%d",
368 		  (int) Bytes, (int) BytesWritten, errno);
369 		}
370 	}
371 
WriteStdioFile(FILE * f,const void * Buffer,unsigned Bytes)372 void WriteStdioFile(FILE *f, const void *Buffer, unsigned Bytes)
373 	{
374 	if (0 == f)
375 		Die("WriteStdioFile failed, f=NULL");
376 	unsigned BytesWritten = fwrite(Buffer, 1, Bytes, f);
377 	if (BytesWritten != Bytes)
378 		{
379 		LogStdioFileState(f);
380 		Die("WriteStdioFile failed, attempted %d bytes, wrote %d bytes, errno=%d",
381 		  (int) Bytes, (int) BytesWritten, errno);
382 		}
383 	}
384 
385 // Return false on EOF, true if line successfully read.
ReadLineStdioFile(FILE * f,char * Line,unsigned Bytes)386 bool ReadLineStdioFile(FILE *f, char *Line, unsigned Bytes)
387 	{
388 	if (feof(f))
389 		return false;
390 	if ((int) Bytes < 0)
391 		Die("ReadLineStdioFile: Bytes < 0");
392 	char *RetVal = fgets(Line, (int) Bytes, f);
393 	if (NULL == RetVal)
394 		{
395 		if (feof(f))
396 			return false;
397 		if (ferror(f))
398 			Die("ReadLineStdioFile: errno=%d", errno);
399 		Die("ReadLineStdioFile: fgets=0, feof=0, ferror=0");
400 		}
401 
402 	if (RetVal != Line)
403 		Die("ReadLineStdioFile: fgets != Buffer");
404 	unsigned n = strlen(Line);
405 	if (n < 1 || Line[n-1] != '\n')
406 		Die("ReadLineStdioFile: line too long or missing end-of-line");
407 	if (n > 0 && (Line[n-1] == '\r' || Line[n-1] == '\n'))
408 		Line[n-1] = 0;
409 	if (n > 1 && (Line[n-2] == '\r' || Line[n-2] == '\n'))
410 		Line[n-2] = 0;
411 	return true;
412 	}
413 
414 // Return false on EOF, true if line successfully read.
ReadLineStdioFile(FILE * f,string & Line)415 bool ReadLineStdioFile(FILE *f, string &Line)
416 	{
417 	Line.clear();
418 	for (;;)
419 		{
420 		int c = fgetc(f);
421 		if (c == -1)
422 			{
423 			if (feof(f))
424 				{
425 				if (!Line.empty())
426 					return true;
427 				return false;
428 				}
429 			Die("ReadLineStdioFile, errno=%d", errno);
430 			}
431 		if (c == '\r')
432 			continue;
433 		if (c == '\n')
434 			return true;
435 		Line.push_back((char) c);
436 		}
437 	}
438 
439 // Copies all of fFrom regardless of current
440 // file position, appends to fTo.
AppendStdioFileToFile(FILE * fFrom,FILE * fTo)441 void AppendStdioFileToFile(FILE *fFrom, FILE *fTo)
442 	{
443 	off_t SavedFromPos = GetStdioFilePos(fFrom);
444 	off_t FileSize = GetStdioFileSize(fFrom);
445 	const off_t BUFF_SIZE = 1024*1024;
446 	char *Buffer = myalloc(char, BUFF_SIZE);
447 	SetStdioFilePos(fFrom, 0);
448 	off_t BytesRemaining = FileSize;
449 	while (BytesRemaining > 0)
450 		{
451 		off_t BytesToRead = BytesRemaining;
452 		if (BytesToRead > BUFF_SIZE)
453 			BytesToRead = BUFF_SIZE;
454 		ReadStdioFile(fFrom, Buffer, (unsigned) BytesToRead);
455 		WriteStdioFile(fTo, Buffer, (unsigned) BytesToRead);
456 		BytesRemaining -= BytesToRead;
457 		}
458 	SetStdioFilePos(fFrom, SavedFromPos);
459 	}
460 
RenameStdioFile(const string & FileNameFrom,const string & FileNameTo)461 void RenameStdioFile(const string &FileNameFrom, const string &FileNameTo)
462 	{
463 	int Ok = rename(FileNameFrom.c_str(), FileNameTo.c_str());
464 	if (Ok != 0)
465 		Die("RenameStdioFile(%s,%s) failed, errno=%d %s",
466 		  FileNameFrom.c_str(), FileNameTo.c_str(), errno, strerror(errno));
467 	}
468 
FlushStdioFile(FILE * f)469 void FlushStdioFile(FILE *f)
470 	{
471 	int Ok = fflush(f);
472 	if (Ok != 0)
473 		Die("fflush(%p)=%d,", f, Ok);
474 	}
475 
CloseStdioFile(FILE * f)476 void CloseStdioFile(FILE *f)
477 	{
478 	if (f == 0)
479 		return;
480 	int Ok = fclose(f);
481 	if (Ok != 0)
482 		Die("fclose(%p)=%d", f, Ok);
483 	FreeBuffer(f);
484 	}
485 
GetStdioFilePos(FILE * f)486 off_t GetStdioFilePos(FILE *f)
487 	{
488 	off_t FilePos = ftello(f);
489 	if (FilePos < 0)
490 		Die("ftello=%d", (int) FilePos);
491 	return FilePos;
492 	}
493 
GetStdioFileSize(FILE * f)494 off_t GetStdioFileSize(FILE *f)
495 	{
496 	off_t CurrentPos = GetStdioFilePos(f);
497 	int Ok = fseeko(f, 0, SEEK_END);
498 	if (Ok < 0)
499 		Die("fseek in GetFileSize");
500 
501 	off_t Length = ftello(f);
502 	if (Length < 0)
503 		Die("ftello in GetFileSize");
504 	SetStdioFilePos(f, CurrentPos);
505 	return Length;
506 	}
507 
DeleteStdioFile(const string & FileName)508 void DeleteStdioFile(const string &FileName)
509 	{
510 	int Ok = remove(FileName.c_str());
511 	if (Ok != 0)
512 		Die("remove(%s) failed, errno=%d %s", FileName.c_str(), errno, strerror(errno));
513 	}
514 
myvstrprintf(string & Str,const char * Format,va_list ArgList)515 void myvstrprintf(string &Str, const char *Format, va_list ArgList)
516 	{
517 	static char szStr[MAX_FORMATTED_STRING_LENGTH];
518 	vsnprintf(szStr, MAX_FORMATTED_STRING_LENGTH-1, Format, ArgList);
519 	szStr[MAX_FORMATTED_STRING_LENGTH - 1] = '\0';
520 	Str.assign(szStr);
521 	}
522 
myvstrprintf(string & Str,const char * Format,...)523 void myvstrprintf(string &Str, const char *Format, ...)
524 	{
525 	va_list ArgList;
526 	va_start(ArgList, Format);
527 	myvstrprintf(Str, Format, ArgList);
528 	va_end(ArgList);
529 	}
530 
531 FILE *g_fLog = 0;
532 
SetLogFileName(const string & FileName)533 void SetLogFileName(const string &FileName)
534 	{
535 	if (g_fLog != 0)
536 		CloseStdioFile(g_fLog);
537 	g_fLog = 0;
538 	if (FileName.empty())
539 		return;
540 	g_fLog = CreateStdioFile(FileName);
541 	}
542 
Log(const char * Format,...)543 void Log(const char *Format, ...)
544 	{
545 	if (g_fLog == 0)
546 		return;
547 
548 	static bool InLog = false;
549 	if (InLog)
550 		return;
551 
552 	InLog = true;
553 	va_list ArgList;
554 	va_start(ArgList, Format);
555 	vfprintf(g_fLog, Format, ArgList);
556 	va_end(ArgList);
557 	fflush(g_fLog);
558 	InLog = false;
559 	}
560 
Die(const char * Format,...)561 void Die(const char *Format, ...)
562 	{
563 	static bool InDie = false;
564 	if (InDie)
565 		exit(1);
566 	InDie = true;
567 	string Msg;
568 
569 	if (g_fLog != 0)
570 		setbuf(g_fLog, 0);
571 	va_list ArgList;
572 	va_start(ArgList, Format);
573 	myvstrprintf(Msg, Format, ArgList);
574 	va_end(ArgList);
575 
576 	fprintf(stderr, "\n\n");
577 	Log("\n");
578 	time_t t = time(0);
579 	Log("%s", asctime(localtime(&t)));
580 	for (unsigned i = 0; i < g_Argv.size(); i++)
581 		{
582 		fprintf(stderr, (i == 0) ? "%s" : " %s", g_Argv[i].c_str());
583 		Log((i == 0) ? "%s" : " %s", g_Argv[i].c_str());
584 		}
585 	fprintf(stderr, "\n");
586 	Log("\n");
587 
588 	time_t CurrentTime = time(0);
589 	unsigned ElapsedSeconds = unsigned(CurrentTime - g_StartTime);
590 	const char *sstr = SecsToStr(ElapsedSeconds);
591 	Log("Elapsed time: %s\n", sstr);
592 
593 	const char *szStr = Msg.c_str();
594 	fprintf(stderr, "\n---Fatal error---\n%s\n", szStr);
595 	Log("\n---Fatal error---\n%s\n", szStr);
596 
597 #ifdef _MSC_VER
598 	if (IsDebuggerPresent())
599  		__debugbreak();
600 	_CrtSetDbgFlag(0);
601 #endif
602 
603 	exit(1);
604 	}
605 
Warning(const char * Format,...)606 void Warning(const char *Format, ...)
607 	{
608 	string Msg;
609 
610 	va_list ArgList;
611 	va_start(ArgList, Format);
612 	myvstrprintf(Msg, Format, ArgList);
613 	va_end(ArgList);
614 
615 	const char *szStr = Msg.c_str();
616 
617 	fprintf(stderr, "\nWARNING: %s\n", szStr);
618 	if (g_fLog != stdout)
619 		{
620 		Log("\nWARNING: %s\n", szStr);
621 		fflush(g_fLog);
622 		}
623 	}
624 
625 #ifdef _MSC_VER
GetMemUseBytes()626 double GetMemUseBytes()
627 	{
628 	HANDLE hProc = GetCurrentProcess();
629 	PROCESS_MEMORY_COUNTERS PMC;
630 	BOOL bOk = GetProcessMemoryInfo(hProc, &PMC, sizeof(PMC));
631 	if (!bOk)
632 		return 1000000;
633 	double Bytes = (double) PMC.WorkingSetSize;
634 	if (Bytes > g_PeakMemUseBytes)
635 		g_PeakMemUseBytes = Bytes;
636 	return Bytes;
637 	}
638 #elif	linux || __linux__
GetMemUseBytes()639 double GetMemUseBytes()
640 	{
641 	static char statm[64];
642 	static int PageSize = 1;
643 	if (0 == statm[0])
644 		{
645 		PageSize = sysconf(_SC_PAGESIZE);
646 		pid_t pid = getpid();
647 		sprintf(statm, "/proc/%d/statm", (int) pid);
648 		}
649 
650 	int fd = open(statm, O_RDONLY);
651 	if (-1 == fd)
652 		return 1000000;
653 	char Buffer[64];
654 	int n = read(fd, Buffer, sizeof(Buffer) - 1);
655 	close(fd);
656 	fd = -1;
657 
658 	if (n <= 0)
659 		return 1000000;
660 
661 	Buffer[n] = 0;
662 	double Pages = atof(Buffer);
663 
664 	double Bytes = Pages*PageSize;
665 	if (Bytes > g_PeakMemUseBytes)
666 		g_PeakMemUseBytes = Bytes;
667 	return Bytes;
668 	}
669 #elif defined(__MACH__)
670 #include <memory.h>
671 #include <stdlib.h>
672 #include <stdio.h>
673 #include <unistd.h>
674 #include <sys/types.h>
675 #include <sys/sysctl.h>
676 #include <sys/socket.h>
677 #include <sys/gmon.h>
678 #include <mach/vm_param.h>
679 #include <netinet/in.h>
680 #include <netinet/icmp6.h>
681 #include <sys/vmmeter.h>
682 #include <sys/proc.h>
683 #include <mach/vm_statistics.h>
684 #include <mach/task_info.h>
685 #include <mach/task.h>
686 #include <mach/mach_init.h>
687 
688 #define DEFAULT_MEM_USE	100000000.0
689 
GetMemUseBytes()690 double GetMemUseBytes()
691 	{
692 	task_t mytask = mach_task_self();
693 	struct task_basic_info ti;
694 	memset((void *) &ti, 0, sizeof(ti));
695 	mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
696 	kern_return_t ok = task_info(mytask, TASK_BASIC_INFO, (task_info_t) &ti, &count);
697 	if (ok == KERN_INVALID_ARGUMENT)
698 		return DEFAULT_MEM_USE;
699 
700 	if (ok != KERN_SUCCESS)
701 		return DEFAULT_MEM_USE;
702 
703 	double Bytes = (double ) ti.resident_size;
704 	if (Bytes > g_PeakMemUseBytes)
705 		g_PeakMemUseBytes = Bytes;
706 	return Bytes;
707 	}
708 #else
GetMemUseBytes()709 double GetMemUseBytes()
710 	{
711 	return 0;
712 	}
713 #endif
714 
GetPeakMemUseBytes()715 double GetPeakMemUseBytes()
716 	{
717 	return g_PeakMemUseBytes;
718 	}
719 
SecsToHHMMSS(int Secs)720 const char *SecsToHHMMSS(int Secs)
721 	{
722 	int HH = Secs/3600;
723 	int MM = (Secs - HH*3600)/60;
724 	int SS = Secs%60;
725 	static char Str[16];
726 	if (HH == 0)
727 		sprintf(Str, "%02d:%02d", MM, SS);
728 	else
729 		sprintf(Str, "%02d:%02d:%02d", HH, MM, SS);
730 	return Str;
731 	}
732 
SecsToStr(double Secs)733 const char *SecsToStr(double Secs)
734 	{
735 	if (Secs >= 10.0)
736 		return SecsToHHMMSS((int) Secs);
737 
738 	static char Str[16];
739 	if (Secs < 1e-6)
740 		sprintf(Str, "%.2gs", Secs);
741 	else if (Secs < 1e-3)
742 		sprintf(Str, "%.2fms", Secs*1e3);
743 	else
744 		sprintf(Str, "%.3fs", Secs);
745 	return Str;
746 	}
747 
MemBytesToStr(double Bytes)748 const char *MemBytesToStr(double Bytes)
749 	{
750 	static char Str[32];
751 
752 	if (Bytes < 1e6)
753 		sprintf(Str, "%.1fkb", Bytes/1e3);
754 	else if (Bytes < 10e6)
755 		sprintf(Str, "%.1fMb", Bytes/1e6);
756 	else if (Bytes < 1e9)
757 		sprintf(Str, "%.0fMb", Bytes/1e6);
758 	else if (Bytes < 10e9)
759 		sprintf(Str, "%.1fGb", Bytes/1e9);
760 	else if (Bytes < 100e9)
761 		sprintf(Str, "%.0fGb", Bytes/1e9);
762 	else
763 		sprintf(Str, "%.3gb", Bytes);
764 	return Str;
765 	}
766 
IntToStr(unsigned i)767 const char *IntToStr(unsigned i)
768 	{
769 	static char Str[32];
770 
771 	double d = (double) i;
772 	if (i < 10000)
773 		sprintf(Str, "%u", i);
774 	else if (i < 1e6)
775 		sprintf(Str, "%.1fk", d/1e3);
776 	else if (i < 10e6)
777 		sprintf(Str, "%.1fM", d/1e6);
778 	else if (i < 1e9)
779 		sprintf(Str, "%.0fM", d/1e6);
780 	else if (i < 10e9)
781 		sprintf(Str, "%.1fG", d/1e9);
782 	else if (i < 100e9)
783 		sprintf(Str, "%.0fG", d/1e9);
784 	else
785 		sprintf(Str, "%.3g", d);
786 	return Str;
787 	}
788 
FloatToStr(double d)789 const char *FloatToStr(double d)
790 	{
791 	static char Str[32];
792 
793 	double a = fabs(d);
794 	if (a < 0.01)
795 		sprintf(Str, "%.3g", a);
796 	else if (a >= 0.01 && a < 1)
797 		sprintf(Str, "%.3f", a);
798 	else if (a <= 10 && a >= 1)
799 		{
800 		double intpart;
801 		if (modf(a, &intpart) < 0.05)
802 			sprintf(Str, "%.0f", d);
803 		else
804 			sprintf(Str, "%.1f", d);
805 		}
806 	else if (a > 10 && a < 10000)
807 		sprintf(Str, "%.0f", d);
808 	else if (a < 1e6)
809 		sprintf(Str, "%.1fk", d/1e3);
810 	else if (a < 10e6)
811 		sprintf(Str, "%.1fM", d/1e6);
812 	else if (a < 1e9)
813 		sprintf(Str, "%.0fM", d/1e6);
814 	else if (a < 10e9)
815 		sprintf(Str, "%.1fG", d/1e9);
816 	else if (a < 100e9)
817 		sprintf(Str, "%.0fG", d/1e9);
818 	else
819 		sprintf(Str, "%.3g", d);
820 	return Str;
821 	}
822 
823 bool opt_quiet = false;
824 bool opt_version = false;
825 bool opt_logopts = false;
826 bool opt_compilerinfo = false;
827 bool opt_help = false;
828 string opt_log = "";
829 
830 bool optset_quiet = false;
831 bool optset_version = false;
832 bool optset_logopts = false;
833 bool optset_compilerinfo = false;
834 bool optset_help = false;
835 bool optset_log = false;
836 
837 static string g_CurrentProgressLine;
838 static string g_ProgressDesc;
839 static unsigned g_ProgressIndex;
840 static unsigned g_ProgressCount;
841 
842 static unsigned g_CurrProgressLineLength;
843 static unsigned g_LastProgressLineLength;
844 static unsigned g_CountsInterval;
845 static unsigned g_StepCalls;
846 static time_t g_TimeLastOutputStep;
847 
GetProgressPrefixStr(string & s)848 static string &GetProgressPrefixStr(string &s)
849 	{
850 	double Bytes = GetMemUseBytes();
851 	unsigned Secs = GetElapsedSecs();
852 	s = string(SecsToHHMMSS(Secs));
853 	if (Bytes > 0)
854 		{
855 		s.push_back(' ');
856 		char Str[32];
857 		sprintf(Str, "%5.5s", MemBytesToStr(Bytes));
858 		s += string(Str);
859 		}
860 	s.push_back(' ');
861 	return s;
862 	}
863 
ProgressLog(const char * Format,...)864 void ProgressLog(const char *Format, ...)
865 	{
866 	string Str;
867 	va_list ArgList;
868 	va_start(ArgList, Format);
869 	myvstrprintf(Str, Format, ArgList);
870 	va_end(ArgList);
871 
872 	Log("%s", Str.c_str());
873 	Progress("%s", Str.c_str());
874 	}
875 
Progress(const char * Format,...)876 void Progress(const char *Format, ...)
877 	{
878 	if (opt_quiet)
879 		return;
880 
881 	string Str;
882 	va_list ArgList;
883 	va_start(ArgList, Format);
884 	myvstrprintf(Str, Format, ArgList);
885 	va_end(ArgList);
886 
887 #if	0
888 	Log("Progress(");
889 	for (unsigned i = 0; i < Str.size(); ++i)
890 		{
891 		char c = Str[i];
892 		if (c == '\r')
893 			Log("\\r");
894 		else if (c == '\n')
895 			Log("\\n");
896 		else
897 			Log("%c", c);
898 		}
899 	Log(")\n");
900 #endif //0
901 
902 	for (unsigned i = 0; i < Str.size(); ++i)
903 		{
904 		if (g_CurrProgressLineLength == 0)
905 			{
906 			string s;
907 			GetProgressPrefixStr(s);
908 			for (unsigned j = 0; j < s.size(); ++j)
909 				{
910 				fputc(s[j], stderr);
911 				++g_CurrProgressLineLength;
912 				}
913 			}
914 
915 		char c = Str[i];
916 		if (c == '\n' || c == '\r')
917 			{
918 			for (unsigned j = g_CurrProgressLineLength; j < g_LastProgressLineLength; ++j)
919 				fputc(' ', stderr);
920 			if (c == '\n')
921 				g_LastProgressLineLength = 0;
922 			else
923 				g_LastProgressLineLength = g_CurrProgressLineLength;
924 			g_CurrProgressLineLength = 0;
925 			fputc(c, stderr);
926 			}
927 		else
928 			{
929 			fputc(c, stderr);
930 			++g_CurrProgressLineLength;
931 			}
932 		}
933 	}
934 
ProgressExit()935 void ProgressExit()
936 	{
937 	time_t Now = time(0);
938 	struct tm *t = localtime(&Now);
939 	const char *s = asctime(t);
940 	unsigned Secs = GetElapsedSecs();
941 
942 	Log("\n");
943 	Log("Finished %s", s); // there is a newline in s
944 	Log("Elapsed time %s\n", SecsToHHMMSS((int) Secs));
945 	Log("Max memory %s\n", MemBytesToStr(g_PeakMemUseBytes));
946 #if	WIN32 && DEBUG
947 // Skip exit(), which can be very slow in DEBUG build
948 // VERY DANGEROUS practice, because it skips global destructors.
949 // But if you know the rules, you can break 'em, right?
950 	ExitProcess(0);
951 #endif
952 	}
953 
PctStr(double x,double y)954 const char *PctStr(double x, double y)
955 	{
956 	if (y == 0)
957 		{
958 		if (x == 0)
959 			return "100%";
960 		else
961 			return "inf%";
962 		}
963 	static char Str[16];
964 	double p = x*100.0/y;
965 	sprintf(Str, "%5.1f%%", p);
966 	return Str;
967 	}
968 
GetProgressLevelStr(string & s)969 string &GetProgressLevelStr(string &s)
970 	{
971 	unsigned Index = g_ProgressIndex;
972 	unsigned Count = g_ProgressCount;
973 	if (Count == UINT_MAX)
974 		{
975 		if (Index == UINT_MAX)
976 			s = "100%";
977 		else
978 			{
979 			char Tmp[16];
980 			sprintf(Tmp, "%u", Index);
981 			s = Tmp;
982 			}
983 		}
984 	else
985 		s = string(PctStr(Index+1, Count));
986 	s += string(" ") + g_ProgressDesc;
987 	return s;
988 	}
989 
ProgressStep(unsigned i,unsigned N,const char * Format,...)990 void ProgressStep(unsigned i, unsigned N, const char *Format, ...)
991 	{
992 	if (opt_quiet)
993 		return;
994 
995 	if (i == 0)
996 		{
997 		string Str;
998 		va_list ArgList;
999 		va_start(ArgList, Format);
1000 		myvstrprintf(Str, Format, ArgList);
1001 		va_end(ArgList);
1002 		g_ProgressDesc = Str;
1003 		g_ProgressIndex = 0;
1004 		g_ProgressCount = N;
1005 		g_CountsInterval = 1;
1006 		g_StepCalls = 0;
1007 		g_TimeLastOutputStep = 0;
1008 		if (g_CurrProgressLineLength > 0)
1009 			Progress("\n");
1010 		}
1011 
1012 	if (i >= N && i != UINT_MAX)
1013 		Die("ProgressStep(%u,%u)", i, N);
1014 	bool IsLastStep = (i == UINT_MAX || i + 1 == N);
1015 	if (!IsLastStep)
1016 		{
1017 		++g_StepCalls;
1018 		if (g_StepCalls%g_CountsInterval != 0)
1019 			return;
1020 
1021 		time_t Now = time(0);
1022 		if (Now == g_TimeLastOutputStep)
1023 			{
1024 			if (g_CountsInterval < 128)
1025 				g_CountsInterval = (g_CountsInterval*3)/2;
1026 			else
1027 				g_CountsInterval += 64;
1028 			return;
1029 			}
1030 		else
1031 			{
1032 			time_t Secs = Now - g_TimeLastOutputStep;
1033 			if (Secs > 1)
1034 				g_CountsInterval = unsigned(g_CountsInterval/(Secs*8));
1035 			}
1036 
1037 		if (g_CountsInterval < 1)
1038 			g_CountsInterval = 1;
1039 
1040 		g_TimeLastOutputStep = Now;
1041 		}
1042 
1043 	g_ProgressIndex = i;
1044 
1045 	if (i > 0)
1046 		{
1047 		va_list ArgList;
1048 		va_start(ArgList, Format);
1049 		myvstrprintf(g_ProgressDesc, Format, ArgList);
1050 		}
1051 
1052 	string LevelStr;
1053 	GetProgressLevelStr(LevelStr);
1054 	Progress(" %s\r", LevelStr.c_str());
1055 
1056 	if (IsLastStep)
1057 		{
1058 		g_CountsInterval = 1;
1059 		fputc('\n', stderr);
1060 		}
1061 	}
1062 
1063 enum OptType
1064 	{
1065 	OT_Flag,
1066 	OT_Tog,
1067 	OT_Int,
1068 	OT_Uns,
1069 	OT_Str,
1070 	OT_Float,
1071 	OT_Enum
1072 	};
1073 
1074 struct OptInfo
1075 	{
1076 	void *Value;
1077 	bool *OptSet;
1078 	string LongName;
1079 	OptType Type;
1080 	int iMin;
1081 	int iMax;
1082 	unsigned uMin;
1083 	unsigned uMax;
1084 	double dMin;
1085 	double dMax;
1086 	map<string, unsigned> EnumValues;
1087 
1088 	bool bDefault;
1089 	int iDefault;
1090 	unsigned uDefault;
1091 	double dDefault;
1092 	string strDefault;
1093 
1094 	string Help;
1095 
operator <OptInfo1096 	bool operator<(const OptInfo &rhs) const
1097 		{
1098 		return LongName < rhs.LongName;
1099 		}
1100 	};
1101 
1102 static set<OptInfo> g_Opts;
1103 
Help()1104 void Help()
1105 	{
1106 	printf("\n");
1107 
1108 	void Usage();
1109 	Usage();
1110 
1111 	for (set<OptInfo>::const_iterator p = g_Opts.begin(); p != g_Opts.end(); ++p)
1112 		{
1113 		const OptInfo &Opt = *p;
1114 
1115 		printf("\n");
1116 		string LongName = Opt.LongName.c_str();
1117 		if (Opt.Type == OT_Tog)
1118 			LongName = string("[no]") + LongName;
1119 		printf("  --%s ", LongName.c_str());
1120 
1121 		switch (Opt.Type)
1122 			{
1123 		case OT_Flag:
1124 			break;
1125 		case OT_Tog:
1126 			break;
1127 		case OT_Int:
1128 			printf("<int>");
1129 			break;
1130 		case OT_Uns:
1131 			printf("<uint>");
1132 			break;
1133 		case OT_Str:
1134 			printf("<str>");
1135 			break;
1136 		case OT_Float:
1137 			printf("<float>");
1138 			break;
1139 		case OT_Enum:
1140 			printf("<enum>");
1141 			break;
1142 		default:
1143 			printf("??type");
1144 			break;
1145 			}
1146 
1147 		printf("  ");
1148 		const string &s = Opt.Help;
1149 		for (string::const_iterator q = s.begin(); q != s.end(); ++q)
1150 			{
1151 			char c = *q;
1152 			if (c == '\n')
1153 				printf("\n   ");
1154 			else
1155 				printf("%c", c);
1156 			}
1157 		printf("\n");
1158 		}
1159 	printf("\n");
1160 	exit(0);
1161 	}
1162 
CmdLineErr(const char * Format,...)1163 void CmdLineErr(const char *Format, ...)
1164 	{
1165 	va_list ArgList;
1166 	va_start(ArgList, Format);
1167 	string Str;
1168 	myvstrprintf(Str, Format, ArgList);
1169 	va_end(ArgList);
1170 	fprintf(stderr, "\n");
1171 	fprintf(stderr, "Invalid command line\n");
1172 	fprintf(stderr, "%s\n", Str.c_str());
1173 	fprintf(stderr, "For list of command-line options use --help.\n");
1174 	fprintf(stderr, "\n");
1175 	exit(1);
1176 	}
1177 
GetOptInfo(const string & LongName,bool ErrIfNotFound)1178 static set<OptInfo>::iterator GetOptInfo(const string &LongName,
1179   bool ErrIfNotFound)
1180 	{
1181 	for (set<OptInfo>::iterator p = g_Opts.begin();
1182 	  p != g_Opts.end(); ++p)
1183 		{
1184 		const OptInfo &Opt = *p;
1185 		if (Opt.LongName == LongName)
1186 			return p;
1187 		if (Opt.Type == OT_Tog && "no" + Opt.LongName == LongName)
1188 			return p;
1189 		}
1190 	if (ErrIfNotFound)
1191 		CmdLineErr("Option --%s is invalid", LongName.c_str());
1192 	return g_Opts.end();
1193 	}
1194 
AddOpt(const OptInfo & Opt)1195 static void AddOpt(const OptInfo &Opt)
1196 	{
1197 	if (GetOptInfo(Opt.LongName, false) != g_Opts.end())
1198 		Die("Option --%s defined twice", Opt.LongName.c_str());
1199 	g_Opts.insert(Opt);
1200 	}
1201 
1202 #ifdef _MSC_VER
1203 #pragma warning(disable: 4505) // unreferenced local function
1204 #endif
1205 
DefineFlagOpt(const string & LongName,const string & Help,void * Value,bool * OptSet)1206 static void DefineFlagOpt(const string &LongName, const string &Help,
1207   void *Value, bool *OptSet)
1208 	{
1209 	*(bool *) Value = false;
1210 
1211 	OptInfo Opt;
1212 	Opt.Value = Value;
1213 	Opt.OptSet = OptSet;
1214 	Opt.LongName = LongName;
1215 	Opt.bDefault = false;
1216 	Opt.Help = Help;
1217 	Opt.Type = OT_Flag;
1218 	AddOpt(Opt);
1219 	}
1220 
DefineTogOpt(const string & LongName,bool Default,const string & Help,void * Value,bool * OptSet)1221 static void DefineTogOpt(const string &LongName, bool Default, const string &Help,
1222   void *Value, bool *OptSet)
1223 	{
1224 	*(bool *) Value = Default;
1225 
1226 	OptInfo Opt;
1227 	Opt.Value = Value;
1228 	Opt.OptSet = OptSet;
1229 	Opt.LongName = LongName;
1230 	Opt.bDefault = Default;
1231 	Opt.Help = Help;
1232 	Opt.Type = OT_Tog;
1233 	AddOpt(Opt);
1234 	}
1235 
DefineIntOpt(const string & LongName,int Default,int Min,int Max,const string & Help,void * Value,bool * OptSet)1236 static void DefineIntOpt(const string &LongName, int Default, int Min, int Max,
1237   const string &Help, void *Value, bool *OptSet)
1238 	{
1239 	*(int *) Value = Default;
1240 
1241 	OptInfo Opt;
1242 	Opt.Value = Value;
1243 	Opt.OptSet = OptSet;
1244 	Opt.LongName = LongName;
1245 	Opt.iDefault = Default;
1246 	Opt.iMin = Min;
1247 	Opt.iMax = Max;
1248 	Opt.Help = Help;
1249 	Opt.Type = OT_Int;
1250 	AddOpt(Opt);
1251 	}
1252 
DefineUnsOpt(const string & LongName,unsigned Default,unsigned Min,unsigned Max,const string & Help,void * Value,bool * OptSet)1253 static void DefineUnsOpt(const string &LongName, unsigned Default, unsigned Min,
1254   unsigned Max, const string &Help, void *Value, bool *OptSet)
1255 	{
1256 	*(unsigned *) Value = Default;
1257 
1258 	OptInfo Opt;
1259 	Opt.Value = Value;
1260 	Opt.OptSet = OptSet;
1261 	Opt.LongName = LongName;
1262 	Opt.uDefault = Default;
1263 	Opt.uMin = Min;
1264 	Opt.uMax = Max;
1265 	Opt.Help = Help;
1266 	Opt.Type = OT_Uns;
1267 	AddOpt(Opt);
1268 	}
1269 
DefineFloatOpt(const string & LongName,double Default,double Min,double Max,const string & Help,void * Value,bool * OptSet)1270 static void DefineFloatOpt(const string &LongName, double Default, double Min,
1271   double Max, const string &Help, void *Value, bool *OptSet)
1272 	{
1273 	*(double *) Value = Default;
1274 
1275 	OptInfo Opt;
1276 	Opt.Value = Value;
1277 	Opt.OptSet = OptSet;
1278 	Opt.LongName = LongName;
1279 	Opt.dDefault = Default;
1280 	Opt.dMin = Min;
1281 	Opt.dMax = Max;
1282 	Opt.Help = Help;
1283 	Opt.Type = OT_Float;
1284 	AddOpt(Opt);
1285 	}
1286 
DefineStrOpt(const string & LongName,const char * Default,const string & Help,void * Value,bool * OptSet)1287 static void DefineStrOpt(const string &LongName, const char *Default,
1288   const string &Help, void *Value, bool *OptSet)
1289 	{
1290 	*(string *) Value = (Default == 0 ? "" : string(Default));
1291 
1292 	OptInfo Opt;
1293 	Opt.Value = Value;
1294 	Opt.OptSet = OptSet;
1295 	Opt.LongName = LongName;
1296 	Opt.strDefault = (Default == 0 ? "" : string(Default));
1297 	Opt.Help = Help;
1298 	Opt.Type = OT_Str;
1299 	AddOpt(Opt);
1300 	}
1301 
ParseEnumValues(const string & Values,map<string,unsigned> & EnumValues)1302 static void ParseEnumValues(const string &Values, map<string, unsigned> &EnumValues)
1303 	{
1304 	EnumValues.clear();
1305 
1306 	string Name;
1307 	string Value;
1308 	bool Eq = false;
1309 	for (string::const_iterator p = Values.begin(); ; ++p)
1310 		{
1311 		char c = (p == Values.end() ? '|' : *p);
1312 		if (isspace(c))
1313 			;
1314 		else if (c == '|')
1315 			{
1316 			if (EnumValues.find(Name) != EnumValues.end())
1317 				Die("Invalid enum values, '%s' defined twice: '%s'",
1318 				  Name.c_str(), Values.c_str());
1319 			if (Name.empty() || Value.empty())
1320 				Die("Invalid enum values, empty name or value: '%s'",
1321 				  Values.c_str());
1322 
1323 			EnumValues[Name] = atoi(Value.c_str());
1324 			Name.clear();
1325 			Value.clear();
1326 			Eq = false;
1327 			}
1328 		else if (c == '=')
1329 			Eq = true;
1330 		else if (Eq)
1331 			Value.push_back(c);
1332 		else
1333 			Name.push_back(c);
1334 		if (p == Values.end())
1335 			return;
1336 		}
1337 	}
1338 
DefineEnumOpt(const string & LongName,const string & ShortName,int Default,const string & Values,const string & Help,void * Value)1339 static void DefineEnumOpt(const string &LongName, const string &ShortName,
1340   int Default, const string &Values, const string &Help, void *Value)
1341 	{
1342 	*(int *) Value = Default;
1343 
1344 	OptInfo Opt;
1345 	Opt.Value = Value;
1346 	Opt.LongName = LongName;
1347 	Opt.iDefault = Default;
1348 	Opt.Help = Help;
1349 	Opt.Type = OT_Enum;
1350 	ParseEnumValues(Values, Opt.EnumValues);
1351 	AddOpt(Opt);
1352 	}
1353 #undef FLAG_OPT
1354 #undef TOG_OPT
1355 #undef INT_OPT
1356 #undef UNS_OPT
1357 #undef FLT_OPT
1358 #undef STR_OPT
1359 #undef ENUM_OPT
1360 #define FLAG_OPT(LongName)							bool opt_##LongName; bool optset_##LongName;
1361 #define TOG_OPT(LongName, Default)					bool opt_##LongName; bool optset_##LongName;
1362 #define INT_OPT(LongName, Default, Min, Max)		int opt_##LongName; bool optset_##LongName;
1363 #define UNS_OPT(LongName, Default, Min, Max)		unsigned opt_##LongName; bool optset_##LongName;
1364 #define FLT_OPT(LongName, Default, Min, Max)		double opt_##LongName; bool optset_##LongName;
1365 #define STR_OPT(LongName, Default)					string opt_##LongName; bool optset_##LongName;
1366 #define ENUM_OPT(LongName, Values, Default)			int opt_##LongName; bool optset_##LongName;
1367 #include "myopts.h"
1368 
EnumStrToInt(const OptInfo & Opt,const string & Value)1369 static int EnumStrToInt(const OptInfo &Opt, const string &Value)
1370 	{
1371 	const map<string, unsigned> &e = Opt.EnumValues;
1372 	string s;
1373 	for (map<string, unsigned>::const_iterator p = e.begin(); p != e.end(); ++p)
1374 		{
1375 		if (Value == p->first)
1376 			return p->second;
1377 		s += " " + p->first;
1378 		}
1379 	CmdLineErr("--%s %s not recognized, valid are: %s",
1380 	  Opt.LongName.c_str(), Value.c_str(), s.c_str());
1381 	ureturn(-1);
1382 	}
1383 
SetOpt(OptInfo & Opt,const string & Value)1384 static void SetOpt(OptInfo &Opt, const string &Value)
1385 	{
1386 	*Opt.OptSet = true;
1387 	switch (Opt.Type)
1388 		{
1389 	case OT_Int:
1390 		{
1391 		*(int *) Opt.Value = atoi(Value.c_str());
1392 		break;
1393 		}
1394 	case OT_Uns:
1395 		{
1396 		unsigned uValue = 0;
1397 		int n = sscanf(Value.c_str(), "%u", &uValue);
1398 		if (n != 1)
1399 			CmdLineErr("Invalid value '%s' for --%s",
1400 			  Value.c_str(), Opt.LongName.c_str());
1401 		*(unsigned *) Opt.Value = uValue;
1402 		break;
1403 		}
1404 	case OT_Float:
1405 		{
1406 		*(double *) Opt.Value = atof(Value.c_str());
1407 		break;
1408 		}
1409 	case OT_Str:
1410 		{
1411 		*(string *) Opt.Value = Value;
1412 		break;
1413 		}
1414 	case OT_Enum:
1415 		{
1416 		*(int *) Opt.Value = EnumStrToInt(Opt, Value);
1417 		break;
1418 		}
1419 	default:
1420 		asserta(false);
1421 		}
1422 	}
1423 
LogOpts()1424 void LogOpts()
1425 	{
1426 	for (set<OptInfo>::const_iterator p = g_Opts.begin(); p != g_Opts.end(); ++p)
1427 		{
1428 		const OptInfo &Opt = *p;
1429 		Log("%s = ", Opt.LongName.c_str());
1430 		switch (Opt.Type)
1431 			{
1432 		case OT_Flag:
1433 			Log("%s", (*(bool *) Opt.Value) ? "yes" : "no");
1434 			break;
1435 		case OT_Tog:
1436 			Log("%s", (*(bool *) Opt.Value) ? "on" : "off");
1437 			break;
1438 		case OT_Int:
1439 			Log("%d", *(int *) Opt.Value);
1440 			break;
1441 		case OT_Uns:
1442 			Log("%u", *(unsigned *) Opt.Value);
1443 			break;
1444 		case OT_Float:
1445 			{
1446 			double Value = *(double *) Opt.Value;
1447 			if (Value == FLT_MAX)
1448 				Log("*");
1449 			else
1450 				Log("%g", Value);
1451 			break;
1452 			}
1453 		case OT_Str:
1454 			Log("%s", (*(string *) Opt.Value).c_str());
1455 			break;
1456 		case OT_Enum:
1457 			Log("%d", *(int *) Opt.Value);
1458 			break;
1459 		default:
1460 			asserta(false);
1461 			}
1462 		Log("\n");
1463 		}
1464 	}
1465 
CompilerInfo()1466 static void CompilerInfo()
1467 	{
1468 #ifdef _FILE_OFFSET_BITS
1469     printf("_FILE_OFFSET_BITS=%d\n", _FILE_OFFSET_BITS);
1470 #else
1471     printf("_FILE_OFFSET_BITS not defined\n");
1472 #endif
1473 
1474 #define x(t)	printf("sizeof(" #t ") = %d\n", (int) sizeof(t));
1475 	x(int)
1476 	x(long)
1477 	x(float)
1478 	x(double)
1479 	x(void *)
1480 	x(off_t)
1481 #undef x
1482 	exit(0);
1483 	}
1484 
Split(const string & Str,vector<string> & Fields,char Sep)1485 void Split(const string &Str, vector<string> &Fields, char Sep)
1486 	{
1487 	Fields.clear();
1488 	const unsigned Length = (unsigned) Str.size();
1489 	string s;
1490 	for (unsigned i = 0; i < Length; ++i)
1491 		{
1492 		char c = Str[i];
1493 		if ((Sep == 0 && isspace(c)) || c == Sep)
1494 			{
1495 			if (!s.empty() || Sep != 0)
1496 				Fields.push_back(s);
1497 			s.clear();
1498 			}
1499 		else
1500 			s.push_back(c);
1501 		}
1502 	if (!s.empty())
1503 		Fields.push_back(s);
1504 	}
1505 
GetArgsFromFile(const string & FileName,vector<string> & Args)1506 static void GetArgsFromFile(const string &FileName, vector<string> &Args)
1507 	{
1508 	Args.clear();
1509 
1510 	FILE *f = OpenStdioFile(FileName);
1511 	string Line;
1512 	while (ReadLineStdioFile(f, Line))
1513 		{
1514 		size_t n = Line.find('#');
1515 		if (n != string::npos)
1516 			Line = Line.substr(0, n);
1517 		vector<string> Fields;
1518 		Split(Line, Fields);
1519 		Args.insert(Args.end(), Fields.begin(), Fields.end());
1520 		}
1521 	CloseStdioFile(f);
1522 	}
1523 
MyCmdLine(int argc,char ** argv)1524 void MyCmdLine(int argc, char **argv)
1525 	{
1526 	static unsigned RecurseDepth = 0;
1527 	++RecurseDepth;
1528 
1529 	DefineFlagOpt("compilerinfo", "Write info about compiler types and #defines to stdout.",
1530 	  (void *) &opt_compilerinfo, &optset_compilerinfo);
1531 	DefineFlagOpt("quiet", "Turn off progress messages.", (void *) &opt_quiet, &optset_quiet);
1532 	DefineFlagOpt("version", "Show version and exit.", (void *) &opt_version, &optset_version);
1533 	DefineFlagOpt("logopts", "Log options.", (void *) &opt_logopts, &optset_logopts);
1534 	DefineFlagOpt("help", "Display command-line options.", (void *) &opt_help, &optset_help);
1535 	DefineStrOpt("log", "", "Log file name.", (void *) &opt_log, &optset_log);
1536 
1537 #undef FLAG_OPT
1538 #undef TOG_OPT
1539 #undef INT_OPT
1540 #undef UNS_OPT
1541 #undef FLT_OPT
1542 #undef STR_OPT
1543 #undef ENUM_OPT
1544 #define FLAG_OPT(LongName)						DefineFlagOpt(#LongName, "help", (void *) &opt_##LongName, &optset_##LongName);
1545 #define TOG_OPT(LongName, Default)				DefineTogOpt(#LongName, Default, "help", (void *) &opt_##LongName, &optset_##LongName);
1546 #define INT_OPT(LongName, Default, Min, Max)	DefineIntOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);
1547 #define UNS_OPT(LongName, Default, Min, Max)	DefineUnsOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);
1548 #define FLT_OPT(LongName, Default, Min, Max)	DefineFloatOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);
1549 #define STR_OPT(LongName, Default)				DefineStrOpt(#LongName, Default, "help", (void *) &opt_##LongName, &optset_##LongName);
1550 #define ENUM_OPT(LongName, Values, Default)		DefineEnumOpt(#LongName, Values, Default, "help", (void *) &opt_##LongName, &optset_##LongName);
1551 #include "myopts.h"
1552 
1553 	if (RecurseDepth == 0)
1554 		g_Argv.clear();
1555 
1556 	for (int i = 0; i < argc; ++i) {
1557 		g_Argv.push_back(string(argv[i]));
1558 	}
1559 
1560 	int i = 1;
1561 	for (;;)
1562 		{
1563 		if (i >= argc)
1564 			break;
1565 		const string &Arg = g_Argv[i];
1566 
1567 		if (Arg.empty())
1568 			continue;
1569 		else if (Arg == "file:" && i + 1 < argc)
1570 			{
1571 			const string &FileName = g_Argv[i+1];
1572 			vector<string> Args;
1573 			GetArgsFromFile(FileName, Args);
1574 			for (vector<string>::const_iterator p = Args.begin();
1575 			  p != Args.end(); ++p)
1576 				{
1577 				g_Argv.push_back(*p);
1578 				++argc;
1579 				}
1580 			i += 2;
1581 			continue;
1582 			}
1583 		else if (Arg.size() > 1 && Arg[0] == '-')
1584 			{
1585 			string LongName = (Arg.size() > 2 && Arg[1] == '-' ? Arg.substr(2) : Arg.substr(1));
1586 			OptInfo Opt = *GetOptInfo(LongName, true);
1587 			*Opt.OptSet = true;
1588 			if (Opt.Type == OT_Flag)
1589 				{
1590 				g_Opts.erase(Opt);
1591 				*(bool *) Opt.Value = true;
1592 				g_Opts.insert(Opt);
1593 				++i;
1594 				continue;
1595 				}
1596 			else if (Opt.Type == OT_Tog)
1597 				{
1598 				g_Opts.erase(Opt);
1599 				if (string("no") + Opt.LongName == LongName)
1600 					*(bool *) Opt.Value = false;
1601 				else
1602 					{
1603 					asserta(Opt.LongName == LongName);
1604 					*(bool *) Opt.Value = true;
1605 					}
1606 				g_Opts.insert(Opt);
1607 				++i;
1608 				continue;
1609 				}
1610 
1611 			++i;
1612 			if (i >= argc)
1613 				CmdLineErr("Missing value for option --%s", LongName.c_str());
1614 
1615 			string Value = g_Argv[i];
1616 			SetOpt(Opt, Value);
1617 
1618 			++i;
1619 			continue;
1620 			}
1621 		else
1622 			CmdLineErr("Expected -option_name or --option_name, got '%s'", Arg.c_str());
1623 		}
1624 
1625 	--RecurseDepth;
1626 	if (RecurseDepth > 0)
1627 		return;
1628 
1629 	if (opt_help)
1630 		Help();
1631 
1632 	if (opt_compilerinfo)
1633 		CompilerInfo();
1634 
1635 	SetLogFileName(opt_log);
1636 
1637 	if (opt_log != "")
1638 		{
1639 		for (int i = 0; i < argc; ++i)
1640 			Log("%s%s", i == 0 ? "" : " ", g_Argv[i].c_str());
1641 		Log("\n");
1642 		time_t Now = time(0);
1643 		struct tm *t = localtime(&Now);
1644 		const char *s = asctime(t);
1645 		Log("Started %s", s); // there is a newline in s
1646 		Log("Version " MY_VERSION ".%s\n", SVN_VERSION);
1647 		Log("\n");
1648 		}
1649 
1650 	if (opt_logopts)
1651 		LogOpts();
1652 	}
1653 
Pct(double x,double y)1654 double Pct(double x, double y)
1655 	{
1656 	if (y == 0.0f)
1657 		return 0.0f;
1658 	return (x*100.0f)/y;
1659 	}
1660 
GetCmdLine(string & s)1661 void GetCmdLine(string &s)
1662 	{
1663 	s.clear();
1664 	for (unsigned i = 0; i < SIZE(g_Argv); ++i)
1665 		{
1666 		if (i > 0)
1667 			s += " ";
1668 		s += g_Argv[i];
1669 		}
1670 	}
1671 
mystrsave(const char * s)1672 char *mystrsave(const char *s)
1673 	{
1674 	unsigned n = unsigned(strlen(s));
1675 	char *t = myalloc(char, n+1);
1676 	memcpy(t, s, n+1);
1677 	return t;
1678 	}
1679 
Logu(unsigned u,unsigned w,unsigned prefixspaces)1680 void Logu(unsigned u, unsigned w, unsigned prefixspaces)
1681 	{
1682 	for (unsigned i = 0; i < prefixspaces; ++i)
1683 		Log(" ");
1684 	if (u == UINT_MAX)
1685 		Log("%*.*s", w, w, "*");
1686 	else
1687 		Log("%*u", w, u);
1688 	}
1689 
Logf(float x,unsigned w,unsigned prefixspaces)1690 void Logf(float x, unsigned w, unsigned prefixspaces)
1691 	{
1692 	for (unsigned i = 0; i < prefixspaces; ++i)
1693 		Log(" ");
1694 	if (x == FLT_MAX)
1695 		Log("%*.*s", w, w, "*");
1696 	else
1697 		Log("%*.2f", w, x);
1698 	}
1699 
1700 static uint32 g_SLCG_state = 1;
1701 
1702 // Numerical values used by Microsoft C, according to wikipedia:
1703 // http://en.wikipedia.org/wiki/Linear_congruential_generator
1704 static uint32 g_SLCG_a = 214013;
1705 static uint32 g_SLCG_c = 2531011;
1706 
1707 // Simple Linear Congruential Generator
1708 // Bad properties; used just to initialize the better generator.
SLCG_rand()1709 static uint32 SLCG_rand()
1710 	{
1711 	g_SLCG_state = g_SLCG_state*g_SLCG_a + g_SLCG_c;
1712 	return g_SLCG_state;
1713 	}
1714 
SLCG_srand(uint32 Seed)1715 static void SLCG_srand(uint32 Seed)
1716 	{
1717 	g_SLCG_state = Seed;
1718 	for (int i = 0; i < 10; ++i)
1719 		SLCG_rand();
1720 	}
1721 
1722 /***
1723 A multiply-with-carry random number generator, see:
1724 http://en.wikipedia.org/wiki/Multiply-with-carry
1725 
1726 The particular multipliers used here were found on
1727 the web where they are attributed to George Marsaglia.
1728 ***/
1729 
1730 static bool g_InitRandDone = false;
1731 static uint32 g_X[5];
1732 
RandInt32()1733 uint32 RandInt32()
1734 	{
1735 	InitRand();
1736 
1737 	uint64 Sum = 2111111111*(uint64) g_X[3] + 1492*(uint64) g_X[2] +
1738 	  1776*(uint64) g_X[1] + 5115*(uint64) g_X[0] + g_X[4];
1739 	g_X[3] = g_X[2];
1740 	g_X[2] = g_X[1];
1741 	g_X[1] = g_X[0];
1742 	g_X[4] = (uint32) (Sum >> 32);
1743 	g_X[0] = (uint32) Sum;
1744 	return g_X[0];
1745 	}
1746 
randu32()1747 unsigned randu32()
1748 	{
1749 	return (unsigned) RandInt32();
1750 	}
1751 
InitRand()1752 void InitRand()
1753 	{
1754 	if (g_InitRandDone)
1755 		return;
1756 // Do this first to avoid recursion
1757 	g_InitRandDone = true;
1758 
1759 	unsigned Seed = (optset_randseed ? opt_randseed : (unsigned) (time(0)*getpid()));
1760 	Log("RandSeed=%u\n", Seed);
1761 	SLCG_srand(Seed);
1762 
1763 	for (unsigned i = 0; i < 5; i++)
1764 		g_X[i] = SLCG_rand();
1765 
1766 	for (unsigned i = 0; i < 100; i++)
1767 		RandInt32();
1768 	}
1769 
1770 // MUST COME AT END BECAUSE OF #undef
1771 #if	RCE_MALLOC
1772 #undef mymalloc
1773 #undef myfree
1774 #undef myfree2
mymalloc(unsigned bytes,const char * FileName,int Line)1775 void *mymalloc(unsigned bytes, const char *FileName, int Line)
1776 	{
1777 	void *rce_malloc(unsigned bytes, const char *FileName, int Line);
1778 	return rce_malloc(bytes, FileName, Line);
1779 	}
1780 
myfree(void * p,const char * FileName,int Line)1781 void myfree(void *p, const char *FileName, int Line)
1782 	{
1783 	void rce_free(void *p, const char *FileName, int Line);
1784 	rce_free(p, FileName, Line);
1785 	}
1786 
myfree2(void * p,unsigned bytes,const char * FileName,int Line)1787 void myfree2(void *p, unsigned bytes, const char *FileName, int Line)
1788 	{
1789 	void rce_free(void *p, const char *FileName, int Line);
1790 	rce_free(p, FileName, Line);
1791 	}
1792 
1793 #else // RCE_MALLOC
mymalloc(unsigned bytes)1794 void *mymalloc(unsigned bytes)
1795 	{
1796 	++g_NewCalls;
1797 	if (g_InitialMemUseBytes == 0)
1798 		g_InitialMemUseBytes = GetMemUseBytes();
1799 
1800 	g_TotalAllocBytes += bytes;
1801 	g_NetBytes += bytes;
1802 	if (g_NetBytes > g_MaxNetBytes)
1803 		{
1804 		if (g_NetBytes > g_MaxNetBytes + 10000000)
1805 			GetMemUseBytes();//to force update of peak
1806 		g_MaxNetBytes = g_NetBytes;
1807 		}
1808 	void *p = malloc(bytes);
1809 	//void *p = _malloc_dbg(bytes, _NORMAL_BLOCK, __FILE__, __LINE__);
1810 	if (0 == p)
1811 		{
1812 		double b = GetMemUseBytes();
1813 		fprintf(stderr, "\nOut of memory mymalloc(%u), curr %.3g bytes",
1814 		  (unsigned) bytes, b);
1815 		void LogAllocs();
1816 		LogAllocs();
1817 #if DEBUG && defined(_MSC_VER)
1818 		asserta(_CrtCheckMemory());
1819 #endif
1820 		Die("Out of memory, mymalloc(%u), curr %.3g bytes\n",
1821 		  (unsigned) bytes, b);
1822 		}
1823 	return p;
1824 	}
1825 
myfree(void * p)1826 void myfree(void *p)
1827 	{
1828 	if (p == 0)
1829 		return;
1830 	free(p);
1831 	//_free_dbg(p, _NORMAL_BLOCK);
1832 	}
1833 
myfree2(void * p,unsigned bytes)1834 void myfree2(void *p, unsigned bytes)
1835 	{
1836 	++g_FreeCalls;
1837 	g_TotalFreeBytes += bytes;
1838 	g_NetBytes -= bytes;
1839 
1840 	if (p == 0)
1841 		return;
1842 	free(p);
1843 	}
1844 #endif
1845