OSDN Git Service

Add libintl
[tortoisegit/TortoiseGitJp.git] / src / Utils / StringUtils.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "StdAfx.h"\r
20 #include "UnicodeUtils.h"\r
21 #include "stringutils.h"\r
22 \r
23 int strwildcmp(const char *wild, const char *string)\r
24 {\r
25         const char *cp = NULL;\r
26         const char *mp = NULL;\r
27         while ((*string) && (*wild != '*')) \r
28         {\r
29                 if ((*wild != *string) && (*wild != '?')) \r
30                 {\r
31                         return 0; \r
32                 }\r
33                 wild++; \r
34                 string++; \r
35         }\r
36         while (*string) \r
37         {\r
38                 if (*wild == '*') \r
39                 {\r
40                         if (!*++wild) \r
41                         {\r
42                                 return 1; \r
43                         } \r
44                         mp = wild; \r
45                         cp = string+1;\r
46                 }\r
47                 else if ((*wild == *string) || (*wild == '?')) \r
48                 {\r
49                         wild++;\r
50                         string++;\r
51                 } \r
52                 else \r
53                 {\r
54                         wild = mp;\r
55                         string = cp++;\r
56                 }\r
57         }\r
58 \r
59         while (*wild == '*') \r
60         {\r
61                 wild++;\r
62         }\r
63         return !*wild;\r
64 }\r
65 \r
66 int wcswildcmp(const wchar_t *wild, const wchar_t *string)\r
67 {\r
68         const wchar_t *cp = NULL;\r
69         const wchar_t *mp = NULL;\r
70         while ((*string) && (*wild != '*')) \r
71         {\r
72                 if ((*wild != *string) && (*wild != '?')) \r
73                 {\r
74                         return 0; \r
75                 }\r
76                 wild++; \r
77                 string++; \r
78         }\r
79         while (*string) \r
80         {\r
81                 if (*wild == '*') \r
82                 {\r
83                         if (!*++wild) \r
84                         {\r
85                                 return 1; \r
86                         } \r
87                         mp = wild; \r
88                         cp = string+1;\r
89                 }\r
90                 else if ((*wild == *string) || (*wild == '?')) \r
91                 {\r
92                         wild++;\r
93                         string++;\r
94                 } \r
95                 else \r
96                 {\r
97                         wild = mp;\r
98                         string = cp++;\r
99                 }\r
100         }\r
101 \r
102         while (*wild == '*') \r
103         {\r
104                 wild++;\r
105         }\r
106         return !*wild;\r
107 }\r
108 \r
109 #ifdef _MFC_VER\r
110 BOOL CStringUtils::WildCardMatch(const CString& wildcard, const CString& string)\r
111 {\r
112         return _tcswildcmp(wildcard, string);\r
113 }\r
114 \r
115 CString CStringUtils::LinesWrap(const CString& longstring, int limit /* = 80 */, bool bCompactPaths /* = true */)\r
116 {\r
117         CString retString;\r
118         CStringArray arWords;\r
119         if (longstring.GetLength() < limit)\r
120                 return longstring;      // no wrapping needed.\r
121         // now start breaking the string into words\r
122 \r
123         int linepos = 0;\r
124         int lineposold = 0;\r
125         CString temp;\r
126         while ((linepos = longstring.Find('\n', linepos)) >= 0)\r
127         {\r
128                 temp = longstring.Mid(lineposold, linepos-lineposold);\r
129                 if (temp.IsEmpty())\r
130                         break;\r
131                 if ((linepos+1)<longstring.GetLength())\r
132                         linepos++;\r
133                 lineposold = linepos;\r
134                 if (!retString.IsEmpty())\r
135                         retString += _T("\n");\r
136                 retString += WordWrap(temp, limit, bCompactPaths);\r
137         }\r
138         temp = longstring.Mid(lineposold);\r
139         if (!temp.IsEmpty())\r
140                 retString += _T("\n");\r
141         retString += WordWrap(temp, limit, bCompactPaths);\r
142         retString.Trim();\r
143         retString.Replace(_T("\n\n"), _T("\n"));\r
144         return retString;\r
145 }\r
146 \r
147 CString CStringUtils::WordWrap(const CString& longstring, int limit /* = 80 */, bool bCompactPaths /* = true */)\r
148 {\r
149         CString retString;\r
150         if (longstring.GetLength() < limit)\r
151                 return longstring;      // no wrapping needed.\r
152         CString temp = longstring;\r
153         while (temp.GetLength() > limit)\r
154         {\r
155                 int pos=0;\r
156                 int oldpos=0;\r
157                 while ((pos>=0)&&(temp.Find(' ', pos)<limit)&&(temp.Find(' ', pos)>0))\r
158                 {\r
159                         oldpos = pos;\r
160                         pos = temp.Find(' ', pos+1);\r
161                 }\r
162                 if (oldpos==0)\r
163                         oldpos = temp.Find(' ');\r
164                 if (pos<0)\r
165                 {\r
166                         retString += temp;\r
167                         temp.Empty();\r
168                 }\r
169                 else\r
170                 {\r
171                         CString longline = oldpos >= 0 ? temp.Left(oldpos+1) : temp;\r
172                         if ((bCompactPaths)&&(longline.GetLength() < MAX_PATH))\r
173                         {\r
174                                 if (((!PathIsFileSpec(longline))&&longline.Find(':')<3)||(PathIsURL(longline)))\r
175                                 {\r
176                                         TCHAR buf[MAX_PATH];\r
177                                         PathCompactPathEx(buf, longline, limit+1, 0);\r
178                                         longline = buf;\r
179                                 }                               \r
180                         }\r
181 \r
182                         retString += longline;\r
183                         if (oldpos >= 0)\r
184                                 temp = temp.Mid(oldpos+1);\r
185                         else\r
186                                 temp.Empty();\r
187                 }\r
188                 retString += _T("\n");\r
189                 pos = oldpos;\r
190         }\r
191         retString += temp;\r
192         retString.Trim();\r
193         return retString;\r
194 }\r
195 \r
196 void CStringUtils::RemoveAccelerators(CString& text)\r
197 {\r
198         int pos = 0;\r
199         while ((pos=text.Find('&',pos))>=0)\r
200         {\r
201                 if (text.GetLength() > (pos-1))\r
202                 {\r
203                         if (text.GetAt(pos+1)!=' ')\r
204                                 text.Delete(pos);\r
205                 }\r
206                 pos++;\r
207         }\r
208 }\r
209 \r
210 \r
211 bool CStringUtils::WriteAsciiStringToClipboard(const CStringA& sClipdata, LCID lcid, HWND hOwningWnd)\r
212 {\r
213         if (OpenClipboard(hOwningWnd))\r
214         {\r
215                 EmptyClipboard();\r
216                 HGLOBAL hClipboardData;\r
217                 hClipboardData = GlobalAlloc(GMEM_DDESHARE, sClipdata.GetLength()+1);\r
218                 if (hClipboardData)\r
219                 {\r
220                         char * pchData;\r
221                         pchData = (char*)GlobalLock(hClipboardData);\r
222                         if (pchData)\r
223                         {\r
224                                 strcpy_s(pchData, sClipdata.GetLength()+1, (LPCSTR)sClipdata);\r
225                                 if (GlobalUnlock(hClipboardData))\r
226                                 {\r
227                                         if (SetClipboardData(CF_TEXT, hClipboardData)==NULL)\r
228                                         {\r
229                                                 HANDLE hlocmem = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, sizeof(LCID));\r
230                                                 PLCID plcid = (PLCID)GlobalLock(hlocmem);\r
231                                                 *plcid = lcid;\r
232                                                 GlobalUnlock(hlocmem);\r
233                                                 SetClipboardData(CF_LOCALE, static_cast<HANDLE>(plcid));        \r
234                                                 CloseClipboard();\r
235                                                 return true;\r
236                                         }\r
237                                 }\r
238                                 else\r
239                                 {\r
240                                         CloseClipboard();\r
241                                         return false;\r
242                                 }\r
243                         }\r
244                         else\r
245                         {\r
246                                 CloseClipboard();\r
247                                 return false;\r
248                         }\r
249                 }\r
250                 else\r
251                 {\r
252                         CloseClipboard();\r
253                         return false;\r
254                 }\r
255                 CloseClipboard();\r
256                 return false;\r
257         }\r
258         return false;\r
259 }\r
260 \r
261 bool CStringUtils::WriteAsciiStringToClipboard(const CStringW& sClipdata, HWND hOwningWnd)\r
262 {\r
263         if (OpenClipboard(hOwningWnd))\r
264         {\r
265                 EmptyClipboard();\r
266                 HGLOBAL hClipboardData;\r
267                 hClipboardData = GlobalAlloc(GMEM_DDESHARE, (sClipdata.GetLength()+1)*sizeof(WCHAR));\r
268                 if (hClipboardData)\r
269                 {\r
270                         WCHAR * pchData;\r
271                         pchData = (WCHAR*)GlobalLock(hClipboardData);\r
272                         if (pchData)\r
273                         {\r
274                                 _tcscpy_s(pchData, sClipdata.GetLength()+1, (LPCWSTR)sClipdata);\r
275                                 if (GlobalUnlock(hClipboardData))\r
276                                 {\r
277                                         if (SetClipboardData(CF_UNICODETEXT, hClipboardData) != NULL)\r
278                                         {\r
279                                                 CStringA sClipdataA = CStringA(sClipdata);\r
280                                                 HGLOBAL hClipboardDataA;\r
281                                                 hClipboardDataA = GlobalAlloc(GMEM_DDESHARE, sClipdataA.GetLength()+1);\r
282                                                 if (hClipboardDataA)\r
283                                                 {\r
284                                                         char * pchDataA;\r
285                                                         pchDataA = (char*)GlobalLock(hClipboardDataA);\r
286                                                         if (pchDataA)\r
287                                                         {\r
288                                                                 strcpy_s(pchDataA, sClipdataA.GetLength()+1, (LPCSTR)sClipdataA);\r
289                                                                 if (GlobalUnlock(hClipboardDataA))\r
290                                                                 {\r
291                                                                         if (SetClipboardData(CF_TEXT, hClipboardDataA) != NULL)\r
292                                                                         {\r
293                                                                                 CloseClipboard();\r
294                                                                                 return true;\r
295                                                                         }\r
296                                                                 }\r
297                                                                 else\r
298                                                                 {\r
299                                                                         CloseClipboard();\r
300                                                                         return false;\r
301                                                                 }\r
302                                                         }\r
303                                                         else\r
304                                                         {\r
305                                                                 CloseClipboard();\r
306                                                                 return false;\r
307                                                         }\r
308                                                 }\r
309 \r
310                                                 CloseClipboard();\r
311                                                 return false;\r
312                                         }\r
313                                 }\r
314                                 else\r
315                                 {\r
316                                         CloseClipboard();\r
317                                         return false;\r
318                                 }\r
319                         }\r
320                         else\r
321                         {\r
322                                 CloseClipboard();\r
323                                 return false;\r
324                         }\r
325                 }\r
326                 else\r
327                 {\r
328                         CloseClipboard();\r
329                         return false;\r
330                 }\r
331                 CloseClipboard();\r
332                 return false;\r
333         }\r
334         return false;\r
335 }\r
336 \r
337 bool CStringUtils::WriteDiffToClipboard(const CStringA& sClipdata, HWND hOwningWnd)\r
338 {\r
339         UINT cFormat = RegisterClipboardFormat(_T("TSVN_UNIFIEDDIFF"));\r
340         if (cFormat == 0)\r
341                 return false;\r
342         if (OpenClipboard(hOwningWnd))\r
343         {\r
344                 EmptyClipboard();\r
345                 HGLOBAL hClipboardData;\r
346                 hClipboardData = GlobalAlloc(GMEM_DDESHARE, sClipdata.GetLength()+1);\r
347                 if (hClipboardData)\r
348                 {\r
349                         char * pchData;\r
350                         pchData = (char*)GlobalLock(hClipboardData);\r
351                         if (pchData)\r
352                         {\r
353                                 strcpy_s(pchData, sClipdata.GetLength()+1, (LPCSTR)sClipdata);\r
354                                 if (GlobalUnlock(hClipboardData))\r
355                                 {\r
356                                         if (SetClipboardData(cFormat,hClipboardData)==NULL)\r
357                                         {\r
358                                                 CloseClipboard();\r
359                                                 return false;\r
360                                         }\r
361                                         if (SetClipboardData(CF_TEXT,hClipboardData)==NULL)\r
362                                         {\r
363                                                 CloseClipboard();\r
364                                                 return false;\r
365                                         }\r
366                                 }\r
367                                 else\r
368                                 {\r
369                                         CloseClipboard();\r
370                                         return false;\r
371                                 }\r
372                         }\r
373                         else\r
374                         {\r
375                                 CloseClipboard();\r
376                                 return false;\r
377                         }\r
378                 }\r
379                 else\r
380                 {\r
381                         CloseClipboard();\r
382                         return false;\r
383                 }\r
384                 CloseClipboard();\r
385                 return true;\r
386         }\r
387         return false;\r
388 }\r
389 \r
390 bool CStringUtils::ReadStringFromTextFile(const CString& path, CString& text)\r
391 {\r
392         if (!PathFileExists(path))\r
393                 return false;\r
394         try\r
395         {\r
396                 CStdioFile file;\r
397                 if (!file.Open(path, CFile::modeRead | CFile::shareDenyWrite))\r
398                         return false;\r
399 \r
400                 CStringA filecontent;\r
401                 UINT filelength = (UINT)file.GetLength();\r
402                 int bytesread = (int)file.Read(filecontent.GetBuffer(filelength), filelength);\r
403                 filecontent.ReleaseBuffer(bytesread);\r
404                 text = CUnicodeUtils::GetUnicode(filecontent);\r
405                 file.Close();\r
406         } \r
407         catch (CFileException* /*pE*/)\r
408         {\r
409                 text.Empty();\r
410         }\r
411         return true;\r
412 }\r
413 \r
414 #endif // #ifdef _MFC_VER\r
415 \r
416 bool CStringUtils::WriteStringToTextFile(const std::wstring& path, const std::wstring& text, bool bUTF8 /* = true */)\r
417 {\r
418         DWORD dwWritten = 0;\r
419         HANDLE hFile = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
420         if (hFile == INVALID_HANDLE_VALUE)\r
421                 return false;\r
422 \r
423         if (bUTF8)\r
424         {\r
425                 std::string buf = CUnicodeUtils::StdGetUTF8(text);\r
426                 if (!WriteFile(hFile, buf.c_str(), buf.length(), &dwWritten, NULL))\r
427                 {\r
428                         CloseHandle(hFile);\r
429                         return false;\r
430                 }\r
431         }\r
432         else\r
433         {\r
434                 if (!WriteFile(hFile, text.c_str(), text.length(), &dwWritten, NULL))\r
435                 {\r
436                         CloseHandle(hFile);\r
437                         return false;\r
438                 }\r
439         }\r
440         CloseHandle(hFile);\r
441         return true;\r
442 }\r
443 \r
444 #define IsCharNumeric(C) (!IsCharAlpha(C) && IsCharAlphaNumeric(C))\r
445 \r
446 int CStringUtils::CompareNumerical(LPCTSTR x_str, LPCTSTR y_str)\r
447 {\r
448         LPCTSTR num_x_begin = x_str, num_y_begin = y_str;\r
449         DWORD num_x_cnt = 0, num_y_cnt = 0;\r
450         int cs_cmp_result = 2;\r
451 \r
452         // skip same chars and remember last numeric part of strings\r
453         while ((*x_str || *y_str) && CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREWIDTH, x_str, 1, y_str, 1) == 2 /* equal */ )\r
454         {\r
455                 if (IsCharNumeric(*x_str))\r
456                 {\r
457                         ++num_x_cnt;\r
458                         ++num_y_cnt;\r
459                 }\r
460                 else\r
461                 {\r
462                         num_x_begin = CharNext(x_str);\r
463                         num_y_begin = CharNext(y_str);\r
464                         num_x_cnt = 0;\r
465                         num_y_cnt = 0;\r
466                         if (cs_cmp_result == 2)\r
467                                 cs_cmp_result = CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, x_str, 1, y_str, 1);\r
468                 }\r
469                 x_str = CharNext(x_str);\r
470                 y_str = CharNext(y_str);\r
471         }\r
472 \r
473         // parse numeric part of first arg\r
474         if (num_x_cnt || IsCharNumeric(*x_str))\r
475         {\r
476                 LPCTSTR x_str_tmp = x_str;\r
477                 while (IsCharNumeric(*x_str_tmp))\r
478                 {\r
479                         ++num_x_cnt;\r
480                         x_str_tmp = CharNext(x_str_tmp);\r
481                 }\r
482 \r
483                 // parse numeric part of second arg\r
484                 if (num_y_cnt || IsCharNumeric(*y_str))\r
485                 {\r
486                         LPCTSTR y_str_tmp = y_str;\r
487                         while (IsCharNumeric(*y_str_tmp))\r
488                         {\r
489                                 ++num_y_cnt;\r
490                                 y_str_tmp = CharNext(y_str_tmp);\r
491                         }\r
492 \r
493                         DWORD num_x_cnt_with_zeros = num_x_cnt, num_y_cnt_with_zeros = num_y_cnt;\r
494 \r
495                         while (num_x_cnt < num_y_cnt)\r
496                         {\r
497                                 if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_y_begin, 1, TEXT("0"), 1) != 2 /* not equal to '0' */ )\r
498                                         return -1;\r
499                                 num_y_begin = CharNext(num_y_begin);\r
500                                 --num_y_cnt;\r
501                         }\r
502 \r
503                         while (num_x_cnt > num_y_cnt)\r
504                         {\r
505                                 if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_x_begin, 1, TEXT("0"), 1) != 2 /* not equal to '0' */ )\r
506                                         return 1;\r
507                                 num_x_begin = CharNext(num_x_begin);\r
508                                 --num_x_cnt;\r
509                         }\r
510 \r
511                         // here num_x_cnt == num_y_cnt\r
512                         int cmp_result = CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_x_begin, num_x_cnt, num_y_begin, num_y_cnt);\r
513 \r
514                         if (cmp_result != 2)\r
515                                 return cmp_result - 2;\r
516                         if (num_x_cnt_with_zeros != num_y_cnt_with_zeros)\r
517                                 return num_x_cnt_with_zeros < num_y_cnt_with_zeros ? -1 : 1;\r
518                         if (cs_cmp_result != 2)\r
519                                 return cs_cmp_result - 2;\r
520                 }\r
521         }\r
522 \r
523         // otherwise, compare literally\r
524         int cmp_result = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREWIDTH, x_str, -1, y_str, -1);\r
525         if (cmp_result != 2)\r
526                 return cmp_result - 2;\r
527         if (cs_cmp_result == 2)\r
528                 cs_cmp_result = CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, x_str, -1, y_str, -1);\r
529         return cs_cmp_result - 2;\r
530 }\r
531 \r
532 \r
533 #if defined(_DEBUG)\r
534 // Some test cases for these classes\r
535 static class StringUtilsTest\r
536 {\r
537 public:\r
538         StringUtilsTest()\r
539         {\r
540                 CString longline = _T("this is a test of how a string can be splitted into several lines");\r
541                 CString splittedline = CStringUtils::WordWrap(longline, 10);\r
542                 ATLTRACE(_T("WordWrap:\n%s\n"), splittedline);\r
543                 splittedline = CStringUtils::LinesWrap(longline, 10);\r
544                 ATLTRACE(_T("LinesWrap:\n%s\n"), splittedline);\r
545                 longline = _T("c:\\this_is_a_very_long\\path_on_windows and of course some other words added to make the line longer");\r
546                 splittedline = CStringUtils::WordWrap(longline, 10);\r
547                 ATLTRACE(_T("WordWrap:\n%s\n"), splittedline);\r
548                 splittedline = CStringUtils::LinesWrap(longline, 10);\r
549                 ATLTRACE(_T("LinesWrap:\n%s\n"), splittedline);\r
550                 longline = _T("Forced failure in https://myserver.com/a_long_url_to_split PROPFIND error");\r
551                 splittedline = CStringUtils::WordWrap(longline, 20);\r
552                 ATLTRACE(_T("WordWrap:\n%s\n"), splittedline);\r
553                 splittedline = CStringUtils::LinesWrap(longline, 20);\r
554                 ATLTRACE(_T("LinesWrap:\n%s\n"), splittedline);\r
555                 longline = _T("Forced\nfailure in https://myserver.com/a_long_url_to_split PROPFIND\nerror");\r
556                 splittedline = CStringUtils::WordWrap(longline, 40);\r
557                 ATLTRACE(_T("WordWrap:\n%s\n"), splittedline);\r
558                 splittedline = CStringUtils::LinesWrap(longline, 40);\r
559                 ATLTRACE(_T("LinesWrap:\n%s\n"), splittedline);\r
560                 longline = _T("Failed to add file\nc:\\export\\spare\\Devl-JBoss\\development\\head\\src\\something\\CoreApplication\\somethingelse\\src\\com\\yetsomthingelse\\shipper\\DAO\\ShipmentInfoDAO1.java\nc:\\export\\spare\\Devl-JBoss\\development\\head\\src\\something\\CoreApplication\\somethingelse\\src\\com\\yetsomthingelse\\shipper\\DAO\\ShipmentInfoDAO2.java");\r
561                 splittedline = CStringUtils::WordWrap(longline);\r
562                 ATLTRACE(_T("WordWrap:\n%s\n"), splittedline);\r
563                 splittedline = CStringUtils::LinesWrap(longline);\r
564                 ATLTRACE(_T("LinesWrap:\n%s\n"), splittedline);\r
565         }\r
566 } StringUtilsTest;\r
567 \r
568 #endif\r