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