Fixed issue #2507: Support keyboard shortcuts in yes/no prompts
[TortoiseGit.git] / src / Utils / StringUtils.cpp
blobe6cbfc711b642cd0fa61859d3ea48ec1ac9207dc
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("TSVN_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))
211 return true;
216 return false;
219 bool CStringUtils::ReadStringFromTextFile(const CString& path, CString& text)
221 if (!PathFileExists(path))
222 return false;
225 CStdioFile file;
226 // w/o typeBinary for some files \r gets dropped
227 if (!file.Open(path, CFile::typeBinary | CFile::modeRead | CFile::shareDenyWrite))
228 return false;
230 CStringA filecontent;
231 UINT filelength = (UINT)file.GetLength();
232 int bytesread = (int)file.Read(filecontent.GetBuffer(filelength), filelength);
233 filecontent.ReleaseBuffer(bytesread);
234 text = CUnicodeUtils::GetUnicode(filecontent);
235 file.Close();
237 catch (CFileException* pE)
239 text.Empty();
240 pE->Delete();
242 return true;
245 #endif // #ifdef _MFC_VER
247 #if defined(CSTRING_AVAILABLE) || defined(_MFC_VER)
248 BOOL CStringUtils::WildCardMatch(const CString& wildcard, const CString& string)
250 return _tcswildcmp(wildcard, string);
253 CString CStringUtils::LinesWrap(const CString& longstring, int limit /* = 80 */, bool bCompactPaths /* = true */)
255 CString retString;
256 if ((longstring.GetLength() < limit) || (limit == 0))
257 return longstring; // no wrapping needed.
258 // now start breaking the string into lines
260 int linepos = 0;
261 int lineposold = 0;
262 CString temp;
263 while ((linepos = longstring.Find('\n', linepos)) >= 0)
265 temp = longstring.Mid(lineposold, linepos-lineposold);
266 if ((linepos+1)<longstring.GetLength())
267 ++linepos;
268 else
269 break;
270 lineposold = linepos;
271 if (!retString.IsEmpty())
272 retString += _T("\n");
273 retString += WordWrap(temp, limit, bCompactPaths, false, 4);
275 temp = longstring.Mid(lineposold);
276 if (!temp.IsEmpty())
277 retString += _T("\n");
278 retString += WordWrap(temp, limit, bCompactPaths, false, 4);
279 retString.Trim();
280 return retString;
283 CString CStringUtils::WordWrap(const CString& longstring, int limit, bool bCompactPaths, bool bForceWrap, int tabSize)
285 int nLength = longstring.GetLength();
286 CString retString;
288 if (limit < 0)
289 limit = 0;
291 int nLineStart = 0;
292 int nLineEnd = 0;
293 int tabOffset = 0;
294 for (int i = 0; i < nLength; ++i)
296 if (i-nLineStart+tabOffset >= limit)
298 if (nLineEnd == nLineStart)
300 if (bForceWrap)
301 nLineEnd = i;
302 else
304 while ((i < nLength) && (longstring[i] != ' ') && (longstring[i] != '\t'))
305 ++i;
306 nLineEnd = i;
309 if (bCompactPaths)
311 CString longline = longstring.Mid(nLineStart, nLineEnd-nLineStart).Left(MAX_PATH-1);
312 if ((bCompactPaths)&&(longline.GetLength() < MAX_PATH))
314 if (((!PathIsFileSpec(longline))&&longline.Find(':')<3)||(PathIsURL(longline)))
316 TCHAR buf[MAX_PATH] = {0};
317 PathCompactPathEx(buf, longline, limit+1, 0);
318 longline = buf;
321 retString += longline;
323 else
324 retString += longstring.Mid(nLineStart, nLineEnd-nLineStart);
325 retString += L"\n";
326 tabOffset = 0;
327 nLineStart = nLineEnd;
329 if (longstring[i] == ' ')
330 nLineEnd = i;
331 if (longstring[i] == '\t')
333 tabOffset += (tabSize - i % tabSize);
334 nLineEnd = i;
337 if (bCompactPaths)
339 CString longline = longstring.Mid(nLineStart).Left(MAX_PATH-1);
340 if ((bCompactPaths)&&(longline.GetLength() < MAX_PATH))
342 if (((!PathIsFileSpec(longline))&&longline.Find(':')<3)||(PathIsURL(longline)))
344 TCHAR buf[MAX_PATH] = {0};
345 PathCompactPathEx(buf, longline, limit+1, 0);
346 longline = buf;
349 retString += longline;
351 else
352 retString += longstring.Mid(nLineStart);
354 return retString;
356 int CStringUtils::GetMatchingLength (const CString& lhs, const CString& rhs)
358 int lhsLength = lhs.GetLength();
359 int rhsLength = rhs.GetLength();
360 int maxResult = min (lhsLength, rhsLength);
362 LPCTSTR pLhs = lhs;
363 LPCTSTR pRhs = rhs;
365 for (int i = 0; i < maxResult; ++i)
366 if (pLhs[i] != pRhs[i])
367 return i;
369 return maxResult;
372 int CStringUtils::FastCompareNoCase (const CStringW& lhs, const CStringW& rhs)
374 // attempt latin-only comparison
376 INT_PTR count = min (lhs.GetLength(), rhs.GetLength()+1);
377 const wchar_t* left = lhs;
378 const wchar_t* right = rhs;
379 for (const wchar_t* last = left + count+1; left < last; ++left, ++right)
381 int leftChar = *left;
382 int rightChar = *right;
384 int diff = leftChar - rightChar;
385 if (diff != 0)
387 // case-sensitive comparison found a difference
389 if ((leftChar | rightChar) >= 0x80)
391 // non-latin char -> fall back to CRT code
392 // (full comparison required as we might have
393 // skipped special chars / UTF plane selectors)
395 return _wcsicmp (lhs, rhs);
398 // normalize to lower case
400 if ((leftChar >= 'A') && (leftChar <= 'Z'))
401 leftChar += 'a' - 'A';
402 if ((rightChar >= 'A') && (rightChar <= 'Z'))
403 rightChar += 'a' - 'A';
405 // compare again
407 diff = leftChar - rightChar;
408 if (diff != 0)
409 return diff;
413 // must be equal (both ended with a 0)
415 return 0;
417 #endif // #if defined(CSTRING_AVAILABLE) || defined(_MFC_VER)
419 bool CStringUtils::WriteStringToTextFile(const std::wstring& path, const std::wstring& text, bool bUTF8 /* = true */)
421 DWORD dwWritten = 0;
422 CAutoFile hFile = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
423 if (!hFile)
424 return false;
426 if (bUTF8)
428 std::string buf = CUnicodeUtils::StdGetUTF8(text);
429 if (!WriteFile(hFile, buf.c_str(), (DWORD)buf.length(), &dwWritten, NULL))
431 return false;
434 else
436 if (!WriteFile(hFile, text.c_str(), (DWORD)text.length(), &dwWritten, NULL))
438 return false;
441 return true;
444 inline static void PipeToNull(TCHAR* ptr)
446 if (*ptr == '|')
447 *ptr = '\0';
450 void CStringUtils::PipesToNulls(TCHAR* buffer, size_t length)
452 TCHAR* ptr = buffer + length;
453 while (ptr != buffer)
455 PipeToNull(ptr);
456 ptr--;
460 void CStringUtils::PipesToNulls(TCHAR* buffer)
462 TCHAR* ptr = buffer;
463 while (*ptr != 0)
465 PipeToNull(ptr);
466 ++ptr;