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  files.cpp
19  *
20  * @brief Code file routines
21  */
22 // ID line follows -- this is updated by SVN
23 // $Id: PatchTool.cpp 6858 2009-06-25 07:48:26Z kimmov $
24
25 #include "StdAfx.h"
26 #include "PatchTool.h"
27 #include "UnicodeString.h"
28 #include "DiffWrapper.h"
29 #include "PathContext.h"
30 #include "PatchDlg.h"
31 #include "paths.h"
32
33 #ifdef _DEBUG
34 #define new DEBUG_NEW
35 #undef THIS_FILE
36 static char THIS_FILE[] = __FILE__;
37 #endif
38
39 /**
40  * @brief Default constructor.
41  */
42 CPatchTool::CPatchTool() : m_bOpenToEditor(false)
43 {
44 }
45
46 /**
47  * @brief Default destructor.
48  */
49 CPatchTool::~CPatchTool()
50 {
51 }
52
53 /** 
54  * @brief Adds files to list for patching.
55  * @param [in] file1 First file to add.
56  * @param [in] file2 Second file to add.
57  */
58 void CPatchTool::AddFiles(const String &file1, const String &file2)
59 {
60         PATCHFILES files;
61         files.lfile = file1;
62         files.rfile = file2;
63
64         // TODO: Read and add file's timestamps
65         m_fileList.push_back(files);
66 }
67
68 /**
69  * @brief Add files with alternative paths.
70  * This function adds files with alternative paths. Alternative path is the
71  * one that is added to the patch file. So while @p file1 and @p file2 are
72  * paths in disk (can be temp file names), @p altPath1 and @p altPath2 are
73  * "visible " paths printed to the patch file.
74  * @param [in] file1 First path in disk.
75  * @param [in] altPath1 First path as printed to the patch file.
76  * @param [in] file2 Second path in disk.
77  * @param [in] altPath2 Second path as printed to the patch file.
78  */
79 void CPatchTool::AddFiles(const String &file1, const String &altPath1,
80                 const String &file2, const String &altPath2)
81 {
82         PATCHFILES files;
83         files.lfile = file1;
84         files.rfile = file2;
85         files.pathLeft = altPath1;
86         files.pathRight = altPath2;
87
88         // TODO: Read and add file's timestamps
89         m_fileList.push_back(files);
90 }
91
92 /** 
93  * @brief Create a patch from files given.
94  * @note Files can be given using AddFiles() or selecting using
95  * CPatchDlg.
96  */
97 int CPatchTool::CreatePatch()
98 {
99         DIFFSTATUS status;
100         bool bResult = true;
101         bool bDiffSuccess;
102         int retVal = 0;
103
104         CPatchDlg dlgPatch;
105
106         // If files already inserted, add them to dialog
107     for(std::vector<PATCHFILES>::iterator iter = m_fileList.begin(); iter != m_fileList.end(); ++iter)
108     {
109         dlgPatch.AddItem(*iter);
110         }
111
112         if (ShowDialog(&dlgPatch))
113         {
114                 if (!paths_CreateIfNeeded(paths_GetPathOnly(dlgPatch.m_fileResult)))
115                 {
116                         LangMessageBox(IDS_FOLDER_NOTEXIST, MB_OK | MB_ICONSTOP);
117                         return 0;
118                 }
119
120                 // Select patch create -mode
121                 m_diffWrapper.SetCreatePatchFile(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 = string_format_string1(_("Could not write to file %1."), 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 = 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 }