Leaked source code of windows server 2003
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.

1381 lines
34 KiB

  1. //
  2. // Debug squirty functions
  3. //
  4. #include "proj.h"
  5. #pragma hdrstop
  6. #if defined(DEBUG) || defined(PRODUCT_PROF)
  7. // (c_szCcshellIniFile and c_szCcshellIniSecDebug are declared in debug.h)
  8. extern CHAR const FAR c_szCcshellIniFile[];
  9. extern CHAR const FAR c_szCcshellIniSecDebug[];
  10. /*----------------------------------------------------------
  11. Purpose: Special verion of atoi. Supports hexadecimal too.
  12. If this function returns FALSE, *piRet is set to 0.
  13. Returns: TRUE if the string is a number, or contains a partial number
  14. FALSE if the string is not a number
  15. Cond: --
  16. */
  17. static
  18. BOOL
  19. MyStrToIntExA(
  20. LPCSTR pszString,
  21. DWORD dwFlags, // STIF_ bitfield
  22. int FAR * piRet)
  23. {
  24. #define IS_DIGIT(ch) InRange(ch, '0', '9')
  25. BOOL bRet;
  26. int n;
  27. BOOL bNeg = FALSE;
  28. LPCSTR psz;
  29. LPCSTR pszAdj;
  30. // Skip leading whitespace
  31. //
  32. for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = CharNextA(psz))
  33. ;
  34. // Determine possible explicit signage
  35. //
  36. if (*psz == '+' || *psz == '-')
  37. {
  38. bNeg = (*psz == '+') ? FALSE : TRUE;
  39. psz++;
  40. }
  41. // Or is this hexadecimal?
  42. //
  43. pszAdj = CharNextA(psz);
  44. if ((STIF_SUPPORT_HEX & dwFlags) &&
  45. *psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
  46. {
  47. // Yes
  48. // (Never allow negative sign with hexadecimal numbers)
  49. bNeg = FALSE;
  50. psz = CharNextA(pszAdj);
  51. pszAdj = psz;
  52. // Do the conversion
  53. //
  54. for (n = 0; ; psz = CharNextA(psz))
  55. {
  56. if (IS_DIGIT(*psz))
  57. n = 0x10 * n + *psz - '0';
  58. else
  59. {
  60. CHAR ch = *psz;
  61. int n2;
  62. if (ch >= 'a')
  63. ch -= 'a' - 'A';
  64. n2 = ch - 'A' + 0xA;
  65. if (n2 >= 0xA && n2 <= 0xF)
  66. n = 0x10 * n + n2;
  67. else
  68. break;
  69. }
  70. }
  71. // Return TRUE if there was at least one digit
  72. bRet = (psz != pszAdj);
  73. }
  74. else
  75. {
  76. // No
  77. pszAdj = psz;
  78. // Do the conversion
  79. for (n = 0; IS_DIGIT(*psz); psz = CharNextA(psz))
  80. n = 10 * n + *psz - '0';
  81. // Return TRUE if there was at least one digit
  82. bRet = (psz != pszAdj);
  83. }
  84. *piRet = bNeg ? -n : n;
  85. return bRet;
  86. }
  87. #endif
  88. #ifdef DEBUG
  89. DWORD g_dwDumpFlags = 0; // DF_*
  90. #ifdef FULL_DEBUG
  91. DWORD g_dwBreakFlags = BF_ONVALIDATE; // BF_*
  92. #else
  93. DWORD g_dwBreakFlags = 0; // BF_*
  94. #endif
  95. DWORD g_dwTraceFlags = 0; // TF_*
  96. DWORD g_dwPrototype = 0;
  97. DWORD g_dwFuncTraceFlags = 0; // FTF_*
  98. // TLS slot used to store depth for CcshellFuncMsg indentation
  99. static DWORD g_tlsStackDepth = TLS_OUT_OF_INDEXES;
  100. // Hack stack depth counter used when g_tlsStackDepth is not available
  101. static DWORD g_dwHackStackDepth = 0;
  102. static char g_szIndentLeader[] = " ";
  103. static WCHAR g_wszIndentLeader[] = L" ";
  104. #pragma data_seg(DATASEG_READONLY)
  105. static CHAR const FAR c_szNewline[] = "\r\n"; // (Deliberately CHAR)
  106. static WCHAR const FAR c_wszNewline[] = TEXTW("\r\n");
  107. #pragma data_seg()
  108. extern CHAR const FAR c_szTrace[]; // (Deliberately CHAR)
  109. extern CHAR const FAR c_szErrorDbg[]; // (Deliberately CHAR)
  110. extern CHAR const FAR c_szWarningDbg[]; // (Deliberately CHAR)
  111. extern WCHAR const FAR c_wszTrace[];
  112. extern WCHAR const FAR c_wszErrorDbg[];
  113. extern WCHAR const FAR c_wszWarningDbg[];
  114. extern const CHAR FAR c_szAssertMsg[];
  115. extern CHAR const FAR c_szAssertFailed[];
  116. extern const WCHAR FAR c_wszAssertMsg[];
  117. extern WCHAR const FAR c_wszAssertFailed[];
  118. void
  119. SetPrefixStringA(
  120. OUT LPSTR pszBuf,
  121. IN DWORD dwFlags)
  122. {
  123. if (TF_ALWAYS == dwFlags)
  124. lstrcpyA(pszBuf, c_szTrace);
  125. else if (IsFlagSet(dwFlags, TF_WARNING))
  126. lstrcpyA(pszBuf, c_szWarningDbg);
  127. else if (IsFlagSet(dwFlags, TF_ERROR))
  128. lstrcpyA(pszBuf, c_szErrorDbg);
  129. else
  130. lstrcpyA(pszBuf, c_szTrace);
  131. }
  132. void
  133. SetPrefixStringW(
  134. OUT LPWSTR pszBuf,
  135. IN DWORD dwFlags)
  136. {
  137. if (TF_ALWAYS == dwFlags)
  138. lstrcpyW(pszBuf, c_wszTrace);
  139. else if (IsFlagSet(dwFlags, TF_WARNING))
  140. lstrcpyW(pszBuf, c_wszWarningDbg);
  141. else if (IsFlagSet(dwFlags, TF_ERROR))
  142. lstrcpyW(pszBuf, c_wszErrorDbg);
  143. else
  144. lstrcpyW(pszBuf, c_wszTrace);
  145. }
  146. // Hack! The MSDEV debugger has some smarts where if it sees
  147. // an ASSERT (all caps) in the source, and there is a debug break,
  148. // then it sticks up a sorta friendly assert message box.
  149. // For the debug function below where the break occurs inside,
  150. // we add a nop ASSERT line in here to fake MSDEV to give us
  151. // a friendly message box.
  152. #undef ASSERT
  153. #define ASSERT(f) DEBUG_BREAK
  154. // BUGBUG (scotth): Use the Ccshell functions. _AssertMsg and
  155. // _DebugMsg are obsolete. They will be removed once all the
  156. // components don't have TEXT() wrapping their debug strings anymore.
  157. void
  158. WINCAPI
  159. _AssertMsgA(
  160. BOOL f,
  161. LPCSTR pszMsg, ...)
  162. {
  163. CHAR ach[1024+40];
  164. va_list vArgs;
  165. if (!f)
  166. {
  167. int cch;
  168. lstrcpyA(ach, c_szAssertMsg);
  169. cch = lstrlenA(ach);
  170. va_start(vArgs, pszMsg);
  171. wvsprintfA(&ach[cch], pszMsg, vArgs);
  172. va_end(vArgs);
  173. OutputDebugStringA(ach);
  174. OutputDebugStringA(c_szNewline);
  175. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  176. ASSERT(0);
  177. }
  178. }
  179. void
  180. WINCAPI
  181. _AssertMsgW(
  182. BOOL f,
  183. LPCWSTR pszMsg, ...)
  184. {
  185. WCHAR ach[1024+40];
  186. va_list vArgs;
  187. if (!f)
  188. {
  189. int cch;
  190. lstrcpyW(ach, c_wszAssertMsg);
  191. cch = lstrlenW(ach);
  192. va_start(vArgs, pszMsg);
  193. wvsprintfW(&ach[cch], pszMsg, vArgs);
  194. va_end(vArgs);
  195. OutputDebugStringW(ach);
  196. OutputDebugStringW(c_wszNewline);
  197. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  198. ASSERT(0);
  199. }
  200. }
  201. void
  202. _AssertStrLenW(
  203. LPCWSTR pszStr,
  204. int iLen)
  205. {
  206. if (pszStr && iLen < lstrlenW(pszStr))
  207. {
  208. ASSERT(0);
  209. }
  210. }
  211. void
  212. _AssertStrLenA(
  213. LPCSTR pszStr,
  214. int iLen)
  215. {
  216. if (pszStr && iLen < lstrlenA(pszStr))
  217. {
  218. ASSERT(0);
  219. }
  220. }
  221. void
  222. WINCAPI
  223. _DebugMsgA(
  224. DWORD flag,
  225. LPCSTR pszMsg, ...)
  226. {
  227. CHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
  228. va_list vArgs;
  229. if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  230. {
  231. int cch;
  232. SetPrefixStringA(ach, flag);
  233. cch = lstrlenA(ach);
  234. va_start(vArgs, pszMsg);
  235. try
  236. {
  237. wvsprintfA(&ach[cch], pszMsg, vArgs);
  238. }
  239. except(EXCEPTION_EXECUTE_HANDLER)
  240. {
  241. OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  242. OutputDebugStringA(pszMsg);
  243. }
  244. va_end(vArgs);
  245. OutputDebugStringA(ach);
  246. OutputDebugStringA(c_szNewline);
  247. if (TF_ALWAYS != flag &&
  248. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  249. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  250. {
  251. DEBUG_BREAK;
  252. }
  253. }
  254. }
  255. void
  256. WINCAPI
  257. _DebugMsgW(
  258. DWORD flag,
  259. LPCWSTR pszMsg, ...)
  260. {
  261. WCHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
  262. va_list vArgs;
  263. if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  264. {
  265. int cch;
  266. SetPrefixStringW(ach, flag);
  267. cch = lstrlenW(ach);
  268. va_start(vArgs, pszMsg);
  269. try
  270. {
  271. wvsprintfW(&ach[cch], pszMsg, vArgs);
  272. }
  273. except(EXCEPTION_EXECUTE_HANDLER)
  274. {
  275. OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  276. OutputDebugStringW(pszMsg);
  277. }
  278. va_end(vArgs);
  279. OutputDebugStringW(ach);
  280. OutputDebugStringW(c_wszNewline);
  281. if (TF_ALWAYS != flag &&
  282. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  283. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  284. {
  285. DEBUG_BREAK;
  286. }
  287. }
  288. }
  289. //
  290. // Smart debug functions
  291. //
  292. /*----------------------------------------------------------
  293. Purpose: Displays assertion string.
  294. Returns: TRUE to debugbreak
  295. Cond: --
  296. */
  297. BOOL
  298. CDECL
  299. CcshellAssertFailedA(
  300. LPCSTR pszFile,
  301. int line,
  302. LPCSTR pszEval,
  303. BOOL bBreakInside)
  304. {
  305. BOOL bRet = FALSE;
  306. LPCSTR psz;
  307. CHAR ach[256];
  308. // Strip off path info from filename string, if present.
  309. //
  310. for (psz = pszFile + lstrlenA(pszFile); psz != pszFile; psz=CharPrevA(pszFile, psz))
  311. {
  312. if ((CharPrevA(pszFile, psz)!= (psz-2)) && *(psz - 1) == '\\')
  313. break;
  314. }
  315. wsprintfA(ach, c_szAssertFailed, psz, line, pszEval);
  316. OutputDebugStringA(ach);
  317. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  318. {
  319. if (bBreakInside)
  320. {
  321. // See the hack we have above about redefining ASSERT
  322. ASSERT(0);
  323. }
  324. else
  325. bRet = TRUE;
  326. }
  327. return bRet;
  328. }
  329. /*----------------------------------------------------------
  330. Purpose: Displays assertion string.
  331. Returns: --
  332. Cond: --
  333. */
  334. BOOL
  335. CDECL
  336. CcshellAssertFailedW(
  337. LPCWSTR pszFile,
  338. int line,
  339. LPCWSTR pszEval,
  340. BOOL bBreakInside)
  341. {
  342. BOOL bRet = FALSE;
  343. LPCWSTR psz;
  344. WCHAR ach[256];
  345. // Strip off path info from filename string, if present.
  346. //
  347. for (psz = pszFile + lstrlenW(pszFile); psz && (psz != pszFile); psz=CharPrevW(pszFile, psz))
  348. {
  349. if ((CharPrevW(pszFile, psz)!= (psz-2)) && *(psz - 1) == TEXT('\\'))
  350. break;
  351. }
  352. // If psz == NULL, CharPrevW failed which implies we are running on Win95. We can get this
  353. // if we get an assert in some of the W functions in shlwapi... Call the A version of assert...
  354. if (!psz)
  355. {
  356. char szFile[MAX_PATH];
  357. char szEval[256]; // since the total output is thhis size should be enough...
  358. WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  359. WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL);
  360. return CcshellAssertFailedA(szFile, line, szEval, bBreakInside);
  361. }
  362. wsprintfW(ach, c_wszAssertFailed, psz, line, pszEval);
  363. OutputDebugStringW(ach);
  364. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  365. {
  366. if (bBreakInside)
  367. {
  368. // See the hack we have above about redefining ASSERT
  369. ASSERT(0);
  370. }
  371. else
  372. bRet = TRUE;
  373. }
  374. return bRet;
  375. }
  376. /*----------------------------------------------------------
  377. Purpose: Keep track of the stack depth for function call trace
  378. messages.
  379. Returns: --
  380. Cond: --
  381. */
  382. void
  383. CcshellStackEnter(void)
  384. {
  385. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  386. {
  387. DWORD dwDepth;
  388. dwDepth = (DWORD)((DWORD_PTR)TlsGetValue(g_tlsStackDepth));
  389. TlsSetValue(g_tlsStackDepth, (LPVOID)((DWORD_PTR)dwDepth + 1));
  390. }
  391. else
  392. {
  393. g_dwHackStackDepth++;
  394. }
  395. }
  396. /*----------------------------------------------------------
  397. Purpose: Keep track of the stack depth for functionc all trace
  398. messages.
  399. Returns: --
  400. Cond: --
  401. */
  402. void
  403. CcshellStackLeave(void)
  404. {
  405. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  406. {
  407. DWORD dwDepth;
  408. dwDepth = (DWORD)((DWORD_PTR)TlsGetValue(g_tlsStackDepth));
  409. if (EVAL(0 < dwDepth))
  410. {
  411. EVAL(TlsSetValue(g_tlsStackDepth, (LPVOID)((DWORD_PTR)dwDepth - 1)));
  412. }
  413. }
  414. else
  415. {
  416. if (EVAL(0 < g_dwHackStackDepth))
  417. {
  418. g_dwHackStackDepth--;
  419. }
  420. }
  421. }
  422. /*----------------------------------------------------------
  423. Purpose: Return the stack depth.
  424. Returns: see above
  425. Cond: --
  426. */
  427. static
  428. DWORD
  429. CcshellGetStackDepth(void)
  430. {
  431. DWORD dwDepth;
  432. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  433. {
  434. dwDepth = (DWORD)((DWORD_PTR)TlsGetValue(g_tlsStackDepth));
  435. }
  436. else
  437. {
  438. dwDepth = g_dwHackStackDepth;
  439. }
  440. return dwDepth;
  441. }
  442. /*----------------------------------------------------------
  443. Purpose: This function converts a multi-byte string to a
  444. wide-char string.
  445. If pszBuf is non-NULL and the converted string can fit in
  446. pszBuf, then *ppszWide will point to the given buffer.
  447. Otherwise, this function will allocate a buffer that can
  448. hold the converted string.
  449. If pszAnsi is NULL, then *ppszWide will be freed. Note
  450. that pszBuf must be the same pointer between the call
  451. that converted the string and the call that frees the
  452. string.
  453. Returns: TRUE
  454. FALSE (if out of memory)
  455. Cond: --
  456. */
  457. BOOL
  458. UnicodeFromAnsi(
  459. LPWSTR * ppwszWide,
  460. LPCSTR pszAnsi, // NULL to clean up
  461. LPWSTR pwszBuf,
  462. int cchBuf)
  463. {
  464. BOOL bRet;
  465. // Convert the string?
  466. if (pszAnsi)
  467. {
  468. // Yes; determine the converted string length
  469. int cch;
  470. LPWSTR pwsz;
  471. int cchAnsi = lstrlenA(pszAnsi)+1;
  472. cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, NULL, 0);
  473. // String too big, or is there no buffer?
  474. if (cch > cchBuf || NULL == pwszBuf)
  475. {
  476. // Yes; allocate space
  477. cchBuf = cch + 1;
  478. pwsz = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cchBuf));
  479. }
  480. else
  481. {
  482. // No; use the provided buffer
  483. pwsz = pwszBuf;
  484. }
  485. if (pwsz)
  486. {
  487. // Convert the string
  488. cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, pwsz, cchBuf);
  489. bRet = (0 < cch);
  490. }
  491. else
  492. {
  493. bRet = FALSE;
  494. }
  495. *ppwszWide = pwsz;
  496. }
  497. else
  498. {
  499. // No; was this buffer allocated?
  500. if (*ppwszWide && pwszBuf != *ppwszWide)
  501. {
  502. // Yes; clean up
  503. LocalFree((HLOCAL)*ppwszWide);
  504. *ppwszWide = NULL;
  505. }
  506. bRet = TRUE;
  507. }
  508. return bRet;
  509. }
  510. /*----------------------------------------------------------
  511. Purpose: Wide-char version of CcshellAssertMsgA
  512. Returns: --
  513. Cond: --
  514. */
  515. void
  516. CDECL
  517. CcshellAssertMsgW(
  518. BOOL f,
  519. LPCWSTR pszMsg, ...)
  520. {
  521. WCHAR ach[1024+40]; // Largest path plus extra
  522. va_list vArgs;
  523. if (!f)
  524. {
  525. int cch;
  526. #if 0
  527. WCHAR wszBuf[1024];
  528. LPWSTR pwsz;
  529. #endif
  530. lstrcpyW(ach, c_wszAssertMsg);
  531. cch = lstrlenW(ach);
  532. va_start(vArgs, pszMsg);
  533. // (We convert the string, rather than simply input an
  534. // LPCWSTR parameter, so the caller doesn't have to wrap
  535. // all the string constants with the TEXT() macro.)
  536. #if 0
  537. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  538. {
  539. wvsprintfW(&ach[cch], pwsz, vArgs);
  540. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  541. }
  542. #endif
  543. // This is a W version of CcshellDebugMsg.
  544. // Don't need to call UnicodeFromAnsi
  545. wvsprintfW(&ach[cch], pszMsg, vArgs);
  546. va_end(vArgs);
  547. OutputDebugStringW(ach);
  548. OutputDebugStringW(c_wszNewline);
  549. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  550. ASSERT(0);
  551. }
  552. }
  553. /*----------------------------------------------------------
  554. Purpose: Wide-char version of CcshellDebugMsgA. Note this
  555. function deliberately takes an ANSI format string
  556. so our trace messages don't all need to be wrapped
  557. in TEXT().
  558. Returns: --
  559. Cond: --
  560. */
  561. void
  562. CDECL
  563. CcshellDebugMsgW(
  564. DWORD flag,
  565. LPCWSTR pszMsg, ...) // (this is deliberately CHAR)
  566. {
  567. WCHAR ach[1024+40]; // Largest path plus extra
  568. va_list vArgs;
  569. if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  570. {
  571. int cch;
  572. #if 0
  573. WCHAR wszBuf[1024];
  574. LPWSTR pwsz;
  575. #endif
  576. SetPrefixStringW(ach, flag);
  577. cch = lstrlenW(ach);
  578. va_start(vArgs, pszMsg);
  579. // (We convert the string, rather than simply input an
  580. // LPCWSTR parameter, so the caller doesn't have to wrap
  581. // all the string constants with the TEXT() macro.)
  582. #if 0
  583. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  584. {
  585. wvsprintfW(&ach[cch], pwsz, vArgs);
  586. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  587. }
  588. #endif
  589. // This is a W version of CcshellDebugMsg.
  590. // Don't need to call UnicodeFromAnsi
  591. wvsprintfW(&ach[cch], pszMsg, vArgs);
  592. va_end(vArgs);
  593. OutputDebugStringW(ach);
  594. OutputDebugStringW(c_wszNewline);
  595. if (TF_ALWAYS != flag &&
  596. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  597. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  598. {
  599. DEBUG_BREAK;
  600. }
  601. }
  602. }
  603. /*----------------------------------------------------------
  604. Purpose: Wide-char version of CcshellFuncMsgA. Note this
  605. function deliberately takes an ANSI format string
  606. so our trace messages don't all need to be wrapped
  607. in TEXT().
  608. Returns: --
  609. Cond: --
  610. */
  611. void
  612. CDECL
  613. CcshellFuncMsgW(
  614. DWORD flag,
  615. LPCWSTR pszMsg, ...) // (this is deliberately CHAR)
  616. {
  617. WCHAR ach[1024+40]; // Largest path plus extra
  618. va_list vArgs;
  619. if (IsFlagSet(g_dwTraceFlags, TF_FUNC) &&
  620. IsFlagSet(g_dwFuncTraceFlags, flag))
  621. {
  622. int cch;
  623. #if 0
  624. WCHAR wszBuf[1024];
  625. LPWSTR pwsz;
  626. #endif
  627. DWORD dwStackDepth;
  628. LPWSTR pszLeaderEnd;
  629. WCHAR chSave;
  630. // Determine the indentation for trace message based on
  631. // stack depth.
  632. dwStackDepth = CcshellGetStackDepth();
  633. if (dwStackDepth < SIZECHARS(g_szIndentLeader))
  634. {
  635. pszLeaderEnd = &g_wszIndentLeader[dwStackDepth];
  636. }
  637. else
  638. {
  639. pszLeaderEnd = &g_wszIndentLeader[SIZECHARS(g_wszIndentLeader)-1];
  640. }
  641. chSave = *pszLeaderEnd;
  642. *pszLeaderEnd = '\0';
  643. wsprintfW(ach, L"%s %s", c_wszTrace, g_wszIndentLeader);
  644. *pszLeaderEnd = chSave;
  645. // Compose remaining string
  646. cch = lstrlenW(ach);
  647. va_start(vArgs, pszMsg);
  648. // (We convert the string, rather than simply input an
  649. // LPCWSTR parameter, so the caller doesn't have to wrap
  650. // all the string constants with the TEXT() macro.)
  651. #if 0
  652. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  653. {
  654. wvsprintfW(&ach[cch], pwsz, vArgs);
  655. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  656. }
  657. #endif
  658. // This is a W version of CcshellDebugMsg.
  659. // Don't need to call UnicodeFromAnsi
  660. wvsprintfW(&ach[cch], pszMsg, vArgs);
  661. va_end(vArgs);
  662. OutputDebugStringW(ach);
  663. OutputDebugStringW(c_wszNewline);
  664. }
  665. }
  666. /*----------------------------------------------------------
  667. Purpose: Assert failed message only
  668. Returns: --
  669. Cond: --
  670. */
  671. void
  672. CDECL
  673. CcshellAssertMsgA(
  674. BOOL f,
  675. LPCSTR pszMsg, ...)
  676. {
  677. CHAR ach[1024+40]; // Largest path plus extra
  678. va_list vArgs;
  679. if (!f)
  680. {
  681. int cch;
  682. lstrcpyA(ach, c_szAssertMsg);
  683. cch = lstrlenA(ach);
  684. va_start(vArgs, pszMsg);
  685. wvsprintfA(&ach[cch], pszMsg, vArgs);
  686. va_end(vArgs);
  687. OutputDebugStringA(ach);
  688. OutputDebugStringA(c_szNewline);
  689. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  690. ASSERT(0);
  691. }
  692. }
  693. /*----------------------------------------------------------
  694. Purpose: Debug spew
  695. Returns: --
  696. Cond: --
  697. */
  698. void
  699. CDECL
  700. CcshellDebugMsgA(
  701. DWORD flag,
  702. LPCSTR pszMsg, ...)
  703. {
  704. CHAR ach[1024+40]; // Largest path plus extra
  705. va_list vArgs;
  706. if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  707. {
  708. int cch;
  709. SetPrefixStringA(ach, flag);
  710. cch = lstrlenA(ach);
  711. va_start(vArgs, pszMsg);
  712. wvsprintfA(&ach[cch], pszMsg, vArgs);
  713. va_end(vArgs);
  714. OutputDebugStringA(ach);
  715. OutputDebugStringA(c_szNewline);
  716. if (TF_ALWAYS != flag &&
  717. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  718. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  719. {
  720. DEBUG_BREAK;
  721. }
  722. }
  723. }
  724. /*----------------------------------------------------------
  725. Purpose: Debug spew for function trace calls
  726. Returns: --
  727. Cond: --
  728. */
  729. void
  730. CDECL
  731. CcshellFuncMsgA(
  732. DWORD flag,
  733. LPCSTR pszMsg, ...)
  734. {
  735. CHAR ach[1024+40]; // Largest path plus extra
  736. va_list vArgs;
  737. if (IsFlagSet(g_dwTraceFlags, TF_FUNC) &&
  738. IsFlagSet(g_dwFuncTraceFlags, flag))
  739. {
  740. int cch;
  741. DWORD dwStackDepth;
  742. LPSTR pszLeaderEnd;
  743. CHAR chSave;
  744. // Determine the indentation for trace message based on
  745. // stack depth.
  746. dwStackDepth = CcshellGetStackDepth();
  747. if (dwStackDepth < sizeof(g_szIndentLeader))
  748. {
  749. pszLeaderEnd = &g_szIndentLeader[dwStackDepth];
  750. }
  751. else
  752. {
  753. pszLeaderEnd = &g_szIndentLeader[sizeof(g_szIndentLeader)-1];
  754. }
  755. chSave = *pszLeaderEnd;
  756. *pszLeaderEnd = '\0';
  757. wsprintfA(ach, "%s %s", c_szTrace, g_szIndentLeader);
  758. *pszLeaderEnd = chSave;
  759. // Compose remaining string
  760. cch = lstrlenA(ach);
  761. va_start(vArgs, pszMsg);
  762. wvsprintfA(&ach[cch], pszMsg, vArgs);
  763. va_end(vArgs);
  764. OutputDebugStringA(ach);
  765. OutputDebugStringA(c_szNewline);
  766. }
  767. }
  768. //
  769. // Debug .ini functions
  770. //
  771. #pragma data_seg(DATASEG_READONLY)
  772. // (These are deliberately CHAR)
  773. CHAR const FAR c_szNull[] = "";
  774. CHAR const FAR c_szZero[] = "0";
  775. CHAR const FAR c_szIniKeyBreakFlags[] = "BreakFlags";
  776. CHAR const FAR c_szIniKeyTraceFlags[] = "TraceFlags";
  777. CHAR const FAR c_szIniKeyFuncTraceFlags[] = "FuncTraceFlags";
  778. CHAR const FAR c_szIniKeyDumpFlags[] = "DumpFlags";
  779. CHAR const FAR c_szIniKeyProtoFlags[] = "Prototype";
  780. #pragma data_seg()
  781. // Some of the .ini processing code was pimped from the sync engine.
  782. //
  783. typedef struct _INIKEYHEADER
  784. {
  785. LPCTSTR pszSectionName;
  786. LPCTSTR pszKeyName;
  787. LPCTSTR pszDefaultRHS;
  788. } INIKEYHEADER;
  789. typedef struct _BOOLINIKEY
  790. {
  791. INIKEYHEADER ikh;
  792. LPDWORD puStorage;
  793. DWORD dwFlag;
  794. } BOOLINIKEY;
  795. typedef struct _INTINIKEY
  796. {
  797. INIKEYHEADER ikh;
  798. LPDWORD puStorage;
  799. } INTINIKEY;
  800. #define PutIniIntCmp(idsSection, idsKey, nNewValue, nSave) \
  801. if ((nNewValue) != (nSave)) PutIniInt(idsSection, idsKey, nNewValue)
  802. #define WritePrivateProfileInt(szApp, szKey, i, lpFileName) \
  803. {CHAR sz[7]; \
  804. WritePrivateProfileString(szApp, szKey, SzFromInt(sz, i), lpFileName);}
  805. #ifdef BOOL_INI_VALUES
  806. /* Boolean TRUE strings used by IsIniYes() (comparison is case-insensitive) */
  807. static LPCTSTR s_rgpszTrue[] =
  808. {
  809. TEXT("1"),
  810. TEXT("On"),
  811. TEXT("True"),
  812. TEXT("Y"),
  813. TEXT("Yes")
  814. };
  815. /* Boolean FALSE strings used by IsIniYes() (comparison is case-insensitive) */
  816. static LPCTSTR s_rgpszFalse[] =
  817. {
  818. TEXT("0"),
  819. TEXT("Off"),
  820. TEXT("False"),
  821. TEXT("N"),
  822. TEXT("No")
  823. };
  824. #endif
  825. #ifdef BOOL_INI_VALUES
  826. /*----------------------------------------------------------
  827. Purpose: Determines whether a string corresponds to a boolean
  828. TRUE value.
  829. Returns: The boolean value (TRUE or FALSE)
  830. Cond: --
  831. */
  832. BOOL
  833. PRIVATE
  834. IsIniYes(
  835. LPCTSTR psz)
  836. {
  837. int i;
  838. BOOL bNotFound = TRUE;
  839. BOOL bResult;
  840. Assert(psz);
  841. /* Is the value TRUE? */
  842. for (i = 0; i < ARRAYSIZE(s_rgpszTrue); i++)
  843. {
  844. if (IsSzEqual(psz, s_rgpszTrue[i]))
  845. {
  846. bResult = TRUE;
  847. bNotFound = FALSE;
  848. break;
  849. }
  850. }
  851. /* Is the value FALSE? */
  852. if (bNotFound)
  853. {
  854. for (i = 0; i < ARRAYSIZE(s_rgpszFalse); i++)
  855. {
  856. if (IsSzEqual(psz, s_rgpszFalse[i]))
  857. {
  858. bResult = FALSE;
  859. bNotFound = FALSE;
  860. break;
  861. }
  862. }
  863. /* Is the value a known string? */
  864. if (bNotFound)
  865. {
  866. /* No. Whine about it. */
  867. TraceMsg(TF_WARNING, "IsIniYes() called on unknown Boolean RHS '%s'.", psz);
  868. bResult = FALSE;
  869. }
  870. }
  871. return bResult;
  872. }
  873. /*----------------------------------------------------------
  874. Purpose: Process keys with boolean RHSs.
  875. Returns: --
  876. Cond: --
  877. */
  878. void
  879. PRIVATE
  880. ProcessBooleans(void)
  881. {
  882. int i;
  883. for (i = 0; i < ARRAYSIZE(s_rgbik); i++)
  884. {
  885. DWORD dwcbKeyLen;
  886. TCHAR szRHS[MAX_BUF];
  887. BOOLINIKEY * pbik = &(s_rgbik[i]);
  888. LPCTSTR lpcszRHS;
  889. /* Look for key. */
  890. dwcbKeyLen = GetPrivateProfileString(pbik->ikh.pszSectionName,
  891. pbik->ikh.pszKeyName, TEXT(""), szRHS,
  892. SIZECHARS(szRHS), c_szCcshellIniFile);
  893. if (dwcbKeyLen)
  894. lpcszRHS = szRHS;
  895. else
  896. lpcszRHS = pbik->ikh.pszDefaultRHS;
  897. if (IsIniYes(lpcszRHS))
  898. {
  899. if (IsFlagClear(*(pbik->puStorage), pbik->dwFlag))
  900. TraceMsg(TF_GENERAL, "ProcessIniFile(): %s set in %s![%s].",
  901. pbik->ikh.pszKeyName,
  902. c_szCcshellIniFile,
  903. pbik->ikh.pszSectionName);
  904. SetFlag(*(pbik->puStorage), pbik->dwFlag);
  905. }
  906. else
  907. {
  908. if (IsFlagSet(*(pbik->puStorage), pbik->dwFlag))
  909. TraceMsg(TF_GENERAL, "ProcessIniFile(): %s cleared in %s![%s].",
  910. pbik->ikh.pszKeyName,
  911. c_szCcshellIniFile,
  912. pbik->ikh.pszSectionName);
  913. ClearFlag(*(pbik->puStorage), pbik->dwFlag);
  914. }
  915. }
  916. }
  917. #endif
  918. #ifdef UNICODE
  919. /*----------------------------------------------------------
  920. Purpose: This function converts a wide-char string to a multi-byte
  921. string.
  922. If pszBuf is non-NULL and the converted string can fit in
  923. pszBuf, then *ppszAnsi will point to the given buffer.
  924. Otherwise, this function will allocate a buffer that can
  925. hold the converted string.
  926. If pszWide is NULL, then *ppszAnsi will be freed. Note
  927. that pszBuf must be the same pointer between the call
  928. that converted the string and the call that frees the
  929. string.
  930. Returns: TRUE
  931. FALSE (if out of memory)
  932. Cond: --
  933. */
  934. static
  935. BOOL
  936. MyAnsiFromUnicode(
  937. LPSTR * ppszAnsi,
  938. LPCWSTR pwszWide, // NULL to clean up
  939. LPSTR pszBuf,
  940. int cchBuf)
  941. {
  942. BOOL bRet;
  943. // Convert the string?
  944. if (pwszWide)
  945. {
  946. // Yes; determine the converted string length
  947. int cch;
  948. LPSTR psz;
  949. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
  950. // String too big, or is there no buffer?
  951. if (cch > cchBuf || NULL == pszBuf)
  952. {
  953. // Yes; allocate space
  954. cchBuf = cch + 1;
  955. psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf));
  956. }
  957. else
  958. {
  959. // No; use the provided buffer
  960. Assert(pszBuf);
  961. psz = pszBuf;
  962. }
  963. if (psz)
  964. {
  965. // Convert the string
  966. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
  967. bRet = (0 < cch);
  968. }
  969. else
  970. {
  971. bRet = FALSE;
  972. }
  973. *ppszAnsi = psz;
  974. }
  975. else
  976. {
  977. // No; was this buffer allocated?
  978. if (*ppszAnsi && pszBuf != *ppszAnsi)
  979. {
  980. // Yes; clean up
  981. LocalFree((HLOCAL)*ppszAnsi);
  982. *ppszAnsi = NULL;
  983. }
  984. bRet = TRUE;
  985. }
  986. return bRet;
  987. }
  988. /*----------------------------------------------------------
  989. Purpose: Wide-char wrapper for StrToIntExA.
  990. Returns: see StrToIntExA
  991. Cond: --
  992. */
  993. static
  994. BOOL
  995. MyStrToIntExW(
  996. LPCWSTR pwszString,
  997. DWORD dwFlags, // STIF_ bitfield
  998. int FAR * piRet)
  999. {
  1000. // Most strings will simply use this temporary buffer, but AnsiFromUnicode
  1001. // will allocate a buffer if the supplied string is bigger.
  1002. CHAR szBuf[MAX_PATH];
  1003. LPSTR pszString;
  1004. BOOL bRet = MyAnsiFromUnicode(&pszString, pwszString, szBuf, SIZECHARS(szBuf));
  1005. if (bRet)
  1006. {
  1007. bRet = MyStrToIntExA(pszString, dwFlags, piRet);
  1008. MyAnsiFromUnicode(&pszString, NULL, szBuf, 0);
  1009. }
  1010. return bRet;
  1011. }
  1012. #endif // UNICODE
  1013. #ifdef UNICODE
  1014. #define MyStrToIntEx MyStrToIntExW
  1015. #else
  1016. #define MyStrToIntEx MyStrToIntExA
  1017. #endif
  1018. /*----------------------------------------------------------
  1019. Purpose: This function reads a .ini file to determine the debug
  1020. flags to set. The .ini file and section are specified
  1021. by the following manifest constants:
  1022. SZ_DEBUGINI
  1023. SZ_DEBUGSECTION
  1024. The debug variables that are set by this function are
  1025. g_dwDumpFlags, g_dwTraceFlags, g_dwBreakFlags, and
  1026. g_dwFuncTraceFlags, g_dwPrototype.
  1027. Returns: TRUE if initialization is successful
  1028. Cond: --
  1029. */
  1030. BOOL
  1031. PUBLIC
  1032. CcshellGetDebugFlags(void)
  1033. {
  1034. CHAR szRHS[MAX_PATH];
  1035. int val;
  1036. // BUGBUG (scotth): Yes, COMCTL32 exports StrToIntEx, but I
  1037. // don't want to cause a dependency delta and force everyone
  1038. // to get a new comctl32 just because they built debug.
  1039. // So use a local version of StrToIntEx.
  1040. // Trace Flags
  1041. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1042. c_szIniKeyTraceFlags,
  1043. c_szNull,
  1044. szRHS,
  1045. SIZECHARS(szRHS),
  1046. c_szCcshellIniFile);
  1047. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1048. g_dwTraceFlags = (DWORD)val;
  1049. TraceMsgA(TF_GENERAL, "CcshellGetDebugFlags(): %s set to %#08x.",
  1050. c_szIniKeyTraceFlags, g_dwTraceFlags);
  1051. // Function trace Flags
  1052. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1053. c_szIniKeyFuncTraceFlags,
  1054. c_szNull,
  1055. szRHS,
  1056. SIZECHARS(szRHS),
  1057. c_szCcshellIniFile);
  1058. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1059. g_dwFuncTraceFlags = (DWORD)val;
  1060. TraceMsgA(TF_GENERAL, "CcshellGetDebugFlags(): %s set to %#08x.",
  1061. c_szIniKeyFuncTraceFlags, g_dwFuncTraceFlags);
  1062. // Dump Flags
  1063. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1064. c_szIniKeyDumpFlags,
  1065. c_szNull,
  1066. szRHS,
  1067. SIZECHARS(szRHS),
  1068. c_szCcshellIniFile);
  1069. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1070. g_dwDumpFlags = (DWORD)val;
  1071. TraceMsgA(TF_GENERAL, "CcshellGetDebugFlags(): %s set to %#08x.",
  1072. c_szIniKeyDumpFlags, g_dwDumpFlags);
  1073. // Break Flags
  1074. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1075. c_szIniKeyBreakFlags,
  1076. c_szNull,
  1077. szRHS,
  1078. SIZECHARS(szRHS),
  1079. c_szCcshellIniFile);
  1080. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1081. g_dwBreakFlags = (DWORD)val;
  1082. TraceMsgA(TF_GENERAL, "CcshellGetDebugFlags(): %s set to %#08x.",
  1083. c_szIniKeyBreakFlags, g_dwBreakFlags);
  1084. // Prototype Flags
  1085. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1086. c_szIniKeyProtoFlags,
  1087. c_szNull,
  1088. szRHS,
  1089. SIZECHARS(szRHS),
  1090. c_szCcshellIniFile);
  1091. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1092. g_dwPrototype = (DWORD)val;
  1093. TraceMsgA(TF_GENERAL, "CcshellGetDebugFlags(): %s set to %#08x.",
  1094. c_szIniKeyProtoFlags, g_dwPrototype);
  1095. return TRUE;
  1096. }
  1097. #endif // DEBUG
  1098. #ifdef PRODUCT_PROF
  1099. DWORD g_dwProfileCAP = 0;
  1100. BOOL PUBLIC CcshellGetDebugFlags(void)
  1101. {
  1102. CHAR szRHS[MAX_PATH];
  1103. int val;
  1104. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1105. "Profile",
  1106. "",
  1107. szRHS,
  1108. SIZECHARS(szRHS),
  1109. c_szCcshellIniFile);
  1110. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1111. g_dwProfileCAP = (DWORD)val;
  1112. return TRUE;
  1113. }
  1114. #endif // PRODUCT_PROF