OSDN Git Service

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