Consistently use TGIT_UNIFIEDDIFF instead of TSVN_UNIFIEDDIFF
[TortoiseGit.git] / src / Utils / StringUtils.cpp
blob2788afe23ff5ad307366bc20733241dc002f8f76
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2011, 2015 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "UnicodeUtils.h"
21 #include "StringUtils.h"
22 #include "ClipboardHelper.h"
23 #include "SmartHandle.h"
25 int strwildcmp(const char *wild, const char *string)
27 const char *cp = NULL;
28 const char *mp = NULL;
29 while ((*string) && (*wild != '*'))
31 if ((*wild != *string) && (*wild != '?'))
33 return 0;
35 ++wild;
36 ++string;
38 while (*string)
40 if (*wild == '*')
42 if (!*++wild)
44 return 1;
46 mp = wild;
47 cp = string+1;
49 else if ((*wild == *string) || (*wild == '?'))
51 ++wild;
52 ++string;
54 else
56 wild = mp;
57 string = cp++;
61 while (*wild == '*')
63 ++wild;
65 return !*wild;
68 int wcswildcmp(const wchar_t *wild, const wchar_t *string)
70 const wchar_t *cp = NULL;
71 const wchar_t *mp = NULL;
72 while ((*string) && (*wild != '*'))
74 if ((*wild != *string) && (*wild != '?'))
76 return 0;
78 ++wild;
79 ++string;
81 while (*string)
83 if (*wild == '*')
85 if (!*++wild)
87 return 1;
89 mp = wild;
90 cp = string+1;
92 else if ((*wild == *string) || (*wild == '?'))
94 ++wild;
95 ++string;
97 else
99 wild = mp;
100 string = cp++;
104 while (*wild == '*')
106 ++wild;
108 return !*wild;
111 #ifdef _MFC_VER
113 void CStringUtils::RemoveAccelerators(CString& text)
115 int pos = 0;
116 while ((pos=text.Find('&',pos))>=0)
118 if (text.GetLength() > (pos-1))
120 if (text.GetAt(pos+1)!=' ')
121 text.Delete(pos);
123 ++pos;
127 bool CStringUtils::WriteAsciiStringToClipboard(const CStringA& sClipdata, LCID lcid, HWND hOwningWnd)
129 CClipboardHelper clipboardHelper;
130 if (clipboardHelper.Open(hOwningWnd))
132 EmptyClipboard();
133 HGLOBAL hClipboardData = CClipboardHelper::GlobalAlloc(sClipdata.GetLength()+1);
134 if (hClipboardData)
136 char* pchData = (char*)GlobalLock(hClipboardData);
137 if (pchData)
139 strcpy_s(pchData, sClipdata.GetLength()+1, (LPCSTR)sClipdata);
140 GlobalUnlock(hClipboardData);
141 if (SetClipboardData(CF_TEXT, hClipboardData))
143 HANDLE hlocmem = CClipboardHelper::GlobalAlloc(sizeof(LCID));
144 if (hlocmem)
146 PLCID plcid = (PLCID)GlobalLock(hlocmem);
147 if (plcid)
149 *plcid = lcid;
150 SetClipboardData(CF_LOCALE, static_cast<HANDLE>(plcid));
152 GlobalUnlock(hlocmem);
154 return true;
159 return false;
162 bool CStringUtils::WriteAsciiStringToClipboard(const CStringW& sClipdata, HWND hOwningWnd)
164 CClipboardHelper clipboardHelper;
165 if (clipboardHelper.Open(hOwningWnd))
167 EmptyClipboard();
168 HGLOBAL hClipboardData = CClipboardHelper::GlobalAlloc((sClipdata.GetLength()+1)*sizeof(WCHAR));
169 if (hClipboardData)
171 WCHAR* pchData = (WCHAR*)GlobalLock(hClipboardData);
172 if (pchData)
174 _tcscpy_s(pchData, sClipdata.GetLength()+1, (LPCWSTR)sClipdata);
175 GlobalUnlock(hClipboardData);
176 if (SetClipboardData(CF_UNICODETEXT, hClipboardData))
178 // no need to also set CF_TEXT : the OS does this
179 // automatically.
180 return true;
185 return false;
188 bool CStringUtils::WriteDiffToClipboard(const CStringA& sClipdata, HWND hOwningWnd)
190 UINT cFormat = RegisterClipboardFormat(_T("TGIT_UNIFIEDDIFF"));
191 if (cFormat == 0)
192 return false;
193 CClipboardHelper clipboardHelper;
194 if (clipboardHelper.Open(hOwningWnd))
196 EmptyClipboard();
197 HGLOBAL hClipboardData = CClipboardHelper::GlobalAlloc(sClipdata.GetLength()+1);
198 if (hClipboardData)
200 char* pchData = (char*)GlobalLock(hClipboardData);
201 if (pchData)
203 strcpy_s(pchData, sClipdata.GetLength()+1, (LPCSTR)sClipdata);
204 GlobalUnlock(hClipboardData);
205 if (SetClipboardData(cFormat,hClipboardData)==NULL)
207 return false;
209 if (SetClipboardData(CF_TEXT, hClipboardData) == NULL)
211 return false;
213 CString sClipdataW = CUnicodeUtils::GetUnicode(sClipdata);
214 auto hClipboardDataW = CClipboardHelper::GlobalAlloc(sClipdataW.GetLength()*sizeof(wchar_t) + 1);
215 if (hClipboardDataW)
217 wchar_t* pchDataW = (wchar_t*)GlobalLock(hClipboardDataW);
218 if (pchDataW)
220 wcscpy_s(pchDataW, sClipdataW.GetLength() + 1, (LPCWSTR)sClipdataW);
221 GlobalUnlock(hClipboardDataW);
222 if (SetClipboardData(CF_UNICODETEXT, hClipboardDataW))
224 return true;
231 return false;
234 bool CStringUtils::ReadStringFromTextFile(const CString& path, CString& text)
236 if (!PathFileExists(path))
237 return false;
240 CStdioFile file;
241 // w/o typeBinary for some files \r gets dropped
242 if (!file.Open(path, CFile::typeBinary | CFile::modeRead | CFile::shareDenyWrite))
243 return false;
245 CStringA filecontent;
246 UINT filelength = (UINT)file.GetLength();
247 int bytesread = (int)file.Read(filecontent.GetBuffer(filelength), filelength);
248 filecontent.ReleaseBuffer(bytesread);
249 text = CUnicodeUtils::GetUnicode(filecontent);
250 file.Close();
252 catch (CFileException* pE)
254 text.Empty();
255 pE->Delete();
257 return true;
260 #endif // #ifdef _MFC_VER
262 #if defined(CSTRING_AVAILABLE) || defined(_MFC_VER)
263 BOOL CStringUtils::WildCardMatch(const CString& wildcard, const CString& string)
265 return _tcswildcmp(wildcard, string);
268 CString CStringUtils::LinesWrap(const CString& longstring, int limit /* = 80 */, bool bCompactPaths /* = true */)
270 CString retString;
271 if ((longstring.GetLength() < limit) || (limit == 0))
272 return longstring; // no wrapping needed.
273 // now start breaking the string into lines
275 int linepos = 0;
276 int lineposold = 0;
277 CString temp;
278 while ((linepos = longstring.Find('\n', linepos)) >= 0)
280 temp = longstring.Mid(lineposold, linepos-lineposold);
281 if ((linepos+1)<longstring.GetLength())
282 ++linepos;
283 else
284 break;
285 lineposold = linepos;
286 if (!retString.IsEmpty())
287 retString += _T("\n");
288 retString += WordWrap(temp, limit, bCompactPaths, false, 4);
290 temp = longstring.Mid(lineposold);
291 if (!temp.IsEmpty())
292 retString += _T("\n");
293 retString += WordWrap(temp, limit, bCompactPaths, false, 4);
294 retString.Trim();
295 return retString;
298 CString CStringUtils::WordWrap(const CString& longstring, int limit, bool bCompactPaths, bool bForceWrap, int tabSize)
300 int nLength = longstring.GetLength();
301 CString retString;
303 if (limit < 0)
304 limit = 0;
306 int nLineStart = 0;
307 int nLineEnd = 0;
308 int tabOffset = 0;
309 for (int i = 0; i < nLength; ++i)
311 if (i-nLineStart+tabOffset >= limit)
313 if (nLineEnd == nLineStart)
315 if (bForceWrap)
316 nLineEnd = i;
317 else
319 while ((i < nLength) && (longstring[i] != ' ') && (longstring[i] != '\t'))
320 ++i;
321 nLineEnd = i;
324 if (bCompactPaths)
326 CString longline = longstring.Mid(nLineStart, nLineEnd-nLineStart).Left(MAX_PATH-1);
327 if ((bCompactPaths)&&(longline.GetLength() < MAX_PATH))
329 if (((!PathIsFileSpec(longline))&&longline.Find(':')<3)||(PathIsURL(longline)))
331 TCHAR buf[MAX_PATH] = {0};
332 PathCompactPathEx(buf, longline, limit+1, 0);
333 longline = buf;
336 retString += longline;
338 else
339 retString += longstring.Mid(nLineStart, nLineEnd-nLineStart);
340 retString += L"\n";
341 tabOffset = 0;
342 nLineStart = nLineEnd;
344 if (longstring[i] == ' ')
345 nLineEnd = i;
346 if (longstring[i] == '\t')
348 tabOffset += (tabSize - i % tabSize);
349 nLineEnd = i;
352 if (bCompactPaths)
354 CString longline = longstring.Mid(nLineStart).Left(MAX_PATH-1);
355 if ((bCompactPaths)&&(longline.GetLength() < MAX_PATH))
357 if (((!PathIsFileSpec(longline))&&longline.Find(':')<3)||(PathIsURL(longline)))
359 TCHAR buf[MAX_PATH] = {0};
360 PathCompactPathEx(buf, longline, limit+1, 0);
361 longline = buf;
364 retString += longline;
366 else
367 retString += longstring.Mid(nLineStart);
369 return retString;
371 int CStringUtils::GetMatchingLength (const CString& lhs, const CString& rhs)
373 int lhsLength = lhs.GetLength();
374 int rhsLength = rhs.GetLength();
375 int maxResult = min (lhsLength, rhsLength);
377 LPCTSTR pLhs = lhs;
378 LPCTSTR pRhs = rhs;
380 for (int i = 0; i < maxResult; ++i)
381 if (pLhs[i] != pRhs[i])
382 return i;
384 return maxResult;
387 int CStringUtils::FastCompareNoCase (const CStringW& lhs, const CStringW& rhs)
389 // attempt latin-only comparison
391 INT_PTR count = min (lhs.GetLength(), rhs.GetLength()+1);
392 const wchar_t* left = lhs;
393 const wchar_t* right = rhs;
394 for (const wchar_t* last = left + count+1; left < last; ++left, ++right)
396 int leftChar = *left;
397 int rightChar = *right;
399 int diff = leftChar - rightChar;
400 if (diff != 0)
402 // case-sensitive comparison found a difference
404 if ((leftChar | rightChar) >= 0x80)
406 // non-latin char -> fall back to CRT code
407 // (full comparison required as we might have
408 // skipped special chars / UTF plane selectors)
410 return _wcsicmp (lhs, rhs);
413 // normalize to lower case
415 if ((leftChar >= 'A') && (leftChar <= 'Z'))
416 leftChar += 'a' - 'A';
417 if ((rightChar >= 'A') && (rightChar <= 'Z'))
418 rightChar += 'a' - 'A';
420 // compare again
422 diff = leftChar - rightChar;
423 if (diff != 0)
424 return diff;
428 // must be equal (both ended with a 0)
430 return 0;
432 #endif // #if defined(CSTRING_AVAILABLE) || defined(_MFC_VER)
434 bool CStringUtils::WriteStringToTextFile(const std::wstring& path, const std::wstring& text, bool bUTF8 /* = true */)
436 DWORD dwWritten = 0;
437 CAutoFile hFile = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
438 if (!hFile)
439 return false;
441 if (bUTF8)
443 std::string buf = CUnicodeUtils::StdGetUTF8(text);
444 if (!WriteFile(hFile, buf.c_str(), (DWORD)buf.length(), &dwWritten, NULL))
446 return false;
449 else
451 if (!WriteFile(hFile, text.c_str(), (DWORD)text.length(), &dwWritten, NULL))
453 return false;
456 return true;
459 inline static void PipeToNull(TCHAR* ptr)
461 if (*ptr == '|')
462 *ptr = '\0';
465 void CStringUtils::PipesToNulls(TCHAR* buffer, size_t length)
467 TCHAR* ptr = buffer + length;
468 while (ptr != buffer)
470 PipeToNull(ptr);
471 ptr--;
475 void CStringUtils::PipesToNulls(TCHAR* buffer)
477 TCHAR* ptr = buffer;
478 while (*ptr != 0)
480 PipeToNull(ptr);
481 ++ptr;