OSDN Git Service

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