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