OSDN Git Service

Merge with stable
[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  PatchTool.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                 if (!paths_CreateIfNeeded(paths_GetPathOnly(dlgPatch.m_fileResult)))
113                 {
114                         LangMessageBox(IDS_FOLDER_NOTEXIST, MB_OK | MB_ICONSTOP);
115                         return 0;
116                 }
117
118                 // Select patch create -mode
119                 m_diffWrapper.SetCreatePatchFile(dlgPatch.m_fileResult);
120                 m_diffWrapper.SetAppendFiles(dlgPatch.m_appendFile);
121                 m_diffWrapper.SetPrediffer(NULL);
122
123                 size_t fileCount = dlgPatch.GetItemCount();
124
125                 m_diffWrapper.WritePatchFileHeader(dlgPatch.m_outputStyle, dlgPatch.m_appendFile);
126                 m_diffWrapper.SetAppendFiles(true);
127
128                 for (size_t index = 0; index < fileCount; index++)
129                 {
130                         const PATCHFILES& files = dlgPatch.GetItemAt(index);
131                         String filename1 = files.lfile.length() == 0 ? _T("NUL") : files.lfile;
132                         String filename2 = files.rfile.length() == 0 ? _T("NUL") : files.rfile;
133                         
134                         // Set up DiffWrapper
135                         m_diffWrapper.SetPaths(PathContext(filename1, filename2), false);
136                         m_diffWrapper.SetAlternativePaths(PathContext(files.pathLeft, files.pathRight));
137                         m_diffWrapper.SetCompareFiles(PathContext(files.lfile, files.rfile));
138                         bDiffSuccess = m_diffWrapper.RunFileDiff();
139                         m_diffWrapper.GetDiffStatus(&status);
140
141                         if (!bDiffSuccess)
142                         {
143                                 LangMessageBox(IDS_FILEERROR, MB_ICONSTOP);
144                                 bResult = false;
145                                 break;
146                         }
147                         else if (status.bBinaries)
148                         {
149                                 LangMessageBox(IDS_CANNOT_CREATE_BINARYPATCH, MB_ICONSTOP);
150                                 bResult = false;
151                                 break;
152                         }
153                         else if (status.bPatchFileFailed)
154                         {
155                                 String errMsg = string_format_string1(_("Could not write to file %1."), dlgPatch.m_fileResult);
156                                 AfxMessageBox(errMsg.c_str(), MB_ICONSTOP);
157                                 bResult = false;
158                                 break;
159                         }
160                 }
161                 
162                 m_diffWrapper.WritePatchFileTerminator(dlgPatch.m_outputStyle);
163
164                 if (bResult && fileCount > 0)
165                 {
166                         LangMessageBox(IDS_DIFF_SUCCEEDED, MB_ICONINFORMATION|MB_DONT_DISPLAY_AGAIN,
167                                             IDS_DIFF_SUCCEEDED);
168                         
169                         m_sPatchFile = dlgPatch.m_fileResult;
170                         m_bOpenToEditor = dlgPatch.m_openToEditor;
171                         retVal = 1;
172                 }
173         }
174         dlgPatch.ClearItems();
175         return retVal;
176 }
177
178 /** 
179  * @brief Show patch options dialog and check options selected.
180  * @return TRUE if user wants to create a patch (didn't cancel dialog).
181  */
182 bool CPatchTool::ShowDialog(CPatchDlg *pDlgPatch)
183 {
184         DIFFOPTIONS diffOptions = {0};
185         PATCHOPTIONS patchOptions;
186         bool bRetVal = true;
187
188         if (pDlgPatch->DoModal() == IDOK)
189         {
190                 // There must be one filepair
191                 if (pDlgPatch->GetItemCount() < 1)
192                         bRetVal = false;
193
194                 // These two are from dropdown list - can't be wrong
195                 patchOptions.outputStyle = pDlgPatch->m_outputStyle;
196                 patchOptions.nContext = pDlgPatch->m_contextLines;
197
198                 // Checkbox - can't be wrong
199                 patchOptions.bAddCommandline = !!pDlgPatch->m_includeCmdLine;
200                 m_diffWrapper.SetPatchOptions(&patchOptions);
201
202                 // These are from checkboxes and radiobuttons - can't be wrong
203                 diffOptions.nIgnoreWhitespace = pDlgPatch->m_whitespaceCompare;
204                 diffOptions.bIgnoreBlankLines = pDlgPatch->m_ignoreBlanks;
205                 m_diffWrapper.SetAppendFiles(pDlgPatch->m_appendFile);
206
207                 // Use this because non-sensitive setting can't write
208                 // patch file EOLs correctly
209                 diffOptions.bIgnoreEol = pDlgPatch->m_ignoreEOLDifference;
210                 
211                 diffOptions.bIgnoreCase = pDlgPatch->m_caseSensitive == false;
212                 m_diffWrapper.SetOptions(&diffOptions);
213         }
214         else
215                 return false;
216
217         return bRetVal;
218 }
219
220 /** 
221  * @brief Returns filename and path for patch-file
222  */
223 String CPatchTool::GetPatchFile() const
224 {
225         return m_sPatchFile;
226 }
227
228 /** 
229  * @brief Returns TRUE if user wants to open patch file
230  * to external editor (specified in WinMerge options).
231  */
232 bool CPatchTool::GetOpenToEditor() const
233 {
234         return m_bOpenToEditor;
235 }