OSDN Git Service

- Replace include guards with #pragma once like winmerge2011
[winmerge-jp/winmerge-jp.git] / Src / PatchTool.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or (at
6 //    your option) any later version.
7 //    
8 //    This program is distributed in the hope that it will be useful, but
9 //    WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  files.cpp
19  *
20  * @brief Code file routines
21  */
22
23 #include "StdAfx.h"
24 #include "PatchTool.h"
25 #include "UnicodeString.h"
26 #include "DiffWrapper.h"
27 #include "PathContext.h"
28 #include "PatchDlg.h"
29 #include "paths.h"
30
31 #ifdef _DEBUG
32 #define new DEBUG_NEW
33 #undef THIS_FILE
34 static char THIS_FILE[] = __FILE__;
35 #endif
36
37 /**
38  * @brief Default constructor.
39  */
40 CPatchTool::CPatchTool() : m_bOpenToEditor(FALSE)
41 {
42 }
43
44 /**
45  * @brief Default destructor.
46  */
47 CPatchTool::~CPatchTool()
48 {
49 }
50
51 /** 
52  * @brief Adds files to list for patching.
53  * @param [in] file1 First file to add.
54  * @param [in] file2 Second file to add.
55  */
56 void CPatchTool::AddFiles(const String &file1, const String &file2)
57 {
58         PATCHFILES files;
59         files.lfile = file1;
60         files.rfile = file2;
61
62         // TODO: Read and add file's timestamps
63         m_fileList.push_back(files);
64 }
65
66 /**
67  * @brief Add files with alternative paths.
68  * This function adds files with alternative paths. Alternative path is the
69  * one that is added to the patch file. So while @p file1 and @p file2 are
70  * paths in disk (can be temp file names), @p altPath1 and @p altPath2 are
71  * "visible " paths printed to the patch file.
72  * @param [in] file1 First path in disk.
73  * @param [in] altPath1 First path as printed to the patch file.
74  * @param [in] file2 Second path in disk.
75  * @param [in] altPath2 Second path as printed to the patch file.
76  */
77 void CPatchTool::AddFiles(const String &file1, const String &altPath1,
78                 const String &file2, const String &altPath2)
79 {
80         PATCHFILES files;
81         files.lfile = file1;
82         files.rfile = file2;
83         files.pathLeft = altPath1;
84         files.pathRight = altPath2;
85
86         // TODO: Read and add file's timestamps
87         m_fileList.push_back(files);
88 }
89
90 /** 
91  * @brief Create a patch from files given.
92  * @note Files can be given using AddFiles() or selecting using
93  * CPatchDlg.
94  */
95 int CPatchTool::CreatePatch()
96 {
97         DIFFSTATUS status;
98         BOOL bResult = TRUE;
99         BOOL bDiffSuccess;
100         int retVal = 0;
101
102         CPatchDlg dlgPatch;
103
104         // If files already inserted, add them to dialog
105     for(std::vector<PATCHFILES>::iterator iter = m_fileList.begin(); iter != m_fileList.end(); ++iter)
106     {
107         dlgPatch.AddItem(*iter);
108         }
109
110         if (ShowDialog(&dlgPatch))
111         {
112                 String path;
113                 paths_SplitFilename((const TCHAR *)dlgPatch.m_fileResult, &path, NULL, NULL);
114                 if (!paths_CreateIfNeeded(path))
115                 {
116                         LangMessageBox(IDS_FOLDER_NOTEXIST, MB_OK | MB_ICONSTOP);
117                         return 0;
118                 }
119
120                 // Select patch create -mode
121                 m_diffWrapper.SetCreatePatchFile((LPCTSTR)dlgPatch.m_fileResult);
122                 m_diffWrapper.SetAppendFiles(!!dlgPatch.m_appendFile);
123                 m_diffWrapper.SetPrediffer(NULL);
124
125                 size_t fileCount = dlgPatch.GetItemCount();
126
127                 m_diffWrapper.WritePatchFileHeader(dlgPatch.m_outputStyle, !!dlgPatch.m_appendFile);
128                 m_diffWrapper.SetAppendFiles(TRUE);
129
130                 for (size_t index = 0; index < fileCount; index++)
131                 {
132                         const PATCHFILES& files = dlgPatch.GetItemAt(index);
133                         String filename1 = files.lfile.length() == 0 ? _T("NUL") : files.lfile;
134                         String filename2 = files.rfile.length() == 0 ? _T("NUL") : files.rfile;
135                         
136                         // Set up DiffWrapper
137                         m_diffWrapper.SetPaths(PathContext(filename1, filename2), FALSE);
138                         m_diffWrapper.SetAlternativePaths(PathContext(files.pathLeft, files.pathRight));
139                         m_diffWrapper.SetCompareFiles(PathContext(files.lfile, files.rfile));
140                         bDiffSuccess = m_diffWrapper.RunFileDiff();
141                         m_diffWrapper.GetDiffStatus(&status);
142
143                         if (!bDiffSuccess)
144                         {
145                                 LangMessageBox(IDS_FILEERROR, MB_ICONSTOP);
146                                 bResult = FALSE;
147                                 break;
148                         }
149                         else if (status.bBinaries)
150                         {
151                                 LangMessageBox(IDS_CANNOT_CREATE_BINARYPATCH, MB_ICONSTOP);
152                                 bResult = FALSE;
153                                 break;
154                         }
155                         else if (status.bPatchFileFailed)
156                         {
157                                 String errMsg = LangFormatString1(IDS_FILEWRITE_ERROR, dlgPatch.m_fileResult);
158                                 AfxMessageBox(errMsg.c_str(), MB_ICONSTOP);
159                                 bResult = FALSE;
160                                 break;
161                         }
162                 }
163                 
164                 m_diffWrapper.WritePatchFileTerminator(dlgPatch.m_outputStyle);
165
166                 if (bResult && fileCount > 0)
167                 {
168                         LangMessageBox(IDS_DIFF_SUCCEEDED, MB_ICONINFORMATION|MB_DONT_DISPLAY_AGAIN,
169                                             IDS_DIFF_SUCCEEDED);
170                         
171                         m_sPatchFile = (LPCTSTR)dlgPatch.m_fileResult;
172                         m_bOpenToEditor = dlgPatch.m_openToEditor;
173                         retVal = 1;
174                 }
175         }
176         dlgPatch.ClearItems();
177         return retVal;
178 }
179
180 /** 
181  * @brief Show patch options dialog and check options selected.
182  * @return TRUE if user wants to create a patch (didn't cancel dialog).
183  */
184 BOOL CPatchTool::ShowDialog(CPatchDlg *pDlgPatch)
185 {
186         DIFFOPTIONS diffOptions = {0};
187         PATCHOPTIONS patchOptions;
188         BOOL bRetVal = TRUE;
189
190         if (pDlgPatch->DoModal() == IDOK)
191         {
192                 // There must be one filepair
193                 if (pDlgPatch->GetItemCount() < 1)
194                         bRetVal = FALSE;
195
196                 // These two are from dropdown list - can't be wrong
197                 patchOptions.outputStyle = pDlgPatch->m_outputStyle;
198                 patchOptions.nContext = pDlgPatch->m_contextLines;
199
200                 // Checkbox - can't be wrong
201                 patchOptions.bAddCommandline = !!pDlgPatch->m_includeCmdLine;
202                 m_diffWrapper.SetPatchOptions(&patchOptions);
203
204                 // These are from checkboxes and radiobuttons - can't be wrong
205                 diffOptions.nIgnoreWhitespace = pDlgPatch->m_whitespaceCompare;
206                 diffOptions.bIgnoreBlankLines = !!pDlgPatch->m_ignoreBlanks;
207                 m_diffWrapper.SetAppendFiles(!!pDlgPatch->m_appendFile);
208
209                 // Use this because non-sensitive setting can't write
210                 // patch file EOLs correctly
211                 diffOptions.bIgnoreEol = !!pDlgPatch->m_ignoreEOLDifference;
212                 
213                 diffOptions.bIgnoreCase = pDlgPatch->m_caseSensitive == FALSE;
214                 m_diffWrapper.SetOptions(&diffOptions);
215         }
216         else
217                 return FALSE;
218
219         return bRetVal;
220 }
221
222 /** 
223  * @brief Returns filename and path for patch-file
224  */
225 String CPatchTool::GetPatchFile() const
226 {
227         return m_sPatchFile;
228 }
229
230 /** 
231  * @brief Returns TRUE if user wants to open patch file
232  * to external editor (specified in WinMerge options).
233  */
234 BOOL CPatchTool::GetOpenToEditor() const
235 {
236         return m_bOpenToEditor;
237 }