OSDN Git Service

Improve plugin system (#797)
[winmerge-jp/winmerge-jp.git] / Plugins / src_VCPP / IgnoreColumns / WinMergeScript.cpp
1 // WinMergeScript.cpp : Implementation of CWinMergeScript
2 #include "stdafx.h"
3 #include "IgnoreColumns.h"
4 #include "WinMergeScript.h"
5 #include "resource.h"
6 #include <atlstr.h>
7
8 /////////////////////////////////////////////////////////////////////////////
9 // CWinMergeScript
10
11 /** 
12  * @brief Get the name of the current dll
13  */
14 LPTSTR GetDllFilename(LPTSTR name, int len)
15 {
16         // careful for the last char, the doc does not give this detail
17         name[len] = 0;
18         GetModuleFileName(_Module.GetModuleInstance(), name, len-1);
19         // find last backslash
20         TCHAR * lastslash = _tcsrchr(name, '/');
21         if (lastslash == 0)             
22                 lastslash = name;
23         else
24                 lastslash ++;
25         TCHAR * lastslash2 = _tcsrchr(lastslash, '\\');
26         if (lastslash2 == 0)            
27                 lastslash2 = name;
28         else
29                 lastslash2 ++;
30         if (lastslash2 != name)
31                 lstrcpy(name, lastslash2);
32         return name;
33 }
34
35 CString KeyName()
36 {
37         TCHAR szKeyName[256];
38         TCHAR name[256+1];
39         GetDllFilename(name, 256);
40         lstrcpy(szKeyName, _T("Software\\Thingamahoochie\\WinMerge\\Plugins\\"));
41         lstrcat(szKeyName, name);
42         return szKeyName;
43 }
44
45 CString RegReadString(const CString& key, const CString& valuename, const CString& defaultValue)
46 {
47         CRegKey reg;
48         if (reg.Open(HKEY_CURRENT_USER, key, KEY_READ) == ERROR_SUCCESS)
49         {
50                 TCHAR value[512] = {0};
51                 DWORD dwSize = sizeof(value) / sizeof(value[0]);
52                 reg.QueryStringValue(valuename, value, &dwSize);
53                 return value;
54         }
55         return defaultValue;
56 }
57
58 int CreateArrayFromRangeString(const TCHAR *rangestr, int (* value)[2])
59 {
60         TCHAR name[256];
61
62         lstrcpy(name, rangestr);
63
64         if (name[0] == 0)
65                 return 0;
66
67         // first pass : prepare the chunks
68         int nValue = 0;
69         TCHAR * token = _tcstok(name, _T(",_"));
70         while( token != NULL )
71         {
72                 nValue ++;
73                 /* Get next token: */
74                 token = _tcstok( NULL, _T(",_") );
75         }
76
77         if (value == 0)
78                 // just return the number of values
79                 return nValue;
80
81         token = name;
82         int i;
83         for (i = 0 ; i < nValue ; i++)
84         {
85                 value[i][0] = _tcstol(token, &token, 10);
86                 while (*token != 0 && !_istdigit(*token))
87                         token ++;
88                 if (token[0] == 0)
89                 {
90                         value[i][1] = value[i][0];
91                 }
92                 else
93                 {
94                         value[i][1] = _tcstol(token, &token, 10);
95                 }
96                 token = token + _tcslen(token) + 1;
97         }
98
99         return nValue;
100 }
101
102 CString CreateRangeStringFromArray(int nExcludedRanges, const int aExcludedRanges[][2])
103 {
104         CString rangestr = _T("");
105         for (int i = 0; i < nExcludedRanges; ++i)
106         {
107                 TCHAR value[256];
108                 if (aExcludedRanges[i][0] > 0 && aExcludedRanges[i][1] > 0)
109                 {
110                         if (aExcludedRanges[i][0] == aExcludedRanges[i][1])
111                         {
112                                 wsprintf(value, _T("%d"), aExcludedRanges[i][0]);
113                                 rangestr += value;
114                         }
115                         else
116                         {
117                                 wsprintf(value, _T("%d-%d"), aExcludedRanges[i][0], aExcludedRanges[i][1]);
118                                 rangestr += value;
119                         }
120                         rangestr += _T(",");
121                 }
122         }
123         if (!rangestr.IsEmpty())
124                 rangestr.Delete(rangestr.GetLength() - 1);
125
126         return rangestr;
127 }
128
129 CString GetColumnRangeString()
130 {
131         TCHAR name[256+1];
132         GetDllFilename(name, 256);
133         CString rangestr;
134         TCHAR * token = _tcspbrk(name, _T(",_"));
135         if (!token)
136                 rangestr = RegReadString(KeyName(), _T("ColumnRanges"), _T(""));
137         else
138                 rangestr = token + 1;
139         
140         int nExcludedRanges = CreateArrayFromRangeString(rangestr, NULL);
141         int (* aExcludedRanges)[2] = new int[nExcludedRanges][2];
142         if (aExcludedRanges == NULL)
143                 nExcludedRanges = 0;
144         else
145                 nExcludedRanges = CreateArrayFromRangeString(rangestr, aExcludedRanges);
146
147         rangestr = CreateRangeStringFromArray(nExcludedRanges, aExcludedRanges);
148
149         delete[] aExcludedRanges;
150
151         return rangestr;
152 }
153
154
155 STDMETHODIMP CWinMergeScript::get_PluginEvent(BSTR *pVal)
156 {
157         *pVal = SysAllocString(L"BUFFER_PREDIFF");
158         return S_OK;
159 }
160
161 STDMETHODIMP CWinMergeScript::get_PluginDescription(BSTR *pVal)
162 {
163         *pVal = SysAllocString(L"Ignore some columns - ignored columns list from the plugin name or the plugin argument");
164         return S_OK;
165 }
166
167 STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR *pVal)
168 {
169         *pVal = SysAllocString(L"\\.txt$");
170         return S_OK;
171 }
172
173 STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL *pVal)
174 {
175         *pVal = VARIANT_TRUE;
176         return S_OK;
177 }
178
179 STDMETHODIMP CWinMergeScript::get_PluginArguments(BSTR *pVal)
180 {
181         *pVal = m_bstrArguments.Copy();
182         return S_OK;
183 }
184
185 STDMETHODIMP CWinMergeScript::put_PluginArguments(BSTR val)
186 {
187         m_bstrArguments = val;
188         return S_OK;
189 }
190
191 STDMETHODIMP CWinMergeScript::get_PluginExtendedProperties(BSTR *pVal)
192 {
193         *pVal = SysAllocString(L"MenuCaption=Ignore Columns");
194         return S_OK;
195 }
196
197 STDMETHODIMP CWinMergeScript::PrediffBufferW(BSTR *pText, INT *pSize, VARIANT_BOOL *pbChanged, VARIANT_BOOL *pbHandled)
198 {
199         WCHAR * pBeginText = *pText;
200         long nSize = *pSize;
201         WCHAR * pEndText = pBeginText + nSize;
202
203         int argc = 0;
204         wchar_t **argv = CommandLineToArgvW(m_bstrArguments.m_str, &argc);
205         CString rangestr = (argc > 0) ? argv[0] : GetColumnRangeString();
206         if (argv)
207                 LocalFree(argv);
208
209         int nExcludedRanges = CreateArrayFromRangeString(rangestr, NULL);
210         int (* aExcludedRanges)[2] = new int[nExcludedRanges][2];
211         if (aExcludedRanges == NULL)
212                 nExcludedRanges = 0;
213         else
214                 nExcludedRanges = CreateArrayFromRangeString(rangestr, aExcludedRanges);
215
216         if (nExcludedRanges == 0)
217         {
218                 *pbChanged = VARIANT_FALSE;
219                 *pbHandled = VARIANT_TRUE;
220                 return S_OK;
221         }
222
223         // character position begins at 1 for user, but at 0 here
224         int i;
225         for (i = 0 ; i < nExcludedRanges ; i++)
226         {
227                 aExcludedRanges[i][0] --;
228                 aExcludedRanges[i][1] --;
229         }
230
231
232         WCHAR * pDst = pBeginText;
233         WCHAR * zoneBegin;
234         WCHAR * lineBegin;
235
236         for (zoneBegin = lineBegin = pBeginText; lineBegin < pEndText ; lineBegin = zoneBegin)
237         {
238                 // next excluded range in the current line
239                 int nextExcludedRange;
240                 for (nextExcludedRange = 0 ; nextExcludedRange < nExcludedRanges ; nextExcludedRange ++)
241                 {
242                         // look for the end of the included zone
243                         WCHAR * zoneEnd = zoneBegin;
244                         WCHAR * zoneMaxEnd = lineBegin + aExcludedRanges[nextExcludedRange][0];
245                         while (zoneEnd < pEndText && zoneEnd < zoneMaxEnd &&
246                                         *zoneEnd != L'\n' && *zoneEnd != L'\r')
247                                 zoneEnd ++;
248
249                         // copy the characters of included columns
250                         wcsncpy(pDst, zoneBegin, zoneEnd - zoneBegin);
251                         pDst += zoneEnd - zoneBegin;
252
253                         // advance the cursor
254                         zoneBegin = zoneEnd;
255
256                         if (zoneEnd < zoneMaxEnd)
257                                 break;
258
259                         // look for the end of the excluded zone
260                         zoneEnd = zoneBegin;
261                         zoneMaxEnd = lineBegin + aExcludedRanges[nextExcludedRange][1] + 1;
262                         while (zoneEnd < pEndText && zoneEnd < zoneMaxEnd &&
263                                         *zoneEnd != L'\n' && *zoneEnd != L'\r')
264                                 zoneEnd ++;
265
266                         // advance the cursor
267                         zoneBegin = zoneEnd;
268
269                         if (zoneEnd < zoneMaxEnd)
270                                 break;
271                 }
272
273                 if (nextExcludedRange == nExcludedRanges)
274                 {
275                         // treat the trailing included zone
276
277                         // look for the end of the included zone
278                         WCHAR * zoneEnd = zoneBegin;
279                         while (zoneEnd < pEndText &&
280                                         *zoneEnd != L'\n' && *zoneEnd != L'\r')
281                                 zoneEnd ++;
282
283                         // copy the characters of included columns
284                         wcsncpy(pDst, zoneBegin, zoneEnd - zoneBegin);
285                         pDst += zoneEnd - zoneBegin;
286
287                         // advance the cursor
288                         zoneBegin = zoneEnd;
289                 }
290                 
291                 // keep possible EOL characters 
292                 WCHAR * eolEnd = zoneBegin;
293                 while (eolEnd < pEndText && 
294                           (*eolEnd == L'\n' || *eolEnd == L'\r'))
295                 {
296                         eolEnd ++;
297                 }
298
299                 if (eolEnd > zoneBegin)
300                 {
301                         // copy the EOL characters
302                         wcsncpy(pDst, zoneBegin, eolEnd - zoneBegin);
303                         pDst += eolEnd - zoneBegin;
304                         // advance the cursor
305                         zoneBegin = eolEnd;
306                 }
307
308         }
309
310
311         delete [] aExcludedRanges;
312
313         // set the new size
314         *pSize = pDst - pBeginText;
315
316         if (*pSize == nSize)
317                 *pbChanged = VARIANT_FALSE;
318         else
319                 *pbChanged = VARIANT_TRUE;
320
321         *pbHandled = VARIANT_TRUE;
322         return S_OK;
323 }
324
325 INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
326 {
327         switch(uiMsg) {
328         case WM_INITDIALOG:
329                 SetDlgItemText(hWnd, IDC_EDIT1, GetColumnRangeString());
330                 return TRUE;
331
332         case WM_COMMAND:
333                 if (LOWORD(wParam) == IDOK)
334                 {
335                         CRegKey reg;
336                         if (reg.Create(HKEY_CURRENT_USER, KeyName(), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE) != ERROR_SUCCESS)
337                                 return FALSE;
338                         TCHAR value[512] = {0};
339                         GetDlgItemText(hWnd, IDC_EDIT1, value, sizeof(value)/sizeof(TCHAR));
340                         reg.SetStringValue(_T("ColumnRanges"), value);
341                         EndDialog(hWnd, IDOK);
342                 }
343                 else if (LOWORD(wParam) == IDCANCEL)
344                 {
345                         EndDialog(hWnd, IDCANCEL);
346                 }
347                 return TRUE;
348                 break;
349
350         default:
351                 break;
352         }
353         return FALSE;
354 }
355
356 STDMETHODIMP CWinMergeScript::ShowSettingsDialog(VARIANT_BOOL *pbHandled)
357 {
358         *pbHandled = (DialogBox(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) == IDOK);
359         return S_OK;
360 }