OSDN Git Service

TGitPath Add Rename handle
[tortoisegit/TortoiseGitJp.git] / src / Git / TGitPath.cpp
1 // TortoiseGit - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseGit\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 "TGitPath.h"\r
21 #include "UnicodeUtils.h"\r
22 #include "GitAdminDir.h"\r
23 #include "PathUtils.h"\r
24 #include <regex>\r
25 #include "git.h"\r
26 #if defined(_MFC_VER)\r
27 //#include "MessageBox.h"\r
28 //#include "AppUtils.h"\r
29 #endif\r
30 \r
31 using namespace std;\r
32 extern CGit g_Git;\r
33 \r
34 CTGitPath::CTGitPath(void) :\r
35         m_bDirectoryKnown(false),\r
36         m_bIsDirectory(false),\r
37         m_bIsURL(false),\r
38         m_bURLKnown(false),\r
39         m_bHasAdminDirKnown(false),\r
40         m_bHasAdminDir(false),\r
41         m_bIsValidOnWindowsKnown(false),\r
42         m_bIsReadOnly(false),\r
43         m_bIsAdminDirKnown(false),\r
44         m_bIsAdminDir(false),\r
45         m_bExists(false),\r
46         m_bExistsKnown(false),\r
47         m_bLastWriteTimeKnown(0),\r
48         m_lastWriteTime(0),\r
49         m_customData(NULL),\r
50         m_bIsSpecialDirectoryKnown(false),\r
51         m_bIsSpecialDirectory(false)\r
52 {\r
53         m_Action=0;\r
54 }\r
55 \r
56 CTGitPath::~CTGitPath(void)\r
57 {\r
58 }\r
59 // Create a TGitPath object from an unknown path type (same as using SetFromUnknown)\r
60 CTGitPath::CTGitPath(const CString& sUnknownPath) :\r
61         m_bDirectoryKnown(false),\r
62         m_bIsDirectory(false),\r
63         m_bIsURL(false),\r
64         m_bURLKnown(false),\r
65         m_bHasAdminDirKnown(false),\r
66         m_bHasAdminDir(false),\r
67         m_bIsValidOnWindowsKnown(false),\r
68         m_bIsReadOnly(false),\r
69         m_bIsAdminDirKnown(false),\r
70         m_bIsAdminDir(false),\r
71         m_bExists(false),\r
72         m_bExistsKnown(false),\r
73         m_bLastWriteTimeKnown(0),\r
74         m_lastWriteTime(0),\r
75         m_customData(NULL),\r
76         m_bIsSpecialDirectoryKnown(false),\r
77         m_bIsSpecialDirectory(false)\r
78 {\r
79         SetFromUnknown(sUnknownPath);\r
80         m_Action=0;\r
81 }\r
82 \r
83 int CTGitPath::ParserAction(CString action)\r
84 {\r
85         action=action.TrimLeft();\r
86         TCHAR c=action.GetAt(0);\r
87         if(c == _T('M'))\r
88                 m_Action|= LOGACTIONS_MODIFIED;\r
89         if(c == _T('R'))\r
90                 m_Action|= LOGACTIONS_REPLACED;\r
91         if(c == _T('A'))\r
92                 m_Action|= LOGACTIONS_ADDED;\r
93         if(c == _T('D'))\r
94                 m_Action|= LOGACTIONS_DELETED;\r
95 \r
96         return m_Action;\r
97 }\r
98 void CTGitPath::SetFromGit(const char* pPath)\r
99 {\r
100         Reset();\r
101         if (pPath == NULL)\r
102                 return;\r
103         int len = MultiByteToWideChar(CP_UTF8, 0, pPath, -1, NULL, 0);\r
104         if (len)\r
105         {\r
106                 len = MultiByteToWideChar(CP_UTF8, 0, pPath, -1, m_sFwdslashPath.GetBuffer(len+1), len+1);\r
107                 m_sFwdslashPath.ReleaseBuffer(len-1);\r
108         }\r
109         SanitizeRootPath(m_sFwdslashPath, true);\r
110 }\r
111 \r
112 void CTGitPath::SetFromGit(const char* pPath, bool bIsDirectory)\r
113 {\r
114         SetFromGit(pPath);\r
115         m_bDirectoryKnown = true;\r
116         m_bIsDirectory = bIsDirectory;\r
117 }\r
118 \r
119 void CTGitPath::SetFromGit(const CString& sPath,CString *oldpath)\r
120 {\r
121         Reset();\r
122         m_sFwdslashPath = sPath;\r
123         SanitizeRootPath(m_sFwdslashPath, true);\r
124         if(oldpath)\r
125                 m_sOldFwdslashPath = *oldpath;\r
126 }\r
127 \r
128 void CTGitPath::SetFromWin(LPCTSTR pPath)\r
129 {\r
130         Reset();\r
131         m_sBackslashPath = pPath;\r
132         SanitizeRootPath(m_sBackslashPath, false);\r
133         ATLASSERT(m_sBackslashPath.Find('/')<0);\r
134 }\r
135 void CTGitPath::SetFromWin(const CString& sPath)\r
136 {\r
137         Reset();\r
138         m_sBackslashPath = sPath;\r
139         SanitizeRootPath(m_sBackslashPath, false);\r
140 }\r
141 void CTGitPath::SetFromWin(const CString& sPath, bool bIsDirectory)\r
142 {\r
143         Reset();\r
144         m_sBackslashPath = sPath;\r
145         m_bIsDirectory = bIsDirectory;\r
146         m_bDirectoryKnown = true;\r
147         SanitizeRootPath(m_sBackslashPath, false);\r
148 }\r
149 void CTGitPath::SetFromUnknown(const CString& sPath)\r
150 {\r
151         Reset();\r
152         // Just set whichever path we think is most likely to be used\r
153 //      GitAdminDir admin;\r
154 //      CString p;\r
155 //      if(admin.HasAdminDir(sPath,&p))\r
156 //              SetFwdslashPath(sPath.Right(sPath.GetLength()-p.GetLength()));\r
157 //      else\r
158                 SetFwdslashPath(sPath);\r
159 }\r
160 \r
161 LPCTSTR CTGitPath::GetWinPath() const\r
162 {\r
163         if(IsEmpty())\r
164         {\r
165                 return _T("");\r
166         }\r
167         if(m_sBackslashPath.IsEmpty())\r
168         {\r
169                 SetBackslashPath(m_sFwdslashPath);\r
170         }\r
171         return m_sBackslashPath;\r
172 }\r
173 // This is a temporary function, to be used during the migration to \r
174 // the path class.  Ultimately, functions consuming paths should take a CTGitPath&, not a CString\r
175 const CString& CTGitPath::GetWinPathString() const\r
176 {\r
177         if(m_sBackslashPath.IsEmpty())\r
178         {\r
179                 SetBackslashPath(m_sFwdslashPath);\r
180         }\r
181         return m_sBackslashPath;\r
182 }\r
183 \r
184 const CString& CTGitPath::GetGitPathString() const\r
185 {\r
186         if(m_sFwdslashPath.IsEmpty())\r
187         {\r
188                 SetFwdslashPath(m_sBackslashPath);\r
189         }\r
190         return m_sFwdslashPath;\r
191 }\r
192 \r
193 const CString &CTGitPath::GetGitOldPathString() const\r
194 {\r
195         return m_sOldFwdslashPath;\r
196 }\r
197 #if 0\r
198 const char* CTGitPath::GetGitApiPath(apr_pool_t *pool) const\r
199 {\r
200         // This funny-looking 'if' is to avoid a subtle problem with empty paths, whereby\r
201         // each call to GetGitApiPath returns a different pointer value.\r
202         // If you made multiple calls to GetGitApiPath on the same string, only the last\r
203         // one would give you a valid pointer to an empty string, because each \r
204         // call would invalidate the previous call's return. \r
205         if(IsEmpty())\r
206         {\r
207                 return "";\r
208         }\r
209         if(m_sFwdslashPath.IsEmpty())\r
210         {\r
211                 SetFwdslashPath(m_sBackslashPath);\r
212         }\r
213         if(m_sUTF8FwdslashPath.IsEmpty())\r
214         {\r
215                 SetUTF8FwdslashPath(m_sFwdslashPath);\r
216         }\r
217         if (svn_path_is_url(m_sUTF8FwdslashPath))\r
218         {\r
219                 m_sUTF8FwdslashPathEscaped = CPathUtils::PathEscape(m_sUTF8FwdslashPath);\r
220                 m_sUTF8FwdslashPathEscaped.Replace("file:////", "file:///\\");\r
221                 m_sUTF8FwdslashPathEscaped = svn_path_canonicalize(m_sUTF8FwdslashPathEscaped, pool);\r
222                 return m_sUTF8FwdslashPathEscaped;\r
223         }\r
224         m_sUTF8FwdslashPath = svn_path_canonicalize(m_sUTF8FwdslashPath, pool);\r
225 \r
226         return m_sUTF8FwdslashPath;\r
227 }\r
228 #endif\r
229 \r
230 const CString& CTGitPath::GetUIPathString() const\r
231 {\r
232         if (m_sUIPath.IsEmpty())\r
233         {\r
234 #if defined(_MFC_VER)\r
235                 //BUGBUG HORRIBLE!!! - CPathUtils::IsEscaped doesn't need to be MFC-only\r
236                 if (IsUrl())\r
237                 {\r
238                         m_sUIPath = CPathUtils::PathUnescape(GetGitPathString());\r
239                         m_sUIPath.Replace(_T("file:////"), _T("file:///\\"));\r
240 \r
241                 }\r
242                 else\r
243 #endif \r
244                 {\r
245                         m_sUIPath = GetWinPathString();\r
246                 }\r
247         }\r
248         return m_sUIPath;\r
249 }\r
250 \r
251 void CTGitPath::SetFwdslashPath(const CString& sPath) const\r
252 {\r
253         m_sFwdslashPath = sPath;\r
254         m_sFwdslashPath.Replace('\\', '/');\r
255 \r
256         // We don't leave a trailing /\r
257         m_sFwdslashPath.TrimRight('/'); \r
258 \r
259         SanitizeRootPath(m_sFwdslashPath, true);\r
260 \r
261         m_sFwdslashPath.Replace(_T("file:////"), _T("file:///\\"));\r
262 \r
263         m_sUTF8FwdslashPath.Empty();\r
264 }\r
265 \r
266 void CTGitPath::SetBackslashPath(const CString& sPath) const\r
267 {\r
268         m_sBackslashPath = sPath;\r
269         m_sBackslashPath.Replace('/', '\\');\r
270         m_sBackslashPath.TrimRight('\\');\r
271         SanitizeRootPath(m_sBackslashPath, false);\r
272 }\r
273 \r
274 void CTGitPath::SetUTF8FwdslashPath(const CString& sPath) const\r
275 {\r
276         m_sUTF8FwdslashPath = CUnicodeUtils::GetUTF8(sPath);\r
277 }\r
278 \r
279 void CTGitPath::SanitizeRootPath(CString& sPath, bool bIsForwardPath) const\r
280 {\r
281         // Make sure to add the trailing slash to root paths such as 'C:'\r
282         if (sPath.GetLength() == 2 && sPath[1] == ':')\r
283         {\r
284                 sPath += (bIsForwardPath) ? _T("/") : _T("\\");\r
285         }\r
286 }\r
287 \r
288 bool CTGitPath::IsUrl() const\r
289 {\r
290 #if 0\r
291         if (!m_bURLKnown)\r
292         {\r
293                 EnsureFwdslashPathSet();\r
294                 if(m_sUTF8FwdslashPath.IsEmpty())\r
295                 {\r
296                         SetUTF8FwdslashPath(m_sFwdslashPath);\r
297                 }\r
298                 m_bIsURL = !!svn_path_is_url(m_sUTF8FwdslashPath);\r
299                 m_bURLKnown = true;\r
300         }\r
301         return m_bIsURL;\r
302 #endif \r
303         return false;\r
304 }\r
305 \r
306 bool CTGitPath::IsDirectory() const\r
307 {\r
308         if(!m_bDirectoryKnown)\r
309         {\r
310                 UpdateAttributes();\r
311         }\r
312         return m_bIsDirectory;\r
313 }\r
314 \r
315 bool CTGitPath::Exists() const\r
316 {\r
317         if (!m_bExistsKnown)\r
318         {\r
319                 UpdateAttributes();\r
320         }\r
321         return m_bExists;\r
322 }\r
323 \r
324 bool CTGitPath::Delete(bool bTrash) const\r
325 {\r
326         EnsureBackslashPathSet();\r
327         ::SetFileAttributes(m_sBackslashPath, FILE_ATTRIBUTE_NORMAL);\r
328         bool bRet = false;\r
329         if (Exists())\r
330         {\r
331                 if ((bTrash)||(IsDirectory()))\r
332                 {\r
333                         TCHAR * buf = new TCHAR[m_sBackslashPath.GetLength()+2];\r
334                         _tcscpy_s(buf, m_sBackslashPath.GetLength()+2, m_sBackslashPath);\r
335                         buf[m_sBackslashPath.GetLength()] = 0;\r
336                         buf[m_sBackslashPath.GetLength()+1] = 0;\r
337                         SHFILEOPSTRUCT shop = {0};\r
338                         shop.wFunc = FO_DELETE;\r
339                         shop.pFrom = buf;\r
340                         shop.fFlags = FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;\r
341                         if (bTrash)\r
342                                 shop.fFlags |= FOF_ALLOWUNDO;\r
343                         bRet = (SHFileOperation(&shop) == 0);\r
344                         delete [] buf;\r
345                 }\r
346                 else\r
347                 {\r
348                         bRet = !!::DeleteFile(m_sBackslashPath);\r
349                 }\r
350         }\r
351         m_bExists = false;\r
352         m_bExistsKnown = true;\r
353         return bRet;\r
354 }\r
355 \r
356 __int64  CTGitPath::GetLastWriteTime() const\r
357 {\r
358         if(!m_bLastWriteTimeKnown)\r
359         {\r
360                 UpdateAttributes();\r
361         }\r
362         return m_lastWriteTime;\r
363 }\r
364 \r
365 bool CTGitPath::IsReadOnly() const\r
366 {\r
367         if(!m_bLastWriteTimeKnown)\r
368         {\r
369                 UpdateAttributes();\r
370         }\r
371         return m_bIsReadOnly;\r
372 }\r
373 \r
374 void CTGitPath::UpdateAttributes() const\r
375 {\r
376         EnsureBackslashPathSet();\r
377         WIN32_FILE_ATTRIBUTE_DATA attribs;\r
378         if(GetFileAttributesEx(m_sBackslashPath, GetFileExInfoStandard, &attribs))\r
379         {\r
380                 m_bIsDirectory = !!(attribs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
381                 m_lastWriteTime = *(__int64*)&attribs.ftLastWriteTime;\r
382                 m_bIsReadOnly = !!(attribs.dwFileAttributes & FILE_ATTRIBUTE_READONLY);\r
383                 m_bExists = true;\r
384         }\r
385         else\r
386         {\r
387                 DWORD err = GetLastError();\r
388                 if ((err == ERROR_FILE_NOT_FOUND)||(err == ERROR_PATH_NOT_FOUND)||(err == ERROR_INVALID_NAME))\r
389                 {\r
390                         m_bIsDirectory = false;\r
391                         m_lastWriteTime = 0;\r
392                         m_bExists = false;\r
393                 }\r
394                 else\r
395                 {\r
396                         m_bIsDirectory = false;\r
397                         m_lastWriteTime = 0;\r
398                         m_bExists = true;\r
399                         return;\r
400                 }\r
401         }\r
402         m_bDirectoryKnown = true;\r
403         m_bLastWriteTimeKnown = true;\r
404         m_bExistsKnown = true;\r
405 }\r
406 \r
407 \r
408 void CTGitPath::EnsureBackslashPathSet() const\r
409 {\r
410         if(m_sBackslashPath.IsEmpty())\r
411         {\r
412                 SetBackslashPath(m_sFwdslashPath);\r
413                 ATLASSERT(IsEmpty() || !m_sBackslashPath.IsEmpty());\r
414         }\r
415 }\r
416 void CTGitPath::EnsureFwdslashPathSet() const\r
417 {\r
418         if(m_sFwdslashPath.IsEmpty())\r
419         {\r
420                 SetFwdslashPath(m_sBackslashPath);\r
421                 ATLASSERT(IsEmpty() || !m_sFwdslashPath.IsEmpty());\r
422         }\r
423 }\r
424 \r
425 \r
426 // Reset all the caches\r
427 void CTGitPath::Reset()\r
428 {\r
429         m_bDirectoryKnown = false;\r
430         m_bURLKnown = false;\r
431         m_bLastWriteTimeKnown = false;\r
432         m_bHasAdminDirKnown = false;\r
433         m_bIsValidOnWindowsKnown = false;\r
434         m_bIsAdminDirKnown = false;\r
435         m_bExistsKnown = false;\r
436         m_bIsSpecialDirectoryKnown = false;\r
437         m_bIsSpecialDirectory = false;\r
438 \r
439         m_sBackslashPath.Empty();\r
440         m_sFwdslashPath.Empty();\r
441         m_sUTF8FwdslashPath.Empty();\r
442         this->m_Action=0;\r
443         this->m_StatAdd=_T("");\r
444         this->m_StatDel=_T("");\r
445         ATLASSERT(IsEmpty());\r
446 }\r
447 \r
448 CTGitPath CTGitPath::GetDirectory() const\r
449 {\r
450         if ((IsDirectory())||(!Exists()))\r
451         {\r
452                 return *this;\r
453         }\r
454         return GetContainingDirectory();\r
455 }\r
456 \r
457 CTGitPath CTGitPath::GetContainingDirectory() const\r
458 {\r
459         EnsureBackslashPathSet();\r
460 \r
461         CString sDirName = m_sBackslashPath.Left(m_sBackslashPath.ReverseFind('\\'));\r
462         if(sDirName.GetLength() == 2 && sDirName[1] == ':')\r
463         {\r
464                 // This is a root directory, which needs a trailing slash\r
465                 sDirName += '\\';\r
466                 if(sDirName == m_sBackslashPath)\r
467                 {\r
468                         // We were clearly provided with a root path to start with - we should return nothing now\r
469                         sDirName.Empty();\r
470                 }\r
471         }\r
472         if(sDirName.GetLength() == 1 && sDirName[0] == '\\')\r
473         {\r
474                 // We have an UNC path and we already are the root\r
475                 sDirName.Empty();\r
476         }\r
477         CTGitPath retVal;\r
478         retVal.SetFromWin(sDirName);\r
479         return retVal;\r
480 }\r
481 \r
482 CString CTGitPath::GetRootPathString() const\r
483 {\r
484         EnsureBackslashPathSet();\r
485         CString workingPath = m_sBackslashPath;\r
486         LPTSTR pPath = workingPath.GetBuffer(MAX_PATH);         // MAX_PATH ok here.\r
487         ATLVERIFY(::PathStripToRoot(pPath));\r
488         workingPath.ReleaseBuffer();\r
489         return workingPath;\r
490 }\r
491 \r
492 \r
493 CString CTGitPath::GetFilename() const\r
494 {\r
495         ATLASSERT(!IsDirectory());\r
496         return GetFileOrDirectoryName();\r
497 }\r
498 \r
499 CString CTGitPath::GetFileOrDirectoryName() const\r
500 {\r
501         EnsureBackslashPathSet();\r
502         return m_sBackslashPath.Mid(m_sBackslashPath.ReverseFind('\\')+1);\r
503 }\r
504 \r
505 CString CTGitPath::GetUIFileOrDirectoryName() const\r
506 {\r
507         GetUIPathString();\r
508         return m_sUIPath.Mid(m_sUIPath.ReverseFind('\\')+1);\r
509 }\r
510 \r
511 CString CTGitPath::GetFileExtension() const\r
512 {\r
513         if(!IsDirectory())\r
514         {\r
515                 EnsureBackslashPathSet();\r
516                 int dotPos = m_sBackslashPath.ReverseFind('.');\r
517                 int slashPos = m_sBackslashPath.ReverseFind('\\');\r
518                 if (dotPos > slashPos)\r
519                         return m_sBackslashPath.Mid(dotPos);\r
520         }\r
521         return CString();\r
522 }\r
523 CString CTGitPath::GetBaseFilename() const\r
524 {\r
525         int dot;\r
526         CString filename=GetFilename();\r
527         dot = filename.ReverseFind(_T('.'));\r
528         if(dot>0)\r
529                 return filename.Left(dot-1);\r
530         else\r
531                 return filename;\r
532 }\r
533 \r
534 bool CTGitPath::ArePathStringsEqual(const CString& sP1, const CString& sP2)\r
535 {\r
536         int length = sP1.GetLength();\r
537         if(length != sP2.GetLength())\r
538         {\r
539                 // Different lengths\r
540                 return false;\r
541         }\r
542         // We work from the end of the strings, because path differences\r
543         // are more likely to occur at the far end of a string\r
544         LPCTSTR pP1Start = sP1;\r
545         LPCTSTR pP1 = pP1Start+(length-1);\r
546         LPCTSTR pP2 = ((LPCTSTR)sP2)+(length-1);\r
547         while(length-- > 0)\r
548         {\r
549                 if(_totlower(*pP1--) != _totlower(*pP2--))\r
550                 {\r
551                         return false;\r
552                 }\r
553         }\r
554         return true;\r
555 }\r
556 \r
557 bool CTGitPath::ArePathStringsEqualWithCase(const CString& sP1, const CString& sP2)\r
558 {\r
559         int length = sP1.GetLength();\r
560         if(length != sP2.GetLength())\r
561         {\r
562                 // Different lengths\r
563                 return false;\r
564         }\r
565         // We work from the end of the strings, because path differences\r
566         // are more likely to occur at the far end of a string\r
567         LPCTSTR pP1Start = sP1;\r
568         LPCTSTR pP1 = pP1Start+(length-1);\r
569         LPCTSTR pP2 = ((LPCTSTR)sP2)+(length-1);\r
570         while(length-- > 0)\r
571         {\r
572                 if((*pP1--) != (*pP2--))\r
573                 {\r
574                         return false;\r
575                 }\r
576         }\r
577         return true;\r
578 }\r
579 \r
580 bool CTGitPath::IsEmpty() const\r
581 {\r
582         // Check the backward slash path first, since the chance that this\r
583         // one is set is higher. In case of a 'false' return value it's a little\r
584         // bit faster.\r
585         return m_sBackslashPath.IsEmpty() && m_sFwdslashPath.IsEmpty();\r
586 }\r
587 \r
588 // Test if both paths refer to the same item\r
589 // Ignores case and slash direction\r
590 bool CTGitPath::IsEquivalentTo(const CTGitPath& rhs) const\r
591 {\r
592         // Try and find a slash direction which avoids having to convert\r
593         // both filenames\r
594         if(!m_sBackslashPath.IsEmpty())\r
595         {\r
596                 // *We've* got a \ path - make sure that the RHS also has a \ path\r
597                 rhs.EnsureBackslashPathSet();\r
598                 return ArePathStringsEqualWithCase(m_sBackslashPath, rhs.m_sBackslashPath);\r
599         }\r
600         else\r
601         {\r
602                 // Assume we've got a fwdslash path and make sure that the RHS has one\r
603                 rhs.EnsureFwdslashPathSet();\r
604                 return ArePathStringsEqualWithCase(m_sFwdslashPath, rhs.m_sFwdslashPath);\r
605         }\r
606 }\r
607 \r
608 bool CTGitPath::IsEquivalentToWithoutCase(const CTGitPath& rhs) const\r
609 {\r
610         // Try and find a slash direction which avoids having to convert\r
611         // both filenames\r
612         if(!m_sBackslashPath.IsEmpty())\r
613         {\r
614                 // *We've* got a \ path - make sure that the RHS also has a \ path\r
615                 rhs.EnsureBackslashPathSet();\r
616                 return ArePathStringsEqual(m_sBackslashPath, rhs.m_sBackslashPath);\r
617         }\r
618         else\r
619         {\r
620                 // Assume we've got a fwdslash path and make sure that the RHS has one\r
621                 rhs.EnsureFwdslashPathSet();\r
622                 return ArePathStringsEqual(m_sFwdslashPath, rhs.m_sFwdslashPath);\r
623         }\r
624 }\r
625 \r
626 bool CTGitPath::IsAncestorOf(const CTGitPath& possibleDescendant) const\r
627 {\r
628         possibleDescendant.EnsureBackslashPathSet();\r
629         EnsureBackslashPathSet();\r
630 \r
631         bool bPathStringsEqual = ArePathStringsEqual(m_sBackslashPath, possibleDescendant.m_sBackslashPath.Left(m_sBackslashPath.GetLength()));\r
632         if (m_sBackslashPath.GetLength() >= possibleDescendant.GetWinPathString().GetLength())\r
633         {\r
634                 return bPathStringsEqual;               \r
635         }\r
636         \r
637         return (bPathStringsEqual && \r
638                         ((possibleDescendant.m_sBackslashPath[m_sBackslashPath.GetLength()] == '\\')||\r
639                         (m_sBackslashPath.GetLength()==3 && m_sBackslashPath[1]==':')));\r
640 }\r
641 \r
642 // Get a string representing the file path, optionally with a base \r
643 // section stripped off the front.\r
644 CString CTGitPath::GetDisplayString(const CTGitPath* pOptionalBasePath /* = NULL*/) const\r
645 {\r
646         EnsureFwdslashPathSet();\r
647         if(pOptionalBasePath != NULL)\r
648         {\r
649                 // Find the length of the base-path without having to do an 'ensure' on it\r
650                 int baseLength = max(pOptionalBasePath->m_sBackslashPath.GetLength(), pOptionalBasePath->m_sFwdslashPath.GetLength());\r
651 \r
652                 // Now, chop that baseLength of the front of the path\r
653                 return m_sFwdslashPath.Mid(baseLength).TrimLeft('/');\r
654         }\r
655         return m_sFwdslashPath;\r
656 }\r
657 \r
658 int CTGitPath::Compare(const CTGitPath& left, const CTGitPath& right)\r
659 {\r
660         left.EnsureBackslashPathSet();\r
661         right.EnsureBackslashPathSet();\r
662         return left.m_sBackslashPath.CompareNoCase(right.m_sBackslashPath);\r
663 }\r
664 \r
665 bool operator<(const CTGitPath& left, const CTGitPath& right)\r
666 {\r
667         return CTGitPath::Compare(left, right) < 0;\r
668 }\r
669 \r
670 bool CTGitPath::PredLeftEquivalentToRight(const CTGitPath& left, const CTGitPath& right)\r
671 {\r
672         return left.IsEquivalentTo(right);\r
673 }\r
674 \r
675 bool CTGitPath::PredLeftSameWCPathAsRight(const CTGitPath& left, const CTGitPath& right)\r
676 {\r
677         if (left.IsAdminDir() && right.IsAdminDir())\r
678         {\r
679                 CTGitPath l = left;\r
680                 CTGitPath r = right;\r
681                 do \r
682                 {\r
683                         l = l.GetContainingDirectory();\r
684                 } while(l.HasAdminDir());\r
685                 do \r
686                 {\r
687                         r = r.GetContainingDirectory();\r
688                 } while(r.HasAdminDir());\r
689                 return l.GetContainingDirectory().IsEquivalentTo(r.GetContainingDirectory());\r
690         }\r
691         return left.GetDirectory().IsEquivalentTo(right.GetDirectory());\r
692 }\r
693 \r
694 bool CTGitPath::CheckChild(const CTGitPath &parent, const CTGitPath& child)\r
695 {\r
696         return parent.IsAncestorOf(child);\r
697 }\r
698 \r
699 void CTGitPath::AppendRawString(const CString& sAppend)\r
700 {\r
701         EnsureFwdslashPathSet();\r
702         CString strCopy = m_sFwdslashPath += sAppend;\r
703         SetFromUnknown(strCopy);\r
704 }\r
705 \r
706 void CTGitPath::AppendPathString(const CString& sAppend)\r
707 {\r
708         EnsureBackslashPathSet();\r
709         CString cleanAppend(sAppend);\r
710         cleanAppend.Replace('/', '\\');\r
711         cleanAppend.TrimLeft('\\');\r
712         m_sBackslashPath.TrimRight('\\');\r
713         CString strCopy = m_sBackslashPath + _T("\\") + cleanAppend;\r
714         SetFromWin(strCopy);\r
715 }\r
716 \r
717 bool CTGitPath::HasAdminDir() const\r
718 {\r
719         if (m_bHasAdminDirKnown)\r
720                 return m_bHasAdminDir;\r
721 \r
722         EnsureBackslashPathSet();\r
723         m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory());\r
724         m_bHasAdminDirKnown = true;\r
725         return m_bHasAdminDir;\r
726 }\r
727 \r
728 bool CTGitPath::IsAdminDir() const\r
729 {\r
730         if (m_bIsAdminDirKnown)\r
731                 return m_bIsAdminDir;\r
732         \r
733         EnsureBackslashPathSet();\r
734         m_bIsAdminDir = g_GitAdminDir.IsAdminDirPath(m_sBackslashPath);\r
735         m_bIsAdminDirKnown = true;\r
736         return m_bIsAdminDir;\r
737 }\r
738 \r
739 bool CTGitPath::IsValidOnWindows() const\r
740 {\r
741         if (m_bIsValidOnWindowsKnown)\r
742                 return m_bIsValidOnWindows;\r
743 \r
744         m_bIsValidOnWindows = false;\r
745         EnsureBackslashPathSet();\r
746         CString sMatch = m_sBackslashPath + _T("\r\n");\r
747         wstring sPattern;\r
748         // the 'file://' URL is just a normal windows path:\r
749         if (sMatch.Left(7).CompareNoCase(_T("file:\\\\"))==0)\r
750         {\r
751                 sMatch = sMatch.Mid(7);\r
752                 sMatch.TrimLeft(_T("\\"));\r
753                 sPattern = _T("^(\\\\\\\\\\?\\\\)?(([a-zA-Z]:|\\\\)\\\\)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");\r
754         }\r
755         else if (IsUrl())\r
756         {\r
757                 sPattern = _T("^((http|https|svn|svn\\+ssh|file)\\:\\\\+([^\\\\@\\:]+\\:[^\\\\@\\:]+@)?\\\\[^\\\\]+(\\:\\d+)?)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<>\\. ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<>\\. ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");\r
758         }\r
759         else\r
760         {\r
761                 sPattern = _T("^(\\\\\\\\\\?\\\\)?(([a-zA-Z]:|\\\\)\\\\)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");\r
762         }\r
763 \r
764         try\r
765         {\r
766                 tr1::wregex rx(sPattern, tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);\r
767                 tr1::wsmatch match;\r
768 \r
769                 wstring rmatch = wstring((LPCTSTR)sMatch);\r
770                 if (tr1::regex_match(rmatch, match, rx))\r
771                 {\r
772                         if (wstring(match[0]).compare(sMatch)==0)\r
773                                 m_bIsValidOnWindows = true;\r
774                 }\r
775                 if (m_bIsValidOnWindows)\r
776                 {\r
777                         // now check for illegal filenames\r
778                         tr1::wregex rx2(_T("\\\\(lpt\\d|com\\d|aux|nul|prn|con)(\\\\|$)"), tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);\r
779                         rmatch = m_sBackslashPath;\r
780                         if (tr1::regex_search(rmatch, rx2, tr1::regex_constants::match_default))\r
781                                 m_bIsValidOnWindows = false;\r
782                 }\r
783         }\r
784         catch (exception) {}\r
785 \r
786         m_bIsValidOnWindowsKnown = true;\r
787         return m_bIsValidOnWindows;\r
788 }\r
789 \r
790 bool CTGitPath::IsSpecialDirectory() const\r
791 {\r
792         if (m_bIsSpecialDirectoryKnown)\r
793                 return m_bIsSpecialDirectory;\r
794 \r
795         static LPCTSTR specialDirectories[]\r
796                 = { _T("trunk"), _T("tags"), _T("branches") };\r
797 \r
798         for (int i=0 ; i<(sizeof(specialDirectories) / sizeof(specialDirectories[0])) ; ++i)\r
799         {\r
800                 CString name = GetFileOrDirectoryName();\r
801                 if (0 == name.CompareNoCase(specialDirectories[i]))\r
802                 {\r
803                         m_bIsSpecialDirectory = true;\r
804                         break;\r
805                 }\r
806         }\r
807 \r
808         m_bIsSpecialDirectoryKnown = true;\r
809 \r
810         return m_bIsSpecialDirectory;\r
811 }\r
812 \r
813 //////////////////////////////////////////////////////////////////////////\r
814 \r
815 CTGitPathList::CTGitPathList()\r
816 {\r
817 \r
818 }\r
819 \r
820 // A constructor which allows a path list to be easily built which one initial entry in\r
821 CTGitPathList::CTGitPathList(const CTGitPath& firstEntry)\r
822 {\r
823         AddPath(firstEntry);\r
824 }\r
825 int CTGitPathList::FillUnRev(int action,CTGitPathList *list)\r
826 {\r
827         int pos=0;\r
828         this->Clear();\r
829         CTGitPath path;\r
830 \r
831         int count;\r
832         if(list==NULL)\r
833                 count=1;\r
834         else\r
835                 count=list->GetCount();\r
836         for(int i=0;i<count;i++)\r
837         {       \r
838                 CString cmd;\r
839                 pos=0;\r
840                 \r
841                 CString ignored;\r
842                 if(action & CTGitPath::LOGACTIONS_IGNORE)\r
843                         ignored= _T(" --ignored");\r
844                 \r
845                 if(list==NULL)\r
846                 {\r
847                         cmd=_T("git.exe ls-files --exclude-standard --full-name --others");\r
848                         cmd+=ignored;\r
849                         \r
850                 }\r
851                 else\r
852                 {       cmd.Format(_T("git.exe ls-files --exclude-standard --full-name --others %s-- \"%s\""),\r
853                                         ignored,\r
854                                         (*list)[i].GetWinPathString());\r
855                 }\r
856                 \r
857                 CString out;\r
858                 g_Git.Run(cmd,&out);\r
859 \r
860                 CString one;\r
861                 while( pos>=0 )\r
862                 {\r
863                         one=out.Tokenize(_T("\n"),pos);\r
864                         if(!one.IsEmpty())\r
865                         {\r
866                                 //SetFromGit will clear all status\r
867                                 path.SetFromGit(one);\r
868                                 path.m_Action=action;\r
869                                 AddPath(path);\r
870                         }\r
871                 }\r
872         }\r
873         return 0;\r
874 }\r
875 int CTGitPathList::ParserFromLog(CString &log)\r
876 {\r
877         this->Clear();\r
878         int pos=0;\r
879         CString one;\r
880         CTGitPath path;\r
881         m_Action=0;\r
882         while( pos>=0 )\r
883         {\r
884                 one=log.Tokenize(_T("\n"),pos);\r
885                 path.Reset();\r
886                 if(one[0]==_T(':'))\r
887                 {\r
888                         int tabstart=0;\r
889                         int actionstart=0;\r
890                         CString pathname;\r
891                         CString action;\r
892                         one.Tokenize(_T("\t"),tabstart);\r
893                         if(tabstart >0)\r
894                         {\r
895                                 action=one.Left(tabstart);\r
896                                 actionstart=action.ReverseFind(_T(' '));\r
897                                 if(actionstart>0)\r
898                                 {\r
899                                         action=action.Right(action.GetLength()-actionstart);\r
900                                 }\r
901                                 pathname=one.Right(one.GetLength()-tabstart);\r
902                                                 \r
903                                 CTGitPath *GitPath=LookForGitPath(pathname);\r
904                                                 \r
905                                 if(GitPath)\r
906                                 {\r
907                                         this->m_Action|=GitPath->ParserAction(action);  \r
908                                                         \r
909                                 }else\r
910                                 {       \r
911                                         int ac=path.ParserAction(action);\r
912                                         if(ac & CTGitPath::LOGACTIONS_REPLACED)\r
913                                         {\r
914                                                 CString oldname;\r
915                                                 int oldnametab=pathname.Find(_T("\t"));\r
916                                                 if(oldnametab>0)\r
917                                                         path.SetFromGit(pathname.Right(pathname.GetLength()-oldnametab-1),&pathname.Left(oldnametab));\r
918                                                 else\r
919                                                 {\r
920                                                         ASSERT(FALSE);\r
921                                                         path.SetFromGit(pathname);\r
922                                                 }\r
923                                         }else\r
924                                                 path.SetFromGit(pathname);\r
925                                         path.m_Action=ac;\r
926                                         //action must be set after setfromgit. SetFromGit will clear all status. \r
927                                         this->m_Action|=ac;\r
928                                         AddPath(path);\r
929                                 }\r
930                         }\r
931                                         \r
932                 }else\r
933                 {\r
934 \r
935                         int tabstart=0;\r
936                         path.Reset();\r
937                         CString StatAdd=(one.Tokenize(_T("\t"),tabstart));\r
938                         if( tabstart< 0)\r
939                                 break;\r
940                         CString StatDel=(one.Tokenize(_T("\t"),tabstart));\r
941                         //SetFromGit will reset all context of GitRev\r
942                         one=one.Right(one.GetLength()-tabstart);\r
943                         int rename=one.Find(_T(" => "));\r
944                         if(rename>0)\r
945                         {\r
946                                 path.SetFromGit(one.Right(one.GetLength()-rename-4),&one.Left(rename));\r
947                         }else\r
948                                 path.SetFromGit(one.Right(one.GetLength()-tabstart));\r
949                                 \r
950                         CTGitPath *GitPath=LookForGitPath(path.GetGitPathString());\r
951                         if(GitPath)\r
952                         {\r
953                                 GitPath->m_StatAdd=StatAdd;\r
954                                 GitPath->m_StatDel=StatDel;\r
955                         }else\r
956                         {\r
957                                 //path.SetFromGit(pathname);\r
958                                 path.m_StatAdd=StatAdd;\r
959                                 path.m_StatDel=StatDel;\r
960                                 AddPath(path);\r
961                         }\r
962                 }\r
963 \r
964         }\r
965         return pos;\r
966 }\r
967 \r
968 void CTGitPathList::AddPath(const CTGitPath& newPath)\r
969 {\r
970         m_paths.push_back(newPath);\r
971         m_commonBaseDirectory.Reset();\r
972 }\r
973 int CTGitPathList::GetCount() const\r
974 {\r
975         return (int)m_paths.size();\r
976 }\r
977 void CTGitPathList::Clear()\r
978 {\r
979         m_paths.clear();\r
980         m_commonBaseDirectory.Reset();\r
981 }\r
982 \r
983 const CTGitPath& CTGitPathList::operator[](INT_PTR index) const\r
984 {\r
985         ATLASSERT(index >= 0 && index < (INT_PTR)m_paths.size());\r
986         return m_paths[index];\r
987 }\r
988 \r
989 bool CTGitPathList::AreAllPathsFiles() const\r
990 {\r
991         // Look through the vector for any directories - if we find them, return false\r
992         return std::find_if(m_paths.begin(), m_paths.end(), std::mem_fun_ref(&CTGitPath::IsDirectory)) == m_paths.end();\r
993 }\r
994 \r
995 \r
996 #if defined(_MFC_VER)\r
997 \r
998 bool CTGitPathList::LoadFromFile(const CTGitPath& filename)\r
999 {\r
1000         Clear();\r
1001         try\r
1002         {\r
1003                 CString strLine;\r
1004                 CStdioFile file(filename.GetWinPath(), CFile::typeBinary | CFile::modeRead | CFile::shareDenyWrite);\r
1005 \r
1006                 // for every selected file/folder\r
1007                 CTGitPath path;\r
1008                 while (file.ReadString(strLine))\r
1009                 {\r
1010                         path.SetFromUnknown(strLine);\r
1011                         AddPath(path);\r
1012                 }\r
1013                 file.Close();\r
1014         }\r
1015         catch (CFileException* pE)\r
1016         {\r
1017                 TRACE("CFileException loading target file list\n");\r
1018                 TCHAR error[10000] = {0};\r
1019                 pE->GetErrorMessage(error, 10000);\r
1020 //              CMessageBox::Show(NULL, error, _T("TortoiseGit"), MB_ICONERROR);\r
1021                 pE->Delete();\r
1022                 return false;\r
1023         }\r
1024         return true;\r
1025 }\r
1026 \r
1027 bool CTGitPathList::WriteToFile(const CString& sFilename, bool bANSI /* = false */) const\r
1028 {\r
1029         try\r
1030         {\r
1031                 if (bANSI)\r
1032                 {\r
1033                         CStdioFile file(sFilename, CFile::typeText | CFile::modeReadWrite | CFile::modeCreate);\r
1034                         PathVector::const_iterator it;\r
1035                         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1036                         {\r
1037                                 CStringA line = CStringA(it->GetGitPathString()) + '\n';\r
1038                                 file.Write(line, line.GetLength());\r
1039                         } \r
1040                         file.Close();\r
1041                 }\r
1042                 else\r
1043                 {\r
1044                         CStdioFile file(sFilename, CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);\r
1045                         PathVector::const_iterator it;\r
1046                         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1047                         {\r
1048                                 file.WriteString(it->GetGitPathString()+_T("\n"));\r
1049                         } \r
1050                         file.Close();\r
1051                 }\r
1052         }\r
1053         catch (CFileException* pE)\r
1054         {\r
1055                 TRACE("CFileException in writing temp file\n");\r
1056                 pE->Delete();\r
1057                 return false;\r
1058         }\r
1059         return true;\r
1060 }\r
1061 \r
1062 \r
1063 void CTGitPathList::LoadFromAsteriskSeparatedString(const CString& sPathString)\r
1064 {\r
1065         int pos = 0;\r
1066         CString temp;\r
1067         for(;;)\r
1068         {\r
1069                 temp = sPathString.Tokenize(_T("*"),pos);\r
1070                 if(temp.IsEmpty())\r
1071                 {\r
1072                         break;\r
1073                 }\r
1074                 AddPath(CTGitPath(CPathUtils::GetLongPathname(temp)));\r
1075         } \r
1076 }\r
1077 \r
1078 CString CTGitPathList::CreateAsteriskSeparatedString() const\r
1079 {\r
1080         CString sRet;\r
1081         PathVector::const_iterator it;\r
1082         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1083         {\r
1084                 if (!sRet.IsEmpty())\r
1085                         sRet += _T("*");\r
1086                 sRet += it->GetWinPathString();\r
1087         }\r
1088         return sRet;\r
1089 }\r
1090 #endif // _MFC_VER\r
1091 \r
1092 bool \r
1093 CTGitPathList::AreAllPathsFilesInOneDirectory() const\r
1094 {\r
1095         // Check if all the paths are files and in the same directory\r
1096         PathVector::const_iterator it;\r
1097         m_commonBaseDirectory.Reset();\r
1098         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1099         {\r
1100                 if(it->IsDirectory())\r
1101                 {\r
1102                         return false;\r
1103                 }\r
1104                 const CTGitPath& baseDirectory = it->GetDirectory();\r
1105                 if(m_commonBaseDirectory.IsEmpty())\r
1106                 {\r
1107                         m_commonBaseDirectory = baseDirectory;\r
1108                 }\r
1109                 else if(!m_commonBaseDirectory.IsEquivalentTo(baseDirectory))\r
1110                 {\r
1111                         // Different path\r
1112                         m_commonBaseDirectory.Reset();\r
1113                         return false;\r
1114                 }\r
1115         }\r
1116         return true;\r
1117 }\r
1118 \r
1119 CTGitPath CTGitPathList::GetCommonDirectory() const\r
1120 {\r
1121         if (m_commonBaseDirectory.IsEmpty())\r
1122         {\r
1123                 PathVector::const_iterator it;\r
1124                 for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1125                 {\r
1126                         const CTGitPath& baseDirectory = it->GetDirectory();\r
1127                         if(m_commonBaseDirectory.IsEmpty())\r
1128                         {\r
1129                                 m_commonBaseDirectory = baseDirectory;\r
1130                         }\r
1131                         else if(!m_commonBaseDirectory.IsEquivalentTo(baseDirectory))\r
1132                         {\r
1133                                 // Different path\r
1134                                 m_commonBaseDirectory.Reset();\r
1135                                 break;\r
1136                         }\r
1137                 }\r
1138         }\r
1139         // since we only checked strings, not paths,\r
1140         // we have to make sure now that we really return a *path* here\r
1141         PathVector::const_iterator iter;\r
1142         for(iter = m_paths.begin(); iter != m_paths.end(); ++iter)\r
1143         {\r
1144                 if (!m_commonBaseDirectory.IsAncestorOf(*iter))\r
1145                 {\r
1146                         m_commonBaseDirectory = m_commonBaseDirectory.GetContainingDirectory();\r
1147                         break;\r
1148                 }\r
1149         }       \r
1150         return m_commonBaseDirectory;\r
1151 }\r
1152 \r
1153 CTGitPath CTGitPathList::GetCommonRoot() const\r
1154 {\r
1155         PathVector::const_iterator it;\r
1156         CString sRoot, sTempRoot;\r
1157         bool bEqual = true;\r
1158 \r
1159         if (GetCount() == 1)\r
1160                 return m_paths[0];\r
1161 \r
1162         int backSlashPos = 0;\r
1163         int searchStartPos = 0;\r
1164         while (bEqual)\r
1165         {\r
1166                 for (it = m_paths.begin(); it != m_paths.end(); ++it)\r
1167                 {\r
1168                         if (backSlashPos == 0)\r
1169                         {\r
1170                                 backSlashPos = it->GetWinPathString().Find('\\', searchStartPos+1);\r
1171                                 if ((backSlashPos < 0)&&(searchStartPos != it->GetWinPathString().GetLength()))\r
1172                                         backSlashPos = it->GetWinPathString().GetLength();\r
1173                         }\r
1174                         else if (it->GetWinPathString().Find('\\', searchStartPos+1) != backSlashPos)\r
1175                         {\r
1176                                 if (it->GetWinPathString().Find('\\', searchStartPos+1) < 0)\r
1177                                 {\r
1178                                         if (it->GetWinPathString().GetLength() != backSlashPos)\r
1179                                         {\r
1180                                                 bEqual = false;\r
1181                                                 break;\r
1182                                         }\r
1183                                 }\r
1184                                 else\r
1185                                 {\r
1186                                         bEqual = false;\r
1187                                         break;\r
1188                                 }\r
1189                         }\r
1190                         if (backSlashPos < 0)\r
1191                         {\r
1192                                 bEqual = false;\r
1193                                 break;\r
1194                         }\r
1195                 }\r
1196                 if (bEqual == false)\r
1197                 {\r
1198                         if (searchStartPos)\r
1199                                 sRoot = m_paths[0].GetWinPathString().Left(searchStartPos+1);\r
1200                 }\r
1201                 else\r
1202                 {\r
1203                         searchStartPos = backSlashPos;\r
1204                 }\r
1205                 backSlashPos = 0;\r
1206         }\r
1207 \r
1208         return CTGitPath(sRoot.TrimRight('\\'));\r
1209 }\r
1210 \r
1211 void CTGitPathList::SortByPathname(bool bReverse /*= false*/)\r
1212 {\r
1213         std::sort(m_paths.begin(), m_paths.end());\r
1214         if (bReverse)\r
1215                 std::reverse(m_paths.begin(), m_paths.end());\r
1216 }\r
1217 \r
1218 void CTGitPathList::DeleteAllFiles(bool bTrash)\r
1219 {\r
1220         PathVector::const_iterator it;\r
1221         if (bTrash)\r
1222         {\r
1223                 SortByPathname();\r
1224                 CString sPaths;\r
1225                 for (it = m_paths.begin(); it != m_paths.end(); ++it)\r
1226                 {\r
1227                         if ((it->Exists())&&(!it->IsDirectory()))\r
1228                         {\r
1229                                 ::SetFileAttributes(it->GetWinPath(), FILE_ATTRIBUTE_NORMAL);\r
1230                                 sPaths += it->GetWinPath();\r
1231                                 sPaths += '\0';\r
1232                         }\r
1233                 }\r
1234                 sPaths += '\0';\r
1235                 sPaths += '\0';\r
1236                 SHFILEOPSTRUCT shop = {0};\r
1237                 shop.wFunc = FO_DELETE;\r
1238                 shop.pFrom = (LPCTSTR)sPaths;\r
1239                 shop.fFlags = FOF_ALLOWUNDO|FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;\r
1240                 SHFileOperation(&shop);\r
1241         }\r
1242         else\r
1243         {\r
1244                 for (it = m_paths.begin(); it != m_paths.end(); ++it)\r
1245                 {\r
1246                         if (!it->IsDirectory())\r
1247                         {\r
1248                                 ::SetFileAttributes(it->GetWinPath(), FILE_ATTRIBUTE_NORMAL);\r
1249                                 ::DeleteFile(it->GetWinPath());\r
1250                         }\r
1251                 }\r
1252         }\r
1253         Clear();\r
1254 }\r
1255 \r
1256 void CTGitPathList::RemoveDuplicates()\r
1257 {\r
1258         SortByPathname();\r
1259         // Remove the duplicates\r
1260         // (Unique moves them to the end of the vector, then erase chops them off)\r
1261         m_paths.erase(std::unique(m_paths.begin(), m_paths.end(), &CTGitPath::PredLeftEquivalentToRight), m_paths.end());\r
1262 }\r
1263 \r
1264 void CTGitPathList::RemoveAdminPaths()\r
1265 {\r
1266         PathVector::iterator it;\r
1267         for(it = m_paths.begin(); it != m_paths.end(); )\r
1268         {\r
1269                 if (it->IsAdminDir())\r
1270                 {\r
1271                         m_paths.erase(it);\r
1272                         it = m_paths.begin();\r
1273                 }\r
1274                 else\r
1275                         ++it;\r
1276         }\r
1277 }\r
1278 \r
1279 void CTGitPathList::RemovePath(const CTGitPath& path)\r
1280 {\r
1281         PathVector::iterator it;\r
1282         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1283         {\r
1284                 if (it->IsEquivalentTo(path))\r
1285                 {\r
1286                         m_paths.erase(it);\r
1287                         return;\r
1288                 }\r
1289         }\r
1290 }\r
1291 \r
1292 void CTGitPathList::RemoveItem(CTGitPath & path)\r
1293 {\r
1294         PathVector::iterator it;\r
1295         for(it = m_paths.begin(); it != m_paths.end(); ++it)\r
1296         {\r
1297                 if (it->GetGitPathString()==path.GetGitPathString())\r
1298                 {\r
1299                         m_paths.erase(it);\r
1300                         return;\r
1301                 }\r
1302         }\r
1303 }\r
1304 void CTGitPathList::RemoveChildren()\r
1305 {\r
1306         SortByPathname();\r
1307         m_paths.erase(std::unique(m_paths.begin(), m_paths.end(), &CTGitPath::CheckChild), m_paths.end());\r
1308 }\r
1309 \r
1310 bool CTGitPathList::IsEqual(const CTGitPathList& list)\r
1311 {\r
1312         if (list.GetCount() != GetCount())\r
1313                 return false;\r
1314         for (int i=0; i<list.GetCount(); ++i)\r
1315         {\r
1316                 if (!list[i].IsEquivalentTo(m_paths[i]))\r
1317                         return false;\r
1318         }\r
1319         return true;\r
1320 }\r
1321 \r
1322 //////////////////////////////////////////////////////////////////////////\r
1323 #if 0\r
1324 apr_array_header_t * CTGitPathList::MakePathArray (apr_pool_t *pool) const\r
1325 {\r
1326         apr_array_header_t *targets = apr_array_make (pool, GetCount(), sizeof(const char *));\r
1327 \r
1328         for(int nItem = 0; nItem < GetCount(); nItem++)\r
1329         {\r
1330                 const char * target = m_paths[nItem].GetGitApiPath(pool);\r
1331                 (*((const char **) apr_array_push (targets))) = target;\r
1332         }\r
1333 \r
1334         return targets;\r
1335 }\r
1336 #endif\r
1337 //////////////////////////////////////////////////////////////////////////\r
1338 \r
1339 #if 0\r
1340 #if defined(_DEBUG)\r
1341 // Some test cases for these classes\r
1342 static class CTGitPathTests\r
1343 {\r
1344 public:\r
1345         CTGitPathTests()\r
1346         {\r
1347                 apr_initialize();\r
1348                 pool = svn_pool_create(NULL);\r
1349                 GetDirectoryTest();\r
1350                 AdminDirTest();\r
1351                 SortTest();\r
1352                 RawAppendTest();\r
1353                 PathAppendTest();\r
1354                 RemoveDuplicatesTest();\r
1355                 RemoveChildrenTest();\r
1356                 ContainingDirectoryTest();\r
1357                 AncestorTest();\r
1358                 SubversionPathTest();\r
1359                 GetCommonRootTest();\r
1360 #if defined(_MFC_VER)\r
1361                 ValidPathAndUrlTest();\r
1362                 ListLoadingTest();\r
1363 #endif\r
1364                 apr_terminate();\r
1365         }\r
1366 \r
1367 private:\r
1368 //      apr_pool_t * pool;\r
1369         void GetDirectoryTest()\r
1370         {\r
1371                 // Bit tricky, this test, because we need to know something about the file\r
1372                 // layout on the machine which is running the test\r
1373                 TCHAR winDir[MAX_PATH+1];\r
1374                 GetWindowsDirectory(winDir, MAX_PATH);\r
1375                 CString sWinDir(winDir);\r
1376 \r
1377                 CTGitPath testPath;\r
1378                 // This is a file which we know will always be there\r
1379                 testPath.SetFromUnknown(sWinDir + _T("\\win.ini"));\r
1380                 ATLASSERT(!testPath.IsDirectory());\r
1381                 ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);\r
1382                 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() == sWinDir);\r
1383 \r
1384                 // Now do the test on the win directory itself - It's hard to be sure about the containing directory\r
1385                 // but we know it must be different to the directory itself\r
1386                 testPath.SetFromUnknown(sWinDir);\r
1387                 ATLASSERT(testPath.IsDirectory());\r
1388                 ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);\r
1389                 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() != sWinDir);\r
1390                 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString().GetLength() < sWinDir.GetLength());\r
1391 \r
1392                 // Try a root path\r
1393                 testPath.SetFromUnknown(_T("C:\\"));\r
1394                 ATLASSERT(testPath.IsDirectory());\r
1395                 ATLASSERT(testPath.GetDirectory().GetWinPathString().CompareNoCase(_T("C:\\"))==0);\r
1396                 ATLASSERT(testPath.GetContainingDirectory().IsEmpty());\r
1397                 // Try a root UNC path\r
1398                 testPath.SetFromUnknown(_T("\\MYSTATION"));\r
1399                 ATLASSERT(testPath.GetContainingDirectory().IsEmpty());\r
1400         }\r
1401 \r
1402         void AdminDirTest()\r
1403         {\r
1404                 CTGitPath testPath;\r
1405                 testPath.SetFromUnknown(_T("c:\\.svndir"));\r
1406                 ATLASSERT(!testPath.IsAdminDir());\r
1407                 testPath.SetFromUnknown(_T("c:\\test.svn"));\r
1408                 ATLASSERT(!testPath.IsAdminDir());\r
1409                 testPath.SetFromUnknown(_T("c:\\.svn"));\r
1410                 ATLASSERT(testPath.IsAdminDir());\r
1411                 testPath.SetFromUnknown(_T("c:\\.svndir\\test"));\r
1412                 ATLASSERT(!testPath.IsAdminDir());\r
1413                 testPath.SetFromUnknown(_T("c:\\.svn\\test"));\r
1414                 ATLASSERT(testPath.IsAdminDir());\r
1415                 \r
1416                 CTGitPathList pathList;\r
1417                 pathList.AddPath(CTGitPath(_T("c:\\.svndir")));\r
1418                 pathList.AddPath(CTGitPath(_T("c:\\.svn")));\r
1419                 pathList.AddPath(CTGitPath(_T("c:\\.svn\\test")));\r
1420                 pathList.AddPath(CTGitPath(_T("c:\\test")));\r
1421                 pathList.RemoveAdminPaths();\r
1422                 ATLASSERT(pathList.GetCount()==2);\r
1423                 pathList.Clear();\r
1424                 pathList.AddPath(CTGitPath(_T("c:\\test")));\r
1425                 pathList.RemoveAdminPaths();\r
1426                 ATLASSERT(pathList.GetCount()==1);\r
1427         }\r
1428         \r
1429         void SortTest()\r
1430         {\r
1431                 CTGitPathList testList;\r
1432                 CTGitPath testPath;\r
1433                 testPath.SetFromUnknown(_T("c:/Z"));\r
1434                 testList.AddPath(testPath);\r
1435                 testPath.SetFromUnknown(_T("c:/B"));\r
1436                 testList.AddPath(testPath);\r
1437                 testPath.SetFromUnknown(_T("c:\\a"));\r
1438                 testList.AddPath(testPath);\r
1439                 testPath.SetFromUnknown(_T("c:/Test"));\r
1440                 testList.AddPath(testPath);\r
1441 \r
1442                 testList.SortByPathname();\r
1443 \r
1444                 ATLASSERT(testList[0].GetWinPathString() == _T("c:\\a"));\r
1445                 ATLASSERT(testList[1].GetWinPathString() == _T("c:\\B"));\r
1446                 ATLASSERT(testList[2].GetWinPathString() == _T("c:\\Test"));\r
1447                 ATLASSERT(testList[3].GetWinPathString() == _T("c:\\Z"));\r
1448         }\r
1449 \r
1450         void RawAppendTest()\r
1451         {\r
1452                 CTGitPath testPath(_T("c:/test/"));\r
1453                 testPath.AppendRawString(_T("/Hello"));\r
1454                 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello"));\r
1455 \r
1456                 testPath.AppendRawString(_T("\\T2"));\r
1457                 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello\\T2"));\r
1458 \r
1459                 CTGitPath testFilePath(_T("C:\\windows\\win.ini"));\r
1460                 CTGitPath testBasePath(_T("c:/temp/myfile.txt"));\r
1461                 testBasePath.AppendRawString(testFilePath.GetFileExtension());\r
1462                 ATLASSERT(testBasePath.GetWinPathString() == _T("c:\\temp\\myfile.txt.ini"));\r
1463         }\r
1464 \r
1465         void PathAppendTest()\r
1466         {\r
1467                 CTGitPath testPath(_T("c:/test/"));\r
1468                 testPath.AppendPathString(_T("/Hello"));\r
1469                 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello"));\r
1470 \r
1471                 testPath.AppendPathString(_T("T2"));\r
1472                 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello\\T2"));\r
1473 \r
1474                 CTGitPath testFilePath(_T("C:\\windows\\win.ini"));\r
1475                 CTGitPath testBasePath(_T("c:/temp/myfile.txt"));\r
1476                 // You wouldn't want to do this in real life - you'd use append-raw\r
1477                 testBasePath.AppendPathString(testFilePath.GetFileExtension());\r
1478                 ATLASSERT(testBasePath.GetWinPathString() == _T("c:\\temp\\myfile.txt\\.ini"));\r
1479         }\r
1480 \r
1481         void RemoveDuplicatesTest()\r
1482         {\r
1483                 CTGitPathList list;\r
1484                 list.AddPath(CTGitPath(_T("Z")));\r
1485                 list.AddPath(CTGitPath(_T("A")));\r
1486                 list.AddPath(CTGitPath(_T("E")));\r
1487                 list.AddPath(CTGitPath(_T("E")));\r
1488 \r
1489                 ATLASSERT(list[2].IsEquivalentTo(list[3]));\r
1490                 ATLASSERT(list[2]==list[3]);\r
1491                 \r
1492                 ATLASSERT(list.GetCount() == 4);\r
1493 \r
1494                 list.RemoveDuplicates();\r
1495 \r
1496                 ATLASSERT(list.GetCount() == 3);\r
1497 \r
1498                 ATLASSERT(list[0].GetWinPathString() == _T("A"));\r
1499                 ATLASSERT(list[1].GetWinPathString().Compare(_T("E")) == 0);\r
1500                 ATLASSERT(list[2].GetWinPathString() == _T("Z"));\r
1501         }\r
1502         \r
1503         void RemoveChildrenTest()\r
1504         {\r
1505                 CTGitPathList list;\r
1506                 list.AddPath(CTGitPath(_T("c:\\test")));\r
1507                 list.AddPath(CTGitPath(_T("c:\\test\\file")));\r
1508                 list.AddPath(CTGitPath(_T("c:\\testfile")));\r
1509                 list.AddPath(CTGitPath(_T("c:\\parent")));\r
1510                 list.AddPath(CTGitPath(_T("c:\\parent\\child")));\r
1511                 list.AddPath(CTGitPath(_T("c:\\parent\\child1")));\r
1512                 list.AddPath(CTGitPath(_T("c:\\parent\\child2")));\r
1513                 \r
1514                 ATLASSERT(list.GetCount() == 7);\r
1515 \r
1516                 list.RemoveChildren();\r
1517                 \r
1518                 ATLTRACE("count = %d\n", list.GetCount());\r
1519                 ATLASSERT(list.GetCount() == 3);\r
1520 \r
1521                 list.SortByPathname();\r
1522 \r
1523                 ATLASSERT(list[0].GetWinPathString().Compare(_T("c:\\parent")) == 0);\r
1524                 ATLASSERT(list[1].GetWinPathString().Compare(_T("c:\\test")) == 0);\r
1525                 ATLASSERT(list[2].GetWinPathString().Compare(_T("c:\\testfile")) == 0);\r
1526         }\r
1527 \r
1528 #if defined(_MFC_VER)\r
1529         void ListLoadingTest()\r
1530         {\r
1531                 TCHAR buf[MAX_PATH];\r
1532                 GetCurrentDirectory(MAX_PATH, buf);\r
1533                 CString sPathList(_T("Path1*c:\\path2 with spaces and stuff*\\funnypath\\*"));\r
1534                 CTGitPathList testList;\r
1535                 testList.LoadFromAsteriskSeparatedString(sPathList);\r
1536 \r
1537                 ATLASSERT(testList.GetCount() == 3);\r
1538                 ATLASSERT(testList[0].GetWinPathString() == CString(buf) + _T("\\Path1"));\r
1539                 ATLASSERT(testList[1].GetWinPathString() == _T("c:\\path2 with spaces and stuff"));\r
1540                 ATLASSERT(testList[2].GetWinPathString() == _T("\\funnypath"));\r
1541                 \r
1542                 ATLASSERT(testList.GetCommonRoot().GetWinPathString() == _T(""));\r
1543                 testList.Clear();\r
1544                 sPathList = _T("c:\\path2 with spaces and stuff*c:\\funnypath\\*");\r
1545                 testList.LoadFromAsteriskSeparatedString(sPathList);\r
1546                 ATLASSERT(testList.GetCommonRoot().GetWinPathString() == _T("c:\\"));\r
1547         }\r
1548 #endif \r
1549 \r
1550         void ContainingDirectoryTest()\r
1551         {\r
1552 \r
1553                 CTGitPath testPath;\r
1554                 testPath.SetFromWin(_T("c:\\a\\b\\c\\d\\e"));\r
1555                 CTGitPath dir;\r
1556                 dir = testPath.GetContainingDirectory();\r
1557                 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b\\c\\d"));\r
1558                 dir = dir.GetContainingDirectory();\r
1559                 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b\\c"));\r
1560                 dir = dir.GetContainingDirectory();\r
1561                 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b"));\r
1562                 dir = dir.GetContainingDirectory();\r
1563                 ATLASSERT(dir.GetWinPathString() == _T("c:\\a"));\r
1564                 dir = dir.GetContainingDirectory();\r
1565                 ATLASSERT(dir.GetWinPathString() == _T("c:\\"));\r
1566                 dir = dir.GetContainingDirectory();\r
1567                 ATLASSERT(dir.IsEmpty());\r
1568                 ATLASSERT(dir.GetWinPathString() == _T(""));\r
1569         }\r
1570         \r
1571         void AncestorTest()\r
1572         {\r
1573                 CTGitPath testPath;\r
1574                 testPath.SetFromWin(_T("c:\\windows"));\r
1575                 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\")))==false);\r
1576                 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows"))));\r
1577                 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windowsdummy")))==false);\r
1578                 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows\\test.txt"))));\r
1579                 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows\\system32\\test.txt"))));\r
1580         }\r
1581 \r
1582         void SubversionPathTest()\r
1583         {\r
1584                 CTGitPath testPath;\r
1585                 testPath.SetFromWin(_T("c:\\"));\r
1586                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:") == 0);\r
1587                 testPath.SetFromWin(_T("c:\\folder"));\r
1588                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:/folder") == 0);\r
1589                 testPath.SetFromWin(_T("c:\\a\\b\\c\\d\\e"));\r
1590                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:/a/b/c/d/e") == 0);\r
1591                 testPath.SetFromUnknown(_T("http://testing/"));\r
1592                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing") == 0);\r
1593                 testPath.SetFromGit(NULL);\r
1594                 ATLASSERT(strlen(testPath.GetGitApiPath(pool))==0);\r
1595 #if defined(_MFC_VER)\r
1596                 testPath.SetFromUnknown(_T("http://testing again"));\r
1597                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20again") == 0);\r
1598                 testPath.SetFromUnknown(_T("http://testing%20again"));\r
1599                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20again") == 0);\r
1600                 testPath.SetFromUnknown(_T("http://testing special chars \344\366\374"));\r
1601                 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20special%20chars%20%c3%a4%c3%b6%c3%bc") == 0);          \r
1602 #endif\r
1603         }\r
1604 \r
1605         void GetCommonRootTest()\r
1606         {\r
1607                 CTGitPath pathA (_T("C:\\Development\\LogDlg.cpp"));\r
1608                 CTGitPath pathB (_T("C:\\Development\\LogDlg.h"));\r
1609                 CTGitPath pathC (_T("C:\\Development\\SomeDir\\LogDlg.h"));\r
1610                 \r
1611                 CTGitPathList list;\r
1612                 list.AddPath(pathA);\r
1613                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development\\LogDlg.cpp"))==0);\r
1614                 list.AddPath(pathB);\r
1615                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development"))==0);\r
1616                 list.AddPath(pathC);\r
1617                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development"))==0);\r
1618 #ifdef _MFC_VER\r
1619                 list.Clear();\r
1620                 CString sPathList = _T("D:\\Development\\StExBar\\StExBar\\src\\setup\\Setup64.wxs*D:\\Development\\StExBar\\StExBar\\src\\setup\\Setup.wxs*D:\\Development\\StExBar\\SKTimeStamp\\src\\setup\\Setup.wxs*D:\\Development\\StExBar\\SKTimeStamp\\src\\setup\\Setup64.wxs");\r
1621                 list.LoadFromAsteriskSeparatedString(sPathList);\r
1622                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("D:\\Development\\StExBar"))==0);\r
1623 \r
1624                 list.Clear();\r
1625                 sPathList = _T("c:\\windows\\explorer.exe*c:\\windows");\r
1626                 list.LoadFromAsteriskSeparatedString(sPathList);\r
1627                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);\r
1628 \r
1629                 list.Clear();\r
1630                 sPathList = _T("c:\\windows\\*c:\\windows");\r
1631                 list.LoadFromAsteriskSeparatedString(sPathList);\r
1632                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);\r
1633 \r
1634                 list.Clear();\r
1635                 sPathList = _T("c:\\windows\\system32*c:\\windows\\system");\r
1636                 list.LoadFromAsteriskSeparatedString(sPathList);\r
1637                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);\r
1638 \r
1639                 list.Clear();\r
1640                 sPathList = _T("c:\\windowsdummy*c:\\windows");\r
1641                 list.LoadFromAsteriskSeparatedString(sPathList);\r
1642                 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\"))==0);\r
1643 #endif\r
1644         }\r
1645         \r
1646         void ValidPathAndUrlTest()\r
1647         {\r
1648                 CTGitPath testPath;\r
1649                 testPath.SetFromWin(_T("c:\\a\\b\\c.test.txt"));\r
1650                 ATLASSERT(testPath.IsValidOnWindows());\r
1651                 testPath.SetFromWin(_T("c:\\"));\r
1652                 ATLASSERT(testPath.IsValidOnWindows());\r
1653                 testPath.SetFromWin(_T("D:\\.Net\\SpindleSearch\\"));\r
1654                 ATLASSERT(testPath.IsValidOnWindows());\r
1655                 testPath.SetFromWin(_T("c"));\r
1656                 ATLASSERT(testPath.IsValidOnWindows());\r
1657                 testPath.SetFromWin(_T("c:\\test folder\\file"));\r
1658                 ATLASSERT(testPath.IsValidOnWindows());\r
1659                 testPath.SetFromWin(_T("c:\\folder\\"));\r
1660                 ATLASSERT(testPath.IsValidOnWindows());\r
1661                 testPath.SetFromWin(_T("c:\\ext.ext.ext\\ext.ext.ext.ext"));\r
1662                 ATLASSERT(testPath.IsValidOnWindows());\r
1663                 testPath.SetFromWin(_T("c:\\.svn"));\r
1664                 ATLASSERT(testPath.IsValidOnWindows());\r
1665                 testPath.SetFromWin(_T("c:\\com\\file"));\r
1666                 ATLASSERT(testPath.IsValidOnWindows());\r
1667                 testPath.SetFromWin(_T("c:\\test\\conf"));\r
1668                 ATLASSERT(testPath.IsValidOnWindows());\r
1669                 testPath.SetFromWin(_T("c:\\LPT"));\r
1670                 ATLASSERT(testPath.IsValidOnWindows());\r
1671                 testPath.SetFromWin(_T("c:\\test\\LPT"));\r
1672                 ATLASSERT(testPath.IsValidOnWindows());\r
1673                 testPath.SetFromWin(_T("c:\\com1test"));\r
1674                 ATLASSERT(testPath.IsValidOnWindows());\r
1675                 testPath.SetFromWin(_T("\\\\?\\c:\\test\\com1test"));\r
1676                 ATLASSERT(testPath.IsValidOnWindows());\r
1677 \r
1678                 testPath.SetFromWin(_T("\\\\Share\\filename"));\r
1679                 ATLASSERT(testPath.IsValidOnWindows());\r
1680                 testPath.SetFromWin(_T("\\\\Share\\filename.extension"));\r
1681                 ATLASSERT(testPath.IsValidOnWindows());\r
1682                 testPath.SetFromWin(_T("\\\\Share\\.svn"));\r
1683                 ATLASSERT(testPath.IsValidOnWindows());\r
1684 \r
1685                 // now the negative tests\r
1686                 testPath.SetFromWin(_T("c:\\test:folder"));\r
1687                 ATLASSERT(!testPath.IsValidOnWindows());\r
1688                 testPath.SetFromWin(_T("c:\\file<name"));\r
1689                 ATLASSERT(!testPath.IsValidOnWindows());\r
1690                 testPath.SetFromWin(_T("c:\\something*else"));\r
1691                 ATLASSERT(!testPath.IsValidOnWindows());\r
1692                 testPath.SetFromWin(_T("c:\\folder\\file?nofile"));\r
1693                 ATLASSERT(!testPath.IsValidOnWindows());\r
1694                 testPath.SetFromWin(_T("c:\\ext.>ension"));\r
1695                 ATLASSERT(!testPath.IsValidOnWindows());\r
1696                 testPath.SetFromWin(_T("c:\\com1\\filename"));\r
1697                 ATLASSERT(!testPath.IsValidOnWindows());\r
1698                 testPath.SetFromWin(_T("c:\\com1"));\r
1699                 ATLASSERT(!testPath.IsValidOnWindows());\r
1700                 testPath.SetFromWin(_T("c:\\com1\\AuX"));\r
1701                 ATLASSERT(!testPath.IsValidOnWindows());\r
1702 \r
1703                 testPath.SetFromWin(_T("\\\\Share\\lpt9\\filename"));\r
1704                 ATLASSERT(!testPath.IsValidOnWindows());\r
1705                 testPath.SetFromWin(_T("\\\\Share\\prn"));\r
1706                 ATLASSERT(!testPath.IsValidOnWindows());\r
1707                 testPath.SetFromWin(_T("\\\\Share\\NUL"));\r
1708                 ATLASSERT(!testPath.IsValidOnWindows());\r
1709                 \r
1710                 // now come some URL tests\r
1711                 testPath.SetFromGit(_T("http://myserver.com/repos/trunk"));\r
1712                 ATLASSERT(testPath.IsValidOnWindows());\r
1713                 testPath.SetFromGit(_T("https://myserver.com/repos/trunk/file%20with%20spaces"));\r
1714                 ATLASSERT(testPath.IsValidOnWindows());\r
1715                 testPath.SetFromGit(_T("svn://myserver.com/repos/trunk/file with spaces"));\r
1716                 ATLASSERT(testPath.IsValidOnWindows());\r
1717                 testPath.SetFromGit(_T("svn+ssh://www.myserver.com/repos/trunk"));\r
1718                 ATLASSERT(testPath.IsValidOnWindows());\r
1719                 testPath.SetFromGit(_T("http://localhost:90/repos/trunk"));\r
1720                 ATLASSERT(testPath.IsValidOnWindows());\r
1721                 testPath.SetFromGit(_T("file:///C:/GitRepos/Tester/Proj1/tags/t2"));\r
1722                 ATLASSERT(testPath.IsValidOnWindows());\r
1723                 // and some negative URL tests\r
1724                 testPath.SetFromGit(_T("httpp://myserver.com/repos/trunk"));\r
1725                 ATLASSERT(!testPath.IsValidOnWindows());\r
1726                 testPath.SetFromGit(_T("https://myserver.com/rep:os/trunk/file%20with%20spaces"));\r
1727                 ATLASSERT(!testPath.IsValidOnWindows());\r
1728                 testPath.SetFromGit(_T("svn://myserver.com/rep<os/trunk/file with spaces"));\r
1729                 ATLASSERT(!testPath.IsValidOnWindows());\r
1730                 testPath.SetFromGit(_T("svn+ssh://www.myserver.com/repos/trunk/prn/"));\r
1731                 ATLASSERT(!testPath.IsValidOnWindows());\r
1732                 testPath.SetFromGit(_T("http://localhost:90/repos/trunk/com1"));\r
1733                 ATLASSERT(!testPath.IsValidOnWindows());\r
1734                 \r
1735         }\r
1736 \r
1737 } TGitPathTestobject;\r
1738 #endif\r
1739 #endif\r
1740 \r
1741 CTGitPath * CTGitPathList::LookForGitPath(CString path)\r
1742 {\r
1743         int i=0;\r
1744         for(i=0;i<this->GetCount();i++)\r
1745         {\r
1746                 if((*this)[i].GetGitPathString() == path )\r
1747                         return (CTGitPath*)&(*this)[i];\r
1748         }\r
1749         return NULL;\r
1750 }\r
1751 \r
1752 CString CTGitPath::GetActionName()\r
1753 {\r
1754         if(m_Action  & CTGitPath::LOGACTIONS_ADDED)\r
1755                 return _T("Added");\r
1756         if(m_Action  & CTGitPath::LOGACTIONS_DELETED)\r
1757                 return _T("Deleted");\r
1758         if(m_Action  & CTGitPath::LOGACTIONS_MODIFIED)\r
1759                 return _T("Modified");\r
1760         if(m_Action  & CTGitPath::LOGACTIONS_REPLACED)\r
1761                 return _T("Rename");\r
1762         return _T("Unknown");\r
1763 }\r
1764 \r
1765 int CTGitPathList::GetAction()\r
1766 {\r
1767         return m_Action;\r
1768 }\r