Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 lines
11 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992-1995 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // debug.c
  13. //
  14. // Description:
  15. // This file contains code yanked from several places to provide debug
  16. // support that works in win 16 and win 32.
  17. //
  18. //
  19. //==========================================================================;
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <stdarg.h>
  23. #include "debug.h"
  24. //
  25. // since we don't UNICODE our debugging messages, use the ASCII entry
  26. // points regardless of how we are compiled.
  27. //
  28. #ifdef _WIN32
  29. #include <wchar.h>
  30. #else
  31. #define lstrcatA lstrcat
  32. #define lstrlenA lstrlen
  33. #define GetProfileIntA GetProfileInt
  34. #define OutputDebugStringA OutputDebugString
  35. #define wsprintfA wsprintf
  36. #define MessageBoxA MessageBox
  37. #endif
  38. #ifdef USEDPF
  39. //
  40. //
  41. //
  42. BOOL __gfDbgEnabled = TRUE; // master enable
  43. UINT __guDbgLevel = 0; // current debug level
  44. #endif
  45. #if defined(USERPF) || defined(USEDPF)
  46. #define LOGSIZE 64000
  47. char pStartOfBuffer[LOGSIZE];
  48. static char* pEndOfBuffer = pStartOfBuffer+LOGSIZE;
  49. char* pHead = pStartOfBuffer;
  50. static char* pTail = pStartOfBuffer;
  51. void listRemoveHead()
  52. {
  53. pHead += lstrlen(pHead) + 1 ;
  54. if (pHead >= pEndOfBuffer) {
  55. pHead = pStartOfBuffer ;
  56. }
  57. }
  58. char* listGetHead()
  59. {
  60. return ( pHead ) ;
  61. }
  62. void listAddTail(char* lpszDebug)
  63. {
  64. int cchDebug ;
  65. cchDebug = lstrlen(lpszDebug) ;
  66. while (TRUE) {
  67. while ( (pTail < pHead) && ((pTail+(cchDebug+1)) > pHead) ) {
  68. listRemoveHead() ;
  69. }
  70. if ((pTail+(cchDebug+1)+2) > pEndOfBuffer) {
  71. for ( ; pTail < pEndOfBuffer-1 ; pTail++ ) {
  72. *pTail = 'X' ;
  73. }
  74. *pTail = '\0' ;
  75. pTail = pStartOfBuffer ;
  76. } else {
  77. lstrcpyn(pTail, lpszDebug, pEndOfBuffer-pTail) ;
  78. pTail += (cchDebug+1) ;
  79. *pTail = '\0' ;
  80. break ;
  81. }
  82. }
  83. }
  84. //--------------------------------------------------------------------------;
  85. //
  86. // DbgDumpQueue
  87. //
  88. // Description:
  89. //
  90. // Arguments:
  91. //
  92. // Return (void):
  93. // No value is returned.
  94. //
  95. //--------------------------------------------------------------------------;
  96. VOID DbgDumpQueue()
  97. {
  98. char* pszDebug;
  99. pszDebug = listGetHead() ;
  100. while ('\0' != *pszDebug) {
  101. OutputDebugString(pszDebug) ;
  102. listRemoveHead() ;
  103. pszDebug = listGetHead() ;
  104. }
  105. return;
  106. }
  107. //--------------------------------------------------------------------------;
  108. //
  109. // void DbgQueueString
  110. //
  111. // Description:
  112. //
  113. //
  114. // Arguments:
  115. // LPSTR sz:
  116. //
  117. // Return (void):
  118. // No value is returned.
  119. //
  120. //--------------------------------------------------------------------------;
  121. void DbgQueueString(LPSTR pString)
  122. {
  123. listAddTail(pString);
  124. }
  125. //--------------------------------------------------------------------------;
  126. //
  127. // void DbgVPrintF
  128. //
  129. // Description:
  130. //
  131. //
  132. // Arguments:
  133. // LPSTR szFormat:
  134. //
  135. // va_list va:
  136. //
  137. // Return (void):
  138. // No value is returned.
  139. //
  140. //--------------------------------------------------------------------------;
  141. void FAR CDECL DbgVPrintF
  142. (
  143. LPSTR szFormat,
  144. va_list va
  145. )
  146. {
  147. char ach[DEBUG_MAX_LINE_LEN];
  148. BOOL fDebugBreak = FALSE;
  149. BOOL fPrefix = TRUE;
  150. BOOL fCRLF = TRUE;
  151. BOOL fQueue = FALSE;
  152. BOOL fDumpQueue = FALSE;
  153. ach[0] = '\0';
  154. for (;;)
  155. {
  156. switch (*szFormat)
  157. {
  158. case '!':
  159. fDebugBreak = TRUE;
  160. szFormat++;
  161. continue;
  162. case '`':
  163. fPrefix = FALSE;
  164. szFormat++;
  165. continue;
  166. case '~':
  167. fCRLF = FALSE;
  168. szFormat++;
  169. continue;
  170. case ';':
  171. fQueue = TRUE;
  172. if (';' == *(szFormat+1)) {
  173. fQueue = FALSE;
  174. fDumpQueue = TRUE;
  175. szFormat++;
  176. }
  177. szFormat++;
  178. continue;
  179. }
  180. break;
  181. }
  182. if (fDebugBreak)
  183. {
  184. ach[0] = '\007';
  185. ach[1] = '\0';
  186. }
  187. if (fPrefix)
  188. {
  189. lstrcatA(ach, DEBUG_MODULE_NAME ": ");
  190. }
  191. #ifdef WIN95
  192. {
  193. char *psz = NULL;
  194. char szDfs[1024]={0};
  195. strcpy(szDfs,szFormat); // make a local copy of format string
  196. while (psz = strstr(szDfs,"%p")) // find each %p
  197. *(psz+1) = 'x'; // replace each %p with %x
  198. #ifdef _WIN32
  199. wvsprintfA(ach + lstrlenA(ach), szDfs, va); // use the local format string
  200. #else
  201. wvsprintf(ach + lstrlenA(ach), szDfs, (LPSTR)va); // use the local format string
  202. #endif
  203. }
  204. #else
  205. {
  206. #ifdef _WIN32
  207. wvsprintfA(ach + lstrlenA(ach), szFormat, va);
  208. #else
  209. wvsprintf(ach + lstrlenA(ach), szFormat, (LPSTR)va);
  210. #endif
  211. }
  212. #endif
  213. if (fCRLF)
  214. {
  215. lstrcatA(ach, "\r\n");
  216. }
  217. if (fDumpQueue)
  218. {
  219. DbgDumpQueue();
  220. }
  221. if (fQueue) {
  222. DbgQueueString(ach);
  223. } else {
  224. OutputDebugStringA(ach);
  225. }
  226. if (fDebugBreak)
  227. {
  228. DebugBreak();
  229. }
  230. } // DbgVPrintF()
  231. #endif // USERPF || USEDPF
  232. #ifdef USEDPF
  233. //--------------------------------------------------------------------------;
  234. //
  235. // void dprintf
  236. //
  237. // Description:
  238. // dprintf() is called by the DPF() macro if DEBUG is defined at compile
  239. // time. It is recommended that you only use the DPF() macro to call
  240. // this function--so you don't have to put #ifdef DEBUG around all
  241. // of your code.
  242. //
  243. // Arguments:
  244. // UINT uDbgLevel:
  245. //
  246. // LPSTR szFormat:
  247. //
  248. // Return (void):
  249. // No value is returned.
  250. //
  251. //--------------------------------------------------------------------------;
  252. void FAR CDECL dprintf
  253. (
  254. UINT uDbgLevel,
  255. LPSTR szFormat,
  256. ...
  257. )
  258. {
  259. va_list va;
  260. if (!__gfDbgEnabled || (__guDbgLevel < uDbgLevel))
  261. return;
  262. va_start(va, szFormat);
  263. DbgVPrintF(szFormat, va);
  264. va_end(va);
  265. } // dprintf()
  266. //--------------------------------------------------------------------------;
  267. //
  268. // BOOL DbgEnable
  269. //
  270. // Description:
  271. //
  272. //
  273. // Arguments:
  274. // BOOL fEnable:
  275. //
  276. // Return (BOOL):
  277. // Returns the previous debugging state.
  278. //
  279. //--------------------------------------------------------------------------;
  280. BOOL WINAPI DbgEnable
  281. (
  282. BOOL fEnable
  283. )
  284. {
  285. BOOL fOldState;
  286. fOldState = __gfDbgEnabled;
  287. __gfDbgEnabled = fEnable;
  288. return (fOldState);
  289. } // DbgEnable()
  290. //--------------------------------------------------------------------------;
  291. //
  292. // UINT DbgSetLevel
  293. //
  294. // Description:
  295. //
  296. //
  297. // Arguments:
  298. // UINT uLevel:
  299. //
  300. // Return (UINT):
  301. // Returns the previous debugging level.
  302. //
  303. //--------------------------------------------------------------------------;
  304. UINT WINAPI DbgSetLevel
  305. (
  306. UINT uLevel
  307. )
  308. {
  309. UINT uOldLevel;
  310. uOldLevel = __guDbgLevel;
  311. __guDbgLevel = uLevel;
  312. return (uOldLevel);
  313. } // DbgSetLevel()
  314. //--------------------------------------------------------------------------;
  315. //
  316. // UINT DbgGetLevel
  317. //
  318. // Description:
  319. //
  320. //
  321. // Arguments:
  322. // None.
  323. //
  324. // Return (UINT):
  325. // Returns the current debugging level.
  326. //
  327. //--------------------------------------------------------------------------;
  328. UINT WINAPI DbgGetLevel
  329. (
  330. void
  331. )
  332. {
  333. return (__guDbgLevel);
  334. } // DbgGetLevel()
  335. //--------------------------------------------------------------------------;
  336. //
  337. // UINT DbgInitialize
  338. //
  339. // Description:
  340. //
  341. //
  342. // Arguments:
  343. // BOOL fEnable:
  344. //
  345. // Return (UINT):
  346. // Returns the debugging level that was set.
  347. //
  348. //--------------------------------------------------------------------------;
  349. UINT WINAPI DbgInitialize
  350. (
  351. BOOL fEnable
  352. )
  353. {
  354. UINT uLevel;
  355. uLevel = GetProfileIntA(DEBUG_SECTION, DEBUG_MODULE_NAME, (UINT)-1);
  356. if ((UINT)-1 == uLevel)
  357. {
  358. //
  359. // if the debug key is not present, then force debug output to
  360. // be disabled. this way running a debug version of a component
  361. // on a non-debugging machine will not generate output unless
  362. // the debug key exists.
  363. //
  364. uLevel = 0;
  365. fEnable = FALSE;
  366. }
  367. DbgSetLevel(uLevel);
  368. DbgEnable(fEnable);
  369. return (__guDbgLevel);
  370. } // DbgInitialize()
  371. #endif // #ifdef USEDPF
  372. //--------------------------------------------------------------------------;
  373. //
  374. // void _Assert
  375. //
  376. // Description:
  377. // This routine is called if the ASSERT macro (defined in debug.h)
  378. // tests and expression that evaluates to FALSE. This routine
  379. // displays an "assertion failed" message box allowing the user to
  380. // abort the program, enter the debugger (the "retry" button), or
  381. // ignore the assertion and continue executing. The message box
  382. // displays the file name and line number of the _Assert() call.
  383. //
  384. // Arguments:
  385. // char * szFile: Filename where assertion occurred.
  386. // int iLine: Line number of assertion.
  387. //
  388. //--------------------------------------------------------------------------;
  389. #ifdef USEASSERT
  390. #ifndef _WIN32
  391. #pragma warning(disable:4704)
  392. #endif
  393. void WINAPI _Assert
  394. (
  395. char * szFile,
  396. int iLine,
  397. char * szExpression
  398. )
  399. {
  400. static char ach[400]; // debug output (avoid stack overflow)
  401. int id;
  402. #ifndef _WIN32
  403. int iExitCode;
  404. #endif
  405. #ifdef DEBUG
  406. if (__gfDbgEnabled)
  407. {
  408. wsprintfA(ach, "Assertion failed in file %s, line %d: (%s)", (LPSTR)szFile, iLine, (LPSTR)szExpression);
  409. OutputDebugString(ach);
  410. DebugBreak();
  411. }
  412. else
  413. #endif
  414. {
  415. wsprintfA(ach, "Assertion failed in file %s, line %d: (%s) [Press RETRY to debug.]", (LPSTR)szFile, iLine, (LPSTR)szExpression);
  416. id = MessageBoxA(NULL, ach, "Assertion Failed",
  417. MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE );
  418. switch (id)
  419. {
  420. case IDABORT: // Kill the application.
  421. #ifndef _WIN32
  422. iExitCode = 0;
  423. _asm {
  424. mov ah, 4Ch;
  425. mov al, BYTE PTR iExitCode;
  426. int 21h;
  427. }
  428. #else
  429. FatalAppExit(0, TEXT("Good Bye"));
  430. #endif // WIN16
  431. break;
  432. case IDRETRY: // Break into the debugger.
  433. DebugBreak();
  434. break;
  435. case IDIGNORE: // Ignore assertion, continue executing.
  436. break;
  437. }
  438. }
  439. } // _Assert
  440. #endif // #ifdef USEASSERT
  441. //--------------------------------------------------------------------------;
  442. //
  443. // void rprintf
  444. //
  445. // Description:
  446. // rprintf() is called by the RPF() macro. It is just like dprintf,
  447. // except that there is no level defined. RPF statements always
  448. // translate to a debug output, regardless of level.
  449. //
  450. // Arguments:
  451. // LPSTR szFormat:
  452. //
  453. // Return (void):
  454. // No value is returned.
  455. //
  456. //--------------------------------------------------------------------------;
  457. #ifdef USERPF
  458. void CDECL rprintf
  459. (
  460. LPSTR szFormat,
  461. ...
  462. )
  463. {
  464. va_list va;
  465. va_start(va, szFormat);
  466. DbgVPrintF(szFormat, va);
  467. va_end(va);
  468. }
  469. #endif // USERPF
  470. #ifndef _WIN32
  471. #pragma warning(default:4704)
  472. #endif