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
307 lines
9.5 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
find.c
|
|
|
|
Abstract:
|
|
|
|
This file implements the search functionality.
|
|
|
|
Author:
|
|
|
|
Jerry Shea (jerrysh) 1-May-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
USHORT
|
|
SearchForString(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PWSTR SearchString,
|
|
IN USHORT StringLength,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN BOOLEAN Reverse,
|
|
IN BOOLEAN SearchAndSetAttr,
|
|
IN ULONG Attr,
|
|
OUT PCOORD StringPosition // not touched for SearchAndSetAttr case.
|
|
)
|
|
{
|
|
PCONSOLE_INFORMATION Console;
|
|
SMALL_RECT Rect;
|
|
COORD MaxPosition;
|
|
COORD EndPosition;
|
|
COORD Position;
|
|
BOOL RecomputeRow;
|
|
SHORT RowIndex;
|
|
PROW Row;
|
|
USHORT ColumnWidth;
|
|
WCHAR SearchString2[SEARCH_STRING_LENGTH * 2 + 1]; // search string buffer
|
|
PWSTR pStr;
|
|
|
|
Console = ScreenInfo->Console;
|
|
|
|
MaxPosition.X = ScreenInfo->ScreenBufferSize.X - StringLength;
|
|
MaxPosition.Y = ScreenInfo->ScreenBufferSize.Y - 1;
|
|
|
|
//
|
|
// calculate starting position
|
|
//
|
|
|
|
if (Console->Flags & CONSOLE_SELECTING) {
|
|
Position.X = min(Console->SelectionAnchor.X, MaxPosition.X);
|
|
Position.Y = Console->SelectionAnchor.Y;
|
|
} else if (Reverse) {
|
|
Position.X = 0;
|
|
Position.Y = 0;
|
|
} else {
|
|
Position.X = MaxPosition.X;
|
|
Position.Y = MaxPosition.Y;
|
|
}
|
|
|
|
//
|
|
// prepare search string
|
|
//
|
|
// Raid #113599 CMD:Find(Japanese strings) does not work correctly
|
|
//
|
|
|
|
ASSERT(StringLength == wcslen(SearchString) && StringLength < ARRAY_SIZE(SearchString2));
|
|
|
|
pStr = SearchString2;
|
|
while (*SearchString) {
|
|
*pStr++ = *SearchString;
|
|
#if defined(CON_TB_MARK)
|
|
//
|
|
// On the screen, one FarEast "FullWidth" character occupies two columns (double width),
|
|
// so we have to share two screen buffer elements for one DBCS character.
|
|
// For example, if the screen shows "AB[DBC]CD", the screen buffer will be,
|
|
// [L'A'] [L'B'] [DBC(Unicode)] [CON_TB_MARK] [L'C'] [L'D']
|
|
// (DBC:: Double Byte Character)
|
|
// CON_TB_MARK is used to indicate that the column is the trainling byte.
|
|
//
|
|
// Before comparing the string with the screen buffer, we need to modify the search
|
|
// string to match the format of the screen buffer.
|
|
// If we find a FullWidth character in the search string, put CON_TB_MARK
|
|
// right after it so that we're able to use NLS functions.
|
|
//
|
|
#else
|
|
//
|
|
// If KAttribute is used, the above example will look like:
|
|
// CharRow.Chars: [L'A'] [L'B'] [DBC(Unicode)] [DBC(Unicode)] [L'C'] [L'D']
|
|
// CharRow.KAttrs: 0 0 LEADING_BYTE TRAILING_BYTE 0 0
|
|
//
|
|
// We do no fixup if SearchAndSetAttr was specified. In this case the search buffer has
|
|
// come straight out of the console buffer, so is already in the required format.
|
|
//
|
|
#endif
|
|
if (!SearchAndSetAttr && IsConsoleFullWidth(Console->hDC, Console->CP, *SearchString)) {
|
|
#if defined(CON_TB_MARK)
|
|
*pStr++ = CON_TB_MARK;
|
|
#else
|
|
*pStr++ = *SearchString;
|
|
#endif
|
|
}
|
|
++SearchString;
|
|
}
|
|
|
|
*pStr = L'\0';
|
|
ColumnWidth = (USHORT)(pStr - SearchString2);
|
|
SearchString = SearchString2;
|
|
|
|
//
|
|
// set the string length in byte
|
|
//
|
|
|
|
StringLength = ColumnWidth * sizeof(WCHAR);
|
|
|
|
//
|
|
// search for the string
|
|
//
|
|
|
|
RecomputeRow = TRUE;
|
|
EndPosition = Position;
|
|
do {
|
|
#if !defined(CON_TB_MARK)
|
|
#if DBG
|
|
int nLoop = 0;
|
|
#endif
|
|
recalc:
|
|
#endif
|
|
if (Reverse) {
|
|
if (--Position.X < 0) {
|
|
Position.X = MaxPosition.X;
|
|
if (--Position.Y < 0) {
|
|
Position.Y = MaxPosition.Y;
|
|
}
|
|
RecomputeRow = TRUE;
|
|
}
|
|
} else {
|
|
if (++Position.X > MaxPosition.X) {
|
|
Position.X = 0;
|
|
if (++Position.Y > MaxPosition.Y) {
|
|
Position.Y = 0;
|
|
}
|
|
RecomputeRow = TRUE;
|
|
}
|
|
}
|
|
if (RecomputeRow) {
|
|
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow + Position.Y) % ScreenInfo->ScreenBufferSize.Y;
|
|
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
|
|
RecomputeRow = FALSE;
|
|
}
|
|
#if !defined(CON_TB_MARK)
|
|
ASSERT(nLoop++ < 2);
|
|
if (Row->CharRow.KAttrs && (Row->CharRow.KAttrs[Position.X] & ATTR_TRAILING_BYTE)) {
|
|
goto recalc;
|
|
}
|
|
#endif
|
|
if (!MyStringCompareW(SearchString, &Row->CharRow.Chars[Position.X], StringLength, IgnoreCase)) {
|
|
|
|
//
|
|
// If this operation was a normal user find, then return now. Otherwise set
|
|
// the attributes of this match, and continue searching the whole buffer.
|
|
//
|
|
|
|
if (!SearchAndSetAttr) {
|
|
|
|
*StringPosition = Position;
|
|
return ColumnWidth;
|
|
}
|
|
else {
|
|
|
|
Rect.Top = Rect.Bottom = Position.Y;
|
|
Rect.Left = Position.X;
|
|
Rect.Right = Rect.Left + ColumnWidth - 1;
|
|
|
|
ColorSelection( Console, &Rect, Attr);
|
|
}
|
|
}
|
|
}
|
|
while (!((Position.X == EndPosition.X) && (Position.Y == EndPosition.Y)));
|
|
|
|
return 0; // the string was not found
|
|
}
|
|
|
|
INT_PTR
|
|
FindDialogProc(
|
|
HWND hWnd,
|
|
UINT Message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PCONSOLE_INFORMATION Console;
|
|
PSCREEN_INFORMATION ScreenInfo;
|
|
USHORT StringLength;
|
|
USHORT ColumnWidth;
|
|
WCHAR szBuf[SEARCH_STRING_LENGTH + 1];
|
|
COORD Position;
|
|
BOOLEAN IgnoreCase;
|
|
BOOLEAN Reverse;
|
|
|
|
switch (Message) {
|
|
case WM_INITDIALOG:
|
|
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
|
|
SendDlgItemMessage(hWnd, ID_FINDSTR, EM_LIMITTEXT, ARRAY_SIZE(szBuf)-1, 0);
|
|
CheckRadioButton(hWnd, ID_FINDUP, ID_FINDDOWN, ID_FINDDOWN);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDOK:
|
|
StringLength = (USHORT)GetDlgItemText(hWnd, ID_FINDSTR, szBuf, ARRAY_SIZE(szBuf));
|
|
if (StringLength == 0) {
|
|
break;
|
|
}
|
|
IgnoreCase = IsDlgButtonChecked(hWnd, ID_FINDCASE) == 0;
|
|
Reverse = IsDlgButtonChecked(hWnd, ID_FINDDOWN) == 0;
|
|
Console = (PCONSOLE_INFORMATION)GetWindowLongPtr(hWnd, DWLP_USER);
|
|
ScreenInfo = Console->CurrentScreenBuffer;
|
|
|
|
ColumnWidth = SearchForString( ScreenInfo,
|
|
szBuf,
|
|
StringLength,
|
|
IgnoreCase,
|
|
Reverse,
|
|
FALSE,
|
|
0,
|
|
&Position);
|
|
if (ColumnWidth != 0) {
|
|
|
|
//
|
|
// Clear any old selections
|
|
//
|
|
|
|
if (Console->Flags & CONSOLE_SELECTING) {
|
|
ClearSelection(Console);
|
|
}
|
|
|
|
//
|
|
// Make the new selection
|
|
//
|
|
|
|
Console->Flags |= CONSOLE_SELECTING;
|
|
Console->SelectionFlags = CONSOLE_MOUSE_SELECTION | CONSOLE_SELECTION_NOT_EMPTY;
|
|
InitializeMouseSelection(Console, Position);
|
|
Console->SelectionRect.Right = Console->SelectionRect.Left + ColumnWidth - 1;
|
|
MyInvert(Console,&Console->SelectionRect);
|
|
SetWinText(Console,msgSelectMode,TRUE);
|
|
|
|
//
|
|
// Make sure the hilited text will be visible
|
|
//
|
|
|
|
if (Console->SelectionRect.Left < ScreenInfo->Window.Left) {
|
|
Position.X = Console->SelectionRect.Left;
|
|
} else if (Console->SelectionRect.Right > ScreenInfo->Window.Right) {
|
|
Position.X = Console->SelectionRect.Right - CONSOLE_WINDOW_SIZE_X(ScreenInfo) + 1;
|
|
} else {
|
|
Position.X = ScreenInfo->Window.Left;
|
|
}
|
|
if (Console->SelectionRect.Top < ScreenInfo->Window.Top) {
|
|
Position.Y = Console->SelectionRect.Top;
|
|
} else if (Console->SelectionRect.Bottom > ScreenInfo->Window.Bottom) {
|
|
Position.Y = Console->SelectionRect.Bottom - CONSOLE_WINDOW_SIZE_Y(ScreenInfo) + 1;
|
|
} else {
|
|
Position.Y = ScreenInfo->Window.Top;
|
|
}
|
|
SetWindowOrigin(ScreenInfo, TRUE, Position);
|
|
return TRUE;
|
|
} else {
|
|
|
|
//
|
|
// The string wasn't found
|
|
//
|
|
|
|
Beep(800, 200);
|
|
}
|
|
break;
|
|
case IDCANCEL:
|
|
EndDialog(hWnd, 0);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
DoFind(
|
|
IN PCONSOLE_INFORMATION Console)
|
|
{
|
|
++DialogBoxCount;
|
|
DialogBoxParam(ghInstance,
|
|
MAKEINTRESOURCE(ID_FINDDLG),
|
|
Console->hWnd,
|
|
FindDialogProc,
|
|
(LPARAM)Console);
|
|
--DialogBoxCount;
|
|
}
|