| File: | rootdir/src/Logger.cpp |
| Warning: | line 184, column 9 Access of 'g_debugcats' at an overflowing index, while it holds only 40 'class CDebugCategory' elements |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // | |||
| 2 | // This file is part of the aMule Project. | |||
| 3 | // | |||
| 4 | // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org ) | |||
| 5 | // | |||
| 6 | // Any parts of this program derived from the xMule, lMule or eMule project, | |||
| 7 | // or contributed by third-party developers are copyrighted by their | |||
| 8 | // respective authors. | |||
| 9 | // | |||
| 10 | // This program is free software; you can redistribute it and/or modify | |||
| 11 | // it under the terms of the GNU General Public License as published by | |||
| 12 | // the Free Software Foundation; either version 2 of the License, or | |||
| 13 | // (at your option) any later version. | |||
| 14 | // | |||
| 15 | // This program is distributed in the hope that it will be useful, | |||
| 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 18 | // GNU General Public License for more details. | |||
| 19 | // | |||
| 20 | // You should have received a copy of the GNU General Public License | |||
| 21 | // along with this program; if not, write to the Free Software | |||
| 22 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |||
| 23 | // | |||
| 24 | ||||
| 25 | #include "Logger.h" | |||
| 26 | #include "amule.h" | |||
| 27 | #include "Preferences.h" | |||
| 28 | #include <common/Macros.h> | |||
| 29 | #include <common/MacrosProgramSpecific.h> | |||
| 30 | #include <sstream> | |||
| 31 | #include <wx/tokenzr.h> | |||
| 32 | #include <wx/wfstream.h> | |||
| 33 | #include <wx/sstream.h> | |||
| 34 | #include <wx/filename.h> | |||
| 35 | ||||
| 36 | ||||
| 37 | DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE)const wxEventType MULE_EVT_LOGLINE = wxNewEventType(); | |||
| 38 | ||||
| 39 | ||||
| 40 | CDebugCategory g_debugcats[] = { | |||
| 41 | CDebugCategory( logGeneral, wxT("General")L"General" ), | |||
| 42 | CDebugCategory( logHasher, wxT("Hasher")L"Hasher" ), | |||
| 43 | CDebugCategory( logClient, wxT("ED2k Client")L"ED2k Client" ), | |||
| 44 | CDebugCategory( logLocalClient, wxT("Local Client Protocol")L"Local Client Protocol" ), | |||
| 45 | CDebugCategory( logRemoteClient, wxT("Remote Client Protocol")L"Remote Client Protocol" ), | |||
| 46 | CDebugCategory( logPacketErrors, wxT("Packet Parsing Errors")L"Packet Parsing Errors" ), | |||
| 47 | CDebugCategory( logCFile, wxT("CFile")L"CFile" ), | |||
| 48 | CDebugCategory( logFileIO, wxT("FileIO")L"FileIO" ), | |||
| 49 | CDebugCategory( logZLib, wxT("ZLib")L"ZLib" ), | |||
| 50 | CDebugCategory( logAICHThread, wxT("AICH-Hasher")L"AICH-Hasher" ), | |||
| 51 | CDebugCategory( logAICHTransfer, wxT("AICH-Transfer")L"AICH-Transfer" ), | |||
| 52 | CDebugCategory( logAICHRecovery, wxT("AICH-Recovery")L"AICH-Recovery" ), | |||
| 53 | CDebugCategory( logListenSocket, wxT("ListenSocket")L"ListenSocket" ), | |||
| 54 | CDebugCategory( logCredits, wxT("Credits")L"Credits" ), | |||
| 55 | CDebugCategory( logClientUDP, wxT("ClientUDPSocket")L"ClientUDPSocket" ), | |||
| 56 | CDebugCategory( logDownloadQueue, wxT("DownloadQueue")L"DownloadQueue" ), | |||
| 57 | CDebugCategory( logIPFilter, wxT("IPFilter")L"IPFilter" ), | |||
| 58 | CDebugCategory( logKnownFiles, wxT("KnownFileList")L"KnownFileList" ), | |||
| 59 | CDebugCategory( logPartFile, wxT("PartFiles")L"PartFiles" ), | |||
| 60 | CDebugCategory( logSHAHashSet, wxT("SHAHashSet")L"SHAHashSet" ), | |||
| 61 | CDebugCategory( logServer, wxT("Servers")L"Servers" ), | |||
| 62 | CDebugCategory( logProxy, wxT("Proxy")L"Proxy" ), | |||
| 63 | CDebugCategory( logSearch, wxT("Searching")L"Searching" ), | |||
| 64 | CDebugCategory( logServerUDP, wxT("ServerUDP")L"ServerUDP" ), | |||
| 65 | CDebugCategory( logClientKadUDP, wxT("Client Kademlia UDP")L"Client Kademlia UDP" ), | |||
| 66 | CDebugCategory( logKadSearch, wxT("Kademlia Search")L"Kademlia Search" ), | |||
| 67 | CDebugCategory( logKadRouting, wxT("Kademlia Routing")L"Kademlia Routing" ), | |||
| 68 | CDebugCategory( logKadIndex, wxT("Kademlia Indexing")L"Kademlia Indexing" ), | |||
| 69 | CDebugCategory( logKadMain, wxT("Kademlia Main Thread")L"Kademlia Main Thread" ), | |||
| 70 | CDebugCategory( logKadPrefs, wxT("Kademlia Preferences")L"Kademlia Preferences" ), | |||
| 71 | CDebugCategory( logPfConvert, wxT("PartFileConvert")L"PartFileConvert" ), | |||
| 72 | CDebugCategory( logMuleUDP, wxT("MuleUDPSocket" )L"MuleUDPSocket" ), | |||
| 73 | CDebugCategory( logThreads, wxT("ThreadScheduler" )L"ThreadScheduler" ), | |||
| 74 | CDebugCategory( logUPnP, wxT("Universal Plug and Play" )L"Universal Plug and Play" ), | |||
| 75 | CDebugCategory( logKadUdpFwTester, wxT("Kademlia UDP Firewall Tester")L"Kademlia UDP Firewall Tester" ), | |||
| 76 | CDebugCategory( logKadPacketTracking, wxT("Kademlia Packet Tracking")L"Kademlia Packet Tracking" ), | |||
| 77 | CDebugCategory( logKadEntryTracking, wxT("Kademlia Entry Tracking")L"Kademlia Entry Tracking" ), | |||
| 78 | CDebugCategory( logEC, wxT("External Connect")L"External Connect" ), | |||
| 79 | CDebugCategory( logHTTP, wxT("HTTP")L"HTTP" ), | |||
| 80 | CDebugCategory( logAsio, wxT("Asio Sockets")L"Asio Sockets" ) | |||
| 81 | }; | |||
| 82 | ||||
| 83 | ||||
| 84 | const int categoryCount = itemsof(g_debugcats)(sizeof(g_debugcats) / sizeof(g_debugcats[0])); | |||
| 85 | ||||
| 86 | ||||
| 87 | ||||
| 88 | #ifdef __DEBUG__ | |||
| 89 | bool CLogger::IsEnabled( DebugType type ) const | |||
| 90 | { | |||
| 91 | int index = (int)type; | |||
| 92 | ||||
| 93 | if ( index >= 0 && index < categoryCount ) { | |||
| 94 | const CDebugCategory& cat = g_debugcats[ index ]; | |||
| 95 | wxASSERT( type == cat.GetType() )do { if ( type == cat.GetType() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp", 95, __FUNCTION__, "type == cat.GetType()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 96 | ||||
| 97 | return ( cat.IsEnabled() && thePrefs::GetVerbose() ); | |||
| 98 | } | |||
| 99 | ||||
| 100 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp" , 100, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 101 | return false; | |||
| 102 | } | |||
| 103 | #endif | |||
| 104 | ||||
| 105 | ||||
| 106 | void CLogger::SetEnabled( DebugType type, bool enabled ) | |||
| 107 | { | |||
| 108 | int index = (int)type; | |||
| 109 | ||||
| 110 | if ( index >= 0 && index < categoryCount ) { | |||
| 111 | CDebugCategory& cat = g_debugcats[ index ]; | |||
| 112 | wxASSERT( type == cat.GetType() )do { if ( type == cat.GetType() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp", 112, __FUNCTION__, "type == cat.GetType()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 113 | ||||
| 114 | cat.SetEnabled( enabled ); | |||
| 115 | } else { | |||
| 116 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp" , 116, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 117 | } | |||
| 118 | } | |||
| 119 | ||||
| 120 | ||||
| 121 | void CLogger::AddLogLine( | |||
| 122 | const wxString& DEBUG_ONLY(file), | |||
| 123 | int DEBUG_ONLY(line), | |||
| 124 | bool critical, | |||
| 125 | DebugType type, | |||
| 126 | const wxString &str, | |||
| 127 | bool toStdout, | |||
| 128 | bool toGUI) | |||
| 129 | { | |||
| 130 | wxString msg(str); | |||
| 131 | // handle Debug messages | |||
| 132 | if (type != logStandard) { | |||
| 133 | if (!critical && !IsEnabled(type)) { | |||
| 134 | return; | |||
| 135 | } | |||
| 136 | if (!critical && thePrefs::GetVerboseLogfile()) { | |||
| 137 | // print non critical debug messages only to the logfile | |||
| 138 | toGUI = false; | |||
| 139 | } | |||
| 140 | int index = (int)type; | |||
| 141 | ||||
| 142 | if ( index >= 0 && index < categoryCount ) { | |||
| 143 | const CDebugCategory& cat = g_debugcats[ index ]; | |||
| 144 | wxASSERT(type == cat.GetType())do { if ( type == cat.GetType() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp", 144, __FUNCTION__, "type == cat.GetType()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 145 | ||||
| 146 | msg = cat.GetName() + wxT(": ")L": " + msg; | |||
| 147 | } else { | |||
| 148 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp" , 148, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 149 | } | |||
| 150 | } | |||
| 151 | ||||
| 152 | #ifdef __DEBUG__ | |||
| 153 | if (line) { | |||
| 154 | msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')L'/') << wxT("(")L"(" << line << wxT("): ")L"): " + msg; | |||
| 155 | } | |||
| 156 | #endif | |||
| 157 | ||||
| 158 | if (toGUI && !wxThread::IsMain()) { | |||
| 159 | // put to background | |||
| 160 | CLoggingEvent Event(critical, toStdout, toGUI, msg); | |||
| 161 | AddPendingEvent(Event); | |||
| 162 | } else { | |||
| 163 | // Try to handle events immediately when possible (to save to file). | |||
| 164 | DoLines(msg, critical, toStdout, toGUI); | |||
| 165 | } | |||
| 166 | } | |||
| 167 | ||||
| 168 | ||||
| 169 | void CLogger::AddLogLine( | |||
| 170 | const wxString &file, | |||
| 171 | int line, | |||
| 172 | bool critical, | |||
| 173 | DebugType type, | |||
| 174 | const std::ostringstream &msg) | |||
| 175 | { | |||
| 176 | AddLogLine(file, line, critical, type, wxString(char2unicode(msg.str().c_str()))); | |||
| 177 | } | |||
| 178 | ||||
| 179 | ||||
| 180 | const CDebugCategory& CLogger::GetDebugCategory( int index ) | |||
| 181 | { | |||
| 182 | wxASSERT( index >= 0 && index < categoryCount )do { if ( index >= 0 && index < categoryCount ) { } else if ( wxTheAssertHandler && (wxOnAssert("Logger.cpp" , 182, __FUNCTION__, "index >= 0 && index < categoryCount" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| ||||
| 183 | ||||
| 184 | return g_debugcats[ index ]; | |||
| ||||
| 185 | } | |||
| 186 | ||||
| 187 | ||||
| 188 | unsigned int CLogger::GetDebugCategoryCount() | |||
| 189 | { | |||
| 190 | return categoryCount; | |||
| 191 | } | |||
| 192 | ||||
| 193 | ||||
| 194 | bool CLogger::OpenLogfile(const wxString & name) | |||
| 195 | { | |||
| 196 | applog = new wxFFileOutputStream(name); | |||
| 197 | bool ret = applog->Ok(); | |||
| 198 | if (ret) { | |||
| 199 | FlushApplog(); | |||
| 200 | m_LogfileName = name; | |||
| 201 | } else { | |||
| 202 | CloseLogfile(); | |||
| 203 | } | |||
| 204 | return ret; | |||
| 205 | } | |||
| 206 | ||||
| 207 | ||||
| 208 | void CLogger::CloseLogfile() | |||
| 209 | { | |||
| 210 | delete applog; | |||
| 211 | applog = NULL__null; | |||
| 212 | m_LogfileName.Clear(); | |||
| 213 | } | |||
| 214 | ||||
| 215 | ||||
| 216 | void CLogger::OnLoggingEvent(class CLoggingEvent& evt) | |||
| 217 | { | |||
| 218 | DoLines(evt.Message(), evt.IsCritical(), evt.ToStdout(), evt.ToGUI()); | |||
| 219 | } | |||
| 220 | ||||
| 221 | ||||
| 222 | void CLogger::DoLines(const wxString & lines, bool critical, bool toStdout, bool toGUI) | |||
| 223 | { | |||
| 224 | // Remove newspace at end | |||
| 225 | wxString bufferline = lines.Strip(wxString::trailing); | |||
| 226 | ||||
| 227 | // Create the timestamp | |||
| 228 | wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ")L" " + wxDateTime::Now().FormatISOTime() | |||
| 229 | #ifdef CLIENT_GUI | |||
| 230 | + wxT(" (remote-GUI): ")L" (remote-GUI): "; | |||
| 231 | #else | |||
| 232 | + wxT(": ")L": "; | |||
| 233 | #endif | |||
| 234 | ||||
| 235 | // critical lines get a ! prepended, ordinary lines a blank | |||
| 236 | // logfile-only lines get a . to prevent transmission on EC | |||
| 237 | wxString prefix = !toGUI ? wxT(".")L"." : (critical ? wxT("!")L"!" : wxT(" ")L" "); | |||
| 238 | ||||
| 239 | if ( bufferline.IsEmpty() ) { | |||
| 240 | // If it's empty we just write a blank line with no timestamp. | |||
| 241 | DoLine(wxT(" \n")L" \n", toStdout, toGUI); | |||
| 242 | } else { | |||
| 243 | // Split multi-line messages into individual lines | |||
| 244 | wxStringTokenizer tokens( bufferline, wxT("\n")L"\n" ); | |||
| 245 | while ( tokens.HasMoreTokens() ) { | |||
| 246 | wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n")L"\n"; | |||
| 247 | DoLine(fullline, toStdout, toGUI); | |||
| 248 | } | |||
| 249 | } | |||
| 250 | } | |||
| 251 | ||||
| 252 | ||||
| 253 | void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI)toGUI) | |||
| 254 | { | |||
| 255 | { | |||
| 256 | wxMutexLocker lock(m_lineLock); | |||
| 257 | ++m_count; | |||
| 258 | ||||
| 259 | // write to logfile | |||
| 260 | m_ApplogBuf += line; | |||
| 261 | FlushApplog(); | |||
| 262 | ||||
| 263 | // write to Stdout | |||
| 264 | if (m_StdoutLog || toStdout) { | |||
| 265 | printf("%s", (const char*)unicode2char(line)); | |||
| 266 | } | |||
| 267 | } | |||
| 268 | #ifndef AMULE_DAEMON | |||
| 269 | // write to Listcontrol | |||
| 270 | if (toGUI) { | |||
| 271 | theApp->AddGuiLogLine(line); | |||
| 272 | } | |||
| 273 | #endif | |||
| 274 | } | |||
| 275 | ||||
| 276 | ||||
| 277 | void CLogger::EmergencyLog(const wxString &message, bool closeLog) | |||
| 278 | { | |||
| 279 | fprintf(stderrstderr, "%s", (const char*)unicode2char(message)); | |||
| 280 | m_ApplogBuf += message; | |||
| 281 | FlushApplog(); | |||
| 282 | if (closeLog && applog) { | |||
| 283 | applog->Close(); | |||
| 284 | applog = NULL__null; | |||
| 285 | } | |||
| 286 | } | |||
| 287 | ||||
| 288 | ||||
| 289 | void CLogger::FlushApplog() | |||
| 290 | { | |||
| 291 | if (applog) { // Wait with output until logfile is actually opened | |||
| 292 | wxStringInputStream stream(m_ApplogBuf); | |||
| 293 | (*applog) << stream; | |||
| 294 | applog->Sync(); | |||
| 295 | m_ApplogBuf.Clear(); | |||
| 296 | } | |||
| 297 | } | |||
| 298 | ||||
| 299 | CLogger theLogger; | |||
| 300 | ||||
| 301 | BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)const wxEventTable CLogger::sm_eventTable = { &wxEvtHandler ::sm_eventTable, &CLogger::sm_eventTableEntries[0] }; const wxEventTable *CLogger::GetEventTable() const { return &CLogger ::sm_eventTable; } wxEventHashTable CLogger::sm_eventHashTable (CLogger::sm_eventTable); wxEventHashTable &CLogger::GetEventHashTable () const { return CLogger::sm_eventHashTable; } const wxEventTableEntry CLogger::sm_eventTableEntries[] = { | |||
| 302 | EVT_MULE_LOGGING(CLogger::OnLoggingEvent)wxEventTableEntry(MULE_EVT_LOGLINE, -1, -1, wxNewEventTableFunctor (MULE_EVT_LOGLINE, (wxObjectEventFunction) (wxEventFunction) static_cast <MuleLogEventFunction>(&CLogger::OnLoggingEvent)), ( wxObject*) __null), | |||
| 303 | END_EVENT_TABLE()wxEventTableEntry(wxEVT_NULL, 0, 0, __null, __null) }; | |||
| 304 | ||||
| 305 | ||||
| 306 | CLoggerTarget::CLoggerTarget() | |||
| 307 | { | |||
| 308 | } | |||
| 309 | ||||
| 310 | void CLoggerTarget::DoLogText(const wxString &msg) | |||
| 311 | { | |||
| 312 | // prevent infinite recursion | |||
| 313 | static bool recursion = false; | |||
| 314 | if (recursion) { | |||
| 315 | return; | |||
| 316 | } | |||
| 317 | recursion = true; | |||
| 318 | ||||
| 319 | // This is much simpler than manually handling all wx log-types. | |||
| 320 | if (msg.StartsWith(_("ERROR: ")wxGetTranslation(("ERROR: "))) || msg.StartsWith(_("WARNING: ")wxGetTranslation(("WARNING: ")))) { | |||
| 321 | AddLogLineC(msg)theLogger.AddLogLine(L"Logger.cpp", 321, true, logStandard, msg ); | |||
| 322 | } else { | |||
| 323 | AddLogLineN(msg)theLogger.AddLogLine(L"Logger.cpp", 323, false, logStandard, msg ); | |||
| 324 | } | |||
| 325 | ||||
| 326 | recursion = false; | |||
| 327 | } | |||
| 328 | ||||
| 329 | CLoggerAccess::CLoggerAccess() | |||
| 330 | { | |||
| 331 | m_bufferlen = 4096; | |||
| 332 | m_buffer = new wxCharBuffer(m_bufferlen); | |||
| 333 | m_logfile = NULL__null; | |||
| 334 | Reset(); | |||
| 335 | } | |||
| 336 | ||||
| 337 | ||||
| 338 | void CLoggerAccess::Reset() | |||
| 339 | { | |||
| 340 | delete m_logfile; | |||
| 341 | m_logfile = new wxFFileInputStream(theLogger.GetLogfileName()); | |||
| 342 | m_pos = 0; | |||
| 343 | m_ready = false; | |||
| 344 | } | |||
| 345 | ||||
| 346 | ||||
| 347 | CLoggerAccess::~CLoggerAccess() | |||
| 348 | { | |||
| 349 | delete m_buffer; | |||
| 350 | delete m_logfile; | |||
| 351 | } | |||
| 352 | ||||
| 353 | ||||
| 354 | // | |||
| 355 | // read a line of text from the logfile if available | |||
| 356 | // (can't believe there's no library function for this >:( ) | |||
| 357 | // | |||
| 358 | bool CLoggerAccess::HasString() | |||
| 359 | { | |||
| 360 | while (!m_ready) { | |||
| 361 | int c = m_logfile->GetC(); | |||
| 362 | if (c == wxEOF) { | |||
| 363 | break; | |||
| 364 | } | |||
| 365 | // check for buffer overrun | |||
| 366 | if (m_pos == m_bufferlen) { | |||
| 367 | m_bufferlen += 1024; | |||
| 368 | m_buffer->extend(m_bufferlen); | |||
| 369 | } | |||
| 370 | m_buffer->data()[m_pos++] = c; | |||
| 371 | if (c == '\n') { | |||
| 372 | if (m_buffer->data()[0] == '.') { | |||
| 373 | // Log-only line, skip | |||
| 374 | m_pos = 0; | |||
| 375 | } else { | |||
| 376 | m_ready = true; | |||
| 377 | } | |||
| 378 | } | |||
| 379 | } | |||
| 380 | return m_ready; | |||
| 381 | } | |||
| 382 | ||||
| 383 | ||||
| 384 | bool CLoggerAccess::GetString(wxString & s) | |||
| 385 | { | |||
| 386 | if (!HasString()) { | |||
| 387 | return false; | |||
| 388 | } | |||
| 389 | s = wxString(m_buffer->data(), wxConvUTF8wxGet_wxConvUTF8(), m_pos); | |||
| 390 | m_pos = 0; | |||
| 391 | m_ready = false; | |||
| 392 | return true; | |||
| 393 | } | |||
| 394 | ||||
| 395 | // Functions for EC logging | |||
| 396 | ||||
| 397 | #ifdef __DEBUG__ | |||
| 398 | #include "ec/cpp/ECLog.h" | |||
| 399 | ||||
| 400 | bool ECLogIsEnabled() | |||
| 401 | { | |||
| 402 | return theLogger.IsEnabled(logEC); | |||
| 403 | } | |||
| 404 | ||||
| 405 | void DoECLogLine(const wxString &line) | |||
| 406 | { | |||
| 407 | // without file/line | |||
| 408 | theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false); | |||
| 409 | } | |||
| 410 | ||||
| 411 | #endif /* __DEBUG__ */ | |||
| 412 | // File_checked_for_headers |