--- /dev/null
+#include <time.h>\r
+#include <stdarg.h>\r
+#include <sys/stat.h>\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <string>\r
+#include <vector>\r
+#include <set>\r
+#include <map>\r
+#include <signal.h>\r
+#include <float.h>\r
+\r
+#ifdef _MSC_VER\r
+#include <crtdbg.h>\r
+#include <process.h>\r
+#include <windows.h>\r
+#include <psapi.h>\r
+#include <io.h>\r
+#else\r
+#include <sys/time.h>\r
+#include <sys/resource.h>\r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <fcntl.h>\r
+#include <stdlib.h>\r
+#endif\r
+\r
+#include "myutils.h"\r
+\r
+const char *SVN_VERSION =\r
+#include "svnversion.h"\r
+;\r
+\r
+#define TEST_UTILS 0\r
+\r
+using namespace std;\r
+\r
+const unsigned MY_IO_BUFSIZ = 32000;\r
+const unsigned MAX_FORMATTED_STRING_LENGTH = 64000;\r
+\r
+static char *g_IOBuffers[256];\r
+static time_t g_StartTime = time(0);\r
+static vector<string> g_Argv;\r
+static double g_PeakMemUseBytes;\r
+\r
+#if TEST_UTILS\r
+void TestUtils()\r
+ {\r
+ const int C = 100000000;\r
+ for (int i = 0; i < C; ++i)\r
+ ProgressStep(i, C, "something or other");\r
+\r
+ Progress("\n");\r
+ Progress("Longer message\r");\r
+ Sleep(1000);\r
+ Progress("Short\r");\r
+ Sleep(1000);\r
+ Progress("And longer again\r");\r
+ Sleep(1000);\r
+ Progress("Shrt\n");\r
+ Sleep(1000);\r
+ const unsigned N = 10;\r
+ unsigned M = 10;\r
+ for (unsigned i = 0; i < N; ++i)\r
+ {\r
+ ProgressStep(i, N, "Allocating 1MB blocks");\r
+ for (unsigned j = 0; j < M; ++j)\r
+ {\r
+ ProgressStep(j, M, "Inner loop"); \r
+ malloc(100000);\r
+ Sleep(500);\r
+ }\r
+ }\r
+ }\r
+#endif // TEST_UTILS\r
+\r
+static void AllocBuffer(FILE *f)\r
+ {\r
+ int fd = fileno(f);\r
+ if (fd < 0 || fd >= 256)\r
+ return;\r
+ if (g_IOBuffers[fd] == 0)\r
+ g_IOBuffers[fd] = myalloc(char, MY_IO_BUFSIZ);\r
+ setvbuf(f, g_IOBuffers[fd], _IOFBF, MY_IO_BUFSIZ);\r
+ }\r
+\r
+static void FreeBuffer(FILE *f)\r
+ {\r
+ int fd = fileno(f);\r
+ if (fd < 0 || fd >= 256)\r
+ return;\r
+ if (g_IOBuffers[fd] == 0)\r
+ return;\r
+ myfree(g_IOBuffers[fd]);\r
+ g_IOBuffers[fd] = 0;\r
+ }\r
+\r
+unsigned GetElapsedSecs()\r
+ {\r
+ return (unsigned) (time(0) - g_StartTime);\r
+ }\r
+\r
+static unsigned g_NewCalls;\r
+static unsigned g_FreeCalls;\r
+static double g_InitialMemUseBytes;\r
+static double g_TotalAllocBytes;\r
+static double g_TotalFreeBytes;\r
+static double g_NetBytes;\r
+static double g_MaxNetBytes;\r
+\r
+void LogAllocStats()\r
+ {\r
+ Log("\n");\r
+ Log(" Allocs %u\n", g_NewCalls);\r
+ Log(" Frees %u\n", g_FreeCalls);\r
+ Log("Initial alloc %s\n", MemBytesToStr(g_InitialMemUseBytes));\r
+ Log(" Total alloc %s\n", MemBytesToStr(g_TotalAllocBytes));\r
+ Log(" Total free %s\n", MemBytesToStr(g_TotalFreeBytes));\r
+ Log(" Net bytes %s\n", MemBytesToStr(g_NetBytes));\r
+ Log("Max net bytes %s\n", MemBytesToStr(g_MaxNetBytes));\r
+ Log(" Peak total %s\n", MemBytesToStr(g_MaxNetBytes + g_InitialMemUseBytes));\r
+ }\r
+\r
+bool StdioFileExists(const string &FileName)\r
+ {\r
+ struct stat SD;\r
+ int i = stat(FileName.c_str(), &SD);\r
+ return i == 0;\r
+ }\r
+\r
+void myassertfail(const char *Exp, const char *File, unsigned Line)\r
+ {\r
+ Die("%s(%u) assert failed: %s", File, Line, Exp);\r
+ }\r
+\r
+bool myisatty(int fd)\r
+ {\r
+ return isatty(fd) != 0;\r
+ }\r
+\r
+#ifdef _MSC_VER\r
+#include <io.h>\r
+int fseeko(FILE *stream, off_t offset, int whence)\r
+ {\r
+ off_t FilePos = _fseeki64(stream, offset, whence);\r
+ return (FilePos == -1L) ? -1 : 0;\r
+ }\r
+#define ftello(fm) (off_t) _ftelli64(fm)\r
+#endif\r
+\r
+void LogStdioFileState(FILE *f)\r
+ {\r
+ unsigned long tellpos = (unsigned long) ftello(f);\r
+ long fseek_pos = fseek(f, 0, SEEK_CUR);\r
+ int fd = fileno(f);\r
+ Log("FILE * %p\n", f);\r
+ Log("fileno %d\n", fd);\r
+ Log("feof %d\n", feof(f));\r
+ Log("ferror %d\n", ferror(f));\r
+ Log("ftell %ld\n", tellpos);\r
+ Log("fseek %ld\n", fseek_pos);\r
+#if !defined(_GNU_SOURCE) && !defined(__APPLE_CC__)\r
+ fpos_t fpos;\r
+ int fgetpos_retval = fgetpos(f, &fpos);\r
+ Log("fpos %ld (retval %d)\n", (long) fpos, fgetpos_retval);\r
+// Log("eof %d\n", _eof(fd));\r
+#endif\r
+#ifdef _MSC_VER\r
+ __int64 pos64 = _ftelli64(f);\r
+ Log("_ftelli64 %lld\n", pos64);\r
+#endif\r
+ }\r
+\r
+FILE *OpenStdioFile(const string &FileName)\r
+ {\r
+ const char *Mode = "rb";\r
+ FILE *f = fopen(FileName.c_str(), Mode);\r
+ if (f == 0)\r
+ {\r
+ if (errno == EFBIG)\r
+ {\r
+ if (sizeof(off_t) == 4)\r
+ Die("File too big, off_t is 32 bits, recompile needed");\r
+ else\r
+ Die("Cannot open '%s', file too big (off_t=%u bits)",\r
+ FileName.c_str(), sizeof(off_t)*8);\r
+ }\r
+ Die("Cannot open %s, errno=%d %s",\r
+ FileName.c_str(), errno, strerror(errno));\r
+ }\r
+ AllocBuffer(f);\r
+ return f;\r
+ }\r
+\r
+FILE *CreateStdioFile(const string &FileName)\r
+ {\r
+ FILE *f = fopen(FileName.c_str(), "wb+");\r
+ if (0 == f)\r
+ Die("Cannot create %s, errno=%d %s",\r
+ FileName.c_str(), errno, strerror(errno));\r
+ AllocBuffer(f);\r
+ return f;\r
+ }\r
+\r
+void SetStdioFilePos(FILE *f, off_t Pos)\r
+ {\r
+ if (0 == f)\r
+ Die("SetStdioFilePos failed, f=NULL");\r
+ int Ok = fseeko(f, Pos, SEEK_SET);\r
+ off_t NewPos = ftello(f);\r
+ if (Ok != 0 || Pos != NewPos)\r
+ {\r
+ LogStdioFileState(f);\r
+ Die("SetStdioFilePos(%d) failed, Ok=%d NewPos=%d",\r
+ (int) Pos, Ok, (int) NewPos);\r
+ }\r
+ }\r
+\r
+void ReadStdioFile(FILE *f, off_t Pos, void *Buffer, unsigned Bytes)\r
+ {\r
+ if (0 == f)\r
+ Die("ReadStdioFile failed, f=NULL");\r
+ SetStdioFilePos(f, Pos);\r
+ unsigned BytesRead = fread(Buffer, 1, Bytes, f);\r
+ if (BytesRead != Bytes)\r
+ {\r
+ LogStdioFileState(f);\r
+ Die("ReadStdioFile failed, attempted %d bytes, read %d bytes, errno=%d",\r
+ (int) Bytes, (int) BytesRead, errno);\r
+ }\r
+ }\r
+\r
+void ReadStdioFile(FILE *f, void *Buffer, unsigned Bytes)\r
+ {\r
+ if (0 == f)\r
+ Die("ReadStdioFile failed, f=NULL");\r
+ unsigned BytesRead = fread(Buffer, 1, Bytes, f);\r
+ if (BytesRead != Bytes)\r
+ {\r
+ LogStdioFileState(f);\r
+ Die("ReadStdioFile failed, attempted %d bytes, read %d bytes, errno=%d",\r
+ (int) Bytes, (int) BytesRead, errno);\r
+ }\r
+ }\r
+\r
+// Return values from functions like lseek, ftell, fgetpos are\r
+// "undefined" for files that cannot seek. Attempt to detect\r
+// whether a file can seek by checking for error returns.\r
+bool CanSetStdioFilePos(FILE *f)\r
+ {\r
+// Common special cases\r
+ if (f == stdin || f == stdout || f == stderr)\r
+ return false;\r
+\r
+ fpos_t CurrPos;\r
+ int ok1 = fgetpos(f, &CurrPos);\r
+ if (ok1 < 0)\r
+ return false;\r
+ int ok2 = fseek(f, 0, SEEK_END);\r
+ if (ok2 < 0)\r
+ return false;\r
+ fpos_t EndPos;\r
+ int ok3 = fgetpos(f, &EndPos);\r
+ int ok4 = fsetpos(f, &CurrPos);\r
+ if (!ok3 || !ok4)\r
+ return false;\r
+ return true;\r
+ }\r
+\r
+byte *ReadAllStdioFile(FILE *f, unsigned &FileSize)\r
+ {\r
+ const unsigned BUFF_SIZE = 1024*1024;\r
+\r
+ if (CanSetStdioFilePos(f))\r
+ {\r
+ off_t Pos = GetStdioFilePos(f);\r
+ off_t FileSize = GetStdioFileSize(f);\r
+ if (FileSize > UINT_MAX)\r
+ Die("ReadAllStdioFile: file size > UINT_MAX");\r
+ SetStdioFilePos(f, 0);\r
+ byte *Buffer = myalloc(byte, unsigned(FileSize));\r
+ ReadStdioFile(f, Buffer, unsigned(FileSize));\r
+ SetStdioFilePos(f, Pos);\r
+ FileSize = unsigned(FileSize);\r
+ return Buffer;\r
+ }\r
+\r
+// Can't seek, read one buffer at a time.\r
+ FileSize = 0;\r
+\r
+// Just to initialize so that first call to realloc works.\r
+ byte *Buffer = (byte *) malloc(4);\r
+ if (Buffer == 0)\r
+ Die("ReadAllStdioFile, out of memory");\r
+ for (;;)\r
+ {\r
+ Buffer = (byte *) realloc(Buffer, FileSize + BUFF_SIZE);\r
+ unsigned BytesRead = fread(Buffer + FileSize, 1, BUFF_SIZE, f);\r
+ FileSize += BytesRead;\r
+ if (BytesRead < BUFF_SIZE)\r
+ {\r
+ Buffer = (byte *) realloc(Buffer, FileSize);\r
+ return Buffer;\r
+ }\r
+ }\r
+ }\r
+\r
+byte *ReadAllStdioFile(const std::string &FileName, off_t &FileSize)\r
+ {\r
+#if WIN32\r
+ FILE *f = OpenStdioFile(FileName);\r
+ FileSize = GetStdioFileSize(f);\r
+ CloseStdioFile(f);\r
+\r
+ HANDLE h = CreateFile(FileName.c_str(), GENERIC_READ, FILE_SHARE_READ,\r
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+ if (h == INVALID_HANDLE_VALUE)\r
+ Die("ReadAllStdioFile:Open(%s) failed", FileName.c_str());\r
+\r
+ unsigned uFileSize = (unsigned) FileSize;\r
+ if ((off_t) uFileSize != FileSize)\r
+ Die("File too big (%.1f Gb): %s", double(FileSize)/1e9, FileName.c_str());\r
+\r
+ byte *Buffer = myalloc(byte, uFileSize);\r
+ DWORD BytesRead;\r
+ ReadFile(h, Buffer, uFileSize, &BytesRead, NULL);\r
+ if (FileSize != BytesRead)\r
+ Die("ReadAllStdioFile:Error reading %s, attempted %u got %u",\r
+ FileName.c_str(), FileSize, (unsigned) BytesRead);\r
+\r
+ CloseHandle(h);\r
+ return Buffer;\r
+#else\r
+ int h = open(FileName.c_str(), O_RDONLY);\r
+ if (h < 0)\r
+ Die("ReadAllStdioFile:Cannot open %s", FileName.c_str());\r
+ FileSize = lseek(h, 0, SEEK_END);\r
+ if (FileSize == (off_t) (-1))\r
+ Die("ReadAllStdioFile:Error seeking %s", FileName.c_str());\r
+ // byte *Buffer = myalloc<byte>(FileSize);\r
+ size_t stBytes = (size_t) FileSize;\r
+ if ((off_t) stBytes != FileSize)\r
+ Die("ReadAllStdioFile: off_t overflow");\r
+ byte *Buffer = (byte *) malloc(stBytes);\r
+ if (Buffer == 0)\r
+ Die("ReadAllStdioFile: failed to allocate %s", MemBytesToStr(stBytes));\r
+ lseek(h, 0, SEEK_SET);\r
+ size_t n = read(h, Buffer, stBytes);\r
+ if (n != FileSize)\r
+ Die("ReadAllStdioFile, Error reading %s, attempted %g got %g",\r
+ FileName.c_str(), (double) FileSize, (double) n);\r
+ close(h);\r
+ return Buffer;\r
+#endif\r
+ }\r
+\r
+void WriteStdioFile(FILE *f, off_t Pos, const void *Buffer, unsigned Bytes)\r
+ {\r
+ if (0 == f)\r
+ Die("WriteStdioFile failed, f=NULL");\r
+ SetStdioFilePos(f, Pos);\r
+ unsigned BytesWritten = fwrite(Buffer, 1, Bytes, f);\r
+ if (BytesWritten != Bytes)\r
+ {\r
+ LogStdioFileState(f);\r
+ Die("WriteStdioFile failed, attempted %d bytes, wrote %d bytes, errno=%d",\r
+ (int) Bytes, (int) BytesWritten, errno);\r
+ }\r
+ }\r
+\r
+void WriteStdioFile(FILE *f, const void *Buffer, unsigned Bytes)\r
+ {\r
+ if (0 == f)\r
+ Die("WriteStdioFile failed, f=NULL");\r
+ unsigned BytesWritten = fwrite(Buffer, 1, Bytes, f);\r
+ if (BytesWritten != Bytes)\r
+ {\r
+ LogStdioFileState(f);\r
+ Die("WriteStdioFile failed, attempted %d bytes, wrote %d bytes, errno=%d",\r
+ (int) Bytes, (int) BytesWritten, errno);\r
+ }\r
+ }\r
+\r
+// Return false on EOF, true if line successfully read.\r
+bool ReadLineStdioFile(FILE *f, char *Line, unsigned Bytes)\r
+ {\r
+ if (feof(f))\r
+ return false;\r
+ if ((int) Bytes < 0)\r
+ Die("ReadLineStdioFile: Bytes < 0");\r
+ char *RetVal = fgets(Line, (int) Bytes, f);\r
+ if (NULL == RetVal)\r
+ {\r
+ if (feof(f))\r
+ return false;\r
+ if (ferror(f))\r
+ Die("ReadLineStdioFile: errno=%d", errno);\r
+ Die("ReadLineStdioFile: fgets=0, feof=0, ferror=0");\r
+ }\r
+\r
+ if (RetVal != Line)\r
+ Die("ReadLineStdioFile: fgets != Buffer");\r
+ unsigned n = strlen(Line);\r
+ if (n < 1 || Line[n-1] != '\n')\r
+ Die("ReadLineStdioFile: line too long or missing end-of-line");\r
+ if (n > 0 && (Line[n-1] == '\r' || Line[n-1] == '\n'))\r
+ Line[n-1] = 0;\r
+ if (n > 1 && (Line[n-2] == '\r' || Line[n-2] == '\n'))\r
+ Line[n-2] = 0;\r
+ return true;\r
+ }\r
+\r
+// Return false on EOF, true if line successfully read.\r
+bool ReadLineStdioFile(FILE *f, string &Line)\r
+ {\r
+ Line.clear();\r
+ for (;;)\r
+ {\r
+ int c = fgetc(f);\r
+ if (c == -1)\r
+ {\r
+ if (feof(f))\r
+ {\r
+ if (!Line.empty())\r
+ return true;\r
+ return false;\r
+ }\r
+ Die("ReadLineStdioFile, errno=%d", errno);\r
+ }\r
+ if (c == '\r')\r
+ continue;\r
+ if (c == '\n')\r
+ return true;\r
+ Line.push_back((char) c);\r
+ }\r
+ }\r
+\r
+// Copies all of fFrom regardless of current\r
+// file position, appends to fTo.\r
+void AppendStdioFileToFile(FILE *fFrom, FILE *fTo)\r
+ {\r
+ off_t SavedFromPos = GetStdioFilePos(fFrom);\r
+ off_t FileSize = GetStdioFileSize(fFrom);\r
+ const off_t BUFF_SIZE = 1024*1024;\r
+ char *Buffer = myalloc(char, BUFF_SIZE);\r
+ SetStdioFilePos(fFrom, 0);\r
+ off_t BytesRemaining = FileSize;\r
+ while (BytesRemaining > 0)\r
+ {\r
+ off_t BytesToRead = BytesRemaining;\r
+ if (BytesToRead > BUFF_SIZE)\r
+ BytesToRead = BUFF_SIZE;\r
+ ReadStdioFile(fFrom, Buffer, (unsigned) BytesToRead);\r
+ WriteStdioFile(fTo, Buffer, (unsigned) BytesToRead);\r
+ BytesRemaining -= BytesToRead;\r
+ }\r
+ SetStdioFilePos(fFrom, SavedFromPos);\r
+ }\r
+\r
+void RenameStdioFile(const string &FileNameFrom, const string &FileNameTo)\r
+ {\r
+ int Ok = rename(FileNameFrom.c_str(), FileNameTo.c_str());\r
+ if (Ok != 0)\r
+ Die("RenameStdioFile(%s,%s) failed, errno=%d %s",\r
+ FileNameFrom.c_str(), FileNameTo.c_str(), errno, strerror(errno));\r
+ }\r
+\r
+void FlushStdioFile(FILE *f)\r
+ {\r
+ int Ok = fflush(f);\r
+ if (Ok != 0)\r
+ Die("fflush(%p)=%d,", f, Ok);\r
+ }\r
+\r
+void CloseStdioFile(FILE *f)\r
+ {\r
+ if (f == 0)\r
+ return;\r
+ int Ok = fclose(f);\r
+ if (Ok != 0)\r
+ Die("fclose(%p)=%d", f, Ok);\r
+ FreeBuffer(f);\r
+ }\r
+\r
+off_t GetStdioFilePos(FILE *f)\r
+ {\r
+ off_t FilePos = ftello(f);\r
+ if (FilePos < 0)\r
+ Die("ftello=%d", (int) FilePos);\r
+ return FilePos;\r
+ }\r
+\r
+off_t GetStdioFileSize(FILE *f)\r
+ {\r
+ off_t CurrentPos = GetStdioFilePos(f);\r
+ int Ok = fseeko(f, 0, SEEK_END);\r
+ if (Ok < 0)\r
+ Die("fseek in GetFileSize");\r
+\r
+ off_t Length = ftello(f);\r
+ if (Length < 0)\r
+ Die("ftello in GetFileSize");\r
+ SetStdioFilePos(f, CurrentPos);\r
+ return Length;\r
+ }\r
+\r
+void DeleteStdioFile(const string &FileName)\r
+ {\r
+ int Ok = remove(FileName.c_str());\r
+ if (Ok != 0)\r
+ Die("remove(%s) failed, errno=%d %s", FileName.c_str(), errno, strerror(errno));\r
+ }\r
+\r
+void myvstrprintf(string &Str, const char *Format, va_list ArgList)\r
+ {\r
+ static char szStr[MAX_FORMATTED_STRING_LENGTH];\r
+ vsnprintf(szStr, MAX_FORMATTED_STRING_LENGTH-1, Format, ArgList);\r
+ szStr[MAX_FORMATTED_STRING_LENGTH - 1] = '\0';\r
+ Str.assign(szStr);\r
+ }\r
+\r
+void myvstrprintf(string &Str, const char *Format, ...)\r
+ {\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Str, Format, ArgList);\r
+ va_end(ArgList);\r
+ }\r
+\r
+FILE *g_fLog = 0;\r
+\r
+void SetLogFileName(const string &FileName)\r
+ {\r
+ if (g_fLog != 0)\r
+ CloseStdioFile(g_fLog);\r
+ g_fLog = 0;\r
+ if (FileName.empty())\r
+ return;\r
+ g_fLog = CreateStdioFile(FileName);\r
+ }\r
+\r
+void Log(const char *Format, ...)\r
+ {\r
+ if (g_fLog == 0)\r
+ return;\r
+\r
+ static bool InLog = false;\r
+ if (InLog)\r
+ return;\r
+\r
+ InLog = true;\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ vfprintf(g_fLog, Format, ArgList);\r
+ va_end(ArgList);\r
+ fflush(g_fLog);\r
+ InLog = false;\r
+ }\r
+\r
+void Die(const char *Format, ...)\r
+ {\r
+ static bool InDie = false;\r
+ if (InDie)\r
+ exit(1);\r
+ InDie = true;\r
+ string Msg;\r
+\r
+ if (g_fLog != 0)\r
+ setbuf(g_fLog, 0);\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Msg, Format, ArgList);\r
+ va_end(ArgList);\r
+\r
+ fprintf(stderr, "\n\n");\r
+ Log("\n");\r
+ time_t t = time(0);\r
+ Log("%s", asctime(localtime(&t)));\r
+ for (unsigned i = 0; i < g_Argv.size(); i++)\r
+ {\r
+ fprintf(stderr, (i == 0) ? "%s" : " %s", g_Argv[i].c_str());\r
+ Log((i == 0) ? "%s" : " %s", g_Argv[i].c_str());\r
+ }\r
+ fprintf(stderr, "\n");\r
+ Log("\n");\r
+\r
+ time_t CurrentTime = time(0);\r
+ unsigned ElapsedSeconds = unsigned(CurrentTime - g_StartTime);\r
+ const char *sstr = SecsToStr(ElapsedSeconds);\r
+ Log("Elapsed time: %s\n", sstr);\r
+\r
+ const char *szStr = Msg.c_str();\r
+ fprintf(stderr, "\n---Fatal error---\n%s\n", szStr);\r
+ Log("\n---Fatal error---\n%s\n", szStr);\r
+\r
+#ifdef _MSC_VER\r
+ if (IsDebuggerPresent())\r
+ __debugbreak();\r
+ _CrtSetDbgFlag(0);\r
+#endif\r
+\r
+ exit(1);\r
+ }\r
+\r
+void Warning(const char *Format, ...)\r
+ {\r
+ string Msg;\r
+\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Msg, Format, ArgList);\r
+ va_end(ArgList);\r
+\r
+ const char *szStr = Msg.c_str();\r
+\r
+ fprintf(stderr, "\nWARNING: %s\n", szStr);\r
+ if (g_fLog != stdout)\r
+ {\r
+ Log("\nWARNING: %s\n", szStr);\r
+ fflush(g_fLog);\r
+ }\r
+ }\r
+\r
+#ifdef _MSC_VER\r
+double GetMemUseBytes()\r
+ {\r
+ HANDLE hProc = GetCurrentProcess();\r
+ PROCESS_MEMORY_COUNTERS PMC;\r
+ BOOL bOk = GetProcessMemoryInfo(hProc, &PMC, sizeof(PMC));\r
+ if (!bOk)\r
+ return 1000000;\r
+ double Bytes = (double) PMC.WorkingSetSize;\r
+ if (Bytes > g_PeakMemUseBytes)\r
+ g_PeakMemUseBytes = Bytes;\r
+ return Bytes;\r
+ }\r
+#elif linux || __linux__\r
+double GetMemUseBytes()\r
+ {\r
+ static char statm[64];\r
+ static int PageSize = 1;\r
+ if (0 == statm[0])\r
+ {\r
+ PageSize = sysconf(_SC_PAGESIZE);\r
+ pid_t pid = getpid();\r
+ sprintf(statm, "/proc/%d/statm", (int) pid);\r
+ }\r
+\r
+ int fd = open(statm, O_RDONLY);\r
+ if (-1 == fd)\r
+ return 1000000;\r
+ char Buffer[64];\r
+ int n = read(fd, Buffer, sizeof(Buffer) - 1);\r
+ close(fd);\r
+ fd = -1;\r
+\r
+ if (n <= 0)\r
+ return 1000000;\r
+\r
+ Buffer[n] = 0;\r
+ double Pages = atof(Buffer);\r
+\r
+ double Bytes = Pages*PageSize;\r
+ if (Bytes > g_PeakMemUseBytes)\r
+ g_PeakMemUseBytes = Bytes;\r
+ return Bytes;\r
+ }\r
+#elif defined(__MACH__)\r
+#include <memory.h>\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+#include <sys/types.h>\r
+#include <sys/sysctl.h>\r
+#include <sys/socket.h>\r
+#include <sys/gmon.h>\r
+#include <mach/vm_param.h>\r
+#include <netinet/in.h>\r
+#include <netinet/icmp6.h>\r
+#include <sys/vmmeter.h>\r
+#include <sys/proc.h>\r
+#include <mach/vm_statistics.h>\r
+#include <mach/task_info.h>\r
+#include <mach/task.h>\r
+#include <mach/mach_init.h>\r
+\r
+#define DEFAULT_MEM_USE 100000000.0\r
+\r
+double GetMemUseBytes()\r
+ {\r
+ task_t mytask = mach_task_self();\r
+ struct task_basic_info ti;\r
+ memset((void *) &ti, 0, sizeof(ti));\r
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;\r
+ kern_return_t ok = task_info(mytask, TASK_BASIC_INFO, (task_info_t) &ti, &count);\r
+ if (ok == KERN_INVALID_ARGUMENT)\r
+ return DEFAULT_MEM_USE;\r
+\r
+ if (ok != KERN_SUCCESS)\r
+ return DEFAULT_MEM_USE;\r
+\r
+ double Bytes = (double ) ti.resident_size;\r
+ if (Bytes > g_PeakMemUseBytes)\r
+ g_PeakMemUseBytes = Bytes;\r
+ return Bytes;\r
+ }\r
+#else\r
+double GetMemUseBytes()\r
+ {\r
+ return 0;\r
+ }\r
+#endif\r
+\r
+double GetPeakMemUseBytes()\r
+ {\r
+ return g_PeakMemUseBytes;\r
+ }\r
+\r
+const char *SecsToHHMMSS(int Secs)\r
+ {\r
+ int HH = Secs/3600;\r
+ int MM = (Secs - HH*3600)/60;\r
+ int SS = Secs%60;\r
+ static char Str[16];\r
+ if (HH == 0)\r
+ sprintf(Str, "%02d:%02d", MM, SS);\r
+ else\r
+ sprintf(Str, "%02d:%02d:%02d", HH, MM, SS);\r
+ return Str;\r
+ }\r
+\r
+const char *SecsToStr(double Secs)\r
+ {\r
+ if (Secs >= 10.0)\r
+ return SecsToHHMMSS((int) Secs);\r
+\r
+ static char Str[16];\r
+ if (Secs < 1e-6)\r
+ sprintf(Str, "%.2gs", Secs);\r
+ else if (Secs < 1e-3)\r
+ sprintf(Str, "%.2fms", Secs*1e3);\r
+ else\r
+ sprintf(Str, "%.3fs", Secs);\r
+ return Str;\r
+ }\r
+\r
+const char *MemBytesToStr(double Bytes)\r
+ {\r
+ static char Str[32];\r
+\r
+ if (Bytes < 1e6)\r
+ sprintf(Str, "%.1fkb", Bytes/1e3);\r
+ else if (Bytes < 10e6)\r
+ sprintf(Str, "%.1fMb", Bytes/1e6);\r
+ else if (Bytes < 1e9)\r
+ sprintf(Str, "%.0fMb", Bytes/1e6);\r
+ else if (Bytes < 10e9)\r
+ sprintf(Str, "%.1fGb", Bytes/1e9);\r
+ else if (Bytes < 100e9)\r
+ sprintf(Str, "%.0fGb", Bytes/1e9);\r
+ else\r
+ sprintf(Str, "%.3gb", Bytes);\r
+ return Str;\r
+ }\r
+\r
+const char *IntToStr(unsigned i)\r
+ {\r
+ static char Str[32];\r
+\r
+ double d = (double) i;\r
+ if (i < 10000)\r
+ sprintf(Str, "%u", i);\r
+ else if (i < 1e6)\r
+ sprintf(Str, "%.1fk", d/1e3);\r
+ else if (i < 10e6)\r
+ sprintf(Str, "%.1fM", d/1e6);\r
+ else if (i < 1e9)\r
+ sprintf(Str, "%.0fM", d/1e6);\r
+ else if (i < 10e9)\r
+ sprintf(Str, "%.1fG", d/1e9);\r
+ else if (i < 100e9)\r
+ sprintf(Str, "%.0fG", d/1e9);\r
+ else\r
+ sprintf(Str, "%.3g", d);\r
+ return Str;\r
+ }\r
+\r
+const char *FloatToStr(double d)\r
+ {\r
+ static char Str[32];\r
+\r
+ double a = fabs(d);\r
+ if (a < 0.01)\r
+ sprintf(Str, "%.3g", a);\r
+ else if (a >= 0.01 && a < 1)\r
+ sprintf(Str, "%.3f", a);\r
+ else if (a <= 10 && a >= 1)\r
+ {\r
+ double intpart;\r
+ if (modf(a, &intpart) < 0.05)\r
+ sprintf(Str, "%.0f", d);\r
+ else\r
+ sprintf(Str, "%.1f", d);\r
+ }\r
+ else if (a > 10 && a < 10000)\r
+ sprintf(Str, "%.0f", d);\r
+ else if (a < 1e6)\r
+ sprintf(Str, "%.1fk", d/1e3);\r
+ else if (a < 10e6)\r
+ sprintf(Str, "%.1fM", d/1e6);\r
+ else if (a < 1e9)\r
+ sprintf(Str, "%.0fM", d/1e6);\r
+ else if (a < 10e9)\r
+ sprintf(Str, "%.1fG", d/1e9);\r
+ else if (a < 100e9)\r
+ sprintf(Str, "%.0fG", d/1e9);\r
+ else\r
+ sprintf(Str, "%.3g", d);\r
+ return Str;\r
+ }\r
+\r
+bool opt_quiet = false;\r
+bool opt_version = false;\r
+bool opt_logopts = false;\r
+bool opt_compilerinfo = false;\r
+bool opt_help = false;\r
+string opt_log = "";\r
+\r
+bool optset_quiet = false;\r
+bool optset_version = false;\r
+bool optset_logopts = false;\r
+bool optset_compilerinfo = false;\r
+bool optset_help = false;\r
+bool optset_log = false;\r
+\r
+static string g_CurrentProgressLine;\r
+static string g_ProgressDesc;\r
+static unsigned g_ProgressIndex;\r
+static unsigned g_ProgressCount;\r
+\r
+static unsigned g_CurrProgressLineLength;\r
+static unsigned g_LastProgressLineLength;\r
+static unsigned g_CountsInterval;\r
+static unsigned g_StepCalls;\r
+static time_t g_TimeLastOutputStep;\r
+\r
+static string &GetProgressPrefixStr(string &s)\r
+ {\r
+ double Bytes = GetMemUseBytes();\r
+ unsigned Secs = GetElapsedSecs();\r
+ s = string(SecsToHHMMSS(Secs));\r
+ if (Bytes > 0)\r
+ {\r
+ s.push_back(' ');\r
+ char Str[32];\r
+ sprintf(Str, "%5.5s", MemBytesToStr(Bytes));\r
+ s += string(Str);\r
+ }\r
+ s.push_back(' ');\r
+ return s;\r
+ }\r
+\r
+void ProgressLog(const char *Format, ...)\r
+ {\r
+ string Str;\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Str, Format, ArgList);\r
+ va_end(ArgList);\r
+\r
+ Log("%s", Str.c_str());\r
+ Progress("%s", Str.c_str());\r
+ }\r
+\r
+void Progress(const char *Format, ...)\r
+ {\r
+ if (opt_quiet)\r
+ return;\r
+\r
+ string Str;\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Str, Format, ArgList);\r
+ va_end(ArgList);\r
+\r
+#if 0\r
+ Log("Progress(");\r
+ for (unsigned i = 0; i < Str.size(); ++i)\r
+ {\r
+ char c = Str[i];\r
+ if (c == '\r')\r
+ Log("\\r");\r
+ else if (c == '\n')\r
+ Log("\\n");\r
+ else\r
+ Log("%c", c);\r
+ }\r
+ Log(")\n");\r
+#endif //0\r
+\r
+ for (unsigned i = 0; i < Str.size(); ++i)\r
+ {\r
+ if (g_CurrProgressLineLength == 0)\r
+ {\r
+ string s;\r
+ GetProgressPrefixStr(s);\r
+ for (unsigned j = 0; j < s.size(); ++j)\r
+ {\r
+ fputc(s[j], stderr);\r
+ ++g_CurrProgressLineLength;\r
+ }\r
+ }\r
+\r
+ char c = Str[i];\r
+ if (c == '\n' || c == '\r')\r
+ {\r
+ for (unsigned j = g_CurrProgressLineLength; j < g_LastProgressLineLength; ++j)\r
+ fputc(' ', stderr);\r
+ if (c == '\n')\r
+ g_LastProgressLineLength = 0;\r
+ else\r
+ g_LastProgressLineLength = g_CurrProgressLineLength;\r
+ g_CurrProgressLineLength = 0;\r
+ fputc(c, stderr);\r
+ }\r
+ else\r
+ {\r
+ fputc(c, stderr);\r
+ ++g_CurrProgressLineLength;\r
+ }\r
+ }\r
+ }\r
+\r
+void ProgressExit()\r
+ {\r
+ time_t Now = time(0);\r
+ struct tm *t = localtime(&Now);\r
+ const char *s = asctime(t);\r
+ unsigned Secs = GetElapsedSecs();\r
+\r
+ Log("\n");\r
+ Log("Finished %s", s); // there is a newline in s\r
+ Log("Elapsed time %s\n", SecsToHHMMSS((int) Secs));\r
+ Log("Max memory %s\n", MemBytesToStr(g_PeakMemUseBytes));\r
+#if WIN32 && DEBUG\r
+// Skip exit(), which can be very slow in DEBUG build\r
+// VERY DANGEROUS practice, because it skips global destructors.\r
+// But if you know the rules, you can break 'em, right?\r
+ ExitProcess(0);\r
+#endif\r
+ }\r
+\r
+const char *PctStr(double x, double y)\r
+ {\r
+ if (y == 0)\r
+ {\r
+ if (x == 0)\r
+ return "100%";\r
+ else\r
+ return "inf%";\r
+ }\r
+ static char Str[16];\r
+ double p = x*100.0/y;\r
+ sprintf(Str, "%5.1f%%", p);\r
+ return Str;\r
+ }\r
+\r
+string &GetProgressLevelStr(string &s)\r
+ {\r
+ unsigned Index = g_ProgressIndex;\r
+ unsigned Count = g_ProgressCount;\r
+ if (Count == UINT_MAX)\r
+ {\r
+ if (Index == UINT_MAX)\r
+ s = "100%";\r
+ else\r
+ {\r
+ char Tmp[16];\r
+ sprintf(Tmp, "%u", Index); \r
+ s = Tmp;\r
+ }\r
+ }\r
+ else\r
+ s = string(PctStr(Index+1, Count));\r
+ s += string(" ") + g_ProgressDesc;\r
+ return s;\r
+ }\r
+\r
+void ProgressStep(unsigned i, unsigned N, const char *Format, ...)\r
+ {\r
+ if (opt_quiet)\r
+ return;\r
+\r
+ if (i == 0)\r
+ {\r
+ string Str;\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(Str, Format, ArgList);\r
+ va_end(ArgList);\r
+ g_ProgressDesc = Str;\r
+ g_ProgressIndex = 0;\r
+ g_ProgressCount = N;\r
+ g_CountsInterval = 1;\r
+ g_StepCalls = 0;\r
+ g_TimeLastOutputStep = 0;\r
+ if (g_CurrProgressLineLength > 0)\r
+ Progress("\n");\r
+ }\r
+\r
+ if (i >= N && i != UINT_MAX)\r
+ Die("ProgressStep(%u,%u)", i, N);\r
+ bool IsLastStep = (i == UINT_MAX || i + 1 == N);\r
+ if (!IsLastStep)\r
+ {\r
+ ++g_StepCalls;\r
+ if (g_StepCalls%g_CountsInterval != 0)\r
+ return;\r
+\r
+ time_t Now = time(0);\r
+ if (Now == g_TimeLastOutputStep)\r
+ {\r
+ if (g_CountsInterval < 128)\r
+ g_CountsInterval = (g_CountsInterval*3)/2;\r
+ else\r
+ g_CountsInterval += 64;\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ time_t Secs = Now - g_TimeLastOutputStep;\r
+ if (Secs > 1)\r
+ g_CountsInterval = unsigned(g_CountsInterval/(Secs*8));\r
+ }\r
+\r
+ if (g_CountsInterval < 1)\r
+ g_CountsInterval = 1;\r
+\r
+ g_TimeLastOutputStep = Now;\r
+ }\r
+\r
+ g_ProgressIndex = i;\r
+\r
+ if (i > 0)\r
+ {\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ myvstrprintf(g_ProgressDesc, Format, ArgList);\r
+ }\r
+\r
+ string LevelStr;\r
+ GetProgressLevelStr(LevelStr);\r
+ Progress(" %s\r", LevelStr.c_str());\r
+\r
+ if (IsLastStep)\r
+ {\r
+ g_CountsInterval = 1;\r
+ fputc('\n', stderr);\r
+ }\r
+ }\r
+\r
+enum OptType\r
+ {\r
+ OT_Flag,\r
+ OT_Tog,\r
+ OT_Int,\r
+ OT_Uns,\r
+ OT_Str,\r
+ OT_Float,\r
+ OT_Enum\r
+ };\r
+\r
+struct OptInfo\r
+ {\r
+ void *Value;\r
+ bool *OptSet;\r
+ string LongName;\r
+ OptType Type;\r
+ int iMin;\r
+ int iMax;\r
+ unsigned uMin;\r
+ unsigned uMax;\r
+ double dMin;\r
+ double dMax;\r
+ map<string, unsigned> EnumValues;\r
+\r
+ bool bDefault;\r
+ int iDefault;\r
+ unsigned uDefault;\r
+ double dDefault;\r
+ string strDefault;\r
+\r
+ string Help;\r
+\r
+ bool operator<(const OptInfo &rhs) const\r
+ {\r
+ return LongName < rhs.LongName;\r
+ }\r
+ };\r
+\r
+static set<OptInfo> g_Opts;\r
+\r
+void Help()\r
+ {\r
+ printf("\n");\r
+\r
+ void Usage();\r
+ Usage();\r
+\r
+ for (set<OptInfo>::const_iterator p = g_Opts.begin(); p != g_Opts.end(); ++p)\r
+ {\r
+ const OptInfo &Opt = *p;\r
+\r
+ printf("\n");\r
+ string LongName = Opt.LongName.c_str();\r
+ if (Opt.Type == OT_Tog)\r
+ LongName = string("[no]") + LongName;\r
+ printf(" --%s ", LongName.c_str());\r
+\r
+ switch (Opt.Type)\r
+ {\r
+ case OT_Flag:\r
+ break;\r
+ case OT_Tog:\r
+ break;\r
+ case OT_Int:\r
+ printf("<int>");\r
+ break;\r
+ case OT_Uns:\r
+ printf("<uint>");\r
+ break;\r
+ case OT_Str:\r
+ printf("<str>");\r
+ break;\r
+ case OT_Float:\r
+ printf("<float>");\r
+ break;\r
+ case OT_Enum:\r
+ printf("<enum>");\r
+ break;\r
+ default:\r
+ printf("??type");\r
+ break;\r
+ }\r
+\r
+ printf(" ");\r
+ const string &s = Opt.Help;\r
+ for (string::const_iterator q = s.begin(); q != s.end(); ++q)\r
+ {\r
+ char c = *q;\r
+ if (c == '\n')\r
+ printf("\n ");\r
+ else\r
+ printf("%c", c);\r
+ }\r
+ printf("\n");\r
+ }\r
+ printf("\n");\r
+ exit(0);\r
+ }\r
+\r
+void CmdLineErr(const char *Format, ...)\r
+ {\r
+ va_list ArgList;\r
+ va_start(ArgList, Format);\r
+ string Str;\r
+ myvstrprintf(Str, Format, ArgList);\r
+ va_end(ArgList);\r
+ fprintf(stderr, "\n");\r
+ fprintf(stderr, "Invalid command line\n");\r
+ fprintf(stderr, "%s\n", Str.c_str());\r
+ fprintf(stderr, "For list of command-line options use --help.\n");\r
+ fprintf(stderr, "\n");\r
+ exit(1);\r
+ }\r
+\r
+static set<OptInfo>::iterator GetOptInfo(const string &LongName,\r
+ bool ErrIfNotFound)\r
+ {\r
+ for (set<OptInfo>::iterator p = g_Opts.begin();\r
+ p != g_Opts.end(); ++p)\r
+ {\r
+ const OptInfo &Opt = *p;\r
+ if (Opt.LongName == LongName)\r
+ return p;\r
+ if (Opt.Type == OT_Tog && "no" + Opt.LongName == LongName)\r
+ return p;\r
+ }\r
+ if (ErrIfNotFound)\r
+ CmdLineErr("Option --%s is invalid", LongName.c_str());\r
+ return g_Opts.end();\r
+ }\r
+\r
+static void AddOpt(const OptInfo &Opt)\r
+ {\r
+ if (GetOptInfo(Opt.LongName, false) != g_Opts.end())\r
+ Die("Option --%s defined twice", Opt.LongName.c_str());\r
+ g_Opts.insert(Opt);\r
+ }\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4505) // unreferenced local function\r
+#endif\r
+\r
+static void DefineFlagOpt(const string &LongName, const string &Help,\r
+ void *Value, bool *OptSet)\r
+ {\r
+ *(bool *) Value = false;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.bDefault = false;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Flag;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void DefineTogOpt(const string &LongName, bool Default, const string &Help,\r
+ void *Value, bool *OptSet)\r
+ {\r
+ *(bool *) Value = Default;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.bDefault = Default;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Tog;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void DefineIntOpt(const string &LongName, int Default, int Min, int Max,\r
+ const string &Help, void *Value, bool *OptSet)\r
+ {\r
+ *(int *) Value = Default;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.iDefault = Default;\r
+ Opt.iMin = Min;\r
+ Opt.iMax = Max;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Int;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void DefineUnsOpt(const string &LongName, unsigned Default, unsigned Min,\r
+ unsigned Max, const string &Help, void *Value, bool *OptSet)\r
+ {\r
+ *(unsigned *) Value = Default;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.uDefault = Default;\r
+ Opt.uMin = Min;\r
+ Opt.uMax = Max;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Uns;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void DefineFloatOpt(const string &LongName, double Default, double Min,\r
+ double Max, const string &Help, void *Value, bool *OptSet)\r
+ {\r
+ *(double *) Value = Default;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.dDefault = Default;\r
+ Opt.dMin = Min;\r
+ Opt.dMax = Max;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Float;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void DefineStrOpt(const string &LongName, const char *Default,\r
+ const string &Help, void *Value, bool *OptSet)\r
+ {\r
+ *(string *) Value = (Default == 0 ? "" : string(Default));\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.OptSet = OptSet;\r
+ Opt.LongName = LongName;\r
+ Opt.strDefault = (Default == 0 ? "" : string(Default));\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Str;\r
+ AddOpt(Opt);\r
+ }\r
+\r
+static void ParseEnumValues(const string &Values, map<string, unsigned> &EnumValues)\r
+ {\r
+ EnumValues.clear();\r
+ \r
+ string Name;\r
+ string Value;\r
+ bool Eq = false;\r
+ for (string::const_iterator p = Values.begin(); ; ++p)\r
+ {\r
+ char c = (p == Values.end() ? '|' : *p);\r
+ if (isspace(c))\r
+ ;\r
+ else if (c == '|')\r
+ {\r
+ if (EnumValues.find(Name) != EnumValues.end())\r
+ Die("Invalid enum values, '%s' defined twice: '%s'",\r
+ Name.c_str(), Values.c_str());\r
+ if (Name.empty() || Value.empty())\r
+ Die("Invalid enum values, empty name or value: '%s'",\r
+ Values.c_str());\r
+\r
+ EnumValues[Name] = atoi(Value.c_str());\r
+ Name.clear();\r
+ Value.clear();\r
+ Eq = false;\r
+ }\r
+ else if (c == '=')\r
+ Eq = true;\r
+ else if (Eq)\r
+ Value.push_back(c);\r
+ else\r
+ Name.push_back(c);\r
+ if (p == Values.end())\r
+ return;\r
+ }\r
+ }\r
+\r
+static void DefineEnumOpt(const string &LongName, const string &ShortName,\r
+ int Default, const string &Values, const string &Help, void *Value)\r
+ {\r
+ *(int *) Value = Default;\r
+\r
+ OptInfo Opt;\r
+ Opt.Value = Value;\r
+ Opt.LongName = LongName;\r
+ Opt.iDefault = Default;\r
+ Opt.Help = Help;\r
+ Opt.Type = OT_Enum;\r
+ ParseEnumValues(Values, Opt.EnumValues);\r
+ AddOpt(Opt);\r
+ }\r
+#undef FLAG_OPT\r
+#undef TOG_OPT\r
+#undef INT_OPT\r
+#undef UNS_OPT\r
+#undef FLT_OPT\r
+#undef STR_OPT\r
+#undef ENUM_OPT\r
+#define FLAG_OPT(LongName) bool opt_##LongName; bool optset_##LongName;\r
+#define TOG_OPT(LongName, Default) bool opt_##LongName; bool optset_##LongName;\r
+#define INT_OPT(LongName, Default, Min, Max) int opt_##LongName; bool optset_##LongName;\r
+#define UNS_OPT(LongName, Default, Min, Max) unsigned opt_##LongName; bool optset_##LongName;\r
+#define FLT_OPT(LongName, Default, Min, Max) double opt_##LongName; bool optset_##LongName;\r
+#define STR_OPT(LongName, Default) string opt_##LongName; bool optset_##LongName;\r
+#define ENUM_OPT(LongName, Values, Default) int opt_##LongName; bool optset_##LongName;\r
+#include "myopts.h"\r
+\r
+static int EnumStrToInt(const OptInfo &Opt, const string &Value)\r
+ {\r
+ const map<string, unsigned> &e = Opt.EnumValues;\r
+ string s;\r
+ for (map<string, unsigned>::const_iterator p = e.begin(); p != e.end(); ++p)\r
+ {\r
+ if (Value == p->first)\r
+ return p->second;\r
+ s += " " + p->first;\r
+ }\r
+ CmdLineErr("--%s %s not recognized, valid are: %s",\r
+ Opt.LongName.c_str(), Value.c_str(), s.c_str());\r
+ ureturn(-1);\r
+ }\r
+\r
+static void SetOpt(OptInfo &Opt, const string &Value)\r
+ {\r
+ *Opt.OptSet = true;\r
+ switch (Opt.Type)\r
+ {\r
+ case OT_Int:\r
+ {\r
+ *(int *) Opt.Value = atoi(Value.c_str());\r
+ break;\r
+ }\r
+ case OT_Uns:\r
+ {\r
+ unsigned uValue = 0;\r
+ int n = sscanf(Value.c_str(), "%u", &uValue);\r
+ if (n != 1)\r
+ CmdLineErr("Invalid value '%s' for --%s",\r
+ Value.c_str(), Opt.LongName.c_str());\r
+ *(unsigned *) Opt.Value = uValue;\r
+ break;\r
+ }\r
+ case OT_Float:\r
+ {\r
+ *(double *) Opt.Value = atof(Value.c_str());\r
+ break;\r
+ }\r
+ case OT_Str:\r
+ {\r
+ *(string *) Opt.Value = Value;\r
+ break;\r
+ }\r
+ case OT_Enum:\r
+ {\r
+ *(int *) Opt.Value = EnumStrToInt(Opt, Value);\r
+ break;\r
+ }\r
+ default:\r
+ asserta(false);\r
+ }\r
+ }\r
+\r
+void LogOpts()\r
+ {\r
+ for (set<OptInfo>::const_iterator p = g_Opts.begin(); p != g_Opts.end(); ++p)\r
+ {\r
+ const OptInfo &Opt = *p;\r
+ Log("%s = ", Opt.LongName.c_str());\r
+ switch (Opt.Type)\r
+ {\r
+ case OT_Flag:\r
+ Log("%s", (*(bool *) Opt.Value) ? "yes" : "no");\r
+ break;\r
+ case OT_Tog:\r
+ Log("%s", (*(bool *) Opt.Value) ? "on" : "off");\r
+ break;\r
+ case OT_Int:\r
+ Log("%d", *(int *) Opt.Value);\r
+ break;\r
+ case OT_Uns:\r
+ Log("%u", *(unsigned *) Opt.Value);\r
+ break;\r
+ case OT_Float:\r
+ {\r
+ double Value = *(double *) Opt.Value;\r
+ if (Value == FLT_MAX)\r
+ Log("*");\r
+ else\r
+ Log("%g", Value);\r
+ break;\r
+ }\r
+ case OT_Str:\r
+ Log("%s", (*(string *) Opt.Value).c_str());\r
+ break;\r
+ case OT_Enum:\r
+ Log("%d", *(int *) Opt.Value);\r
+ break;\r
+ default:\r
+ asserta(false);\r
+ }\r
+ Log("\n");\r
+ }\r
+ }\r
+\r
+static void CompilerInfo()\r
+ {\r
+#ifdef _FILE_OFFSET_BITS\r
+ printf("_FILE_OFFSET_BITS=%d\n", _FILE_OFFSET_BITS);\r
+#else\r
+ printf("_FILE_OFFSET_BITS not defined\n");\r
+#endif\r
+\r
+#define x(t) printf("sizeof(" #t ") = %d\n", (int) sizeof(t));\r
+ x(int)\r
+ x(long)\r
+ x(float)\r
+ x(double)\r
+ x(void *)\r
+ x(off_t)\r
+#undef x\r
+ exit(0);\r
+ }\r
+\r
+void Split(const string &Str, vector<string> &Fields, char Sep)\r
+ {\r
+ Fields.clear();\r
+ const unsigned Length = (unsigned) Str.size();\r
+ string s;\r
+ for (unsigned i = 0; i < Length; ++i)\r
+ {\r
+ char c = Str[i];\r
+ if ((Sep == 0 && isspace(c)) || c == Sep)\r
+ {\r
+ if (!s.empty() || Sep != 0)\r
+ Fields.push_back(s);\r
+ s.clear();\r
+ }\r
+ else\r
+ s.push_back(c);\r
+ }\r
+ if (!s.empty())\r
+ Fields.push_back(s);\r
+ }\r
+\r
+static void GetArgsFromFile(const string &FileName, vector<string> &Args)\r
+ {\r
+ Args.clear();\r
+\r
+ FILE *f = OpenStdioFile(FileName);\r
+ string Line;\r
+ while (ReadLineStdioFile(f, Line))\r
+ {\r
+ size_t n = Line.find('#');\r
+ if (n != string::npos)\r
+ Line = Line.substr(0, n);\r
+ vector<string> Fields;\r
+ Split(Line, Fields);\r
+ Args.insert(Args.end(), Fields.begin(), Fields.end());\r
+ }\r
+ CloseStdioFile(f);\r
+ }\r
+\r
+void MyCmdLine(int argc, char **argv)\r
+ {\r
+ static unsigned RecurseDepth = 0;\r
+ ++RecurseDepth;\r
+\r
+ DefineFlagOpt("compilerinfo", "Write info about compiler types and #defines to stdout.",\r
+ (void *) &opt_compilerinfo, &optset_compilerinfo);\r
+ DefineFlagOpt("quiet", "Turn off progress messages.", (void *) &opt_quiet, &optset_quiet);\r
+ DefineFlagOpt("version", "Show version and exit.", (void *) &opt_version, &optset_version);\r
+ DefineFlagOpt("logopts", "Log options.", (void *) &opt_logopts, &optset_logopts);\r
+ DefineFlagOpt("help", "Display command-line options.", (void *) &opt_help, &optset_help);\r
+ DefineStrOpt("log", "", "Log file name.", (void *) &opt_log, &optset_log);\r
+\r
+#undef FLAG_OPT\r
+#undef TOG_OPT\r
+#undef INT_OPT\r
+#undef UNS_OPT\r
+#undef FLT_OPT\r
+#undef STR_OPT\r
+#undef ENUM_OPT\r
+#define FLAG_OPT(LongName) DefineFlagOpt(#LongName, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define TOG_OPT(LongName, Default) DefineTogOpt(#LongName, Default, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define INT_OPT(LongName, Default, Min, Max) DefineIntOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define UNS_OPT(LongName, Default, Min, Max) DefineUnsOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define FLT_OPT(LongName, Default, Min, Max) DefineFloatOpt(#LongName, Default, Min, Max, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define STR_OPT(LongName, Default) DefineStrOpt(#LongName, Default, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#define ENUM_OPT(LongName, Values, Default) DefineEnumOpt(#LongName, Values, Default, "help", (void *) &opt_##LongName, &optset_##LongName);\r
+#include "myopts.h"\r
+\r
+ if (RecurseDepth == 0)\r
+ g_Argv.clear();\r
+\r
+ for (int i = 0; i < argc; ++i) {\r
+ g_Argv.push_back(string(argv[i]));\r
+ }\r
+\r
+ int i = 1;\r
+ for (;;)\r
+ {\r
+ if (i >= argc)\r
+ break;\r
+ const string &Arg = g_Argv[i];\r
+ \r
+ if (Arg.empty())\r
+ continue;\r
+ else if (Arg == "file:" && i + 1 < argc)\r
+ {\r
+ const string &FileName = g_Argv[i+1];\r
+ vector<string> Args;\r
+ GetArgsFromFile(FileName, Args);\r
+ for (vector<string>::const_iterator p = Args.begin();\r
+ p != Args.end(); ++p)\r
+ {\r
+ g_Argv.push_back(*p);\r
+ ++argc;\r
+ }\r
+ i += 2;\r
+ continue;\r
+ }\r
+ else if (Arg.size() > 1 && Arg[0] == '-')\r
+ {\r
+ string LongName = (Arg.size() > 2 && Arg[1] == '-' ? Arg.substr(2) : Arg.substr(1));\r
+ OptInfo Opt = *GetOptInfo(LongName, true);\r
+ *Opt.OptSet = true;\r
+ if (Opt.Type == OT_Flag)\r
+ {\r
+ g_Opts.erase(Opt);\r
+ *(bool *) Opt.Value = true;\r
+ g_Opts.insert(Opt);\r
+ ++i;\r
+ continue;\r
+ }\r
+ else if (Opt.Type == OT_Tog)\r
+ {\r
+ g_Opts.erase(Opt);\r
+ if (string("no") + Opt.LongName == LongName)\r
+ *(bool *) Opt.Value = false;\r
+ else\r
+ {\r
+ asserta(Opt.LongName == LongName);\r
+ *(bool *) Opt.Value = true;\r
+ }\r
+ g_Opts.insert(Opt);\r
+ ++i;\r
+ continue;\r
+ }\r
+\r
+ ++i;\r
+ if (i >= argc)\r
+ CmdLineErr("Missing value for option --%s", LongName.c_str());\r
+\r
+ string Value = g_Argv[i];\r
+ SetOpt(Opt, Value);\r
+\r
+ ++i;\r
+ continue;\r
+ }\r
+ else\r
+ CmdLineErr("Expected -option_name or --option_name, got '%s'", Arg.c_str());\r
+ }\r
+\r
+ --RecurseDepth;\r
+ if (RecurseDepth > 0)\r
+ return;\r
+\r
+ if (opt_help)\r
+ Help();\r
+\r
+ if (opt_compilerinfo)\r
+ CompilerInfo();\r
+\r
+ SetLogFileName(opt_log);\r
+\r
+ if (opt_log != "")\r
+ {\r
+ for (int i = 0; i < argc; ++i)\r
+ Log("%s%s", i == 0 ? "" : " ", g_Argv[i].c_str());\r
+ Log("\n");\r
+ time_t Now = time(0);\r
+ struct tm *t = localtime(&Now);\r
+ const char *s = asctime(t);\r
+ Log("Started %s", s); // there is a newline in s\r
+ Log("Version " MY_VERSION ".%s\n", SVN_VERSION);\r
+ Log("\n");\r
+ }\r
+\r
+ if (opt_logopts)\r
+ LogOpts();\r
+ }\r
+\r
+double Pct(double x, double y)\r
+ {\r
+ if (y == 0.0f)\r
+ return 0.0f;\r
+ return (x*100.0f)/y;\r
+ }\r
+\r
+void GetCmdLine(string &s)\r
+ {\r
+ s.clear();\r
+ for (unsigned i = 0; i < SIZE(g_Argv); ++i)\r
+ {\r
+ if (i > 0)\r
+ s += " ";\r
+ s += g_Argv[i];\r
+ }\r
+ }\r
+\r
+char *mystrsave(const char *s)\r
+ {\r
+ unsigned n = unsigned(strlen(s));\r
+ char *t = myalloc(char, n+1);\r
+ memcpy(t, s, n+1);\r
+ return t;\r
+ }\r
+\r
+void Logu(unsigned u, unsigned w, unsigned prefixspaces)\r
+ {\r
+ for (unsigned i = 0; i < prefixspaces; ++i)\r
+ Log(" ");\r
+ if (u == UINT_MAX)\r
+ Log("%*.*s", w, w, "*");\r
+ else\r
+ Log("%*u", w, u);\r
+ }\r
+\r
+void Logf(float x, unsigned w, unsigned prefixspaces)\r
+ {\r
+ for (unsigned i = 0; i < prefixspaces; ++i)\r
+ Log(" ");\r
+ if (x == FLT_MAX)\r
+ Log("%*.*s", w, w, "*");\r
+ else\r
+ Log("%*.2f", w, x);\r
+ }\r
+\r
+static uint32 g_SLCG_state = 1;\r
+\r
+// Numerical values used by Microsoft C, according to wikipedia:\r
+// http://en.wikipedia.org/wiki/Linear_congruential_generator\r
+static uint32 g_SLCG_a = 214013;\r
+static uint32 g_SLCG_c = 2531011;\r
+\r
+// Simple Linear Congruential Generator\r
+// Bad properties; used just to initialize the better generator.\r
+static uint32 SLCG_rand()\r
+ {\r
+ g_SLCG_state = g_SLCG_state*g_SLCG_a + g_SLCG_c;\r
+ return g_SLCG_state;\r
+ }\r
+\r
+static void SLCG_srand(uint32 Seed)\r
+ {\r
+ g_SLCG_state = Seed;\r
+ for (int i = 0; i < 10; ++i)\r
+ SLCG_rand();\r
+ }\r
+\r
+/***\r
+A multiply-with-carry random number generator, see:\r
+http://en.wikipedia.org/wiki/Multiply-with-carry\r
+\r
+The particular multipliers used here were found on\r
+the web where they are attributed to George Marsaglia.\r
+***/\r
+\r
+static bool g_InitRandDone = false;\r
+static uint32 g_X[5];\r
+\r
+uint32 RandInt32()\r
+ {\r
+ InitRand();\r
+\r
+ uint64 Sum = 2111111111*(uint64) g_X[3] + 1492*(uint64) g_X[2] +\r
+ 1776*(uint64) g_X[1] + 5115*(uint64) g_X[0] + g_X[4];\r
+ g_X[3] = g_X[2];\r
+ g_X[2] = g_X[1];\r
+ g_X[1] = g_X[0];\r
+ g_X[4] = (uint32) (Sum >> 32);\r
+ g_X[0] = (uint32) Sum;\r
+ return g_X[0];\r
+ }\r
+\r
+unsigned randu32()\r
+ {\r
+ return (unsigned) RandInt32();\r
+ }\r
+\r
+void InitRand()\r
+ {\r
+ if (g_InitRandDone)\r
+ return;\r
+// Do this first to avoid recursion\r
+ g_InitRandDone = true;\r
+\r
+ unsigned Seed = (optset_randseed ? opt_randseed : (unsigned) (time(0)*getpid()));\r
+ Log("RandSeed=%u\n", Seed);\r
+ SLCG_srand(Seed);\r
+\r
+ for (unsigned i = 0; i < 5; i++)\r
+ g_X[i] = SLCG_rand();\r
+\r
+ for (unsigned i = 0; i < 100; i++)\r
+ RandInt32();\r
+ }\r
+\r
+// MUST COME AT END BECAUSE OF #undef\r
+#if RCE_MALLOC\r
+#undef mymalloc\r
+#undef myfree\r
+#undef myfree2\r
+void *mymalloc(unsigned bytes, const char *FileName, int Line)\r
+ {\r
+ void *rce_malloc(unsigned bytes, const char *FileName, int Line);\r
+ return rce_malloc(bytes, FileName, Line);\r
+ }\r
+\r
+void myfree(void *p, const char *FileName, int Line)\r
+ {\r
+ void rce_free(void *p, const char *FileName, int Line);\r
+ rce_free(p, FileName, Line);\r
+ }\r
+\r
+void myfree2(void *p, unsigned bytes, const char *FileName, int Line)\r
+ {\r
+ void rce_free(void *p, const char *FileName, int Line);\r
+ rce_free(p, FileName, Line);\r
+ }\r
+\r
+#else // RCE_MALLOC\r
+void *mymalloc(unsigned bytes)\r
+ {\r
+ ++g_NewCalls;\r
+ if (g_InitialMemUseBytes == 0)\r
+ g_InitialMemUseBytes = GetMemUseBytes();\r
+\r
+ g_TotalAllocBytes += bytes;\r
+ g_NetBytes += bytes;\r
+ if (g_NetBytes > g_MaxNetBytes)\r
+ {\r
+ if (g_NetBytes > g_MaxNetBytes + 10000000)\r
+ GetMemUseBytes();//to force update of peak\r
+ g_MaxNetBytes = g_NetBytes;\r
+ }\r
+ void *p = malloc(bytes);\r
+ //void *p = _malloc_dbg(bytes, _NORMAL_BLOCK, __FILE__, __LINE__);\r
+ if (0 == p)\r
+ {\r
+ double b = GetMemUseBytes();\r
+ fprintf(stderr, "\nOut of memory mymalloc(%u), curr %.3g bytes",\r
+ (unsigned) bytes, b);\r
+ void LogAllocs();\r
+ LogAllocs();\r
+#if DEBUG && defined(_MSC_VER)\r
+ asserta(_CrtCheckMemory());\r
+#endif\r
+ Die("Out of memory, mymalloc(%u), curr %.3g bytes\n",\r
+ (unsigned) bytes, b);\r
+ }\r
+ return p;\r
+ }\r
+\r
+void myfree(void *p)\r
+ {\r
+ if (p == 0)\r
+ return;\r
+ free(p);\r
+ //_free_dbg(p, _NORMAL_BLOCK);\r
+ }\r
+\r
+void myfree2(void *p, unsigned bytes)\r
+ {\r
+ ++g_FreeCalls;\r
+ g_TotalFreeBytes += bytes;\r
+ g_NetBytes -= bytes;\r
+\r
+ if (p == 0)\r
+ return;\r
+ free(p);\r
+ }\r
+#endif\r