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