OSDN Git Service

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