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