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.

307 lines
9.5 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. find.c
  5. Abstract:
  6. This file implements the search functionality.
  7. Author:
  8. Jerry Shea (jerrysh) 1-May-1997
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. USHORT
  14. SearchForString(
  15. IN PSCREEN_INFORMATION ScreenInfo,
  16. IN PWSTR SearchString,
  17. IN USHORT StringLength,
  18. IN BOOLEAN IgnoreCase,
  19. IN BOOLEAN Reverse,
  20. IN BOOLEAN SearchAndSetAttr,
  21. IN ULONG Attr,
  22. OUT PCOORD StringPosition // not touched for SearchAndSetAttr case.
  23. )
  24. {
  25. PCONSOLE_INFORMATION Console;
  26. SMALL_RECT Rect;
  27. COORD MaxPosition;
  28. COORD EndPosition;
  29. COORD Position;
  30. BOOL RecomputeRow;
  31. SHORT RowIndex;
  32. PROW Row;
  33. USHORT ColumnWidth;
  34. WCHAR SearchString2[SEARCH_STRING_LENGTH * 2 + 1]; // search string buffer
  35. PWSTR pStr;
  36. Console = ScreenInfo->Console;
  37. MaxPosition.X = ScreenInfo->ScreenBufferSize.X - StringLength;
  38. MaxPosition.Y = ScreenInfo->ScreenBufferSize.Y - 1;
  39. //
  40. // calculate starting position
  41. //
  42. if (Console->Flags & CONSOLE_SELECTING) {
  43. Position.X = min(Console->SelectionAnchor.X, MaxPosition.X);
  44. Position.Y = Console->SelectionAnchor.Y;
  45. } else if (Reverse) {
  46. Position.X = 0;
  47. Position.Y = 0;
  48. } else {
  49. Position.X = MaxPosition.X;
  50. Position.Y = MaxPosition.Y;
  51. }
  52. //
  53. // prepare search string
  54. //
  55. // Raid #113599 CMD:Find(Japanese strings) does not work correctly
  56. //
  57. ASSERT(StringLength == wcslen(SearchString) && StringLength < ARRAY_SIZE(SearchString2));
  58. pStr = SearchString2;
  59. while (*SearchString) {
  60. *pStr++ = *SearchString;
  61. #if defined(CON_TB_MARK)
  62. //
  63. // On the screen, one FarEast "FullWidth" character occupies two columns (double width),
  64. // so we have to share two screen buffer elements for one DBCS character.
  65. // For example, if the screen shows "AB[DBC]CD", the screen buffer will be,
  66. // [L'A'] [L'B'] [DBC(Unicode)] [CON_TB_MARK] [L'C'] [L'D']
  67. // (DBC:: Double Byte Character)
  68. // CON_TB_MARK is used to indicate that the column is the trainling byte.
  69. //
  70. // Before comparing the string with the screen buffer, we need to modify the search
  71. // string to match the format of the screen buffer.
  72. // If we find a FullWidth character in the search string, put CON_TB_MARK
  73. // right after it so that we're able to use NLS functions.
  74. //
  75. #else
  76. //
  77. // If KAttribute is used, the above example will look like:
  78. // CharRow.Chars: [L'A'] [L'B'] [DBC(Unicode)] [DBC(Unicode)] [L'C'] [L'D']
  79. // CharRow.KAttrs: 0 0 LEADING_BYTE TRAILING_BYTE 0 0
  80. //
  81. // We do no fixup if SearchAndSetAttr was specified. In this case the search buffer has
  82. // come straight out of the console buffer, so is already in the required format.
  83. //
  84. #endif
  85. if (!SearchAndSetAttr && IsConsoleFullWidth(Console->hDC, Console->CP, *SearchString)) {
  86. #if defined(CON_TB_MARK)
  87. *pStr++ = CON_TB_MARK;
  88. #else
  89. *pStr++ = *SearchString;
  90. #endif
  91. }
  92. ++SearchString;
  93. }
  94. *pStr = L'\0';
  95. ColumnWidth = (USHORT)(pStr - SearchString2);
  96. SearchString = SearchString2;
  97. //
  98. // set the string length in byte
  99. //
  100. StringLength = ColumnWidth * sizeof(WCHAR);
  101. //
  102. // search for the string
  103. //
  104. RecomputeRow = TRUE;
  105. EndPosition = Position;
  106. do {
  107. #if !defined(CON_TB_MARK)
  108. #if DBG
  109. int nLoop = 0;
  110. #endif
  111. recalc:
  112. #endif
  113. if (Reverse) {
  114. if (--Position.X < 0) {
  115. Position.X = MaxPosition.X;
  116. if (--Position.Y < 0) {
  117. Position.Y = MaxPosition.Y;
  118. }
  119. RecomputeRow = TRUE;
  120. }
  121. } else {
  122. if (++Position.X > MaxPosition.X) {
  123. Position.X = 0;
  124. if (++Position.Y > MaxPosition.Y) {
  125. Position.Y = 0;
  126. }
  127. RecomputeRow = TRUE;
  128. }
  129. }
  130. if (RecomputeRow) {
  131. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow + Position.Y) % ScreenInfo->ScreenBufferSize.Y;
  132. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  133. RecomputeRow = FALSE;
  134. }
  135. #if !defined(CON_TB_MARK)
  136. ASSERT(nLoop++ < 2);
  137. if (Row->CharRow.KAttrs && (Row->CharRow.KAttrs[Position.X] & ATTR_TRAILING_BYTE)) {
  138. goto recalc;
  139. }
  140. #endif
  141. if (!MyStringCompareW(SearchString, &Row->CharRow.Chars[Position.X], StringLength, IgnoreCase)) {
  142. //
  143. // If this operation was a normal user find, then return now. Otherwise set
  144. // the attributes of this match, and continue searching the whole buffer.
  145. //
  146. if (!SearchAndSetAttr) {
  147. *StringPosition = Position;
  148. return ColumnWidth;
  149. }
  150. else {
  151. Rect.Top = Rect.Bottom = Position.Y;
  152. Rect.Left = Position.X;
  153. Rect.Right = Rect.Left + ColumnWidth - 1;
  154. ColorSelection( Console, &Rect, Attr);
  155. }
  156. }
  157. }
  158. while (!((Position.X == EndPosition.X) && (Position.Y == EndPosition.Y)));
  159. return 0; // the string was not found
  160. }
  161. INT_PTR
  162. FindDialogProc(
  163. HWND hWnd,
  164. UINT Message,
  165. WPARAM wParam,
  166. LPARAM lParam
  167. )
  168. {
  169. PCONSOLE_INFORMATION Console;
  170. PSCREEN_INFORMATION ScreenInfo;
  171. USHORT StringLength;
  172. USHORT ColumnWidth;
  173. WCHAR szBuf[SEARCH_STRING_LENGTH + 1];
  174. COORD Position;
  175. BOOLEAN IgnoreCase;
  176. BOOLEAN Reverse;
  177. switch (Message) {
  178. case WM_INITDIALOG:
  179. SetWindowLongPtr(hWnd, DWLP_USER, lParam);
  180. SendDlgItemMessage(hWnd, ID_FINDSTR, EM_LIMITTEXT, ARRAY_SIZE(szBuf)-1, 0);
  181. CheckRadioButton(hWnd, ID_FINDUP, ID_FINDDOWN, ID_FINDDOWN);
  182. return TRUE;
  183. case WM_COMMAND:
  184. switch (LOWORD(wParam)) {
  185. case IDOK:
  186. StringLength = (USHORT)GetDlgItemText(hWnd, ID_FINDSTR, szBuf, ARRAY_SIZE(szBuf));
  187. if (StringLength == 0) {
  188. break;
  189. }
  190. IgnoreCase = IsDlgButtonChecked(hWnd, ID_FINDCASE) == 0;
  191. Reverse = IsDlgButtonChecked(hWnd, ID_FINDDOWN) == 0;
  192. Console = (PCONSOLE_INFORMATION)GetWindowLongPtr(hWnd, DWLP_USER);
  193. ScreenInfo = Console->CurrentScreenBuffer;
  194. ColumnWidth = SearchForString( ScreenInfo,
  195. szBuf,
  196. StringLength,
  197. IgnoreCase,
  198. Reverse,
  199. FALSE,
  200. 0,
  201. &Position);
  202. if (ColumnWidth != 0) {
  203. //
  204. // Clear any old selections
  205. //
  206. if (Console->Flags & CONSOLE_SELECTING) {
  207. ClearSelection(Console);
  208. }
  209. //
  210. // Make the new selection
  211. //
  212. Console->Flags |= CONSOLE_SELECTING;
  213. Console->SelectionFlags = CONSOLE_MOUSE_SELECTION | CONSOLE_SELECTION_NOT_EMPTY;
  214. InitializeMouseSelection(Console, Position);
  215. Console->SelectionRect.Right = Console->SelectionRect.Left + ColumnWidth - 1;
  216. MyInvert(Console,&Console->SelectionRect);
  217. SetWinText(Console,msgSelectMode,TRUE);
  218. //
  219. // Make sure the hilited text will be visible
  220. //
  221. if (Console->SelectionRect.Left < ScreenInfo->Window.Left) {
  222. Position.X = Console->SelectionRect.Left;
  223. } else if (Console->SelectionRect.Right > ScreenInfo->Window.Right) {
  224. Position.X = Console->SelectionRect.Right - CONSOLE_WINDOW_SIZE_X(ScreenInfo) + 1;
  225. } else {
  226. Position.X = ScreenInfo->Window.Left;
  227. }
  228. if (Console->SelectionRect.Top < ScreenInfo->Window.Top) {
  229. Position.Y = Console->SelectionRect.Top;
  230. } else if (Console->SelectionRect.Bottom > ScreenInfo->Window.Bottom) {
  231. Position.Y = Console->SelectionRect.Bottom - CONSOLE_WINDOW_SIZE_Y(ScreenInfo) + 1;
  232. } else {
  233. Position.Y = ScreenInfo->Window.Top;
  234. }
  235. SetWindowOrigin(ScreenInfo, TRUE, Position);
  236. return TRUE;
  237. } else {
  238. //
  239. // The string wasn't found
  240. //
  241. Beep(800, 200);
  242. }
  243. break;
  244. case IDCANCEL:
  245. EndDialog(hWnd, 0);
  246. return TRUE;
  247. }
  248. break;
  249. default:
  250. break;
  251. }
  252. return FALSE;
  253. }
  254. VOID
  255. DoFind(
  256. IN PCONSOLE_INFORMATION Console)
  257. {
  258. ++DialogBoxCount;
  259. DialogBoxParam(ghInstance,
  260. MAKEINTRESOURCE(ID_FINDDLG),
  261. Console->hWnd,
  262. FindDialogProc,
  263. (LPARAM)Console);
  264. --DialogBoxCount;
  265. }