📄 ceditview_diff.cpp
字号:
// $Id: CEditView_Diff.cpp,v 1.14 2004/08/06 15:39:55 genta Exp $
/*! @file
@brief DIFF差分表示
@author MIK
@date 2002/05/25 ExecCmd を参考にDIFF実行結果を取り込む処理作成
$Revision: 1.14 $
*/
/*
Copyright (C) 1998-2001, Norio Nakatani
Copyright (C) 2001, GAE, YAZAKI, hor
Copyright (C) 2002, hor, MIK
Copyright (C) 2003, MIK
This source code is designed for sakura editor.
Please contact the copyright holders to use this code for other purpose.
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include "sakura_rc.h"
#include "etc_uty.h"
#include "global.h"
#include "CDlgDiff.h"
#include "CEditDoc.h"
#include "CEditView.h"
#include "CDocLine.h"
#include "CDocLineMgr.h"
#include "CWaitCursor.h"
#include "COsVersionInfo.h"
#include "mymessage.h"
#include "debug.h"
#define SAKURA_DIFF_TEMP_PREFIX "sakura_diff_"
/*! 差分表示
@note HandleCommandからの呼び出し対応(ダイアログあり版)
@author MIK
@date 2002/05/25
@date 2002/11/09 編集中ファイルを許可
*/
void CEditView::Command_Diff_Dialog( void )
{
CDlgDiff cDlgDiff;
bool bTmpFile1, bTmpFile2;
char szTmpFile1[_MAX_PATH * 2];
char szTmpFile2[_MAX_PATH * 2];
char *pszTmpName;
bTmpFile1 = false;
bTmpFile2 = false;
strcpy( szTmpFile1, "" );
strcpy( szTmpFile2, "" );
//DIFF差分表示ダイアログを表示する
if( FALSE == cDlgDiff.DoModal( m_hInstance, m_hWnd, (LPARAM)m_pcEditDoc,
m_pcEditDoc->GetFilePath(),
m_pcEditDoc->IsModified() ) )
{
return;
}
//自ファイル
if( m_pcEditDoc->IsModified() )
{
/*
MessageBox( NULL,
"差分コマンド実行は失敗しました。\nファイルを保存してから行ってください。",
"DIFF差分表示",
MB_OK | MB_ICONEXCLAMATION );
return;
*/
pszTmpName = _tempnam( NULL, SAKURA_DIFF_TEMP_PREFIX );
if( NULL == pszTmpName )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"差分コマンド実行は失敗しました。" );
return;
}
strcpy( szTmpFile1, pszTmpName );
free( pszTmpName );
bTmpFile1 = true;
// 編集中ファイルを一時ファイルに保存する
if( MakeDiffTmpFile( szTmpFile1, NULL ) == FALSE )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"差分コマンド実行は失敗しました。\n\n一時ファイルを作成できないか、または行が長すぎます。" );
goto finish;
}
}
else
{
bTmpFile1 = false;
strcpy( szTmpFile1, m_pcEditDoc->GetFilePath() );
if( strlen( szTmpFile1 ) == 0 ) return;
}
//相手ファイル
if( cDlgDiff.m_bIsModifiedDst ) /* 相手先ファイルは編集中か? */
{
/*
MessageBox( NULL,
"差分コマンド実行は失敗しました。\nファイルを保存してから行ってください。",
"DIFF差分表示",
MB_OK | MB_ICONEXCLAMATION );
return;
*/
pszTmpName = _tempnam( NULL, SAKURA_DIFF_TEMP_PREFIX );
if( NULL == pszTmpName )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"差分コマンド実行は失敗しました。" );
goto finish;
}
strcpy( szTmpFile2, pszTmpName );
free( pszTmpName );
bTmpFile2 = true;
// 相手先編集中ファイルを一時ファイルに保存する
if( MakeDiffTmpFile( szTmpFile2, cDlgDiff.m_hWnd_Dst ) == FALSE )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"差分コマンド実行は失敗しました。\n\n一時ファイルを作成できないか、または行が長すぎます。" );
goto finish;
}
}
else
{
bTmpFile2 = false;
strcpy( szTmpFile2, cDlgDiff.m_szFile2 );
if( strlen( szTmpFile2 ) == 0 ) return;
}
/* 差分表示 */
Command_Diff( szTmpFile1, szTmpFile2, cDlgDiff.m_nDiffFlgOpt );
finish:;
//一時ファイルを削除する
if( bTmpFile1 ) unlink( szTmpFile1 );
if( bTmpFile2 ) unlink( szTmpFile2 );
return;
}
/*! 差分表示
@param pszFile1 [in] 旧ファイル名
@param pszFile2 [in] 新ファイル名
@param nFlgOpt [in] 0b000000000
||||||+--- -i ignore-case 大文字小文字同一視
|||||+---- -w ignore-all-space 空白無視
||||+----- -b ignore-space-change 空白変更無視
|||+------ -B ignore-blank-lines 空行無視
||+------- -t expand-tabs TAB-SPACE変換
|+-------- (編集中のファイルが旧ファイル)
+--------- (DIFF差分がないときにメッセージ表示)
@note HandleCommandからの呼び出し対応(ダイアログなし版)
@author MIK
@date 2002/05/25
*/
void CEditView::Command_Diff(
const char *pszFile1,
const char *pszFile2,
int nFlgOpt )
/*
bool bFlgCase, //大文字小文字同一視
bool bFlgBlank, //空白無視
bool bFlgWhite, //空白変更無視
bool bFlgBLine, //空行無視
bool bFlgTabSpc, //TAB-SPACE変換
bool bFlgFile12, //編集中のファイルが旧ファイル
*/
{
char cmdline[1024];
HANDLE hStdOutWrite, hStdOutRead;
// CDlgCancel cDlgCancel;
CWaitCursor cWaitCursor( m_hWnd );
int nFlgFile12 = 1;
/* exeのあるフォルダ */
char szPath[_MAX_PATH + 1];
char szExeFolder[_MAX_PATH + 1];
::GetModuleFileName(
::GetModuleHandle( NULL ),
szPath, sizeof( szPath )
);
/* ファイルのフルパスを、フォルダとファイル名に分割 */
/* [c:\work\test\aaa.txt] → [c:\work\test] + [aaa.txt] */
::SplitPath_FolderAndFile( szPath, szExeFolder, NULL );
// From Here Dec. 28, 2002 MIK
// diff.exeの存在チェック
wsprintf( cmdline, "%s\\%s", szExeFolder, "diff.exe" );
if( -1 == ::GetFileAttributes( cmdline ) )
{
::MYMESSAGEBOX( m_hWnd, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
_T( "差分コマンド実行は失敗しました。\n\nDIFF.EXE が見つかりません。" ) );
return;
}
//今あるDIFF差分を消去する。
if( m_pcEditDoc->m_cDocLineMgr.IsDiffUse() )
Command_Diff_Reset();
//m_pcEditDoc->m_cDocLineMgr.ResetAllDiffMark();
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
//子プロセスの標準出力と接続するパイプを作成
SECURITY_ATTRIBUTES sa;
ZeroMemory( &sa, sizeof(SECURITY_ATTRIBUTES) );
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
hStdOutRead = hStdOutWrite = 0;
if( CreatePipe( &hStdOutRead, &hStdOutWrite, &sa, 1000 ) == FALSE )
{
//エラー。対策無し
return;
}
//継承不能にする
DuplicateHandle( GetCurrentProcess(), hStdOutRead,
GetCurrentProcess(), NULL,
0, FALSE, DUPLICATE_SAME_ACCESS );
//CreateProcessに渡すSTARTUPINFOを作成
STARTUPINFO sui;
ZeroMemory( &sui, sizeof(STARTUPINFO) );
sui.cb = sizeof(STARTUPINFO);
sui.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
sui.wShowWindow = SW_HIDE;
sui.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
sui.hStdOutput = hStdOutWrite;
sui.hStdError = hStdOutWrite;
//オプションを作成する
char szOption[16]; // "-cwbBt"
strcpy( szOption, "-" );
if( nFlgOpt & 0x0001 ) strcat( szOption, "i" ); //-i ignore-case 大文字小文字同一視
if( nFlgOpt & 0x0002 ) strcat( szOption, "w" ); //-w ignore-all-space 空白無視
if( nFlgOpt & 0x0004 ) strcat( szOption, "b" ); //-b ignore-space-change 空白変更無視
if( nFlgOpt & 0x0008 ) strcat( szOption, "B" ); //-B ignore-blank-lines 空行無視
if( nFlgOpt & 0x0010 ) strcat( szOption, "t" ); //-t expand-tabs TAB-SPACE変換
if( strcmp( szOption, "-" ) == 0 ) strcpy( szOption, "" ); //オプションなし
if( nFlgOpt & 0x0020 ) nFlgFile12 = 0;
else nFlgFile12 = 1;
// To Here Dec. 28, 2002 MIK
//OSバージョン取得
COsVersionInfo cOsVer;
//コマンドライン文字列作成(MAX:1024)
if (cOsVer.IsWin32NT()){
wsprintf( cmdline, "cmd.exe /C \"\"%s\\%s\" %s \"%s\" \"%s\"\"",
szExeFolder, //sakura.exeパス
"diff.exe", //diff.exe
szOption, //diffオプション
( nFlgFile12 ? pszFile2 : pszFile1 ),
( nFlgFile12 ? pszFile1 : pszFile2 )
);
}
else{
wsprintf( cmdline, "command.com /C \"%s\\%s\" %s \"%s\" \"%s\"",
szExeFolder, //sakura.exeパス
"diff.exe", //diff.exe
szOption, //diffオプション
( nFlgFile12 ? pszFile2 : pszFile1 ),
( nFlgFile12 ? pszFile1 : pszFile2 )
);
}
//コマンドライン実行
if( CreateProcess( NULL, cmdline, NULL, NULL, TRUE,
CREATE_NEW_CONSOLE, NULL, NULL, &sui, &pi ) == FALSE )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"差分コマンド実行は失敗しました。\n\n%s", cmdline );
goto finish;
}
{
DWORD read_cnt;
DWORD new_cnt;
char work[1024];
int j;
bool bLoopFlag = true;
bool bLineHead = true; //行頭か
bool bDiffInfo = false; //DIFF情報か
int nDiffLen = 0; //DIFF情報長
char szDiffData[100]; //DIFF情報
bool bFirst = true; //先頭か? //@@@ 2003.05.31 MIK
//中断ダイアログ表示
// cDlgCancel.DoModeless( m_hInstance, m_hwndParent, IDD_EXECRUNNING );
//実行結果の取り込み
do {
//処理中のユーザー操作を可能にする
// if( !::BlockingHook( cDlgCancel.m_hWnd ) )
// {
// bDiffInfo = false;
// break;
// }
//中断ボタン押下チェック
// if( cDlgCancel.IsCanceled() )
// {
//指定されたプロセスと、そのプロセスが持つすべてのスレッドを終了させます。
// ::TerminateProcess( pi.hProcess, 0 );
// bDiffInfo = false;
// break;
// }
//プロセスが終了していないか確認
// Jul. 04, 2003 genta CPUを100%使い果たすのを防ぐため 200msec休む
// Jan. 23, 2004 genta
// 子プロセスの出力をどんどん受け取らないと子プロセスが
// 停止してしまうため,待ち時間を200msから20msに減らす
if( WaitForSingleObject( pi.hProcess, 20 ) == WAIT_OBJECT_0 )
{
//終了していればループフラグをFALSEとする
//ただしループの終了条件は プロセス終了 && パイプが空
bLoopFlag = FALSE;
}
new_cnt = 0;
if( PeekNamedPipe( hStdOutRead, NULL, 0, NULL, &new_cnt, NULL ) )
{
while( new_cnt > 0 ) //待機中のものがある
{
if( new_cnt >= sizeof(work) - 2 ) //パイプから読み出す量を調整
{
new_cnt = sizeof(work) - 2;
}
ReadFile( hStdOutRead, &work[0], new_cnt, &read_cnt, NULL ); //パイプから読み出し
if( read_cnt == 0 )
{
// Jan. 23, 2004 genta while追加のため制御を変更
break;
}
//@@@ 2003.05.31 MIK
// 先頭がBinary filesならバイナリファイルのため意味のある差分が取られなかった
if( bFirst )
{
bFirst = false;
if( strncmp( work, "Binary files ", strlen( "Binary files " ) ) == 0 )
{
::MYMESSAGEBOX( NULL, MB_OK | MB_ICONEXCLAMATION, GSTR_APPNAME,
"DIFF差分を行おうとしたファイルはバイナリファイルです。" );
goto finish;
}
}
//読み出した文字列をチェックする
for( j = 0; j < (int)read_cnt/*-1*/; j++ )
{
if( bLineHead )
{
if( work[j] != '\n' && work[j] != '\r' )
{
bLineHead = false;
//DIFF情報の始まりか?
if( work[j] >= '0' && work[j] <= '9' )
{
bDiffInfo = true;
nDiffLen = 0;
szDiffData[nDiffLen++] = work[j];
}
/*
else if( work[j] == '<' || work[j] == '>' || work[j] == '-' )
{
bDiffInfo = false;
nDiffLen = 0;
}
*/
}
}
else
{
//行末に達したか?
if( work[j] == '\n' || work[j] == '\r' )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -