00001
00002
00003
00004
00005
00023 #ifndef HDEBUG_H
00024 # define HDEBUG_H
00025
00026 #ifndef __DEBUG__
00027 # define __DEBUG__ 0
00028 #endif
00029
00030 #if __DEBUG__
00031
00032 #define SEND_TO_STDERR 1
00033 #define SEND_TO_PRINTD 0
00034
00044 class HDebug : public HObjNoCopy
00045 {
00046 typedef HObjNoCopy base_class;
00047 static StringPtr ClassName(void) { return "HDebug"; }
00048
00049
00050
00051 protected:
00052 FILE * m_pfLog;
00053
00054
00055
00056 public:
00057 HDebug(void) : m_pfLog(NULL)
00058 { }
00059
00060 virtual
00061 ~HDebug(void)
00062 { Close(); }
00063
00064
00065
00066 public:
00075 static void
00076 Check(bool bPassed, StringPtr pstrTest, StringPtr pstrFile, uint32 uLine)
00077 {
00078 if (!bPassed)
00079 {
00080 const uint32 kMaxMsgLen = MAX_PATH * 2;
00081 Text szMsg[kMaxMsgLen+1] = { '\0' };
00082
00083 (void) STR_SPRINTF( szMsg, kMaxMsgLen,
00084 "Sanity check at %s(%lu): \"%s\"",
00085 pstrFile, uLine, pstrTest);
00086
00087 if (GI_messagebox( NULL, WGF_MB_ICON_STOP|WGF_MB_CANCEL,
00088 const_cast<TextPtr>("Sanity Check?"),
00089 szMsg) == ID_OK)
00090 {
00091 GetLog().LogV("%s approved.\n", szMsg);
00092 }
00093 else
00094 throw std::runtime_error(szMsg);
00095 }
00096 }
00100 void
00101 Close(void)
00102 {
00103 if (IsOpen() && fclose(m_pfLog) == 0)
00104 m_pfLog = NULL;
00105 }
00109 void
00110 Flush(void) const
00111 {
00112 if (IsOpen())
00113 (void) fflush(m_pfLog);
00114 }
00124 void
00125 Log(StringPtr pstr) const
00126 {
00127 int32 nLen = STR_NLEN(pstr, KB(8));
00128
00129 if (nLen <= 0)
00130 return;
00131
00132 #if SEND_TO_STDERR
00133 (void) fwrite(pstr, sizeof(Text), nLen, stderr);
00134 #endif
00135 #if SEND_TO_PRINTD
00136 (void) printd( (char *)(pstr) );
00137 #endif
00138 if (IsOpen())
00139 {
00140 (void) fwrite(pstr, sizeof(Text), nLen, m_pfLog);
00141 Flush();
00142 }
00143 }
00154 void
00155 LogHex(uint8 const * pData, uint32 uBytes) const
00156 {
00157 if (GOOD_PTR(pData))
00158 {
00159 uint32 uOffset = 0;
00160
00161 uBytes = min(uBytes, KB(1));
00162
00163 while (uOffset < uBytes)
00164 {
00165 LogV("0x%04lX :", uOffset);
00166 for (uint32 udx = 0; udx < 16 && uOffset < uBytes; ++udx)
00167 LogV(" %02X", pData[uOffset++]);
00168 Log(kStrEOL);
00169 }
00170
00171 Flush();
00172 }
00173 }
00185 void
00186 LogMsg(StringPtr pstrClass, HANDLE hWnd, const s_gi_msg * pMsg) const
00187 {
00188 StringPtr pstr = NULL;
00189
00190 if (NULL_PTR(pMsg))
00191 return;
00192
00193 switch (pMsg->type)
00194 {
00195 case MSG_APPLICATIONS_CHANGED:
00196 case MSG_APPLICATIONS_SWITCHED:
00197 case MSG_GUI_DRAW_CHILD:
00198 case MSG_GUI_WINDOW_FOCUS_GET:
00199 case MSG_GUI_WINDOW_FOCUS_LOST:
00200 case MSG_GUI_REDRAW:
00201 case MSG_MOUSE_MOVE:
00202
00203 return;
00204
00205 case MSG_COMMAND:
00206 LogV( "%s[0x%08lX] => MSG_COMMAND (%u)\n",
00207 pstrClass, int32(hWnd), pMsg->para1);
00208 return;
00209
00210 case MSG_MOUSE_BUT1_PRESSED:
00211 LogV( "%s[0x%08lX] => MSG_MOUSE_BUT1_PRESSED at (%u, %u)\n",
00212 pstrClass, int32(hWnd), pMsg->para1, pMsg->para2);
00213 return;
00214
00215 case MSG_MOUSE_BUT2_PRESSED:
00216 LogV( "%s[0x%08lX] => MSG_MOUSE_BUT2_PRESSED at (%u, %u)\n",
00217 pstrClass, int32(hWnd), pMsg->para1, pMsg->para2);
00218 return;
00219
00220 case MSG_WINDOW_SIZED:
00221 LogV( "%s[0x%08lX] => MSG_WINDOW_SIZED (%d, %d, %d, %d)\n",
00222 pstrClass, int32(hWnd), pMsg->rect.x1, pMsg->rect.y1, pMsg->rect.x2, pMsg->rect.y2);
00223 return;
00224
00225 case MSG_DESTROY: pstr = "MSG_DESTROY"; break;
00226 case MSG_GUI_CLOSE_WIN: pstr = "MSG_GUI_CLOSE_WIN"; break;
00227 case MSG_GUI_CREATE_WINDOW: pstr = "MSG_GUI_CREATE_WINDOW"; break;
00228 case MSG_GUI_WINDOW_CLOSE: pstr = "MSG_GUI_WINDOW_CLOSE"; break;
00229 case MSG_GUI_WINDOW_CREATED: pstr = "MSG_GUI_WINDOW_CREATED"; break;
00230 case MSG_GUI_WINDOW_SIZED: pstr = "MSG_GUI_WINDOW_SIZED"; break;
00231 case MSG_KEY_DOWN: pstr = "MSG_KEY_DOWN"; break;
00232 case MSG_KEY_UP: pstr = "MSG_KEY_UP"; break;
00233 case MSG_MOUSE_BUT1_RELEASED: pstr = "MSG_MOUSE_BUT1_RELEASED"; break;
00234 case MSG_MOUSE_BUT2_RELEASED: pstr = "MSG_MOUSE_BUT2_RELEASED"; break;
00235 case MSG_MOUSE_ENTER: pstr = "MSG_MOUSE_ENTER"; break;
00236 case MSG_MOUSE_LEAVE: pstr = "MSG_MOUSE_LEAVE"; break;
00237
00238 case MSG_PRE_DESTROY: pstr = "MSG_PRE_DESTROY"; break;
00239 case MSG_THEME_CHANGED: pstr = "MSG_THEME_CHANGED"; break;
00240 case MSG_TIMER: pstr = "MSG_TIMER"; break;
00241 case MSG_TIMER_REACHED: pstr = "MSG_TIMER_REACHED"; break;
00242 case MSG_WINDOW_DESTROY: pstr = "MSG_WINDOW_DESTROY"; break;
00243 case MSG_WINDOW_SHOW: pstr = "MSG_WINDOW_SHOW"; break;
00244
00245
00246 case WM_WG_CHECKBOX_CHANGED: pstr = "WM_WG_CHECKBOX_CHANGED"; break;
00247
00248 default:
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 if (pMsg->type >= 10100 && pMsg->type <= 10199)
00263 {
00264 LogV( "%s[0x%08lX] => COMBO WIDGET MSG#%04u\n",
00265 pstrClass, int32(hWnd), (pMsg->type - 10100));
00266 }
00267 else if (pMsg->type >= 10200 && pMsg->type <= 10299)
00268 {
00269 LogV( "%s[0x%08lX] => TEXT WIDGET MSG#%04u\n",
00270 pstrClass, int32(hWnd), (pMsg->type - 10200));
00271 }
00272 else if (pMsg->type >= 10300 && pMsg->type <= 10399)
00273 {
00274 LogV( "%s[0x%08lX] => LISTBOX WIDGET MSG#%04u\n",
00275 pstrClass, int32(hWnd), (pMsg->type - 10300));
00276 }
00277 else if (pMsg->type >= 10400 && pMsg->type <= 10499)
00278 {
00279 LogV( "%s[0x%08lX] => CLIENT WIDGET MSG#%04u\n",
00280 pstrClass, int32(hWnd), (pMsg->type - 10400));
00281 }
00282 else if (pMsg->type >= 10500 && pMsg->type <= 10599)
00283 {
00284 LogV( "%s[0x%08lX] => TITLE WIDGET MSG#%04u\n",
00285 pstrClass, int32(hWnd), (pMsg->type - 10500));
00286 }
00287 else if (pMsg->type >= 10800 && pMsg->type <= 11999)
00288 {
00289 LogV( "%s[0x%08lX] => GENERIC WIDGET MSG#%04u\n",
00290 pstrClass, int32(hWnd), (pMsg->type - 10800));
00291 }
00292 else if (pMsg->type >= 12000 && pMsg->type <= 12099)
00293 {
00294 LogV( "%s[0x%08lX] => TREE WIDGET MSG#%04u\n",
00295 pstrClass, int32(hWnd), (pMsg->type - 12000));
00296 }
00297 else if (pMsg->type >= 13000 && pMsg->type <= 13099)
00298 {
00299 LogV( "%s[0x%08lX] => POPUP WIDGET MSG#%04u\n",
00300 pstrClass, int32(hWnd), (pMsg->type - 13000));
00301 }
00302 else if (pMsg->type >= 14000 && pMsg->type <= 14099)
00303 {
00304 LogV( "%s[0x%08lX] => CHECBOX WIDGET MSG#%04u\n",
00305 pstrClass, int32(hWnd), (pMsg->type - 14000));
00306 }
00307 else
00308 {
00309 LogV( "%s[0x%08lX] => Unrecognized message %u\n",
00310 pstrClass, int32(hWnd), pMsg->type);
00311 }
00312 return;
00313
00314 }
00315
00316 LogV( "%s[0x%08lX] => %s\n",
00317 pstrClass, int32(hWnd), pstr);
00318
00319 Flush();
00320 }
00330 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00331 GCC_ONLY( __attribute__ ((format (printf,2,3))) )
00332 #endif
00333 void
00334 LogV(StringPtr pstr, ...) const
00335 {
00336 if (GOOD_PTR(pstr))
00337 {
00338 const uint32 kMaxOut = 2047;
00339 va_list vaList;
00340 Text szOut[kMaxOut+1];
00341
00342 va_start(vaList, pstr);
00343 Humble::safe_vsprintf(szOut, kMaxOut, pstr, vaList);
00344 va_end(vaList);
00345
00346 Log(szOut);
00347 }
00348 }
00358 bool
00359 Open(StringPtr pstrLogFile)
00360 {
00361 if (GOOD_PTR(pstrLogFile))
00362 {
00363 Close();
00364 m_pfLog = fopen(pstrLogFile, "w+t");
00365 }
00366
00367 return IsOpen();
00368 }
00369
00370
00371
00372 public:
00375 static HDebug & GetLog(void)
00376 {
00377 static HDebug me;
00378 return me;
00379 }
00380
00381
00382
00385 inline bool IsOpen(void) const
00386 { return GOOD_PTR(m_pfLog); }
00387 };
00388
00389
00390
00394
00396 # define ASSERT(x) if (x) ; else throw HAssertion(#x,__FILE__,__LINE__)
00397
00398 # define ASSERT_HND(h) if (GOOD_HND(h)) ; else throw HAssertion(#h " is NULL",__FILE__,__LINE__)
00399
00400 # define ASSERT_PTR(p) if (GOOD_PTR(p)) ; else throw HAssertion(#p " is NULL",__FILE__,__LINE__)
00401
00402 # define ASSERT_STR(s) if (STR_VALID(s)) ; else throw HAssertion(#s " is invalid",__FILE__,__LINE__)
00403
00404 # define DEBUG_CHECK(x) HDebug::Check((x),#x,__FILE__,__LINE__)
00405
00406 # define DEBUG_LOG HDebug::GetLog().LogV
00407
00408 # define DEBUG_HEX(p,u) HDebug::GetLog().LogHex((p),(u))
00409
00410 # define DEBUG_MSG(x,w,p) HDebug::GetLog().LogMsg((x),(w),(p))
00411
00412 # define DEBUG_ONLY(x) x
00413
00414 #else // !__DEBUG__
00415 inline void ignore(...) { }
00416
00417 # define ASSERT(x) NOTHING
00418 # define ASSERT_HND(x) NOTHING
00419 # define ASSERT_PTR(x) NOTHING
00420 # define ASSERT_STR(x) NOTHING
00421 # define DEBUG_CHECK(x) NOTHING
00422 # define DEBUG_LOG ignore
00423 # define DEBUG_HEX(p,u) NOTHING
00424 # define DEBUG_MSG(t,w,p) NOTHING
00425 # define DEBUG_ONLY(x) NOTHING
00426 #endif // __DEBUG__
00427
00428 #endif // HDEBUG_H
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474