OSDN Git Service

*Read Index File Directory. Overlay basic working. include "conflict, modified and...
[tortoisegit/TortoiseGitJp.git] / src / Git / GitStatus.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 \r
20 #include "stdafx.h"\r
21 //#include "resource.h"\r
22 #include "..\TortoiseShell\resource.h"\r
23 //#include "git_config.h"\r
24 #include "GitStatus.h"\r
25 #include "UnicodeUtils.h"\r
26 //#include "GitGlobal.h"\r
27 //#include "GitHelpers.h"\r
28 #ifdef _MFC_VER\r
29 //#     include "Git.h"\r
30 //#     include "MessageBox.h"\r
31 //#     include "registry.h"\r
32 //#     include "TGitPath.h"\r
33 //#     include "PathUtils.h"\r
34 #endif\r
35 #include "git.h"\r
36 #include "gitindex.h"\r
37 \r
38 CGitIndexFileMap g_IndexFileMap;\r
39 \r
40 GitStatus::GitStatus(bool * pbCanceled)\r
41         : status(NULL)\r
42 {\r
43 #if 0\r
44         m_pool = git_pool_create (NULL);\r
45         \r
46         git_error_clear(git_client_create_context(&ctx, m_pool));\r
47         \r
48         if (pbCanceled)\r
49         {\r
50                 ctx->cancel_func = cancel;\r
51                 ctx->cancel_baton = pbCanceled;\r
52         }\r
53 \r
54 #ifdef _MFC_VER\r
55         git_error_clear(git_config_ensure(NULL, m_pool));\r
56         \r
57         // set up authentication\r
58         m_prompt.Init(m_pool, ctx);\r
59 \r
60         // set up the configuration\r
61         m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
62 \r
63         if (m_err)\r
64         {\r
65                 ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);\r
66                 git_error_clear(m_err);\r
67                 git_pool_destroy (m_pool);                                      // free the allocated memory\r
68                 exit(-1);\r
69         }\r
70 \r
71         // set up the Git_SSH param\r
72         CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));\r
73         if (tgit_ssh.IsEmpty())\r
74                 tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");\r
75         tgit_ssh.Replace('\\', '/');\r
76         if (!tgit_ssh.IsEmpty())\r
77         {\r
78                 git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,\r
79                         APR_HASH_KEY_STRING);\r
80                 git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));\r
81         }\r
82 #else\r
83         git_error_clear(git_config_ensure(NULL, m_pool));\r
84 \r
85         // set up the configuration\r
86         m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
87 \r
88 #endif\r
89 #endif\r
90 }\r
91 \r
92 GitStatus::~GitStatus(void)\r
93 {\r
94 #if 0\r
95         git_error_clear(m_err);\r
96         git_pool_destroy (m_pool);                                      // free the allocated memory\r
97 #endif\r
98 }\r
99 \r
100 void GitStatus::ClearPool()\r
101 {\r
102 #if 0\r
103         git_pool_clear(m_pool);\r
104 #endif\r
105 }\r
106 \r
107 #ifdef _MFC_VER\r
108 CString GitStatus::GetLastErrorMsg() const\r
109 {\r
110 //      return Git::GetErrorString(m_err);\r
111         return CString("");\r
112 }\r
113 #else\r
114 stdstring GitStatus::GetLastErrorMsg() const\r
115 {\r
116 \r
117         stdstring msg;\r
118 #if 0\r
119         char errbuf[256];\r
120 \r
121         if (m_err != NULL)\r
122         {\r
123                 git_error_t * ErrPtr = m_err;\r
124                 if (ErrPtr->message)\r
125                 {\r
126                         msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
127                 }\r
128                 else\r
129                 {\r
130                         /* Is this a Subversion-specific error code? */\r
131                         if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
132                                 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
133                                 msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
134                         /* Otherwise, this must be an APR error code. */\r
135                         else\r
136                         {\r
137                                 git_error_t *temp_err = NULL;\r
138                                 const char * err_string = NULL;\r
139                                 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
140                                 if (temp_err)\r
141                                 {\r
142                                         git_error_clear (temp_err);\r
143                                         msg = _T("Can't recode error string from APR");\r
144                                 }\r
145                                 else\r
146                                 {\r
147                                         msg = CUnicodeUtils::StdGetUnicode(err_string);\r
148                                 }\r
149                         }\r
150 \r
151                 }\r
152 \r
153                 while (ErrPtr->child)\r
154                 {\r
155                         ErrPtr = ErrPtr->child;\r
156                         msg += _T("\n");\r
157                         if (ErrPtr->message)\r
158                         {\r
159                                 msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
160                         }\r
161                         else\r
162                         {\r
163                                 /* Is this a Subversion-specific error code? */\r
164                                 if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
165                                         && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
166                                         msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
167                                 /* Otherwise, this must be an APR error code. */\r
168                                 else\r
169                                 {\r
170                                         git_error_t *temp_err = NULL;\r
171                                         const char * err_string = NULL;\r
172                                         temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
173                                         if (temp_err)\r
174                                         {\r
175                                                 git_error_clear (temp_err);\r
176                                                 msg += _T("Can't recode error string from APR");\r
177                                         }\r
178                                         else\r
179                                         {\r
180                                                 msg += CUnicodeUtils::StdGetUnicode(err_string);\r
181                                         }\r
182                                 }\r
183 \r
184                         }\r
185                 }\r
186                 return msg;\r
187         } // if (m_err != NULL)\r
188 #endif\r
189         return msg;\r
190 }\r
191 #endif\r
192 \r
193 // static method\r
194 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)\r
195 {\r
196         git_wc_status_kind                      statuskind;\r
197 //      git_client_ctx_t *                      ctx;\r
198         \r
199 //      apr_pool_t *                            pool;\r
200 //      git_error_t *                           err;\r
201         BOOL                                            err;\r
202         BOOL                                            isDir;\r
203         CString                                         sProjectRoot;\r
204 \r
205         isDir = path.IsDirectory();\r
206         if (!path.HasAdminDir(&sProjectRoot))\r
207                 return git_wc_status_none;\r
208 \r
209 //      pool = git_pool_create (NULL);                          // create the memory pool\r
210 \r
211 //      git_error_clear(git_client_create_context(&ctx, pool));\r
212 \r
213 //      git_revnum_t youngest = Git_INVALID_REVNUM;\r
214 //      git_opt_revision_t rev;\r
215 //      rev.kind = git_opt_revision_unspecified;\r
216         statuskind = git_wc_status_none;\r
217 \r
218         const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source\r
219 \r
220         //LPCSTR lpszSubPath = NULL;\r
221         CString sSubPath;\r
222         CString s = path.GetWinPathString();\r
223         if (s.GetLength() > sProjectRoot.GetLength())\r
224         {\r
225                 sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/));\r
226         //      lpszSubPath = sSubPath;\r
227         }\r
228 \r
229 #if 1\r
230         // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here\r
231         //UINT nFlags = WGEFF_SingleFile;\r
232         //if (!bIsRecursive)\r
233         //      nFlags |= WGEFF_NoRecurse;\r
234         //if (!lpszSubPath)\r
235                 // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)\r
236         //      nFlags |= WGEFF_EmptyAsNormal;\r
237 #else\r
238         // enumerate all files, recursively if requested\r
239         UINT nFlags = 0;\r
240         if (!bIsRecursive)\r
241                 nFlags |= WGEFF_NoRecurse;\r
242 #endif\r
243 \r
244         //err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getallstatus, &statuskind);\r
245         \r
246         err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&statuskind);\r
247 \r
248         /*err = git_client_status4 (&youngest,\r
249                                                         path.GetSVNApiPath(pool),\r
250                                                         &rev,\r
251                                                         getallstatus,\r
252                                                         &statuskind,\r
253                                                         depth,\r
254                                                         TRUE,           //getall\r
255                                                         FALSE,          //update\r
256                                                         TRUE,           //noignore\r
257                                                         FALSE,          //ignore externals\r
258                                                         NULL,\r
259                                                         ctx,\r
260                                                         pool);*/\r
261 \r
262         // Error present\r
263         if (err != NULL)\r
264         {\r
265 //              git_error_clear(err);\r
266 //              git_pool_destroy (pool);                                //free allocated memory\r
267                 return git_wc_status_none;      \r
268         }\r
269 \r
270 //      git_pool_destroy (pool);                                //free allocated memory\r
271 \r
272         return statuskind;\r
273 }\r
274 \r
275 // static method\r
276 git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)\r
277 {\r
278         return GetAllStatus(path, git_depth_infinity);\r
279 }\r
280 \r
281 // static method\r
282 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)\r
283 {\r
284         if (GetStatusRanking(status1) >= GetStatusRanking(status2))\r
285                 return status1;\r
286         return status2;\r
287 }\r
288 // static private method\r
289 int GitStatus::GetStatusRanking(git_wc_status_kind status)\r
290 {\r
291         switch (status)\r
292         {\r
293                 case git_wc_status_none:\r
294                         return 0;\r
295                 case git_wc_status_unversioned:\r
296                         return 1;\r
297                 case git_wc_status_ignored:\r
298                         return 2;\r
299                 case git_wc_status_incomplete:\r
300                         return 4;\r
301                 case git_wc_status_normal:\r
302                 case git_wc_status_external:\r
303                         return 5;\r
304                 case git_wc_status_added:\r
305                         return 6;\r
306                 case git_wc_status_missing:\r
307                         return 7;\r
308                 case git_wc_status_deleted:\r
309                         return 8;\r
310                 case git_wc_status_replaced:\r
311                         return 9;\r
312                 case git_wc_status_modified:\r
313                         return 10;\r
314                 case git_wc_status_merged:\r
315                         return 11;\r
316                 case git_wc_status_conflicted:\r
317                         return 12;\r
318                 case git_wc_status_obstructed:\r
319                         return 13;\r
320         }\r
321         return 0;\r
322 }\r
323 \r
324 git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */)\r
325 {\r
326         // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of\r
327         //       Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right\r
328         //       after the call again\r
329 \r
330 //      apr_hash_t *                            statushash;\r
331 //      apr_hash_t *                            exthash;\r
332 //      apr_array_header_t *            statusarray;\r
333 //      const sort_item*                        item;\r
334         \r
335 //      git_error_clear(m_err);\r
336 //      statushash = apr_hash_make(m_pool);\r
337 //      exthash = apr_hash_make(m_pool);\r
338         git_revnum_t youngest = GIT_INVALID_REVNUM;\r
339 //      git_opt_revision_t rev;\r
340 //      rev.kind = git_opt_revision_unspecified;\r
341 \r
342         CString sProjectRoot;\r
343         if ( !path.HasAdminDir(&sProjectRoot) )\r
344                 return youngest;\r
345 \r
346         struct hashbaton_t hashbaton;\r
347 //      hashbaton.hash = statushash;\r
348 //      hashbaton.exthash = exthash;\r
349         hashbaton.pThis = this;\r
350 \r
351         //LPCSTR lpszSubPath = NULL;\r
352         CString sSubPath;\r
353         CString s = path.GetWinPathString();\r
354         if (s.GetLength() > sProjectRoot.GetLength())\r
355         {\r
356                 sSubPath = CString(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/));\r
357         //      lpszSubPath = sSubPath;\r
358         }\r
359 \r
360         \r
361         // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here\r
362         //UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse;\r
363         //if (!lpszSubPath)\r
364         //      // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)\r
365         //      nFlags |= WGEFF_EmptyAsNormal;\r
366 \r
367         m_status.prop_status = m_status.text_status = git_wc_status_none;\r
368 \r
369         // NOTE: currently wgEnumFiles_safe_safe_safe will not enumerate file if it isn't versioned (so status will be git_wc_status_none)\r
370         //m_err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getstatus, &m_status);\r
371 \r
372         m_err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&m_status.text_status);\r
373         \r
374         /*m_err = git_client_status4 (&youngest,\r
375                                                         path.GetGitApiPath(m_pool),\r
376                                                         &rev,\r
377                                                         getstatushash,\r
378                                                         &hashbaton,\r
379                                                         git_depth_empty,                //depth\r
380                                                         TRUE,           //getall\r
381                                                         update,         //update\r
382                                                         noignore,               //noignore\r
383                                                         noexternals,\r
384                                                         NULL,\r
385                                                         ctx,\r
386                                                         m_pool);*/\r
387 \r
388 \r
389         // Error present if function is not under version control\r
390         if (m_err) /*|| (apr_hash_count(statushash) == 0)*/\r
391         {\r
392                 status = NULL;\r
393 //              return -2;      \r
394                 return GIT_INVALID_REVNUM;\r
395         }\r
396 \r
397         // Convert the unordered hash to an ordered, sorted array\r
398         /*statusarray = sort_hash (statushash,\r
399                                                           sort_compare_items_as_paths,\r
400                                                           m_pool);*/\r
401 \r
402         // only the first entry is needed (no recurse)\r
403 //      item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);\r
404         \r
405 //      status = (git_wc_status2_t *) item->value;\r
406         status = &m_status;\r
407 \r
408         if (update)\r
409         {\r
410                 //const BYTE *sha1 = wgGetRevisionID_safe(CStringA(sProjectRoot), NULL);\r
411                 //if (sha1)\r
412                 //      youngest = ConvertHashToRevnum(sha1);\r
413         }\r
414 \r
415         return youngest;\r
416 }\r
417 \r
418 git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update, git_depth_t depth, bool bNoIgnore /* = true */, bool bNoExternals /* = false */)\r
419 {\r
420         static git_wc_status2 st;\r
421 /*\r
422         m_fileCache.Reset();\r
423 \r
424         m_fileCache.Init( CStringA( path.GetWinPathString().GetString() ) );\r
425 MessageBox(NULL, path.GetWinPathString(), _T("GetFirstFile"), MB_OK);\r
426         m_fileCache.m_pFileIter = m_fileCache.m_pFiles;\r
427         st.text_status = git_wc_status_none;\r
428 \r
429         if (m_fileCache.m_pFileIter)\r
430         {\r
431                 switch(m_fileCache.m_pFileIter->nStatus)\r
432                 {\r
433                 case WGFS_Normal: st.text_status = git_wc_status_normal; break;\r
434                 case WGFS_Modified: st.text_status = git_wc_status_modified; break;\r
435                 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;\r
436                 }\r
437 \r
438                 //retPath.SetFromGit((const char*)item->key);\r
439 \r
440                 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;\r
441         }\r
442 \r
443         return &st;\r
444 */\r
445 #if 0\r
446         const sort_item*                        item;\r
447 \r
448         git_error_clear(m_err);\r
449         m_statushash = apr_hash_make(m_pool);\r
450         m_externalhash = apr_hash_make(m_pool);\r
451         headrev = Git_INVALID_REVNUM;\r
452         git_opt_revision_t rev;\r
453         rev.kind = git_opt_revision_unspecified;\r
454         struct hashbaton_t hashbaton;\r
455         hashbaton.hash = m_statushash;\r
456         hashbaton.exthash = m_externalhash;\r
457         hashbaton.pThis = this;\r
458         m_statushashindex = 0;\r
459         m_err = git_client_status4 (&headrev,\r
460                                                         path.GetGitApiPath(m_pool),\r
461                                                         &rev,\r
462                                                         getstatushash,\r
463                                                         &hashbaton,\r
464                                                         depth,\r
465                                                         TRUE,           //getall\r
466                                                         update,         //update\r
467                                                         bNoIgnore,      //noignore\r
468                                                         bNoExternals,           //noexternals\r
469                                                         NULL,\r
470                                                         ctx,\r
471                                                         m_pool);\r
472 \r
473 \r
474         // Error present if function is not under version control\r
475         if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))\r
476         {\r
477                 return NULL;    \r
478         }\r
479 \r
480         // Convert the unordered hash to an ordered, sorted array\r
481         m_statusarray = sort_hash (m_statushash,\r
482                                                                 sort_compare_items_as_paths,\r
483                                                                 m_pool);\r
484 \r
485         // only the first entry is needed (no recurse)\r
486         m_statushashindex = 0;\r
487         item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
488         retPath.SetFromGit((const char*)item->key);\r
489         return (git_wc_status2_t *) item->value;\r
490 #endif\r
491 \r
492         return 0;\r
493 }\r
494 \r
495 unsigned int GitStatus::GetVersionedCount() const\r
496 {\r
497 //      return /**/m_fileCache.GetFileCount();\r
498 \r
499         unsigned int count = 0;\r
500 #if 0\r
501         const sort_item* item;\r
502         for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)\r
503         {\r
504                 item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);\r
505                 if (item)\r
506                 {\r
507                         if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)\r
508                                 count++;                                \r
509                 }\r
510         }\r
511 #endif\r
512         return count;\r
513 }\r
514 \r
515 git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& retPath)\r
516 {\r
517         static git_wc_status2 st;\r
518 \r
519         st.text_status = git_wc_status_none;\r
520 \r
521         /*if (m_fileCache.m_pFileIter)\r
522         {\r
523                 switch(m_fileCache.m_pFileIter->nStatus)\r
524                 {\r
525                 case WGFS_Normal: st.text_status = git_wc_status_normal; break;\r
526                 case WGFS_Modified: st.text_status = git_wc_status_modified; break;\r
527                 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;\r
528                 }\r
529 \r
530                 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;\r
531         }*/\r
532 \r
533         return &st;\r
534 \r
535 #if 0\r
536         const sort_item*                        item;\r
537 \r
538         if ((m_statushashindex+1) >= apr_hash_count(m_statushash))\r
539                 return NULL;\r
540         m_statushashindex++;\r
541 \r
542         item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
543         retPath.SetFromGit((const char*)item->key);\r
544         return (git_wc_status2_t *) item->value;\r
545 #endif\r
546         return 0;\r
547 }\r
548 \r
549 bool GitStatus::IsExternal(const CTGitPath& path) const\r
550 {\r
551 #if 0\r
552         if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))\r
553                 return true;\r
554 #endif\r
555         return false;\r
556 }\r
557 \r
558 bool GitStatus::IsInExternal(const CTGitPath& path) const\r
559 {\r
560 #if 0\r
561         if (apr_hash_count(m_statushash) == 0)\r
562                 return false;\r
563 \r
564         GitPool localpool(m_pool);\r
565         apr_hash_index_t *hi;\r
566         const char* key;\r
567         for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi)) \r
568         {\r
569                 apr_hash_this(hi, (const void**)&key, NULL, NULL);\r
570                 if (key)\r
571                 {\r
572                         if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))\r
573                                 return true;\r
574                 }\r
575         }\r
576 #endif\r
577         return false;\r
578 }\r
579 \r
580 \r
581 void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)\r
582 {\r
583         TCHAR * buf;\r
584         switch (status)\r
585         {\r
586                 case git_wc_status_none:\r
587                         buf = _T("none\0");\r
588                         break;\r
589                 case git_wc_status_unversioned:\r
590                         buf = _T("unversioned\0");\r
591                         break;\r
592                 case git_wc_status_normal:\r
593                         buf = _T("normal\0");\r
594                         break;\r
595                 case git_wc_status_added:\r
596                         buf = _T("added\0");\r
597                         break;\r
598                 case git_wc_status_missing:\r
599                         buf = _T("missing\0");\r
600                         break;\r
601                 case git_wc_status_deleted:\r
602                         buf = _T("deleted\0");\r
603                         break;\r
604                 case git_wc_status_replaced:\r
605                         buf = _T("replaced\0");\r
606                         break;\r
607                 case git_wc_status_modified:\r
608                         buf = _T("modified\0");\r
609                         break;\r
610                 case git_wc_status_merged:\r
611                         buf = _T("merged\0");\r
612                         break;\r
613                 case git_wc_status_conflicted:\r
614                         buf = _T("conflicted\0");\r
615                         break;\r
616                 case git_wc_status_obstructed:\r
617                         buf = _T("obstructed\0");\r
618                         break;\r
619                 case git_wc_status_ignored:\r
620                         buf = _T("ignored");\r
621                         break;\r
622                 case git_wc_status_external:\r
623                         buf = _T("external");\r
624                         break;\r
625                 case git_wc_status_incomplete:\r
626                         buf = _T("incomplete\0");\r
627                         break;\r
628                 default:\r
629                         buf = _T("\0");\r
630                         break;\r
631         }\r
632         _stprintf_s(string, buflen, _T("%s"), buf);\r
633 }\r
634 \r
635 void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)\r
636 {\r
637         switch (status)\r
638         {\r
639                 case git_wc_status_none:\r
640                         LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
641                         break;\r
642                 case git_wc_status_unversioned:\r
643                         LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);\r
644                         break;\r
645                 case git_wc_status_normal:\r
646                         LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);\r
647                         break;\r
648                 case git_wc_status_added:\r
649                         LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);\r
650                         break;\r
651                 case git_wc_status_missing:\r
652                         LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);\r
653                         break;\r
654                 case git_wc_status_deleted:\r
655                         LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);\r
656                         break;\r
657                 case git_wc_status_replaced:\r
658                         LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);\r
659                         break;\r
660                 case git_wc_status_modified:\r
661                         LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);\r
662                         break;\r
663                 case git_wc_status_merged:\r
664                         LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);\r
665                         break;\r
666                 case git_wc_status_conflicted:\r
667                         LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);\r
668                         break;\r
669                 case git_wc_status_ignored:\r
670                         LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);\r
671                         break;\r
672                 case git_wc_status_obstructed:\r
673                         LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);\r
674                         break;\r
675                 case git_wc_status_external:\r
676                         LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);\r
677                         break;\r
678                 case git_wc_status_incomplete:\r
679                         LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);\r
680                         break;\r
681                 default:\r
682                         LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
683                         break;\r
684         }\r
685 }\r
686 \r
687 #ifdef _MFC_VER\r
688 CString GitStatus::GetDepthString(git_depth_t depth)\r
689 {\r
690 #if 0\r
691         CString sDepth;\r
692         switch (depth)\r
693         {\r
694         case git_depth_unknown:\r
695                 sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);\r
696                 break;\r
697         case git_depth_empty:\r
698                 sDepth.LoadString(IDS_Git_DEPTH_EMPTY);\r
699                 break;\r
700         case git_depth_files:\r
701                 sDepth.LoadString(IDS_Git_DEPTH_FILES);\r
702                 break;\r
703         case git_depth_immediates:\r
704                 sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);\r
705                 break;\r
706         case git_depth_infinity:\r
707                 sDepth.LoadString(IDS_Git_DEPTH_INFINITE);\r
708                 break;\r
709         }\r
710         return sDepth;\r
711 #endif\r
712         return CString("");\r
713 }\r
714 #endif\r
715 \r
716 void GitStatus::GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang)\r
717 {\r
718 #if 0\r
719         switch (depth)\r
720         {\r
721         case git_depth_unknown:\r
722                 LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);\r
723                 break;\r
724         case git_depth_empty:\r
725                 LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);\r
726                 break;\r
727         case git_depth_files:\r
728                 LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);\r
729                 break;\r
730         case git_depth_immediates:\r
731                 LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);\r
732                 break;\r
733         case git_depth_infinity:\r
734                 LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);\r
735                 break;\r
736         }\r
737 #endif\r
738 }\r
739 \r
740 \r
741 int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)\r
742 {\r
743         const STRINGRESOURCEIMAGE* pImage;\r
744         const STRINGRESOURCEIMAGE* pImageEnd;\r
745         ULONG nResourceSize;\r
746         HGLOBAL hGlobal;\r
747         UINT iIndex;\r
748         int ret;\r
749 \r
750         HRSRC hResource =  FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);\r
751         if (!hResource)\r
752         {\r
753                 // try the default language before giving up!\r
754                 hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);\r
755                 if (!hResource)\r
756                         return 0;\r
757         }\r
758         hGlobal = LoadResource(hInstance, hResource);\r
759         if (!hGlobal)\r
760                 return 0;\r
761         pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);\r
762         if(!pImage)\r
763                 return 0;\r
764 \r
765         nResourceSize = ::SizeofResource(hInstance, hResource);\r
766         pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);\r
767         iIndex = uID&0x000f;\r
768 \r
769         while ((iIndex > 0) && (pImage < pImageEnd))\r
770         {\r
771                 pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));\r
772                 iIndex--;\r
773         }\r
774         if (pImage >= pImageEnd)\r
775                 return 0;\r
776         if (pImage->nLength == 0)\r
777                 return 0;\r
778 \r
779         ret = pImage->nLength;\r
780         if (pImage->nLength > nBufferMax)\r
781         {\r
782                 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);\r
783                 lpBuffer[nBufferMax-1] = 0;\r
784         }\r
785         else\r
786         {\r
787                 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);\r
788                 lpBuffer[ret] = 0;\r
789         }\r
790         return ret;\r
791 }\r
792 \r
793 BOOL GitStatus::getallstatus(const struct wgFile_s *pFile, void *pUserData)\r
794 {\r
795         git_wc_status_kind * s = (git_wc_status_kind *)pUserData;\r
796         *s = GitStatus::GetMoreImportant(*s, GitStatusFromWingit(pFile->nStatus));\r
797         return FALSE;\r
798 }\r
799 \r
800 BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)\r
801 {\r
802         git_wc_status2_t * s = (git_wc_status2_t*)pUserData;\r
803         s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));\r
804         return FALSE;\r
805 }\r
806 \r
807 #if 0\r
808 git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
809 {\r
810         git_wc_status_kind * s = (git_wc_status_kind *)baton;\r
811         *s = GitStatus::GetMoreImportant(*s, status->text_status);\r
812         *s = GitStatus::GetMoreImportant(*s, status->prop_status);\r
813         return Git_NO_ERROR;\r
814 }\r
815 #endif\r
816 \r
817 #if 0\r
818 git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
819 {\r
820         hashbaton_t * hash = (hashbaton_t *)baton;\r
821         const StdStrAVector& filterList = hash->pThis->m_filterFileList;\r
822         if (status->text_status == git_wc_status_external)\r
823         {\r
824                 apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);\r
825                 return Git_NO_ERROR;\r
826         }\r
827         if(filterList.size() > 0)\r
828         {\r
829                 // We have a filter active - we're only interested in files which are in \r
830                 // the filter  \r
831                 if(!binary_search(filterList.begin(), filterList.end(), path))\r
832                 {\r
833                         // This item is not in the filter - don't store it\r
834                         return Git_NO_ERROR;\r
835                 }\r
836         }\r
837         git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);\r
838         apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);\r
839         return Git_NO_ERROR;\r
840 }\r
841 \r
842 apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,\r
843                                                                                 int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),\r
844                                                                                 apr_pool_t *pool)\r
845 {\r
846         apr_hash_index_t *hi;\r
847         apr_array_header_t *ary;\r
848 \r
849         /* allocate an array with only one element to begin with. */\r
850         ary = apr_array_make (pool, 1, sizeof(sort_item));\r
851 \r
852         /* loop over hash table and push all keys into the array */\r
853         for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))\r
854         {\r
855                 sort_item *item = (sort_item*)apr_array_push (ary);\r
856 \r
857                 apr_hash_this (hi, &item->key, &item->klen, &item->value);\r
858         }\r
859 \r
860         /* now quick sort the array.  */\r
861         qsort (ary->elts, ary->nelts, ary->elt_size,\r
862                 (int (*)(const void *, const void *))comparison_func);\r
863 \r
864         return ary;\r
865 }\r
866 \r
867 int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)\r
868 {\r
869         const char *astr, *bstr;\r
870 \r
871         astr = (const char*)a->key;\r
872         bstr = (const char*)b->key;\r
873         return git_path_compare_paths (astr, bstr);\r
874 }\r
875 #endif\r
876 \r
877 git_error_t* GitStatus::cancel(void *baton)\r
878 {\r
879 #if 0\r
880         volatile bool * canceled = (bool *)baton;\r
881         if (*canceled)\r
882         {\r
883                 CString temp;\r
884                 temp.LoadString(IDS_Git_USERCANCELLED);\r
885                 return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));\r
886         }\r
887         return Git_NO_ERROR;\r
888 #endif \r
889         return 0;\r
890 }\r
891 \r
892 #ifdef _MFC_VER\r
893 \r
894 // Set-up a filter to restrict the files which will have their status stored by a get-status\r
895 void GitStatus::SetFilter(const CTGitPathList& fileList)\r
896 {\r
897         m_filterFileList.clear();\r
898         for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)\r
899         {\r
900 //              m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));\r
901         }\r
902         // Sort the list so that we can do binary searches\r
903         std::sort(m_filterFileList.begin(), m_filterFileList.end());\r
904 }\r
905 \r
906 void GitStatus::ClearFilter()\r
907 {\r
908         m_filterFileList.clear();\r
909 }\r
910 \r
911 #endif // _MFC_VER\r
912 \r