]> git.donarmstrong.com Git - mothur.git/blobdiff - uchime_src/myutils.cpp
added uchime_src folder. added biom parameter to make.shared. added biom as a current...
[mothur.git] / uchime_src / myutils.cpp
diff --git a/uchime_src/myutils.cpp b/uchime_src/myutils.cpp
new file mode 100644 (file)
index 0000000..4fa92b1
--- /dev/null
@@ -0,0 +1,1844 @@
+#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