OSDN Git Service

Build Success
authorFrank Li <lznuaa@gmail.com>
Thu, 6 Nov 2008 14:33:33 +0000 (22:33 +0800)
committerFrank Li <lznuaa@gmail.com>
Thu, 6 Nov 2008 14:33:33 +0000 (22:33 +0800)
TortoiseShell/GitAdminDir.cpp [new file with mode: 0644]
TortoiseShell/GitAdminDir.h [new file with mode: 0644]
TortoiseShell/GitStatus.cpp [new file with mode: 0644]
TortoiseShell/GitStatus.h [new file with mode: 0644]
TortoiseShell/TGitPath.cpp [new file with mode: 0644]
TortoiseShell/TGitPath.h [new file with mode: 0644]

diff --git a/TortoiseShell/GitAdminDir.cpp b/TortoiseShell/GitAdminDir.cpp
new file mode 100644 (file)
index 0000000..3ed2137
--- /dev/null
@@ -0,0 +1,131 @@
+// TortoiseGit - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+#include "StdAfx.h"\r
+#include "UnicodeUtils.h"\r
+#include "GitAdminDir.h"\r
+\r
+GitAdminDir g_GitAdminDir;\r
+\r
+GitAdminDir::GitAdminDir()\r
+       : m_nInit(0)\r
+//     , m_bVSNETHack(false)\r
+//     , m_pool(NULL)\r
+{\r
+}\r
+\r
+GitAdminDir::~GitAdminDir()\r
+{\r
+//     if (m_nInit)\r
+//              (m_pool);\r
+}\r
+\r
+bool GitAdminDir::Init()\r
+{\r
+       if (m_nInit==0)\r
+       {\r
+#if 0  \r
+               m_bVSNETHack = false;\r
+               m_pool = svn_pool_create(NULL);\r
+               size_t ret = 0;\r
+               getenv_s(&ret, NULL, 0, "GIT_ASP_DOT_NET_HACK");\r
+               if (ret)\r
+               {\r
+                       svn_error_clear(svn_wc_set_adm_dir("_git", m_pool));\r
+                       m_bVSNETHack = true;\r
+               }\r
+#endif\r
+       }\r
+       m_nInit++;\r
+       return true;\r
+}\r
+\r
+bool GitAdminDir::Close()\r
+{\r
+       m_nInit--;\r
+       if (m_nInit>0)\r
+               return false;\r
+#if 0\r
+       svn_pool_destroy(m_pool);\r
+#endif\r
+       return true;\r
+}\r
+\r
+bool GitAdminDir::IsAdminDirName(const CString& name) const\r
+{\r
+#if 0\r
+       CStringA nameA = CUnicodeUtils::GetUTF8(name).MakeLower();\r
+       return !!svn_wc_is_adm_dir(nameA, m_pool);\r
+#endif\r
+       return name == ".git";\r
+}\r
+\r
+bool GitAdminDir::HasAdminDir(const CString& path) const\r
+{\r
+       return HasAdminDir(path, !!PathIsDirectory(path));\r
+}\r
+\r
+bool GitAdminDir::HasAdminDir(const CString& path, bool bDir) const\r
+{\r
+       if (path.IsEmpty())\r
+               return false;\r
+       bool bHasAdminDir = false;\r
+       CString sDirName = path;\r
+       if (!bDir)\r
+       {\r
+               sDirName = path.Left(path.ReverseFind('\\'));\r
+       }\r
+       \r
+       do\r
+       {\r
+               if(PathFileExists(sDirName + _T("\\.git")))\r
+                       return true;\r
+               sDirName = sDirName.Left(sDirName.ReverseFind('\\'));\r
+\r
+       }while(sDirName.ReverseFind('\\')>0);\r
+\r
+       return false;\r
+       \r
+}\r
+\r
+bool GitAdminDir::IsAdminDirPath(const CString& path) const\r
+{\r
+       if (path.IsEmpty())\r
+               return false;\r
+       bool bIsAdminDir = false;\r
+       CString lowerpath = path;\r
+       lowerpath.MakeLower();\r
+       int ind = -1;\r
+       int ind1 = 0;\r
+       while ((ind1 = lowerpath.Find(_T("\\.git"), ind1))>=0)\r
+       {\r
+               ind = ind1++;\r
+               if (ind == (lowerpath.GetLength() - 5))\r
+               {\r
+                       bIsAdminDir = true;\r
+                       break;\r
+               }\r
+               else if (lowerpath.Find(_T("\\.git\\"), ind)>=0)\r
+               {\r
+                       bIsAdminDir = true;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       return bIsAdminDir;\r
+}\r
+\r
diff --git a/TortoiseShell/GitAdminDir.h b/TortoiseShell/GitAdminDir.h
new file mode 100644 (file)
index 0000000..8620acb
--- /dev/null
@@ -0,0 +1,43 @@
+#pragma once\r
+\r
+class GitAdminDir\r
+{\r
+public:\r
+       GitAdminDir(void);\r
+       ~GitAdminDir(void);\r
+       /**\r
+        * Initializes the global object. Call this after apr is initialized but\r
+        * before using any other methods of this class.\r
+        */\r
+       bool Init();\r
+       /**\r
+        * Clears the memory pool. Call this before you clear *all* pools\r
+        * with apr_pool_terminate(). If you don't use apr_pool_terminate(), then\r
+        * this method doesn't need to be called, because the deconstructor will\r
+        * do the same too.\r
+        */\r
+       bool Close();\r
+       \r
+       /// Returns true if \a name is the admin dir name\r
+       bool IsAdminDirName(const CString& name) const;\r
+       \r
+       /// Returns true if the path points to or below an admin directory\r
+       bool IsAdminDirPath(const CString& path) const;\r
+       \r
+       /// Returns true if the path (file or folder) has an admin directory \r
+       /// associated, i.e. if the path is in a working copy.\r
+       bool HasAdminDir(const CString& path) const;\r
+       bool HasAdminDir(const CString& path, bool bDir) const;\r
+       \r
+       /// Returns true if the admin dir name is set to "_svn".\r
+       bool IsVSNETHackActive() const {return m_bVSNETHack;}\r
+       \r
+       CString GetAdminDirName() const {return _T(".git");}\r
+       CString GetVSNETAdminDirName() const {return _T("_git");}\r
+private:\r
+       bool m_bVSNETHack;\r
+       int m_nInit;\r
+\r
+};\r
+\r
+extern GitAdminDir g_GitAdminDir;
\ No newline at end of file
diff --git a/TortoiseShell/GitStatus.cpp b/TortoiseShell/GitStatus.cpp
new file mode 100644 (file)
index 0000000..3759b12
--- /dev/null
@@ -0,0 +1,774 @@
+// TortoiseGit - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+\r
+#include "stdafx.h"\r
+#include "resource.h"\r
+#include "..\TortoiseShell\resource.h"\r
+//#include "git_config.h"\r
+#include "GitStatus.h"\r
+#include "UnicodeUtils.h"\r
+//#include "GitGlobal.h"\r
+//#include "GitHelpers.h"\r
+#ifdef _MFC_VER\r
+#      include "Git.h"\r
+#      include "MessageBox.h"\r
+#      include "registry.h"\r
+#      include "TGitPath.h"\r
+#      include "PathUtils.h"\r
+#endif\r
+\r
+GitStatus::GitStatus(bool * pbCanceled)\r
+       : status(NULL)\r
+{\r
+#if 0\r
+       m_pool = git_pool_create (NULL);\r
+       \r
+       git_error_clear(git_client_create_context(&ctx, m_pool));\r
+       \r
+       if (pbCanceled)\r
+       {\r
+               ctx->cancel_func = cancel;\r
+               ctx->cancel_baton = pbCanceled;\r
+       }\r
+\r
+#ifdef _MFC_VER\r
+       git_error_clear(git_config_ensure(NULL, m_pool));\r
+       \r
+       // set up authentication\r
+       m_prompt.Init(m_pool, ctx);\r
+\r
+       // set up the configuration\r
+       m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
+\r
+       if (m_err)\r
+       {\r
+               ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);\r
+               git_error_clear(m_err);\r
+               git_pool_destroy (m_pool);                                      // free the allocated memory\r
+               exit(-1);\r
+       }\r
+\r
+       // set up the Git_SSH param\r
+       CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));\r
+       if (tgit_ssh.IsEmpty())\r
+               tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");\r
+       tgit_ssh.Replace('\\', '/');\r
+       if (!tgit_ssh.IsEmpty())\r
+       {\r
+               git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,\r
+                       APR_HASH_KEY_STRING);\r
+               git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));\r
+       }\r
+#else\r
+       git_error_clear(git_config_ensure(NULL, m_pool));\r
+\r
+       // set up the configuration\r
+       m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
+\r
+#endif\r
+#endif\r
+}\r
+\r
+GitStatus::~GitStatus(void)\r
+{\r
+#if 0\r
+       git_error_clear(m_err);\r
+       git_pool_destroy (m_pool);                                      // free the allocated memory\r
+#endif\r
+}\r
+\r
+void GitStatus::ClearPool()\r
+{\r
+#if 0\r
+       git_pool_clear(m_pool);\r
+#endif\r
+}\r
+\r
+#ifdef _MFC_VER\r
+CString GitStatus::GetLastErrorMsg() const\r
+{\r
+       return Git::GetErrorString(m_err);\r
+}\r
+#else\r
+stdstring GitStatus::GetLastErrorMsg() const\r
+{\r
+\r
+       stdstring msg;\r
+#if 0\r
+       char errbuf[256];\r
+\r
+       if (m_err != NULL)\r
+       {\r
+               git_error_t * ErrPtr = m_err;\r
+               if (ErrPtr->message)\r
+               {\r
+                       msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
+               }\r
+               else\r
+               {\r
+                       /* Is this a Subversion-specific error code? */\r
+                       if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
+                               && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
+                               msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
+                       /* Otherwise, this must be an APR error code. */\r
+                       else\r
+                       {\r
+                               git_error_t *temp_err = NULL;\r
+                               const char * err_string = NULL;\r
+                               temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
+                               if (temp_err)\r
+                               {\r
+                                       git_error_clear (temp_err);\r
+                                       msg = _T("Can't recode error string from APR");\r
+                               }\r
+                               else\r
+                               {\r
+                                       msg = CUnicodeUtils::StdGetUnicode(err_string);\r
+                               }\r
+                       }\r
+\r
+               }\r
+\r
+               while (ErrPtr->child)\r
+               {\r
+                       ErrPtr = ErrPtr->child;\r
+                       msg += _T("\n");\r
+                       if (ErrPtr->message)\r
+                       {\r
+                               msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Is this a Subversion-specific error code? */\r
+                               if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
+                                       && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
+                                       msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
+                               /* Otherwise, this must be an APR error code. */\r
+                               else\r
+                               {\r
+                                       git_error_t *temp_err = NULL;\r
+                                       const char * err_string = NULL;\r
+                                       temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
+                                       if (temp_err)\r
+                                       {\r
+                                               git_error_clear (temp_err);\r
+                                               msg += _T("Can't recode error string from APR");\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               msg += CUnicodeUtils::StdGetUnicode(err_string);\r
+                                       }\r
+                               }\r
+\r
+                       }\r
+               }\r
+               return msg;\r
+       } // if (m_err != NULL)\r
+#endif\r
+       return msg;\r
+}\r
+#endif\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)\r
+{\r
+       git_wc_status_kind                      statuskind;\r
+#if 0\r
+       git_client_ctx_t *                      ctx;\r
+       \r
+       apr_pool_t *                            pool;\r
+       git_error_t *                           err;\r
+       BOOL                                            isDir;\r
+\r
+       isDir = path.IsDirectory();\r
+       if (!path.HasAdminDir())\r
+               return git_wc_status_none;\r
+\r
+       pool = git_pool_create (NULL);                          // create the memory pool\r
+\r
+       git_error_clear(git_client_create_context(&ctx, pool));\r
+\r
+       git_revnum_t youngest = Git_INVALID_REVNUM;\r
+       git_opt_revision_t rev;\r
+       rev.kind = git_opt_revision_unspecified;\r
+       statuskind = git_wc_status_none;\r
+       err = git_client_status4 (&youngest,\r
+                                                       path.GetGitApiPath(pool),\r
+                                                       &rev,\r
+                                                       getallstatus,\r
+                                                       &statuskind,\r
+                                                       depth,\r
+                                                       TRUE,           //getall\r
+                                                       FALSE,          //update\r
+                                                       TRUE,           //noignore\r
+                                                       FALSE,          //ignore externals\r
+                                                       NULL,\r
+                                                       ctx,\r
+                                                       pool);\r
+\r
+       // Error present\r
+       if (err != NULL)\r
+       {\r
+               git_error_clear(err);\r
+               git_pool_destroy (pool);                                //free allocated memory\r
+               return git_wc_status_none;      \r
+       }\r
+\r
+       git_pool_destroy (pool);                                //free allocated memory\r
+#endif\r
+       return statuskind;\r
+}\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)\r
+{\r
+       return GetAllStatus(path, git_depth_infinity);\r
+}\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)\r
+{\r
+       if (GetStatusRanking(status1) >= GetStatusRanking(status2))\r
+               return status1;\r
+       return status2;\r
+}\r
+// static private method\r
+int GitStatus::GetStatusRanking(git_wc_status_kind status)\r
+{\r
+       switch (status)\r
+       {\r
+               case git_wc_status_none:\r
+                       return 0;\r
+               case git_wc_status_unversioned:\r
+                       return 1;\r
+               case git_wc_status_ignored:\r
+                       return 2;\r
+               case git_wc_status_incomplete:\r
+                       return 4;\r
+               case git_wc_status_normal:\r
+               case git_wc_status_external:\r
+                       return 5;\r
+               case git_wc_status_added:\r
+                       return 6;\r
+               case git_wc_status_missing:\r
+                       return 7;\r
+               case git_wc_status_deleted:\r
+                       return 8;\r
+               case git_wc_status_replaced:\r
+                       return 9;\r
+               case git_wc_status_modified:\r
+                       return 10;\r
+               case git_wc_status_merged:\r
+                       return 11;\r
+               case git_wc_status_conflicted:\r
+                       return 12;\r
+               case git_wc_status_obstructed:\r
+                       return 13;\r
+       }\r
+       return 0;\r
+}\r
+\r
+git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */)\r
+{\r
+#if 0\r
+       apr_hash_t *                            statushash;\r
+       apr_hash_t *                            exthash;\r
+       apr_array_header_t *            statusarray;\r
+       const sort_item*                        item;\r
+       \r
+       git_error_clear(m_err);\r
+       statushash = apr_hash_make(m_pool);\r
+       exthash = apr_hash_make(m_pool);\r
+       git_revnum_t youngest = Git_INVALID_REVNUM;\r
+       git_opt_revision_t rev;\r
+       rev.kind = git_opt_revision_unspecified;\r
+       struct hashbaton_t hashbaton;\r
+       hashbaton.hash = statushash;\r
+       hashbaton.exthash = exthash;\r
+       hashbaton.pThis = this;\r
+       m_err = git_client_status4 (&youngest,\r
+                                                       path.GetGitApiPath(m_pool),\r
+                                                       &rev,\r
+                                                       getstatushash,\r
+                                                       &hashbaton,\r
+                                                       git_depth_empty,                //depth\r
+                                                       TRUE,           //getall\r
+                                                       update,         //update\r
+                                                       noignore,               //noignore\r
+                                                       noexternals,\r
+                                                       NULL,\r
+                                                       ctx,\r
+                                                       m_pool);\r
+\r
+\r
+       // Error present if function is not under version control\r
+       if ((m_err != NULL) || (apr_hash_count(statushash) == 0))\r
+       {\r
+               status = NULL;\r
+               return -2;      \r
+       }\r
+\r
+       // Convert the unordered hash to an ordered, sorted array\r
+       statusarray = sort_hash (statushash,\r
+                                                         sort_compare_items_as_paths,\r
+                                                         m_pool);\r
+\r
+       // only the first entry is needed (no recurse)\r
+       item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);\r
+       \r
+       status = (git_wc_status2_t *) item->value;\r
+       \r
+       return youngest;\r
+#endif\r
+       return "";\r
+}\r
+git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update, git_depth_t depth, bool bNoIgnore /* = true */, bool bNoExternals /* = false */)\r
+{\r
+#if 0\r
+       const sort_item*                        item;\r
+\r
+       git_error_clear(m_err);\r
+       m_statushash = apr_hash_make(m_pool);\r
+       m_externalhash = apr_hash_make(m_pool);\r
+       headrev = Git_INVALID_REVNUM;\r
+       git_opt_revision_t rev;\r
+       rev.kind = git_opt_revision_unspecified;\r
+       struct hashbaton_t hashbaton;\r
+       hashbaton.hash = m_statushash;\r
+       hashbaton.exthash = m_externalhash;\r
+       hashbaton.pThis = this;\r
+       m_statushashindex = 0;\r
+       m_err = git_client_status4 (&headrev,\r
+                                                       path.GetGitApiPath(m_pool),\r
+                                                       &rev,\r
+                                                       getstatushash,\r
+                                                       &hashbaton,\r
+                                                       depth,\r
+                                                       TRUE,           //getall\r
+                                                       update,         //update\r
+                                                       bNoIgnore,      //noignore\r
+                                                       bNoExternals,           //noexternals\r
+                                                       NULL,\r
+                                                       ctx,\r
+                                                       m_pool);\r
+\r
+\r
+       // Error present if function is not under version control\r
+       if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))\r
+       {\r
+               return NULL;    \r
+       }\r
+\r
+       // Convert the unordered hash to an ordered, sorted array\r
+       m_statusarray = sort_hash (m_statushash,\r
+                                                               sort_compare_items_as_paths,\r
+                                                               m_pool);\r
+\r
+       // only the first entry is needed (no recurse)\r
+       m_statushashindex = 0;\r
+       item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
+       retPath.SetFromGit((const char*)item->key);\r
+       return (git_wc_status2_t *) item->value;\r
+#endif\r
+\r
+       return 0;\r
+}\r
+\r
+unsigned int GitStatus::GetVersionedCount() const\r
+{\r
+\r
+       unsigned int count = 0;\r
+#if 0\r
+       const sort_item* item;\r
+       for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)\r
+       {\r
+               item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);\r
+               if (item)\r
+               {\r
+                       if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)\r
+                               count++;                                \r
+               }\r
+       }\r
+#endif\r
+       return count;\r
+}\r
+\r
+git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& retPath)\r
+{\r
+#if 0\r
+       const sort_item*                        item;\r
+\r
+       if ((m_statushashindex+1) >= apr_hash_count(m_statushash))\r
+               return NULL;\r
+       m_statushashindex++;\r
+\r
+       item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
+       retPath.SetFromGit((const char*)item->key);\r
+       return (git_wc_status2_t *) item->value;\r
+#endif\r
+       return 0;\r
+}\r
+\r
+bool GitStatus::IsExternal(const CTGitPath& path) const\r
+{\r
+#if 0\r
+       if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))\r
+               return true;\r
+#endif\r
+       return false;\r
+}\r
+\r
+bool GitStatus::IsInExternal(const CTGitPath& path) const\r
+{\r
+#if 0\r
+       if (apr_hash_count(m_statushash) == 0)\r
+               return false;\r
+\r
+       GitPool localpool(m_pool);\r
+       apr_hash_index_t *hi;\r
+       const char* key;\r
+       for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi)) \r
+       {\r
+               apr_hash_this(hi, (const void**)&key, NULL, NULL);\r
+               if (key)\r
+               {\r
+                       if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))\r
+                               return true;\r
+               }\r
+       }\r
+#endif\r
+       return false;\r
+}\r
+\r
+\r
+void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)\r
+{\r
+       TCHAR * buf;\r
+       switch (status)\r
+       {\r
+               case git_wc_status_none:\r
+                       buf = _T("none\0");\r
+                       break;\r
+               case git_wc_status_unversioned:\r
+                       buf = _T("unversioned\0");\r
+                       break;\r
+               case git_wc_status_normal:\r
+                       buf = _T("normal\0");\r
+                       break;\r
+               case git_wc_status_added:\r
+                       buf = _T("added\0");\r
+                       break;\r
+               case git_wc_status_missing:\r
+                       buf = _T("missing\0");\r
+                       break;\r
+               case git_wc_status_deleted:\r
+                       buf = _T("deleted\0");\r
+                       break;\r
+               case git_wc_status_replaced:\r
+                       buf = _T("replaced\0");\r
+                       break;\r
+               case git_wc_status_modified:\r
+                       buf = _T("modified\0");\r
+                       break;\r
+               case git_wc_status_merged:\r
+                       buf = _T("merged\0");\r
+                       break;\r
+               case git_wc_status_conflicted:\r
+                       buf = _T("conflicted\0");\r
+                       break;\r
+               case git_wc_status_obstructed:\r
+                       buf = _T("obstructed\0");\r
+                       break;\r
+               case git_wc_status_ignored:\r
+                       buf = _T("ignored");\r
+                       break;\r
+               case git_wc_status_external:\r
+                       buf = _T("external");\r
+                       break;\r
+               case git_wc_status_incomplete:\r
+                       buf = _T("incomplete\0");\r
+                       break;\r
+               default:\r
+                       buf = _T("\0");\r
+                       break;\r
+       }\r
+       _stprintf_s(string, buflen, _T("%s"), buf);\r
+}\r
+\r
+void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)\r
+{\r
+       switch (status)\r
+       {\r
+               case git_wc_status_none:\r
+                       LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
+                       break;\r
+               case git_wc_status_unversioned:\r
+                       LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_normal:\r
+                       LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);\r
+                       break;\r
+               case git_wc_status_added:\r
+                       LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_missing:\r
+                       LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);\r
+                       break;\r
+               case git_wc_status_deleted:\r
+                       LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_replaced:\r
+                       LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_modified:\r
+                       LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_merged:\r
+                       LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_conflicted:\r
+                       LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_ignored:\r
+                       LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_obstructed:\r
+                       LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);\r
+                       break;\r
+               case git_wc_status_external:\r
+                       LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);\r
+                       break;\r
+               case git_wc_status_incomplete:\r
+                       LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);\r
+                       break;\r
+               default:\r
+                       LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
+                       break;\r
+       }\r
+}\r
+\r
+#ifdef _MFC_VER\r
+CString GitStatus::GetDepthString(git_depth_t depth)\r
+{\r
+       CString sDepth;\r
+       switch (depth)\r
+       {\r
+       case git_depth_unknown:\r
+               sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);\r
+               break;\r
+       case git_depth_empty:\r
+               sDepth.LoadString(IDS_Git_DEPTH_EMPTY);\r
+               break;\r
+       case git_depth_files:\r
+               sDepth.LoadString(IDS_Git_DEPTH_FILES);\r
+               break;\r
+       case git_depth_immediates:\r
+               sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);\r
+               break;\r
+       case git_depth_infinity:\r
+               sDepth.LoadString(IDS_Git_DEPTH_INFINITE);\r
+               break;\r
+       }\r
+       return sDepth;\r
+}\r
+#endif\r
+\r
+void GitStatus::GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang)\r
+{\r
+#if 0\r
+       switch (depth)\r
+       {\r
+       case git_depth_unknown:\r
+               LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);\r
+               break;\r
+       case git_depth_empty:\r
+               LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);\r
+               break;\r
+       case git_depth_files:\r
+               LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);\r
+               break;\r
+       case git_depth_immediates:\r
+               LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);\r
+               break;\r
+       case git_depth_infinity:\r
+               LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);\r
+               break;\r
+       }\r
+#endif\r
+}\r
+\r
+\r
+int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)\r
+{\r
+       const STRINGRESOURCEIMAGE* pImage;\r
+       const STRINGRESOURCEIMAGE* pImageEnd;\r
+       ULONG nResourceSize;\r
+       HGLOBAL hGlobal;\r
+       UINT iIndex;\r
+       int ret;\r
+\r
+       HRSRC hResource =  FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);\r
+       if (!hResource)\r
+       {\r
+               // try the default language before giving up!\r
+               hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);\r
+               if (!hResource)\r
+                       return 0;\r
+       }\r
+       hGlobal = LoadResource(hInstance, hResource);\r
+       if (!hGlobal)\r
+               return 0;\r
+       pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);\r
+       if(!pImage)\r
+               return 0;\r
+\r
+       nResourceSize = ::SizeofResource(hInstance, hResource);\r
+       pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);\r
+       iIndex = uID&0x000f;\r
+\r
+       while ((iIndex > 0) && (pImage < pImageEnd))\r
+       {\r
+               pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));\r
+               iIndex--;\r
+       }\r
+       if (pImage >= pImageEnd)\r
+               return 0;\r
+       if (pImage->nLength == 0)\r
+               return 0;\r
+\r
+       ret = pImage->nLength;\r
+       if (pImage->nLength > nBufferMax)\r
+       {\r
+               wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);\r
+               lpBuffer[nBufferMax-1] = 0;\r
+       }\r
+       else\r
+       {\r
+               wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);\r
+               lpBuffer[ret] = 0;\r
+       }\r
+       return ret;\r
+}\r
+\r
+#if 0\r
+git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
+{\r
+       git_wc_status_kind * s = (git_wc_status_kind *)baton;\r
+       *s = GitStatus::GetMoreImportant(*s, status->text_status);\r
+       *s = GitStatus::GetMoreImportant(*s, status->prop_status);\r
+       return Git_NO_ERROR;\r
+}\r
+#endif\r
+\r
+#if 0\r
+git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
+{\r
+       hashbaton_t * hash = (hashbaton_t *)baton;\r
+       const StdStrAVector& filterList = hash->pThis->m_filterFileList;\r
+       if (status->text_status == git_wc_status_external)\r
+       {\r
+               apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);\r
+               return Git_NO_ERROR;\r
+       }\r
+       if(filterList.size() > 0)\r
+       {\r
+               // We have a filter active - we're only interested in files which are in \r
+               // the filter  \r
+               if(!binary_search(filterList.begin(), filterList.end(), path))\r
+               {\r
+                       // This item is not in the filter - don't store it\r
+                       return Git_NO_ERROR;\r
+               }\r
+       }\r
+       git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);\r
+       apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);\r
+       return Git_NO_ERROR;\r
+}\r
+\r
+apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,\r
+                                                                               int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),\r
+                                                                               apr_pool_t *pool)\r
+{\r
+       apr_hash_index_t *hi;\r
+       apr_array_header_t *ary;\r
+\r
+       /* allocate an array with only one element to begin with. */\r
+       ary = apr_array_make (pool, 1, sizeof(sort_item));\r
+\r
+       /* loop over hash table and push all keys into the array */\r
+       for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))\r
+       {\r
+               sort_item *item = (sort_item*)apr_array_push (ary);\r
+\r
+               apr_hash_this (hi, &item->key, &item->klen, &item->value);\r
+       }\r
+\r
+       /* now quick sort the array.  */\r
+       qsort (ary->elts, ary->nelts, ary->elt_size,\r
+               (int (*)(const void *, const void *))comparison_func);\r
+\r
+       return ary;\r
+}\r
+\r
+int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)\r
+{\r
+       const char *astr, *bstr;\r
+\r
+       astr = (const char*)a->key;\r
+       bstr = (const char*)b->key;\r
+       return git_path_compare_paths (astr, bstr);\r
+}\r
+#endif\r
+\r
+git_error_t* GitStatus::cancel(void *baton)\r
+{\r
+#if 0\r
+       volatile bool * canceled = (bool *)baton;\r
+       if (*canceled)\r
+       {\r
+               CString temp;\r
+               temp.LoadString(IDS_Git_USERCANCELLED);\r
+               return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));\r
+       }\r
+       return Git_NO_ERROR;\r
+#endif \r
+       return 0;\r
+}\r
+\r
+#ifdef _MFC_VER\r
+\r
+// Set-up a filter to restrict the files which will have their status stored by a get-status\r
+void GitStatus::SetFilter(const CTGitPathList& fileList)\r
+{\r
+       m_filterFileList.clear();\r
+       for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)\r
+       {\r
+               m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));\r
+       }\r
+       // Sort the list so that we can do binary searches\r
+       std::sort(m_filterFileList.begin(), m_filterFileList.end());\r
+}\r
+\r
+void GitStatus::ClearFilter()\r
+{\r
+       m_filterFileList.clear();\r
+}\r
+\r
+#endif // _MFC_VER\r
+\r
diff --git a/TortoiseShell/GitStatus.h b/TortoiseShell/GitStatus.h
new file mode 100644 (file)
index 0000000..440fc99
--- /dev/null
@@ -0,0 +1,271 @@
+#pragma once\r
+\r
+#ifdef _MFC_VER\r
+#      include "SVNPrompt.h"\r
+#endif\r
+#include "TGitPath.h"\r
+\r
+#pragma warning (push,1)\r
+typedef std::basic_string<wchar_t> wide_string;\r
+#ifdef UNICODE\r
+#      define stdstring wide_string\r
+#else\r
+#      define stdstring std::string\r
+#endif\r
+#pragma warning (pop)\r
+\r
+#include "TGitPath.h"\r
+\r
+typedef enum type_git_wc_status_kind\r
+{\r
+       git_wc_status_none,\r
+       git_wc_status_unversioned,\r
+       git_wc_status_ignored,\r
+       git_wc_status_normal,\r
+       git_wc_status_external,\r
+       git_wc_status_incomplete,\r
+       git_wc_status_missing,\r
+       git_wc_status_deleted,\r
+       git_wc_status_replaced,\r
+       git_wc_status_modified,\r
+       git_wc_status_merged,\r
+       git_wc_status_added,\r
+       git_wc_status_conflicted,\r
+       git_wc_status_obstructed,\r
+\r
+}git_wc_status_kind;\r
+\r
+typedef enum\r
+{\r
+       git_depth_empty,\r
+       git_depth_infinity,\r
+       git_depth_unknown,\r
+       git_depth_files,\r
+       git_depth_immediates,\r
+}git_depth_t;\r
+\r
+\r
+\r
+typedef CString git_revnum_t;\r
+typedef int git_wc_status2_t;\r
+typedef int git_error_t;\r
+\r
+#define MAX_STATUS_STRING_LENGTH               256\r
+\r
+/**\r
+ * \ingroup Git\r
+ * Handles Subversion status of working copies.\r
+ */\r
+class GitStatus\r
+{\r
+public:\r
+       GitStatus(bool * pbCanceled = NULL);\r
+       ~GitStatus(void);\r
+\r
+\r
+       /**\r
+        * Reads the Subversion status of the working copy entry. No\r
+        * recurse is done, even if the entry is a directory.\r
+        * If the status of the text and property part are different\r
+        * then the more important status is returned.\r
+        */\r
+       static git_wc_status_kind GetAllStatus(const CTGitPath& path, git_depth_t depth = git_depth_empty);\r
+\r
+       /**\r
+        * Reads the Subversion status of the working copy entry and all its\r
+        * subitems. The resulting status is determined by using priorities for\r
+        * each status. The status with the highest priority is then returned.\r
+        * If the status of the text and property part are different then\r
+        * the more important status is returned.\r
+        */\r
+       static git_wc_status_kind GetAllStatusRecursive(const CTGitPath& path);\r
+\r
+       /**\r
+        * Returns the status which is more "important" of the two statuses specified.\r
+        * This is used for the "recursive" status functions on folders - i.e. which status\r
+        * should be returned for a folder which has several files with different statuses\r
+        * in it.\r
+        */                                     \r
+       static git_wc_status_kind GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2);\r
+       \r
+       /**\r
+        * Checks if a status is "important", i.e. if the status indicates that the user should know about it.\r
+        * E.g. a "normal" status is not important, but "modified" is.\r
+        * \param status the status to check\r
+        */\r
+       static BOOL IsImportant(git_wc_status_kind status) {return (GetMoreImportant(git_wc_status_added, status)==status);}\r
+\r
+       /**\r
+        * Reads the Subversion text status of the working copy entry. No\r
+        * recurse is done, even if the entry is a directory.\r
+        * The result is stored in the public member variable status.\r
+        * Use this method if you need detailed information about a file/folder, not just the raw status (like "normal", "modified").\r
+        * \r
+        * \param path the pathname of the entry\r
+        * \param update true if the status should be updated with the repository. Default is false.\r
+        * \return If update is set to true the HEAD revision of the repository is returned. If update is false then -1 is returned.\r
+        * \remark If the return value is -2 then the status could not be obtained.\r
+        */\r
+       git_revnum_t GetStatus(const CTGitPath& path, bool update = false, bool noignore = false, bool noexternals = false);\r
+\r
+       /**\r
+        * Returns a string representation of a Subversion status.\r
+        * \param status the status enum\r
+        * \param string a string representation\r
+        */\r
+       static void GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string);\r
+       static void GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang);\r
+\r
+       /**\r
+        * Returns the string representation of a depth.\r
+        */\r
+#ifdef _MFC_VER\r
+       static CString GetDepthString(Git_depth_t depth);\r
+#endif\r
+       static void GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang);\r
+\r
+       /**\r
+        * Returns the status of the first file of the given path. Use GetNextFileStatus() to obtain\r
+        * the status of the next file in the list.\r
+        * \param path the path of the folder from where the status list should be obtained\r
+        * \param retPath the path of the file for which the status was returned\r
+        * \param update set this to true if you want the status to be updated with the repository (needs network access)\r
+        * \param recurse true to fetch the status recursively\r
+        * \param bNoIgnore true to not fetch the ignored files\r
+        * \param bNoExternals true to not fetch the status of included Git:externals\r
+        * \return the status\r
+        */\r
+       git_wc_status2_t * GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update = false, git_depth_t depth = git_depth_infinity, bool bNoIgnore = true, bool bNoExternals = false);\r
+       unsigned int GetFileCount() const {return /*apr_hash_count(m_statushash);*/0;}\r
+       unsigned int GetVersionedCount() const;\r
+       /**\r
+        * Returns the status of the next file in the file list. If no more files are in the list then NULL is returned.\r
+        * See GetFirstFileStatus() for details.\r
+        */\r
+       git_wc_status2_t * GetNextFileStatus(CTGitPath& retPath);\r
+       /**\r
+        * Checks if a path is an external folder.\r
+        * This is necessary since Subversion returns two entries for external folders: one with the status Git_wc_status_external\r
+        * and one with the 'real' status of that folder. GetFirstFileStatus() and GetNextFileStatus() only return the 'real'\r
+        * status, so with this method it's possible to check if the status also is Git_wc_status_external.\r
+        */\r
+       bool IsExternal(const CTGitPath& path) const;\r
+       /**\r
+        * Checks if a path is in an external folder.\r
+        */\r
+       bool IsInExternal(const CTGitPath& path) const;\r
+\r
+       /**\r
+        * Clears the memory pool.\r
+        */\r
+       void ClearPool();\r
+\r
+       /**\r
+        * This member variable hold the status of the last call to GetStatus().\r
+        */\r
+       git_wc_status2_t *                      status;                         ///< the status result of GetStatus()\r
+\r
+       git_revnum_t                            headrev;                        ///< the head revision fetched with GetFirstStatus()\r
+\r
+       bool *                                          m_pbCanceled;\r
+#ifdef _MFC_VER\r
+friend class Git;      // So that Git can get to our m_err\r
+       /**\r
+        * Returns the last error message as a CString object.\r
+        */\r
+       CString GetLastErrorMsg() const;\r
+\r
+       /** \r
+        * Set a list of paths which will be considered when calling GetFirstFileStatus.\r
+        * If a filter is set, then GetFirstFileStatus/GetNextFileStatus will only return items which are in the filter list\r
+        */\r
+       void SetFilter(const CTGitPathList& fileList);\r
+       void ClearFilter();\r
+\r
+#else\r
+       /**\r
+        * Returns the last error message as a CString object.\r
+        */\r
+       stdstring GetLastErrorMsg() const;\r
+#endif\r
+\r
+\r
+protected:\r
+//     apr_pool_t *                            m_pool;                 ///< the memory pool\r
+private:\r
+       typedef struct sort_item\r
+       {\r
+               const void *key;\r
+//             apr_ssize_t klen;\r
+               void *value;\r
+       } sort_item;\r
+\r
+       typedef struct hashbaton_t\r
+       {\r
+               GitStatus*              pThis;\r
+//             apr_hash_t *    hash;\r
+//             apr_hash_t *    exthash;\r
+       } hash_baton_t;\r
+\r
+//     git_client_ctx_t *                      ctx;\r
+       git_wc_status_kind                      m_allstatus;    ///< used by GetAllStatus and GetAllStatusRecursive\r
+       git_error_t *                           m_err;                  ///< Subversion error baton\r
+\r
+#ifdef _MFC_VER\r
+       GitPrompt                                       m_prompt;\r
+#endif\r
+\r
+       /**\r
+        * Returns a numeric value indicating the importance of a status. \r
+        * A higher number indicates a more important status.\r
+        */\r
+       static int GetStatusRanking(git_wc_status_kind status);\r
+\r
+       /**\r
+        * Callback function which collects the raw status from a Git_client_status() function call\r
+        */\r
+//     static git_error_t * getallstatus (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool);\r
+\r
+       /**\r
+        * Callback function which stores the raw status from a Git_client_status() function call\r
+        * in a hash table.\r
+        */\r
+//     static git_error_t * getstatushash (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool);\r
+\r
+       /**\r
+        * helper function to sort a hash to an array\r
+        */\r
+//     static apr_array_header_t * sort_hash (apr_hash_t *ht, int (*comparison_func) (const sort_item *,\r
+//                                                                             const sort_item *), apr_pool_t *pool);\r
+\r
+       /**\r
+        * Callback function used by qsort() which does the comparison of two elements\r
+        */\r
+       static int __cdecl sort_compare_items_as_paths (const sort_item *a, const sort_item *b);\r
+\r
+       //for GetFirstFileStatus and GetNextFileStatus\r
+//     apr_hash_t *                            m_statushash;\r
+//     apr_array_header_t *            m_statusarray;\r
+       unsigned int                            m_statushashindex;\r
+//     apr_hash_t *                            m_externalhash;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4200)\r
+       struct STRINGRESOURCEIMAGE\r
+       {\r
+               WORD nLength;\r
+               WCHAR achString[];\r
+       };\r
+#pragma warning(pop)   // C4200\r
+\r
+       static int LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage);\r
+       static git_error_t* cancel(void *baton);\r
+\r
+       // A sorted list of filenames (in Git format, in lowercase) \r
+       // when this list is set, we only pick-up files during a GetStatus which are found in this list\r
+       typedef std::vector<std::string> StdStrAVector;\r
+       StdStrAVector m_filterFileList;\r
+};\r
+\r
+\r
+       
\ No newline at end of file
diff --git a/TortoiseShell/TGitPath.cpp b/TortoiseShell/TGitPath.cpp
new file mode 100644 (file)
index 0000000..8c51170
--- /dev/null
@@ -0,0 +1,10 @@
+#include "StdAfx.h"\r
+#include "TGitPath.h"\r
+\r
+CTGitPath::CTGitPath(void)\r
+{\r
+}\r
+\r
+CTGitPath::~CTGitPath(void)\r
+{\r
+}\r
diff --git a/TortoiseShell/TGitPath.h b/TortoiseShell/TGitPath.h
new file mode 100644 (file)
index 0000000..e590eb8
--- /dev/null
@@ -0,0 +1,318 @@
+#pragma once\r
+\r
+class CTGitPath\r
+{\r
+public:\r
+       CTGitPath(void);\r
+       ~CTGitPath(void);\r
+       public:\r
+       /**\r
+        * Set the path as an UTF8 string with forward slashes\r
+        */\r
+       void SetFromGit(const char* pPath);\r
+       void SetFromGit(const char* pPath, bool bIsDirectory);\r
+       void SetFromGit(const CString& sPath);\r
+       /**\r
+        * Set the path as UNICODE with backslashes\r
+        */\r
+       void SetFromWin(LPCTSTR pPath);\r
+       void SetFromWin(const CString& sPath);\r
+       void SetFromWin(const CString& sPath, bool bIsDirectory);\r
+       /**\r
+        * Set the path from an unknown source.\r
+        */\r
+       void SetFromUnknown(const CString& sPath);\r
+       /**\r
+        * Returns the path in Windows format, i.e. with backslashes\r
+        */\r
+       LPCTSTR GetWinPath() const;\r
+       /**\r
+        * Returns the path in Windows format, i.e. with backslashes\r
+        */\r
+       const CString& GetWinPathString() const;\r
+       /**\r
+        * Returns the path with forward slashes.\r
+        */\r
+       const CString& GetGitPathString() const;\r
+       /**\r
+        * Returns the path completely prepared to be fed the the Git APIs\r
+        * It will be in UTF8, with URLs escaped, if necessary\r
+        */\r
+//     const char* GetGitApiPath(apr_pool_t *pool) const;\r
+       /**\r
+        * Returns the path for showing in an UI.\r
+        *\r
+        * URL's are returned with forward slashes, unescaped if necessary\r
+        * Paths are returned with backward slashes\r
+        */\r
+       const CString& GetUIPathString() const;\r
+       /**\r
+        * Checks if the path is an URL.\r
+        */\r
+       bool IsUrl() const;\r
+       /**\r
+        * Returns true if the path points to a directory\r
+        */\r
+       bool IsDirectory() const;\r
+       /**\r
+        * Returns the directory. If the path points to a directory, then the path\r
+        * is returned unchanged. If the path points to a file, the path to the \r
+        * parent directory is returned.\r
+        */\r
+       CTGitPath GetDirectory() const;\r
+       /**\r
+       * Returns the the directory which contains the item the path refers to.\r
+       * If the path is a directory, then this returns the directory above it.\r
+       * If the path is to a file, then this returns the directory which contains the path\r
+       * parent directory is returned.\r
+       */\r
+       CTGitPath GetContainingDirectory() const;\r
+       /**\r
+        * Get the 'root path' (e.g. "c:\") - Used to pass to GetDriveType \r
+        */\r
+       CString GetRootPathString() const;\r
+       /**\r
+        * Returns the filename part of the full path.\r
+        * \remark don't call this for directories.\r
+        */\r
+       CString GetFilename() const;\r
+       /**\r
+        * Returns the item's name without the full path.\r
+        */\r
+       CString GetFileOrDirectoryName() const;\r
+       /**\r
+        * Returns the item's name without the full path, unescaped if necessary.\r
+        */\r
+       CString GetUIFileOrDirectoryName() const;\r
+       /**\r
+        * Returns the file extension, including the dot.\r
+        * \remark Returns an empty string for directories\r
+        */\r
+       CString GetFileExtension() const;\r
+\r
+       bool IsEmpty() const;\r
+       void Reset();\r
+       /**\r
+        * Checks if two paths are equal. The slashes are taken care of.\r
+        */\r
+       bool IsEquivalentTo(const CTGitPath& rhs) const;\r
+       bool IsEquivalentToWithoutCase(const CTGitPath& rhs) const;\r
+       bool operator==(const CTGitPath& x) const {return IsEquivalentTo(x);}\r
+       \r
+       /**\r
+        * Checks if \c possibleDescendant is a child of this path.\r
+        */\r
+       bool IsAncestorOf(const CTGitPath& possibleDescendant) const;\r
+       /**\r
+        * Get a string representing the file path, optionally with a base \r
+        * section stripped off the front\r
+        * Returns a string with fwdslash paths \r
+        */\r
+       CString GetDisplayString(const CTGitPath* pOptionalBasePath = NULL) const;\r
+       /**\r
+        * Compares two paths. Slash format is irrelevant.\r
+        */\r
+       static int Compare(const CTGitPath& left, const CTGitPath& right);\r
+\r
+       /** As PredLeftLessThanRight, but for checking if paths are equivalent \r
+        */\r
+       static bool PredLeftEquivalentToRight(const CTGitPath& left, const CTGitPath& right);\r
+\r
+       /** Checks if the left path is pointing to the same working copy path as the right.\r
+        * The same wc path means the paths are equivalent once all the admin dir path parts\r
+        * are removed. This is used in the TGitCache crawler to filter out all the 'duplicate'\r
+        * paths to crawl.\r
+        */\r
+       static bool PredLeftSameWCPathAsRight(const CTGitPath& left, const CTGitPath& right);\r
+       \r
+       static bool CheckChild(const CTGitPath &parent, const CTGitPath& child);\r
+\r
+       /**\r
+        * appends a string to this path. \r
+        *\remark - missing slashes are not added - this is just a string concatenation, but with\r
+        * preservation of the proper caching behavior.\r
+        * If you want to join a file- or directory-name onto the path, you should use AppendPathString\r
+        */\r
+       void AppendRawString(const CString& sAppend);\r
+\r
+       /**\r
+       * appends a part of a path to this path. \r
+       *\remark - missing slashes are dealt with properly. Don't use this to append a file extension, for example\r
+       * \r
+       */\r
+       void AppendPathString(const CString& sAppend);\r
+\r
+       /**\r
+        * Get the file modification time - returns zero for files which don't exist\r
+        * Returns a FILETIME structure cast to an __int64, for easy comparisons\r
+        */\r
+       __int64 GetLastWriteTime() const;\r
+       \r
+       bool IsReadOnly() const;\r
+       \r
+       /**\r
+        * Checks if the path really exists.\r
+        */\r
+       bool Exists() const;\r
+       \r
+       /**\r
+        * Deletes the file/folder\r
+        * \param bTrash if true, uses the Windows trash bin when deleting.\r
+        */\r
+       bool Delete(bool bTrash) const;\r
+\r
+       /**\r
+        * Checks if a Subversion admin directory is present. For files, the check\r
+        * is done in the same directory. For folders, it checks if the folder itself\r
+        * contains an admin directory.\r
+        */\r
+       bool HasAdminDir() const;\r
+       \r
+       /**\r
+        * Checks if the path point to or below a Subversion admin directory (.Git).\r
+        */\r
+       bool IsAdminDir() const;\r
+\r
+       void SetCustomData(LPARAM lp) {m_customData = lp;}\r
+       LPARAM GetCustomData() {return m_customData;}\r
+\r
+       /**\r
+        * Checks if the path or URL is valid on Windows.\r
+        * A path is valid if conforms to the specs in the windows API.\r
+        * An URL is valid if the path checked out from it is valid\r
+        * on windows. That means an URL which is valid according to the WWW specs\r
+        * isn't necessarily valid as a windows path (e.g. http://myserver.com/repos/file:name \r
+        * is a valid URL, but the path is illegal on windows ("file:name" is illegal), so\r
+        * this function would return \c false for that URL).\r
+        */\r
+       bool IsValidOnWindows() const;\r
+\r
+       /**\r
+        * Checks to see if the path or URL represents one of the special directories\r
+        * (branches, tags, or trunk).\r
+        */\r
+       bool IsSpecialDirectory() const;\r
+private:\r
+       // All these functions are const, and all the data\r
+       // is mutable, in order that the hidden caching operations\r
+       // can be carried out on a const CTGitPath object, which is what's \r
+       // likely to be passed between functions\r
+       // The public 'SetFromxxx' functions are not const, and so the proper \r
+       // const-correctness semantics are preserved\r
+       void SetFwdslashPath(const CString& sPath) const;\r
+       void SetBackslashPath(const CString& sPath) const;\r
+       void SetUTF8FwdslashPath(const CString& sPath) const;\r
+       void EnsureBackslashPathSet() const;\r
+       void EnsureFwdslashPathSet() const;\r
+       /**\r
+        * Checks if two path strings are equal. No conversion of slashes is done!\r
+        * \remark for slash-independent comparison, use IsEquivalentTo()\r
+        */\r
+       static bool ArePathStringsEqual(const CString& sP1, const CString& sP2);\r
+       static bool ArePathStringsEqualWithCase(const CString& sP1, const CString& sP2);\r
+       \r
+       /**\r
+        * Adds the required trailing slash to local root paths such as 'C:'\r
+        */\r
+       void SanitizeRootPath(CString& sPath, bool bIsForwardPath) const;\r
+\r
+       void UpdateAttributes() const;\r
+\r
+private:\r
+       mutable CString m_sBackslashPath;\r
+       mutable CString m_sFwdslashPath;\r
+       mutable CString m_sUIPath;\r
+       mutable CStringA m_sUTF8FwdslashPath;\r
+       mutable CStringA m_sUTF8FwdslashPathEscaped;\r
+       // Have we yet determined if this is a directory or not?\r
+       mutable bool m_bDirectoryKnown;\r
+       mutable bool m_bIsDirectory;\r
+       mutable bool m_bLastWriteTimeKnown;\r
+       mutable bool m_bURLKnown;\r
+       mutable bool m_bIsURL;\r
+       mutable __int64 m_lastWriteTime;\r
+       mutable bool m_bIsReadOnly;\r
+       mutable bool m_bHasAdminDirKnown;\r
+       mutable bool m_bHasAdminDir;\r
+       mutable bool m_bIsValidOnWindowsKnown;\r
+       mutable bool m_bIsValidOnWindows;\r
+       mutable bool m_bIsAdminDirKnown;\r
+       mutable bool m_bIsAdminDir;\r
+       mutable bool m_bExists;\r
+       mutable bool m_bExistsKnown;\r
+       mutable LPARAM m_customData;\r
+       mutable bool m_bIsSpecialDirectoryKnown;\r
+       mutable bool m_bIsSpecialDirectory;\r
+\r
+       friend bool operator<(const CTGitPath& left, const CTGitPath& right);\r
+};\r
+/**\r
+ * Compares two paths and return true if left is earlier in sort order than right\r
+ * (Uses CTGitPath::Compare logic, but is suitable for std::sort and similar)\r
+ */\r
+ bool operator<(const CTGitPath& left, const CTGitPath& right);\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * This class represents a list of paths\r
+ */\r
+class CTGitPathList \r
+{\r
+public:\r
+       CTGitPathList();\r
+       // A constructor which allows a path list to be easily built with one initial entry in\r
+       explicit CTGitPathList(const CTGitPath& firstEntry);\r
+\r
+public:\r
+       void AddPath(const CTGitPath& newPath);\r
+       bool LoadFromFile(const CTGitPath& filename);\r
+       bool WriteToFile(const CString& sFilename, bool bANSI = false) const;\r
+\r
+       /**\r
+        * Load from the path argument string, when the 'path' parameter is used\r
+        * This is a list of paths, with '*' between them\r
+        */\r
+       void LoadFromAsteriskSeparatedString(const CString& sPathString);\r
+       CString CreateAsteriskSeparatedString() const;\r
+\r
+       int GetCount() const;\r
+       void Clear();\r
+       const CTGitPath& operator[](INT_PTR index) const;\r
+       bool AreAllPathsFiles() const;\r
+       bool AreAllPathsFilesInOneDirectory() const;\r
+       CTGitPath GetCommonDirectory() const;\r
+       CTGitPath GetCommonRoot() const;\r
+       void SortByPathname(bool bReverse = false);\r
+       /** \r
+        * Delete all the files in the list, then clear the list.\r
+        * \param bTrash if true, the items are deleted using the Windows trash bin\r
+        */\r
+       void DeleteAllFiles(bool bTrash);\r
+       /** Remove duplicate entries from the list (sorts the list as a side-effect */\r
+       void RemoveDuplicates();\r
+       /** Removes all paths which are on or in a Subversion admin directory */\r
+       void RemoveAdminPaths();\r
+       void RemovePath(const CTGitPath& path);\r
+       /** \r
+        * Removes all child items and leaves only the top folders. Useful if you\r
+        * create the list to remove them (i.e. if you remove a parent folder, the\r
+        * child files and folders don't have to be deleted anymore)\r
+        */\r
+       void RemoveChildren();\r
+\r
+       /** Checks if two CTGitPathLists are the same */\r
+       bool IsEqual(const CTGitPathList& list);\r
+\r
+       /** Convert into the Git API parameter format */\r
+//     apr_array_header_t * MakePathArray (apr_pool_t *pool) const;\r
+\r
+private:\r
+       typedef std::vector<CTGitPath> PathVector;\r
+       PathVector m_paths;\r
+       // If the list contains just files in one directory, then\r
+       // this contains the directory name\r
+       mutable CTGitPath m_commonBaseDirectory;\r
+};\r