/* * CrissCross * A multi-purpose cross-platform library. * * A product of Uplink Laboratories. * * (c) 2006-2008 Steven Noonan. * Licensed under the New BSD License. * */ #include #include #include #include #ifdef TARGET_OS_MACOSX extern "C" int NSApplicationMain(int argc, const char *argv []); #endif #ifdef SDL_APPLICATION #ifndef TARGET_OS_WINDOWS #include #else #define main SDL_main #endif #endif using namespace std; using namespace CrissCross::Data; using namespace CrissCross::Debug; using namespace CrissCross::IO; Console *g_stderr; Console *g_stdout; #ifdef DETECT_MEMORY_LEAKS #pragma warning ( disable: 4312 ) #ifdef ENABLE_MEMLEAK_STATS _CrtMemState s1, s2, s3; #endif void ParseMemoryLeakFile(const char *_inputFilename, const char *_outputFilename) { /* */ /* Start up */ /* */ RedBlackTree combined; RedBlackTree frequency; int unrecognised = 0; /* */ /* Open the file and start parsing */ /* */ FILE *memoryfile = fopen(_inputFilename, "rb"); while (memoryfile && !feof(memoryfile)) { char thisline[1024]; fgets(thisline, 1024, memoryfile); if (!strncmp(thisline, " Data:", 6) == 0) { /* This line is a data line - useless to us */ if (strchr(thisline, ':')) { /* This line does not have a source file location - useless to us */ /* Get the size */ char *lastcomma = strrchr(thisline, ','); if (lastcomma == 0) continue; char *ssize = lastcomma + 2; int size; char unused[32]; sscanf(ssize, "%d %s", &size, unused); /* Get the source file name */ char *sourcelocation = thisline; char *colon = strrchr(thisline, ':'); *(colon - 1) = '\x0'; /* Put the result into our BTree */ int result = 0; bool found = combined.find(sourcelocation, result); if (found) combined.replace(sourcelocation, result + size); else combined.insert(sourcelocation, size); found = frequency.find(sourcelocation, result); if (frequency.exists(sourcelocation)) frequency.replace(sourcelocation, result + size); else frequency.insert(sourcelocation, 1); } else { char *lastcomma = strrchr(thisline, ','); if (lastcomma) { char *ssize = lastcomma + 2; int size; char unused[32]; sscanf(ssize, "%d %s", &size, unused); unrecognised += size; } } } } fclose(memoryfile); /* */ /* Sort the results into a list */ /* */ LList sorted; DArray *dataI = combined.ConvertIndexToDArray(); DArray *dataD = combined.ConvertToDArray(); int totalsize = 0; for (size_t i = 0; i < dataI->size(); i++) { if (dataI->valid(i)) { char *newsource = dataI->get(i); int newsize = dataD->get(i); totalsize += newsize; bool inserted = false; for (size_t i = 0; i < sorted.size(); i++) { char *existingsource = sorted.get(i); int existingsize; combined.find(existingsource, existingsize); if (newsize <= existingsize) { sorted.insert_at(newsource, i); inserted = true; break; } } if (!inserted) sorted.insert(newsource); } } delete dataI; delete dataD; /* */ /* Open the output file */ /* */ if (sorted.size()) { FILE *output = fopen(_outputFilename, "wt"); /* */ /* Print out our sorted list */ /* */ fprintf(output, "Total recognised memory leaks : %d Kbytes\n", int( totalsize / 1024 )); fprintf(output, "Total unrecognised memory leaks : %d Kbytes\n\n", int( unrecognised / 1024 )); for (int k = (int)sorted.size() - 1; k >= 0 && k < (int)sorted.size(); k--) { char *source = sorted.get(k); CoreAssert(source); int size; combined.find(source, size); int freq; frequency.find(source, freq); if (size > 1048576) { fprintf(output, "%-95s (%d MB in %d leaks)\n", source, int( size / 1048576 ), freq); } else if (size > 2048) { fprintf(output, "%-95s (%d KB in %d leaks)\n", source, int( size / 1024 ), freq); } else { fprintf(output, "%-95s (%d bytes in %d leaks)\n", source, size, freq); } } /* */ /* Clean up */ fclose(output); } } void AppPrintMemoryLeaks(char *_filename) { /* */ /* Print all raw memory leak data to a temporary file */ #ifdef ENABLE_MEMLEAK_STATS _CrtMemCheckpoint(&s2); #endif char tmpFilename[512]; sprintf(tmpFilename, "%s.tmp", _filename); OFSTRUCT ofstruct; HFILE file = OpenFile(tmpFilename, &ofstruct, OF_CREATE); CoreAssert(file); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, ( _HFILE )file); BOOL memLeakFound = _CrtDumpMemoryLeaks(); #ifdef ENABLE_MEMLEAK_STATS _CrtMemDifference(&s3, &s1, &s2); _CrtMemDumpStatistics(&s3); #endif _lclose(file); /* */ /* Parse the temp file into a sensible format */ if (memLeakFound) ParseMemoryLeakFile(tmpFilename, _filename); /* */ /* Delete the temporary file */ #ifdef TARGET_OS_WINDOWS DeleteFileA(tmpFilename); #else unlink(tmpFilename); #endif } #endif #ifdef __cplusplus extern "C" { #endif #ifdef COCOA_APPLICATION int RunApplication(int argc, char * *argv) { return NSApplicationMain(argc, (const char * *)argv); } #endif int main(int argc, char * *argv) { int retval = 0; #ifdef TARGET_OS_NDSFIRMWARE fatInitDefault(); #endif #ifdef ENABLE_MEMLEAK_STATS _CrtMemCheckpoint(&s1); #endif g_stderr = new Console(stderr, NULL); g_stdout = new Console(stdout, NULL); #ifdef ENABLE_CRASHREPORTS __try #endif { #ifndef _WINDOWS retval = RunApplication(argc, argv); #else retval = RunApplication(__argc, __argv); #endif } #ifdef ENABLE_CRASHREPORTS __except(RecordExceptionInfo(GetExceptionInformation(), "WinMain", CC_LIB_NAME, CC_LIB_VERSION)){ } #endif delete g_stderr; g_stderr = NULL; delete g_stdout; g_stdout = NULL; #ifdef DETECT_MEMORY_LEAKS AppPrintMemoryLeaks("memleak.txt"); #endif return retval; } #ifdef TARGET_OS_WINDOWS #ifndef SDL_APPLICATION int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE _hPrevInstance, LPSTR _cmdLine, int _iCmdShow) { main(__argc, __argv); } #endif #endif #ifdef __cplusplus } #endif