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