OSDN Git Service

bac495377081f613c2858881a70c057c61d5f73d
[winmerge-jp/winmerge-jp.git] / Plugins / src_VCPP / IgnoreFieldsComma / WinMergeScript.cpp
1 // WinMergeScript.cpp : Implementation of CWinMergeScript
2 #include "stdafx.h"
3 #include "IgnoreFieldsComma.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 fields - ignored fields list from the plugin name");
164         return S_OK;
165 }
166
167 // not used yet
168 STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR *pVal)
169 {
170         *pVal = SysAllocString(L"\\.csv$");
171         return S_OK;
172 }
173
174 // not used yet
175 STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL *pVal)
176 {
177         *pVal = VARIANT_TRUE;
178         return S_OK;
179 }
180
181 STDMETHODIMP CWinMergeScript::PrediffBufferW(BSTR *pText, INT *pSize, VARIANT_BOOL *pbChanged, VARIANT_BOOL *pbHandled)
182 {
183         WCHAR * pBeginText = *pText;
184         long nSize = *pSize;
185         WCHAR * pEndText = pBeginText + nSize;
186
187         CString rangestr = GetColumnRangeString();
188
189         int nExcludedRanges = CreateArrayFromRangeString(rangestr, NULL);
190         int (* aExcludedRanges)[2] = new int[nExcludedRanges][2];
191         if (aExcludedRanges == NULL)
192                 nExcludedRanges = 0;
193         else
194                 nExcludedRanges = CreateArrayFromRangeString(rangestr, aExcludedRanges);
195
196         if (nExcludedRanges == 0)
197         {
198                 *pbChanged = VARIANT_FALSE;
199                 *pbHandled = VARIANT_TRUE;
200                 return S_OK;
201         }
202
203         // first column is 1 for user, but is 0 here
204         int i;
205         for (i = 0 ; i < nExcludedRanges ; i++)
206         {
207                 aExcludedRanges[i][0] --;
208                 aExcludedRanges[i][1] --;
209         }
210
211
212         WCHAR * pDst = pBeginText;
213         WCHAR * columnBegin;
214
215         // change this to change the delimiter between fields
216         const WCHAR delimiter = L',';
217
218         const WCHAR quote = RegReadString(_T("Software\\Thingamahoochie\\WinMerge\\Settings"), _T("TableQuoteCharacter"), _T("\""))[0];
219         const bool allowNewlinesInQuotes =
220                 _ttoi(RegReadString(_T("Software\\Thingamahoochie\\WinMerge\\Settings"), _T("TableAllowNewlinesInQuotes"), _T("1"))) != 0;
221
222         // order of the column in the current line
223         int iColumn = 0;
224         // next excluded column range in the current line
225         int nextExcludedRange = 0;
226
227         for (columnBegin = pBeginText; columnBegin < pEndText ; )
228         {
229                 bool inQuote = false;
230                 // search for the end of the column (columnEnd = first excluded character)
231                 WCHAR * columnEnd = columnBegin;
232                 if (allowNewlinesInQuotes)
233                 {
234                         while (columnEnd < pEndText &&
235                                 !(!inQuote && (*columnEnd == L'\n' || *columnEnd == L'\r' || *columnEnd == delimiter)))
236                         {
237                                 if (*columnEnd == quote)
238                                         inQuote = !inQuote;
239                                 columnEnd++;
240                         }
241                 }
242                 else
243                 {
244                         while (columnEnd < pEndText &&
245                                 !(*columnEnd == L'\n' || *columnEnd == L'\r' || (!inQuote && *columnEnd == delimiter)))
246                         {
247                                 if (*columnEnd == quote)
248                                         inQuote = !inQuote;
249                                 columnEnd++;
250                         }
251                 }
252
253                 // determine the status of this column
254                 if (nextExcludedRange < nExcludedRanges && iColumn > aExcludedRanges[nextExcludedRange][1])
255                         nextExcludedRange ++;
256                 BOOL bIsColumnIncluded = TRUE;
257                 if (nextExcludedRange < nExcludedRanges && iColumn >= aExcludedRanges[nextExcludedRange][0])
258                         bIsColumnIncluded = FALSE;
259
260                 // copy the characters of included columns
261                 if (bIsColumnIncluded)
262                 {
263                         wcsncpy(pDst, columnBegin, columnEnd - columnBegin);
264                         pDst += columnEnd - columnBegin;
265                 }
266
267                 // advance the cursor
268                 columnBegin = columnEnd;
269
270                 // keep possible tabulation (only one)
271                 if (columnBegin < pEndText)
272                         if (*columnBegin == delimiter)
273                         {
274                                 // copy the tabulation
275                                 *pDst = delimiter;
276                                 pDst ++;
277                                 // advance the cursor
278                                 columnBegin ++;
279                                 // next column
280                                 iColumn ++;
281                         }
282
283                 // keep possible EOL characters 
284                 WCHAR * eolEnd = columnBegin;
285                 while (eolEnd < pEndText && (*eolEnd == L'\n' || *eolEnd == L'\r'))
286                 {
287                         eolEnd ++;
288                 }
289
290                 if (eolEnd > columnBegin)
291                 {
292                         // copy the EOL characters
293                         wcsncpy(pDst, columnBegin, eolEnd - columnBegin);
294                         pDst += eolEnd - columnBegin;
295                         // advance the cursor
296                         columnBegin = eolEnd;
297                         // reset the column counter
298                         iColumn = 0;
299                         nextExcludedRange = 0;
300                 }
301         }
302
303
304         delete [] aExcludedRanges;
305
306         // set the new size
307         *pSize = pDst - pBeginText;
308
309         if (*pSize == nSize)
310                 *pbChanged = VARIANT_FALSE;
311         else
312                 *pbChanged = VARIANT_TRUE;
313
314         *pbHandled = VARIANT_TRUE;
315         return S_OK;
316 }
317
318 INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
319 {
320         switch(uiMsg) {
321         case WM_INITDIALOG:
322                 SetDlgItemText(hWnd, IDC_EDIT1, GetColumnRangeString());
323                 return TRUE;
324
325         case WM_COMMAND:
326                 if (LOWORD(wParam) == IDOK)
327                 {
328                         CRegKey reg;
329                         if (reg.Create(HKEY_CURRENT_USER, KeyName(), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE) != ERROR_SUCCESS)
330                                 return FALSE;
331                         TCHAR value[512] = {0};
332                         GetDlgItemText(hWnd, IDC_EDIT1, value, sizeof(value)/sizeof(TCHAR));
333                         reg.SetStringValue(_T("ColumnRanges"), value);
334                         EndDialog(hWnd, IDOK);
335                 }
336                 else if (LOWORD(wParam) == IDCANCEL)
337                 {
338                         EndDialog(hWnd, IDCANCEL);
339                 }
340                 return TRUE;
341                 break;
342
343         default:
344                 break;
345         }
346         return FALSE;
347 }
348
349 STDMETHODIMP CWinMergeScript::ShowSettingsDialog(VARIANT_BOOL *pbHandled)
350 {
351         *pbHandled = (DialogBox(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) == IDOK);
352         return S_OK;
353 }