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