OSDN Git Service

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