-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCGrepAgent.cpp
1963 lines (1826 loc) · 65.8 KB
/
CGrepAgent.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*! @file */
/*
Copyright (C) 2018-2021, Sakura Editor Organization
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "StdAfx.h"
#include "CGrepAgent.h"
#include "CGrepEnumKeys.h"
#include "CGrepEnumFilterFiles.h"
#include "CGrepEnumFilterFolders.h"
#include "CSearchAgent.h"
#include "dlg/CDlgCancel.h"
#include "_main/CAppMode.h"
#include "COpeBlk.h"
#include "window/CEditWnd.h"
#include "charset/CCodeMediator.h"
#include "view/colors/CColorStrategy.h"
#include "charset/CCodeFactory.h"
#include "charset/CCodeBase.h"
#include "charset/CCodePage.h"
#include "io/CFileLoad.h"
#include "io/CBinaryStream.h"
#include "util/window.h"
#include "util/module.h"
#include "util/string_ex2.h"
#include "debug/CRunningTimer.h"
#include <iterator>
#include <deque>
#include <memory>
#include "sakura_rc.h"
#define UICHECK_INTERVAL_MILLISEC 100 // UI確認の時間間隔
#define ADDTAIL_INTERVAL_MILLISEC 50 // 結果出力の時間間隔
#define UIFILENAME_INTERVAL_MILLISEC 15 // Cancelダイアログのファイル名表示更新間隔
/*!
* 指定された文字列をタイプ別設定に従ってエスケープする
*/
inline CNativeW EscapeStringLiteral( const STypeConfig& type, const CNativeW& cmemString )
{
CNativeW cmemWork2( cmemString );
if( FALSE == type.m_ColorInfoArr[COLORIDX_WSTRING].m_bDisp ){
// 2011.11.28 色指定が無効ならエスケープしない
}else
if( type.m_nStringType == STRING_LITERAL_CPP || type.m_nStringType == STRING_LITERAL_CSHARP
|| type.m_nStringType == STRING_LITERAL_PYTHON ){ /* 文字列区切り記号エスケープ方法 */
cmemWork2.Replace( L"\\", L"\\\\" );
cmemWork2.Replace( L"\'", L"\\\'" );
cmemWork2.Replace( L"\"", L"\\\"" );
}else if( type.m_nStringType == STRING_LITERAL_PLSQL ){
cmemWork2.Replace( L"\'", L"\'\'" );
cmemWork2.Replace( L"\"", L"\"\"" );
}
return cmemWork2;
}
/*!
* パスリストを文字列化する
*/
template<class ContainerType>
std::wstring FormatPathList( const ContainerType& containter )
{
std::wstring strPatterns;
bool firstItem = true;
for( const auto& pattern : containter ){
// パスリストは ':' で区切る(2つ目以降の前に付加する)
if( firstItem ){
firstItem = false;
}else {
strPatterns += L';';
}
// ';' を含むパス名は引用符で囲む
if( std::wstring::npos != std::wstring_view( pattern ).find( L';' ) ){
strPatterns += L'"';
strPatterns += pattern;
strPatterns += L'"';
}else{
strPatterns += pattern;
}
}
return strPatterns;
}
CGrepAgent::CGrepAgent()
: m_bGrepMode( false ) /* Grepモードか */
, m_bGrepRunning( false ) /* Grep処理中 */
, m_dwTickAddTail( 0 )
, m_dwTickUICheck( 0 )
, m_dwTickUIFileName( 0 )
{
}
ECallbackResult CGrepAgent::OnBeforeClose()
{
//GREP処理中は終了できない
if( m_bGrepRunning ){
// アクティブにする
ActivateFrameWindow( CEditWnd::getInstance()->GetHwnd() ); //@@@ 2003.06.25 MIK
TopInfoMessage(
CEditWnd::getInstance()->GetHwnd(),
LS(STR_GREP_RUNNINNG)
);
return CALLBACK_INTERRUPT;
}
return CALLBACK_CONTINUE;
}
void CGrepAgent::OnAfterSave(const SSaveInfo& sSaveInfo)
{
// 名前を付けて保存から再ロードが除去された分の不足処理を追加(ANSI版との差異) // 2009.08.12 ryoji
m_bGrepMode = false; // grepウィンドウは通常ウィンドウ化
CAppMode::getInstance()->m_szGrepKey[0] = L'\0';
}
/*!
@date 2014.03.09 novice 最後の\\を取り除くのをやめる(d:\\ -> d:になる)
*/
void CGrepAgent::CreateFolders( const WCHAR* pszPath, std::vector<std::wstring>& vPaths )
{
std::wstring strPath( pszPath );
const int nPathLen = static_cast<int>( strPath.length() );
WCHAR* token;
int nPathPos = 0;
while( NULL != (token = my_strtok<WCHAR>( strPath.data(), nPathLen, &nPathPos, L";")) ){
std::wstring strTemp( token );
// パスに含まれる '"' を削除する
strTemp.erase( std::remove( strTemp.begin(), strTemp.end(), L'"' ), strTemp.end() );
/* ロングファイル名を取得する */
WCHAR szTmp2[_MAX_PATH];
if( ::GetLongFileName( strTemp.c_str(), szTmp2 ) ){
vPaths.push_back( szTmp2 );
}else{
vPaths.emplace_back( strTemp );
}
}
}
/*! 最後の\\を取り除く
@date 2014.03.09 novice 新規作成
*/
std::wstring CGrepAgent::ChopYen( const std::wstring& str )
{
std::wstring dst = str;
size_t nPathLen = dst.length();
// 最後のフォルダ区切り記号を削除する
// [A:\]などのルートであっても削除
for(size_t i = 0; i < nPathLen; i++ ){
#ifdef _MBCS
if( _IS_SJIS_1( (unsigned char)dst[i] ) && (i + 1 < nPathLen) && _IS_SJIS_2( (unsigned char)dst[i + 1] ) ){
// SJIS読み飛ばし
i++;
} else
#endif
if( L'\\' == dst[i] && i == nPathLen - 1 ){
dst.resize( nPathLen - 1 );
break;
}
}
return dst;
}
void CGrepAgent::AddTail( CEditView* pcEditView, const CNativeW& cmem, bool bAddStdout )
{
m_dwTickAddTail = ::GetTickCount();
if( bAddStdout ){
HANDLE out = ::GetStdHandle(STD_OUTPUT_HANDLE);
if( out && out != INVALID_HANDLE_VALUE ){
CMemory cmemOut;
std::unique_ptr<CCodeBase> pcCodeBase( CCodeFactory::CreateCodeBase(
pcEditView->GetDocument()->GetDocumentEncoding(), 0) );
pcCodeBase->UnicodeToCode( cmem, &cmemOut );
DWORD dwWrite = 0;
::WriteFile(out, cmemOut.GetRawPtr(), cmemOut.GetRawLength(), &dwWrite, NULL);
}
}else{
pcEditView->GetCommander().Command_ADDTAIL( cmem.GetStringPtr(), cmem.GetStringLength() );
pcEditView->GetCommander().Command_GOFILEEND( FALSE );
if( !CEditWnd::getInstance()->UpdateTextWrap() ) // 折り返し方法関連の更新 // 2008.06.10 ryoji
CEditWnd::getInstance()->RedrawAllViews( pcEditView ); // 他のペインの表示を更新
}
}
/*! Grep実行
@param[in] pcmGrepKey 検索パターン
@param[in] pcmGrepFile 検索対象ファイルパターン(!で除外指定))
@param[in] pcmGrepFolder 検索対象フォルダ
@date 2008.12.07 nasukoji ファイル名パターンのバッファオーバラン対策
@date 2008.12.13 genta 検索パターンのバッファオーバラン対策
@date 2012.10.13 novice 検索オプションをクラスごと代入
*/
DWORD CGrepAgent::DoGrep(
CEditView* pcViewDst,
bool bGrepReplace,
const CNativeW* pcmGrepKey,
const CNativeW* pcmGrepReplace,
const CNativeW* pcmGrepFile,
const CNativeW* pcmGrepFolder,
bool bGrepCurFolder,
BOOL bGrepSubFolder,
bool bGrepStdout,
bool bGrepHeader,
const SSearchOption& sSearchOption,
ECodeType nGrepCharSet, // 2002/09/21 Moca 文字コードセット選択
int nGrepOutputLineType,
int nGrepOutputStyle,
bool bGrepOutputFileOnly,
bool bGrepOutputBaseFolder,
bool bGrepSeparateFolder,
bool bGrepPaste,
bool bGrepBackup
)
{
MY_RUNNINGTIMER( cRunningTimer, "CEditView::DoGrep" );
// 再入不可
if( this->m_bGrepRunning ){
assert_warning( false == this->m_bGrepRunning );
return 0xffffffff;
}
this->m_bGrepRunning = true;
int nHitCount = 0;
CDlgCancel cDlgCancel;
HWND hwndCancel;
// Jun. 27, 2001 genta 正規表現ライブラリの差し替え
CBregexp cRegexp;
CNativeW cmemMessage;
CNativeW cUnicodeBuffer;
int nWork;
SGrepOption sGrepOption;
/*
|| バッファサイズの調整
*/
cmemMessage.AllocStringBuffer( 4000 );
cUnicodeBuffer.AllocStringBuffer( 4000 );
pcViewDst->m_bDoing_UndoRedo = true;
/* アンドゥバッファの処理 */
if( NULL != pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk ){ /* 操作ブロック */
//@@@2002.2.2 YAZAKI NULLじゃないと進まないので、とりあえずコメント。&NULLのときは、new COpeBlkする。
// while( NULL != m_pcOpeBlk ){}
// delete m_pcOpeBlk;
// m_pcOpeBlk = NULL;
}
else {
pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk = new COpeBlk;
pcViewDst->GetDocument()->m_cDocEditor.m_nOpeBlkRedawCount = 0;
}
pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk->AddRef();
pcViewDst->m_bCurSrchKeyMark = true; /* 検索文字列のマーク */
pcViewDst->m_strCurSearchKey = pcmGrepKey->GetStringPtr(); /* 検索文字列 */
pcViewDst->m_sCurSearchOption = sSearchOption; // 検索オプション
pcViewDst->m_nCurSearchKeySequence = GetDllShareData().m_Common.m_sSearch.m_nSearchKeySequence;
// 置換後文字列の準備
CNativeW cmemReplace;
if( bGrepReplace ){
if( bGrepPaste ){
// 矩形・ラインモード貼り付けは未サポート
bool bColmnSelect;
bool bLineSelect = false;
if( !pcViewDst->MyGetClipboardData( cmemReplace, &bColmnSelect, GetDllShareData().m_Common.m_sEdit.m_bEnableLineModePaste? &bLineSelect: NULL ) ){
this->m_bGrepRunning = false;
pcViewDst->m_bDoing_UndoRedo = false;
ErrorMessage( pcViewDst->m_hwndParent, LS(STR_DLGREPLC_CLIPBOARD) );
return 0;
}
if( bLineSelect ){
int len = cmemReplace.GetStringLength();
if( cmemReplace[len - 1] != WCODE::CR && cmemReplace[len - 1] != WCODE::LF ){
cmemReplace.AppendString(pcViewDst->GetDocument()->m_cDocEditor.GetNewLineCode().GetValue2());
}
}
if( GetDllShareData().m_Common.m_sEdit.m_bConvertEOLPaste ){
CLogicInt len = cmemReplace.GetStringLength();
wchar_t *pszConvertedText = new wchar_t[len * 2]; // 全文字\n→\r\n変換で最大の2倍になる
CLogicInt nConvertedTextLen = pcViewDst->m_cCommander.ConvertEol(cmemReplace.GetStringPtr(), len, pszConvertedText);
cmemReplace.SetString(pszConvertedText, nConvertedTextLen);
delete [] pszConvertedText;
}
}else{
cmemReplace = *pcmGrepReplace;
}
}
/* 正規表現 */
// From Here Jun. 27 genta
/*
Grepを行うに当たって検索・画面色分け用正規表現バッファも
初期化する.これはGrep検索結果の色分けを行うため.
Note: ここで強調するのは最後の検索文字列であって
Grep対象パターンではないことに注意
*/
if( !pcViewDst->m_sSearchPattern.SetPattern(pcViewDst->GetHwnd(), pcViewDst->m_strCurSearchKey.c_str(), pcViewDst->m_strCurSearchKey.size(),
pcViewDst->m_sCurSearchOption, &pcViewDst->m_CurRegexp) ){
this->m_bGrepRunning = false;
pcViewDst->m_bDoing_UndoRedo = false;
pcViewDst->SetUndoBuffer();
return 0;
}
//2014.06.13 別ウィンドウで検索したとき用にGrepダイアログの検索キーを設定
pcViewDst->m_pcEditWnd->m_cDlgGrep.m_strText = pcmGrepKey->GetStringPtr();
pcViewDst->m_pcEditWnd->m_cDlgGrep.m_bSetText = true;
pcViewDst->m_pcEditWnd->m_cDlgGrepReplace.m_strText = pcmGrepKey->GetStringPtr();
if( bGrepReplace ){
pcViewDst->m_pcEditWnd->m_cDlgGrepReplace.m_strText2 = pcmGrepReplace->GetStringPtr();
}
pcViewDst->m_pcEditWnd->m_cDlgGrepReplace.m_bSetText = true;
hwndCancel = cDlgCancel.DoModeless( G_AppInstance(), pcViewDst->m_hwndParent, IDD_GREPRUNNING );
::SetDlgItemInt( hwndCancel, IDC_STATIC_HITCOUNT, 0, FALSE );
::DlgItem_SetText( hwndCancel, IDC_STATIC_CURFILE, L" " ); // 2002/09/09 Moca add
::CheckDlgButton( hwndCancel, IDC_CHECK_REALTIMEVIEW, GetDllShareData().m_Common.m_sSearch.m_bGrepRealTimeView ); // 2003.06.23 Moca
// 2008.12.13 genta パターンが長すぎる場合は登録しない
// (正規表現が途中で途切れると困るので)
// 2011.12.10 Moca 表示の際に...に切り捨てられるので登録するように
wcsncpy_s( CAppMode::getInstance()->m_szGrepKey, _countof(CAppMode::getInstance()->m_szGrepKey), pcmGrepKey->GetStringPtr(), _TRUNCATE );
this->m_bGrepMode = true;
// 2007.07.22 genta
// バージョン番号取得のため,処理を前の方へ移動した
CSearchStringPattern pattern;
{
/* 検索パターンのコンパイル */
bool bError;
if( bGrepReplace && !bGrepPaste ){
// Grep置換
// 2015.03.03 Grep置換がoptGlobalじゃないバグを修正
bError = !pattern.SetPattern(pcViewDst->GetHwnd(), pcmGrepKey->GetStringPtr(), pcmGrepKey->GetStringLength(),
cmemReplace.GetStringPtr(), sSearchOption, &cRegexp, true);
}else{
bError = !pattern.SetPattern(pcViewDst->GetHwnd(), pcmGrepKey->GetStringPtr(), pcmGrepKey->GetStringLength(),
sSearchOption, &cRegexp);
}
if( bError ){
this->m_bGrepRunning = false;
pcViewDst->m_bDoing_UndoRedo = false;
pcViewDst->SetUndoBuffer();
return 0;
}
}
// Grepオプションまとめ
sGrepOption.bGrepSubFolder = FALSE != bGrepSubFolder;
sGrepOption.bGrepStdout = bGrepStdout;
sGrepOption.bGrepHeader = bGrepHeader;
sGrepOption.nGrepCharSet = nGrepCharSet;
sGrepOption.nGrepOutputLineType = nGrepOutputLineType;
sGrepOption.nGrepOutputStyle = nGrepOutputStyle;
sGrepOption.bGrepOutputFileOnly = bGrepOutputFileOnly;
sGrepOption.bGrepOutputBaseFolder = bGrepOutputBaseFolder;
sGrepOption.bGrepSeparateFolder = bGrepSeparateFolder;
sGrepOption.bGrepReplace = bGrepReplace;
sGrepOption.bGrepPaste = bGrepPaste;
sGrepOption.bGrepBackup = bGrepBackup;
if( sGrepOption.bGrepReplace ){
// Grep否定行はGrep置換では無効
if( sGrepOption.nGrepOutputLineType == 2 ){
sGrepOption.nGrepOutputLineType = 1; // 行単位
}
}
//2002.02.08 Grepアイコンも大きいアイコンと小さいアイコンを別々にする。
HICON hIconBig, hIconSmall;
// Dec, 2, 2002 genta アイコン読み込み方法変更
hIconBig = GetAppIcon( G_AppInstance(), ICON_DEFAULT_GREP, FN_GREP_ICON, false );
hIconSmall = GetAppIcon( G_AppInstance(), ICON_DEFAULT_GREP, FN_GREP_ICON, true );
// Sep. 10, 2002 genta
// CEditWndに新設した関数を使うように
CEditWnd* pCEditWnd = CEditWnd::getInstance(); // Sep. 10, 2002 genta
pCEditWnd->SetWindowIcon( hIconSmall, ICON_SMALL );
pCEditWnd->SetWindowIcon( hIconBig, ICON_BIG );
CGrepEnumKeys cGrepEnumKeys;
{
int nErrorNo = cGrepEnumKeys.SetFileKeys( pcmGrepFile->GetStringPtr() );
if( nErrorNo != 0 ){
this->m_bGrepRunning = false;
pcViewDst->m_bDoing_UndoRedo = false;
pcViewDst->SetUndoBuffer();
const WCHAR* pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS0);
if( nErrorNo == 1 ){
pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS1);
}
else if( nErrorNo == 2 ){
pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS2);
}
ErrorMessage( pcViewDst->m_hwndParent, L"%s", pszErrorMessage );
return 0;
}
}
// 出力対象ビューのタイプ別設定(grepout固定)
const STypeConfig& type = pcViewDst->m_pcEditDoc->m_cDocType.GetDocumentAttribute();
std::vector<std::wstring> vPaths;
CreateFolders( pcmGrepFolder->GetStringPtr(), vPaths );
nWork = pcmGrepKey->GetStringLength(); // 2003.06.10 Moca あらかじめ長さを計算しておく
/* 最後にテキストを追加 */
CNativeW cmemWork;
cmemMessage.AppendString( LS( STR_GREP_SEARCH_CONDITION ) ); //L"\r\n□検索条件 "
if( 0 < nWork ){
cmemMessage.AppendString( L"\"" );
cmemMessage += EscapeStringLiteral(type, *pcmGrepKey);
cmemMessage.AppendString( L"\"\r\n" );
}else{
cmemMessage.AppendString( LS( STR_GREP_SEARCH_FILE ) ); //L"「ファイル検索」\r\n"
}
if( bGrepReplace ){
cmemMessage.AppendString( LS(STR_GREP_REPLACE_TO) );
if( bGrepPaste ){
cmemMessage.AppendString( LS(STR_GREP_PASTE_CLIPBOAD) );
}else{
cmemMessage.AppendString( L"\"" );
cmemMessage += EscapeStringLiteral(type, cmemReplace);
cmemMessage.AppendString( L"\"\r\n" );
}
}
cmemMessage.AppendString( LS( STR_GREP_SEARCH_TARGET ) ); //L"検索対象 "
{
// 解析済みのファイルパターン配列を取得する
const auto& vecSearchFileKeys = cGrepEnumKeys.m_vecSearchFileKeys;
std::wstring strPatterns = FormatPathList( vecSearchFileKeys );
cmemMessage.AppendString( strPatterns.c_str(), strPatterns.length() );
}
cmemMessage.AppendString( L"\r\n" );
cmemMessage.AppendString( LS( STR_GREP_SEARCH_FOLDER ) ); //L"フォルダ "
{
// フォルダリストから末尾のバックスラッシュを削ったパスリストを作る
std::list<std::wstring> folders;
std::transform( vPaths.cbegin(), vPaths.cend(), std::back_inserter( folders ), []( const auto& path ) { return ChopYen( path ); } );
std::wstring strPatterns = FormatPathList( folders );
cmemMessage.AppendString( strPatterns.c_str(), strPatterns.length() );
}
cmemMessage.AppendString( L"\r\n" );
cmemMessage.AppendString(LS(STR_GREP_EXCLUDE_FILE)); //L"除外ファイル "
{
// 除外ファイルの解析済みリストを取得る
auto excludeFiles = cGrepEnumKeys.GetExcludeFiles();
std::wstring strPatterns = FormatPathList( excludeFiles );
cmemMessage.AppendString( strPatterns.c_str(), strPatterns.length() );
}
cmemMessage.AppendString(L"\r\n");
cmemMessage.AppendString(LS(STR_GREP_EXCLUDE_FOLDER)); //L"除外フォルダ "
{
// 除外フォルダの解析済みリストを取得する
auto excludeFolders = cGrepEnumKeys.GetExcludeFolders();
std::wstring strPatterns = FormatPathList( excludeFolders );
cmemMessage.AppendString( strPatterns.c_str(), strPatterns.length() );
}
cmemMessage.AppendString(L"\r\n");
const wchar_t* pszWork;
if( sGrepOption.bGrepSubFolder ){
pszWork = LS( STR_GREP_SUBFOLDER_YES ); //L" (サブフォルダも検索)\r\n"
}else{
pszWork = LS( STR_GREP_SUBFOLDER_NO ); //L" (サブフォルダを検索しない)\r\n"
}
cmemMessage.AppendString( pszWork );
if( 0 < nWork ){ // 2003.06.10 Moca ファイル検索の場合は表示しない // 2004.09.26 条件誤り修正
if( sSearchOption.bWordOnly ){
/* 単語単位で探す */
cmemMessage.AppendString( LS( STR_GREP_COMPLETE_WORD ) ); //L" (単語単位で探す)\r\n"
}
if( sSearchOption.bLoHiCase ){
pszWork = LS( STR_GREP_CASE_SENSITIVE ); //L" (英大文字小文字を区別する)\r\n"
}else{
pszWork = LS( STR_GREP_IGNORE_CASE ); //L" (英大文字小文字を区別しない)\r\n"
}
cmemMessage.AppendString( pszWork );
if( sSearchOption.bRegularExp ){
// 2007.07.22 genta : 正規表現ライブラリのバージョンも出力する
cmemMessage.AppendString( LS( STR_GREP_REGEX_DLL ) ); //L" (正規表現:"
cmemMessage.AppendString( cRegexp.GetVersionW() );
cmemMessage.AppendString( L")\r\n" );
}
}
if( CODE_AUTODETECT == sGrepOption.nGrepCharSet ){
cmemMessage.AppendString( LS( STR_GREP_CHARSET_AUTODETECT ) ); //L" (文字コードセットの自動判別)\r\n"
}else if(IsValidCodeOrCPType(sGrepOption.nGrepCharSet)){
cmemMessage.AppendString( LS( STR_GREP_CHARSET ) ); //L" (文字コードセット:"
WCHAR szCpName[100];
CCodePage::GetNameNormal(szCpName, sGrepOption.nGrepCharSet);
cmemMessage.AppendString( szCpName );
cmemMessage.AppendString( L")\r\n" );
}
if( 0 < nWork ){ // 2003.06.10 Moca ファイル検索の場合は表示しない // 2004.09.26 条件誤り修正
if( sGrepOption.nGrepOutputLineType == 1 ){
/* 該当行 */
pszWork = LS( STR_GREP_SHOW_MATCH_LINE ); //L" (一致した行を出力)\r\n"
}else if( sGrepOption.nGrepOutputLineType == 2 ){
// 否該当行
pszWork = LS( STR_GREP_SHOW_MATCH_NOHITLINE ); //L" (一致しなかった行を出力)\r\n"
}else{
if( bGrepReplace && sSearchOption.bRegularExp && !bGrepPaste ){
pszWork = LS(STR_GREP_SHOW_FIRST_LINE);
}else{
pszWork = LS( STR_GREP_SHOW_MATCH_AREA );
}
}
cmemMessage.AppendString( pszWork );
if( sGrepOption.bGrepOutputFileOnly ){
pszWork = LS( STR_GREP_SHOW_FIRST_MATCH ); //L" (ファイル毎最初のみ検索)\r\n"
cmemMessage.AppendString( pszWork );
}
}
cmemMessage.AppendString( L"\r\n\r\n" );
nWork = cmemMessage.GetStringLength();
pszWork = cmemMessage.GetStringPtr();
//@@@ 2002.01.03 YAZAKI Grep直後はカーソルをGrep直前の位置に動かす
CLayoutInt tmp_PosY_Layout = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount();
if( 0 < nWork && sGrepOption.bGrepHeader ){
AddTail( pcViewDst, cmemMessage, sGrepOption.bGrepStdout );
}
cmemMessage._SetStringLength(0);
pszWork = NULL;
// 2007.07.22 genta バージョンを取得するために,
// 正規表現の初期化を上へ移動
/* 表示処理ON/OFF */
// 2003.06.23 Moca 共通設定で変更できるように
// 2008.06.08 ryoji 全ビューの表示ON/OFFを同期させる
// SetDrawSwitch(false);
if( !CEditWnd::getInstance()->UpdateTextWrap() ) // 折り返し方法関連の更新
CEditWnd::getInstance()->RedrawAllViews( pcViewDst ); // 他のペインの表示を更新
const bool bDrawSwitchOld = pcViewDst->SetDrawSwitch(0 != GetDllShareData().m_Common.m_sSearch.m_bGrepRealTimeView);
CGrepEnumOptions cGrepEnumOptions;
CGrepEnumFiles cGrepExceptAbsFiles;
cGrepExceptAbsFiles.Enumerates(L"", cGrepEnumKeys.m_vecExceptAbsFileKeys, cGrepEnumOptions);
CGrepEnumFolders cGrepExceptAbsFolders;
cGrepExceptAbsFolders.Enumerates(L"", cGrepEnumKeys.m_vecExceptAbsFolderKeys, cGrepEnumOptions);
int nGrepTreeResult = 0;
for( int nPath = 0; nPath < (int)vPaths.size(); nPath++ ){
bool bOutputBaseFolder = false;
std::wstring sPath = ChopYen( vPaths[nPath] );
int nTreeRet = DoGrepTree(
pcViewDst,
&cDlgCancel,
pcmGrepKey->GetStringPtr(),
cmemReplace,
cGrepEnumKeys,
cGrepExceptAbsFiles,
cGrepExceptAbsFolders,
sPath.c_str(),
sPath.c_str(),
sSearchOption,
sGrepOption,
pattern,
&cRegexp,
0,
bOutputBaseFolder,
&nHitCount,
cmemMessage,
cUnicodeBuffer
);
if( nTreeRet == -1 ){
nGrepTreeResult = -1;
break;
}
nGrepTreeResult += nTreeRet;
}
if( 0 < cmemMessage.GetStringLength() ) {
AddTail( pcViewDst, cmemMessage, sGrepOption.bGrepStdout );
cmemMessage._SetStringLength(0);
}
if( -1 == nGrepTreeResult && sGrepOption.bGrepHeader ){
const wchar_t* p = LS( STR_GREP_SUSPENDED ); //L"中断しました。\r\n"
CNativeW cmemSuspend;
cmemSuspend.SetString( p );
AddTail( pcViewDst, cmemSuspend, sGrepOption.bGrepStdout );
}
if( sGrepOption.bGrepHeader ){
WCHAR szBuffer[128];
if( bGrepReplace ){
auto_sprintf( szBuffer, LS(STR_GREP_REPLACE_COUNT), nHitCount );
}else{
auto_sprintf( szBuffer, LS( STR_GREP_MATCH_COUNT ), nHitCount );
}
CNativeW cmemOutput;
cmemOutput.SetString( szBuffer );
AddTail( pcViewDst, cmemOutput, sGrepOption.bGrepStdout );
#if defined(_DEBUG) && defined(TIME_MEASURE)
auto_sprintf( szBuffer, LS(STR_GREP_TIMER), cRunningTimer.Read() );
cmemOutput.SetString( szBuffer );
AddTail( pcViewDst, cmemOutput, sGrepOption.bGrepStdout );
#endif
}
pcViewDst->GetCaret().MoveCursor( CLayoutPoint(CLayoutInt(0), tmp_PosY_Layout), true ); // カーソルをGrep直前の位置に戻す。
cDlgCancel.CloseDialog( 0 );
/* アクティブにする */
ActivateFrameWindow( CEditWnd::getInstance()->GetHwnd() );
/* アンドゥバッファの処理 */
pcViewDst->SetUndoBuffer();
// Apr. 13, 2001 genta
// Grep実行後はファイルを変更無しの状態にする.
pcViewDst->m_pcEditDoc->m_cDocEditor.SetModified(false,false);
this->m_bGrepRunning = false;
pcViewDst->m_bDoing_UndoRedo = false;
/* 表示処理ON/OFF */
pCEditWnd->SetDrawSwitchOfAllViews( bDrawSwitchOld );
/* 再描画 */
if( !pCEditWnd->UpdateTextWrap() ) // 折り返し方法関連の更新 // 2008.06.10 ryoji
pCEditWnd->RedrawAllViews( NULL );
if( !bGrepCurFolder ){
// 現行フォルダを検索したフォルダに変更
if( 0 < vPaths.size() ){
::SetCurrentDirectory( vPaths[0].c_str() );
}
}
return nHitCount;
}
/*! @brief Grep実行
@date 2001.06.27 genta 正規表現ライブラリの差し替え
@date 2003.06.23 Moca サブフォルダ→ファイルだったのをファイル→サブフォルダの順に変更
@date 2003.06.23 Moca ファイル名から""を取り除くように
@date 2003.03.27 みく 除外ファイル指定の導入と重複検索防止の追加.
大部分が変更されたため,個別の変更点記入は無し.
*/
int CGrepAgent::DoGrepTree(
CEditView* pcViewDst,
CDlgCancel* pcDlgCancel, //!< [in] Cancelダイアログへのポインタ
const wchar_t* pszKey, //!< [in] 検索キー
const CNativeW& cmGrepReplace,
CGrepEnumKeys& cGrepEnumKeys, //!< [in] 検索対象ファイルパターン
CGrepEnumFiles& cGrepExceptAbsFiles, //!< [in] 除外ファイル絶対パス
CGrepEnumFolders& cGrepExceptAbsFolders, //!< [in] 除外フォルダ絶対パス
const WCHAR* pszPath, //!< [in] 検索対象パス
const WCHAR* pszBasePath, //!< [in] 検索対象パス(ベースフォルダ)
const SSearchOption& sSearchOption, //!< [in] 検索オプション
const SGrepOption& sGrepOption, //!< [in] Grepオプション
const CSearchStringPattern& pattern, //!< [in] 検索パターン
CBregexp* pRegexp, //!< [in] 正規表現コンパイルデータ。既にコンパイルされている必要がある
int nNest, //!< [in] ネストレベル
bool& bOutputBaseFolder, //!< [i/o] ベースフォルダ名出力
int* pnHitCount, //!< [i/o] ヒット数の合計
CNativeW& cmemMessage, //!< [i/o] Grep結果文字列
CNativeW& cUnicodeBuffer
)
{
int i;
int count;
LPCWSTR lpFileName;
int nWork = 0;
int nHitCountOld = -100;
bool bOutputFolderName = false;
int nBasePathLen = wcslen(pszBasePath);
CGrepEnumOptions cGrepEnumOptions;
CGrepEnumFilterFiles cGrepEnumFilterFiles;
cGrepEnumFilterFiles.Enumerates( pszPath, cGrepEnumKeys, cGrepEnumOptions, cGrepExceptAbsFiles );
/*
* カレントフォルダのファイルを探索する。
*/
count = cGrepEnumFilterFiles.GetCount();
for( i = 0; i < count; i++ ){
lpFileName = cGrepEnumFilterFiles.GetFileName( i );
DWORD dwNow = ::GetTickCount();
if( dwNow - m_dwTickUICheck > UICHECK_INTERVAL_MILLISEC ){
m_dwTickUICheck = dwNow;
/* 処理中のユーザー操作を可能にする */
if( !::BlockingHook( pcDlgCancel->GetHwnd() ) ){
goto cancel_return;
}
/* 中断ボタン押下チェック */
if( pcDlgCancel->IsCanceled() ){
goto cancel_return;
}
/* 表示設定をチェック */
CEditWnd::getInstance()->SetDrawSwitchOfAllViews(
0 != ::IsDlgButtonChecked( pcDlgCancel->GetHwnd(), IDC_CHECK_REALTIMEVIEW )
);
}
// 定期的に grep 中のファイル名表示を更新
if( dwNow - m_dwTickUIFileName > UIFILENAME_INTERVAL_MILLISEC ){
m_dwTickUIFileName = dwNow;
::DlgItem_SetText( pcDlgCancel->GetHwnd(), IDC_STATIC_CURFILE, lpFileName );
}
std::wstring currentFile = pszPath;
currentFile += L"\\";
currentFile += lpFileName;
int nBasePathLen2 = nBasePathLen + 1;
if( (int)wcslen(pszPath) < nBasePathLen2 ){
nBasePathLen2 = nBasePathLen;
}
/* ファイル内の検索 */
int nRet;
if( sGrepOption.bGrepReplace ){
nRet = DoGrepReplaceFile(
pcViewDst,
pcDlgCancel,
pszKey,
cmGrepReplace,
lpFileName,
sSearchOption,
sGrepOption,
pattern,
pRegexp,
pnHitCount,
currentFile.c_str(),
pszBasePath,
(sGrepOption.bGrepSeparateFolder && sGrepOption.bGrepOutputBaseFolder ? pszPath + nBasePathLen2 : pszPath),
(sGrepOption.bGrepSeparateFolder ? lpFileName : currentFile.c_str() + nBasePathLen + 1),
bOutputBaseFolder,
bOutputFolderName,
cmemMessage,
cUnicodeBuffer
);
}else{
nRet = DoGrepFile(
pcViewDst,
pcDlgCancel,
pszKey,
lpFileName,
sSearchOption,
sGrepOption,
pattern,
pRegexp,
pnHitCount,
currentFile.c_str(),
pszBasePath,
(sGrepOption.bGrepSeparateFolder && sGrepOption.bGrepOutputBaseFolder ? pszPath + nBasePathLen2 : pszPath),
(sGrepOption.bGrepSeparateFolder ? lpFileName : currentFile.c_str() + nBasePathLen + 1),
bOutputBaseFolder,
bOutputFolderName,
cmemMessage,
cUnicodeBuffer
);
}
// 2003.06.23 Moca リアルタイム表示のときは早めに表示
if( pcViewDst->GetDrawSwitch() ){
if( LTEXT('\0') != pszKey[0] ){
// データ検索のときファイルの合計が最大10MBを超えたら表示
nWork += ( cGrepEnumFilterFiles.GetFileSizeLow( i ) + 1023 ) / 1024;
}
if( 10000 < nWork ){
nHitCountOld = -100; // 即表示
}
}
/* 結果出力 */
if( 0 < cmemMessage.GetStringLength() &&
(*pnHitCount - nHitCountOld) >= 10 &&
(::GetTickCount() - m_dwTickAddTail) > ADDTAIL_INTERVAL_MILLISEC
){
AddTail( pcViewDst, cmemMessage, sGrepOption.bGrepStdout );
cmemMessage._SetStringLength(0);
nWork = 0;
nHitCountOld = *pnHitCount;
}
if( -1 == nRet ){
goto cancel_return;
}
}
/*
* サブフォルダを検索する。
*/
if( sGrepOption.bGrepSubFolder ){
CGrepEnumOptions cGrepEnumOptionsDir;
CGrepEnumFilterFolders cGrepEnumFilterFolders;
cGrepEnumFilterFolders.Enumerates( pszPath, cGrepEnumKeys, cGrepEnumOptionsDir, cGrepExceptAbsFolders );
count = cGrepEnumFilterFolders.GetCount();
for( i = 0; i < count; i++ ){
lpFileName = cGrepEnumFilterFolders.GetFileName( i );
DWORD dwNow = ::GetTickCount();
if( dwNow - m_dwTickUICheck > UICHECK_INTERVAL_MILLISEC ) {
m_dwTickUICheck = dwNow;
//サブフォルダの探索を再帰呼び出し。
/* 処理中のユーザー操作を可能にする */
if( !::BlockingHook( pcDlgCancel->GetHwnd() ) ){
goto cancel_return;
}
/* 中断ボタン押下チェック */
if( pcDlgCancel->IsCanceled() ){
goto cancel_return;
}
/* 表示設定をチェック */
CEditWnd::getInstance()->SetDrawSwitchOfAllViews(
0 != ::IsDlgButtonChecked( pcDlgCancel->GetHwnd(), IDC_CHECK_REALTIMEVIEW )
);
}
//フォルダ名を作成する。
// 2010.08.01 キャンセルでメモリーリークしてました
std::wstring currentPath = pszPath;
currentPath += L"\\";
currentPath += lpFileName;
int nGrepTreeResult = DoGrepTree(
pcViewDst,
pcDlgCancel,
pszKey,
cmGrepReplace,
cGrepEnumKeys,
cGrepExceptAbsFiles,
cGrepExceptAbsFolders,
currentPath.c_str(),
pszBasePath,
sSearchOption,
sGrepOption,
pattern,
pRegexp,
nNest + 1,
bOutputBaseFolder,
pnHitCount,
cmemMessage,
cUnicodeBuffer
);
if( -1 == nGrepTreeResult ){
goto cancel_return;
}
::DlgItem_SetText( pcDlgCancel->GetHwnd(), IDC_STATIC_CURPATH, pszPath ); //@@@ 2002.01.10 add サブフォルダから戻ってきたら...
}
}
::DlgItem_SetText( pcDlgCancel->GetHwnd(), IDC_STATIC_CURFILE, LTEXT(" ") ); // 2002/09/09 Moca add
return 0;
cancel_return:;
/* 結果出力 */
if( 0 < cmemMessage.GetStringLength() ){
AddTail( pcViewDst, cmemMessage, sGrepOption.bGrepStdout );
cmemMessage._SetStringLength(0);
}
return -1;
}
/*! @brief マッチした行番号と桁番号をGrep結果に出力する為に文字列化
auto_sprintf 関数を 書式文字列 "(%I64d,%d)" で実行するのと同等の処理結果を生成
高速化の為に自前実装に置き換え
@return 出力先文字列
*/
template <size_t nCapacity>
static inline
wchar_t* lineColumnToString(
wchar_t (&strWork)[nCapacity], /*!< [out] 出力先 */
LONGLONG nLine, /*!< [in] マッチした行番号(1~) */
int nColumn /*!< [in] マッチした桁番号(1~) */
)
{
// int2dec_destBufferSufficientLength 関数の
// 戻り値から -1 しているのは終端0文字の分を削っている為
constexpr size_t requiredMinimumCapacity =
1 // (
+ int2dec_destBufferSufficientLength<LONGLONG>() - 1 // I64d
+ 1 // ,
+ int2dec_destBufferSufficientLength<int32_t>() - 1 // %d
+ 1 // )
+ 1 // \0 終端0文字の分
;
static_assert(nCapacity >= requiredMinimumCapacity, "nCapacity not enough.");
wchar_t* p = strWork;
*p++ = L'(';
p += int2dec(nLine, p);
*p++ = L',';
p += int2dec(nColumn, p);
*p++ = L')';
*p = '\0';
#ifdef _DEBUG
// Debug 版に限って両方実行して、両者が一致することを確認
wchar_t strWork2[requiredMinimumCapacity];
::auto_sprintf( strWork2, L"(%I64d,%d)", nLine, nColumn );
assert(wcscmp(strWork, strWork2) == 0);
#endif
return strWork;
}
/*! @brief Grep結果を構築する
pWorkは充分なメモリ領域を持っているコト
@date 2002/08/29 Moca バイナリーデータに対応 pnWorkLen 追加
@date 2013.11.05 Moca cmemMessageに直接追加するように
*/
void CGrepAgent::SetGrepResult(
/* データ格納先 */
CNativeW& cmemMessage,
/* マッチしたファイルの情報 */
const WCHAR* pszFilePath, /*!< [in] フルパス or 相対パス*/
const WCHAR* pszCodeName, /*!< [in] 文字コード情報." [SJIS]"とか */
/* マッチした行の情報 */
LONGLONG nLine, /*!< [in] マッチした行番号(1~) */
int nColumn, /*!< [in] マッチした桁番号(1~) */
const wchar_t* pCompareData, /*!< [in] 行の文字列 */
int nLineLen, /*!< [in] 行の文字列の長さ */
int nEolCodeLen, /*!< [in] EOLの長さ */
/* マッチした文字列の情報 */
const wchar_t* pMatchData, /*!< [in] マッチした文字列 */
int nMatchLen, /*!< [in] マッチした文字列の長さ */
/* オプション */
const SGrepOption& sGrepOption
)
{
CNativeW cmemBuf(L"");
wchar_t strWork[64];
const wchar_t * pDispData;
int k;
bool bEOL = true;
int nMaxOutStr = 0;
/* ノーマル */
if( 1 == sGrepOption.nGrepOutputStyle ){
if( sGrepOption.bGrepOutputBaseFolder || sGrepOption.bGrepSeparateFolder ){
cmemBuf.AppendString( L"・" );
}
cmemBuf.AppendString( pszFilePath );
cmemBuf.AppendString( lineColumnToString(strWork, nLine, nColumn) );
cmemBuf.AppendString( pszCodeName );
cmemBuf.AppendString( L": " );
nMaxOutStr = 2000; // 2003.06.10 Moca 最大長変更
}
/* WZ風 */
else if( 2 == sGrepOption.nGrepOutputStyle ){
::auto_sprintf( strWork, L"・(%6I64d,%-5d): ", nLine, nColumn );
cmemBuf.AppendString( strWork );
nMaxOutStr = 2500; // 2003.06.10 Moca 最大長変更
}
// 結果のみ
else if( 3 == sGrepOption.nGrepOutputStyle ){
nMaxOutStr = 2500;
}
/* 該当行 */
if( sGrepOption.nGrepOutputLineType != 0 ){
pDispData = pCompareData;
k = nLineLen - nEolCodeLen;
if( nMaxOutStr < k ){
k = nMaxOutStr; // 2003.06.10 Moca 最大長変更
}