OSDN Git Service

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