Fix Crash Problem When TortoiseGit Install before Msysgit.
[TortoiseGit.git] / src / Git / GitStatus.cpp
blob6d549a6ecd8e377664fa50d53ef377b2fdfe3d98
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 //#include "resource.h"
22 #include "..\TortoiseShell\resource.h"
23 //#include "git_config.h"
24 #include "GitStatus.h"
25 #include "UnicodeUtils.h"
26 //#include "GitGlobal.h"
27 //#include "GitHelpers.h"
28 #ifdef _MFC_VER
29 //# include "Git.h"
30 //# include "MessageBox.h"
31 //# include "registry.h"
32 //# include "TGitPath.h"
33 //# include "PathUtils.h"
34 #endif
35 #include "git.h"
37 GitStatus::GitStatus(bool * pbCanceled)
38 : status(NULL)
40 #if 0
41 m_pool = git_pool_create (NULL);
43 git_error_clear(git_client_create_context(&ctx, m_pool));
45 if (pbCanceled)
47 ctx->cancel_func = cancel;
48 ctx->cancel_baton = pbCanceled;
51 #ifdef _MFC_VER
52 git_error_clear(git_config_ensure(NULL, m_pool));
54 // set up authentication
55 m_prompt.Init(m_pool, ctx);
57 // set up the configuration
58 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
60 if (m_err)
62 ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);
63 git_error_clear(m_err);
64 git_pool_destroy (m_pool); // free the allocated memory
65 exit(-1);
68 // set up the Git_SSH param
69 CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));
70 if (tgit_ssh.IsEmpty())
71 tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");
72 tgit_ssh.Replace('\\', '/');
73 if (!tgit_ssh.IsEmpty())
75 git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,
76 APR_HASH_KEY_STRING);
77 git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));
79 #else
80 git_error_clear(git_config_ensure(NULL, m_pool));
82 // set up the configuration
83 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
85 #endif
86 #endif
89 GitStatus::~GitStatus(void)
91 #if 0
92 git_error_clear(m_err);
93 git_pool_destroy (m_pool); // free the allocated memory
94 #endif
97 void GitStatus::ClearPool()
99 #if 0
100 git_pool_clear(m_pool);
101 #endif
104 #ifdef _MFC_VER
105 CString GitStatus::GetLastErrorMsg() const
107 // return Git::GetErrorString(m_err);
108 return CString("");
110 #else
111 stdstring GitStatus::GetLastErrorMsg() const
114 stdstring msg;
115 #if 0
116 char errbuf[256];
118 if (m_err != NULL)
120 git_error_t * ErrPtr = m_err;
121 if (ErrPtr->message)
123 msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);
125 else
127 /* Is this a Subversion-specific error code? */
128 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
129 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
130 msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
131 /* Otherwise, this must be an APR error code. */
132 else
134 git_error_t *temp_err = NULL;
135 const char * err_string = NULL;
136 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
137 if (temp_err)
139 git_error_clear (temp_err);
140 msg = _T("Can't recode error string from APR");
142 else
144 msg = CUnicodeUtils::StdGetUnicode(err_string);
150 while (ErrPtr->child)
152 ErrPtr = ErrPtr->child;
153 msg += _T("\n");
154 if (ErrPtr->message)
156 msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);
158 else
160 /* Is this a Subversion-specific error code? */
161 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
162 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
163 msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
164 /* Otherwise, this must be an APR error code. */
165 else
167 git_error_t *temp_err = NULL;
168 const char * err_string = NULL;
169 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
170 if (temp_err)
172 git_error_clear (temp_err);
173 msg += _T("Can't recode error string from APR");
175 else
177 msg += CUnicodeUtils::StdGetUnicode(err_string);
183 return msg;
184 } // if (m_err != NULL)
185 #endif
186 return msg;
188 #endif
190 // static method
191 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)
193 git_wc_status_kind statuskind;
194 // git_client_ctx_t * ctx;
196 // apr_pool_t * pool;
197 // git_error_t * err;
198 BOOL err;
199 BOOL isDir;
200 CString sProjectRoot;
202 isDir = path.IsDirectory();
203 if (!path.HasAdminDir(&sProjectRoot))
204 return git_wc_status_none;
206 // pool = git_pool_create (NULL); // create the memory pool
208 // git_error_clear(git_client_create_context(&ctx, pool));
210 // git_revnum_t youngest = Git_INVALID_REVNUM;
211 // git_opt_revision_t rev;
212 // rev.kind = git_opt_revision_unspecified;
213 statuskind = git_wc_status_none;
215 const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source
217 LPCSTR lpszSubPath = NULL;
218 CStringA sSubPath;
219 CString s = path.GetWinPathString();
220 if (s.GetLength() > sProjectRoot.GetLength())
222 sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/));
223 lpszSubPath = sSubPath;
226 #if 1
227 // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here
228 UINT nFlags = WGEFF_SingleFile;
229 if (!bIsRecursive)
230 nFlags |= WGEFF_NoRecurse;
231 if (!lpszSubPath)
232 // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)
233 nFlags |= WGEFF_EmptyAsNormal;
234 #else
235 // enumerate all files, recursively if requested
236 UINT nFlags = 0;
237 if (!bIsRecursive)
238 nFlags |= WGEFF_NoRecurse;
239 #endif
241 err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getallstatus, &statuskind);
243 /*err = git_client_status4 (&youngest,
244 path.GetSVNApiPath(pool),
245 &rev,
246 getallstatus,
247 &statuskind,
248 depth,
249 TRUE, //getall
250 FALSE, //update
251 TRUE, //noignore
252 FALSE, //ignore externals
253 NULL,
254 ctx,
255 pool);*/
257 // Error present
258 if (err != NULL)
260 // git_error_clear(err);
261 // git_pool_destroy (pool); //free allocated memory
262 return git_wc_status_none;
265 // git_pool_destroy (pool); //free allocated memory
267 return statuskind;
270 // static method
271 git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)
273 return GetAllStatus(path, git_depth_infinity);
276 // static method
277 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)
279 if (GetStatusRanking(status1) >= GetStatusRanking(status2))
280 return status1;
281 return status2;
283 // static private method
284 int GitStatus::GetStatusRanking(git_wc_status_kind status)
286 switch (status)
288 case git_wc_status_none:
289 return 0;
290 case git_wc_status_unversioned:
291 return 1;
292 case git_wc_status_ignored:
293 return 2;
294 case git_wc_status_incomplete:
295 return 4;
296 case git_wc_status_normal:
297 case git_wc_status_external:
298 return 5;
299 case git_wc_status_added:
300 return 6;
301 case git_wc_status_missing:
302 return 7;
303 case git_wc_status_deleted:
304 return 8;
305 case git_wc_status_replaced:
306 return 9;
307 case git_wc_status_modified:
308 return 10;
309 case git_wc_status_merged:
310 return 11;
311 case git_wc_status_conflicted:
312 return 12;
313 case git_wc_status_obstructed:
314 return 13;
316 return 0;
319 git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */)
321 // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of
322 // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right
323 // after the call again
325 // apr_hash_t * statushash;
326 // apr_hash_t * exthash;
327 // apr_array_header_t * statusarray;
328 // const sort_item* item;
330 // git_error_clear(m_err);
331 // statushash = apr_hash_make(m_pool);
332 // exthash = apr_hash_make(m_pool);
333 git_revnum_t youngest = GIT_INVALID_REVNUM;
334 // git_opt_revision_t rev;
335 // rev.kind = git_opt_revision_unspecified;
337 CString sProjectRoot;
338 if ( !path.HasAdminDir(&sProjectRoot) )
339 return youngest;
341 struct hashbaton_t hashbaton;
342 // hashbaton.hash = statushash;
343 // hashbaton.exthash = exthash;
344 hashbaton.pThis = this;
346 LPCSTR lpszSubPath = NULL;
347 CStringA sSubPath;
348 CString s = path.GetWinPathString();
349 if (s.GetLength() > sProjectRoot.GetLength())
351 sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/));
352 lpszSubPath = sSubPath;
355 // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here
356 UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse;
357 if (!lpszSubPath)
358 // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)
359 nFlags |= WGEFF_EmptyAsNormal;
361 m_status.prop_status = m_status.text_status = git_wc_status_none;
363 // NOTE: currently wgEnumFiles_safe_safe_safe will not enumerate file if it isn't versioned (so status will be git_wc_status_none)
364 m_err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getstatus, &m_status);
366 /*m_err = git_client_status4 (&youngest,
367 path.GetGitApiPath(m_pool),
368 &rev,
369 getstatushash,
370 &hashbaton,
371 git_depth_empty, //depth
372 TRUE, //getall
373 update, //update
374 noignore, //noignore
375 noexternals,
376 NULL,
377 ctx,
378 m_pool);*/
381 // Error present if function is not under version control
382 if ((m_err != NULL) /*|| (apr_hash_count(statushash) == 0)*/)
384 status = NULL;
385 // return -2;
386 return GIT_INVALID_REVNUM;
389 // Convert the unordered hash to an ordered, sorted array
390 /*statusarray = sort_hash (statushash,
391 sort_compare_items_as_paths,
392 m_pool);*/
394 // only the first entry is needed (no recurse)
395 // item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);
397 // status = (git_wc_status2_t *) item->value;
398 status = &m_status;
400 if (update)
402 const BYTE *sha1 = wgGetRevisionID_safe(CStringA(sProjectRoot), NULL);
403 if (sha1)
404 youngest = ConvertHashToRevnum(sha1);
407 return youngest;
410 git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update, git_depth_t depth, bool bNoIgnore /* = true */, bool bNoExternals /* = false */)
412 static git_wc_status2 st;
414 m_fileCache.Reset();
416 m_fileCache.Init( CStringA( path.GetWinPathString().GetString() ) );
417 MessageBox(NULL, path.GetWinPathString(), _T("GetFirstFile"), MB_OK);
418 m_fileCache.m_pFileIter = m_fileCache.m_pFiles;
419 st.text_status = git_wc_status_none;
421 if (m_fileCache.m_pFileIter)
423 switch(m_fileCache.m_pFileIter->nStatus)
425 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
426 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
427 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
430 //retPath.SetFromGit((const char*)item->key);
432 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
435 return &st;
437 #if 0
438 const sort_item* item;
440 git_error_clear(m_err);
441 m_statushash = apr_hash_make(m_pool);
442 m_externalhash = apr_hash_make(m_pool);
443 headrev = Git_INVALID_REVNUM;
444 git_opt_revision_t rev;
445 rev.kind = git_opt_revision_unspecified;
446 struct hashbaton_t hashbaton;
447 hashbaton.hash = m_statushash;
448 hashbaton.exthash = m_externalhash;
449 hashbaton.pThis = this;
450 m_statushashindex = 0;
451 m_err = git_client_status4 (&headrev,
452 path.GetGitApiPath(m_pool),
453 &rev,
454 getstatushash,
455 &hashbaton,
456 depth,
457 TRUE, //getall
458 update, //update
459 bNoIgnore, //noignore
460 bNoExternals, //noexternals
461 NULL,
462 ctx,
463 m_pool);
466 // Error present if function is not under version control
467 if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))
469 return NULL;
472 // Convert the unordered hash to an ordered, sorted array
473 m_statusarray = sort_hash (m_statushash,
474 sort_compare_items_as_paths,
475 m_pool);
477 // only the first entry is needed (no recurse)
478 m_statushashindex = 0;
479 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
480 retPath.SetFromGit((const char*)item->key);
481 return (git_wc_status2_t *) item->value;
482 #endif
484 return 0;
487 unsigned int GitStatus::GetVersionedCount() const
489 // return /**/m_fileCache.GetFileCount();
491 unsigned int count = 0;
492 #if 0
493 const sort_item* item;
494 for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)
496 item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);
497 if (item)
499 if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)
500 count++;
503 #endif
504 return count;
507 git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& retPath)
509 static git_wc_status2 st;
511 st.text_status = git_wc_status_none;
513 /*if (m_fileCache.m_pFileIter)
515 switch(m_fileCache.m_pFileIter->nStatus)
517 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
518 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
519 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
522 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
525 return &st;
527 #if 0
528 const sort_item* item;
530 if ((m_statushashindex+1) >= apr_hash_count(m_statushash))
531 return NULL;
532 m_statushashindex++;
534 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
535 retPath.SetFromGit((const char*)item->key);
536 return (git_wc_status2_t *) item->value;
537 #endif
538 return 0;
541 bool GitStatus::IsExternal(const CTGitPath& path) const
543 #if 0
544 if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))
545 return true;
546 #endif
547 return false;
550 bool GitStatus::IsInExternal(const CTGitPath& path) const
552 #if 0
553 if (apr_hash_count(m_statushash) == 0)
554 return false;
556 GitPool localpool(m_pool);
557 apr_hash_index_t *hi;
558 const char* key;
559 for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi))
561 apr_hash_this(hi, (const void**)&key, NULL, NULL);
562 if (key)
564 if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))
565 return true;
568 #endif
569 return false;
573 void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)
575 TCHAR * buf;
576 switch (status)
578 case git_wc_status_none:
579 buf = _T("none\0");
580 break;
581 case git_wc_status_unversioned:
582 buf = _T("unversioned\0");
583 break;
584 case git_wc_status_normal:
585 buf = _T("normal\0");
586 break;
587 case git_wc_status_added:
588 buf = _T("added\0");
589 break;
590 case git_wc_status_missing:
591 buf = _T("missing\0");
592 break;
593 case git_wc_status_deleted:
594 buf = _T("deleted\0");
595 break;
596 case git_wc_status_replaced:
597 buf = _T("replaced\0");
598 break;
599 case git_wc_status_modified:
600 buf = _T("modified\0");
601 break;
602 case git_wc_status_merged:
603 buf = _T("merged\0");
604 break;
605 case git_wc_status_conflicted:
606 buf = _T("conflicted\0");
607 break;
608 case git_wc_status_obstructed:
609 buf = _T("obstructed\0");
610 break;
611 case git_wc_status_ignored:
612 buf = _T("ignored");
613 break;
614 case git_wc_status_external:
615 buf = _T("external");
616 break;
617 case git_wc_status_incomplete:
618 buf = _T("incomplete\0");
619 break;
620 default:
621 buf = _T("\0");
622 break;
624 _stprintf_s(string, buflen, _T("%s"), buf);
627 void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)
629 switch (status)
631 case git_wc_status_none:
632 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
633 break;
634 case git_wc_status_unversioned:
635 LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);
636 break;
637 case git_wc_status_normal:
638 LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);
639 break;
640 case git_wc_status_added:
641 LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);
642 break;
643 case git_wc_status_missing:
644 LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);
645 break;
646 case git_wc_status_deleted:
647 LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);
648 break;
649 case git_wc_status_replaced:
650 LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);
651 break;
652 case git_wc_status_modified:
653 LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);
654 break;
655 case git_wc_status_merged:
656 LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);
657 break;
658 case git_wc_status_conflicted:
659 LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);
660 break;
661 case git_wc_status_ignored:
662 LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);
663 break;
664 case git_wc_status_obstructed:
665 LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);
666 break;
667 case git_wc_status_external:
668 LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);
669 break;
670 case git_wc_status_incomplete:
671 LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);
672 break;
673 default:
674 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
675 break;
679 #ifdef _MFC_VER
680 CString GitStatus::GetDepthString(git_depth_t depth)
682 #if 0
683 CString sDepth;
684 switch (depth)
686 case git_depth_unknown:
687 sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);
688 break;
689 case git_depth_empty:
690 sDepth.LoadString(IDS_Git_DEPTH_EMPTY);
691 break;
692 case git_depth_files:
693 sDepth.LoadString(IDS_Git_DEPTH_FILES);
694 break;
695 case git_depth_immediates:
696 sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);
697 break;
698 case git_depth_infinity:
699 sDepth.LoadString(IDS_Git_DEPTH_INFINITE);
700 break;
702 return sDepth;
703 #endif
704 return CString("");
706 #endif
708 void GitStatus::GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang)
710 #if 0
711 switch (depth)
713 case git_depth_unknown:
714 LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);
715 break;
716 case git_depth_empty:
717 LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);
718 break;
719 case git_depth_files:
720 LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);
721 break;
722 case git_depth_immediates:
723 LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);
724 break;
725 case git_depth_infinity:
726 LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);
727 break;
729 #endif
733 int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)
735 const STRINGRESOURCEIMAGE* pImage;
736 const STRINGRESOURCEIMAGE* pImageEnd;
737 ULONG nResourceSize;
738 HGLOBAL hGlobal;
739 UINT iIndex;
740 int ret;
742 HRSRC hResource = FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);
743 if (!hResource)
745 // try the default language before giving up!
746 hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);
747 if (!hResource)
748 return 0;
750 hGlobal = LoadResource(hInstance, hResource);
751 if (!hGlobal)
752 return 0;
753 pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);
754 if(!pImage)
755 return 0;
757 nResourceSize = ::SizeofResource(hInstance, hResource);
758 pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);
759 iIndex = uID&0x000f;
761 while ((iIndex > 0) && (pImage < pImageEnd))
763 pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));
764 iIndex--;
766 if (pImage >= pImageEnd)
767 return 0;
768 if (pImage->nLength == 0)
769 return 0;
771 ret = pImage->nLength;
772 if (pImage->nLength > nBufferMax)
774 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);
775 lpBuffer[nBufferMax-1] = 0;
777 else
779 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);
780 lpBuffer[ret] = 0;
782 return ret;
785 BOOL GitStatus::getallstatus(const struct wgFile_s *pFile, void *pUserData)
787 git_wc_status_kind * s = (git_wc_status_kind *)pUserData;
788 *s = GitStatus::GetMoreImportant(*s, GitStatusFromWingit(pFile->nStatus));
789 return FALSE;
792 BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)
794 git_wc_status2_t * s = (git_wc_status2_t*)pUserData;
795 s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));
796 return FALSE;
799 #if 0
800 git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)
802 git_wc_status_kind * s = (git_wc_status_kind *)baton;
803 *s = GitStatus::GetMoreImportant(*s, status->text_status);
804 *s = GitStatus::GetMoreImportant(*s, status->prop_status);
805 return Git_NO_ERROR;
807 #endif
809 #if 0
810 git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)
812 hashbaton_t * hash = (hashbaton_t *)baton;
813 const StdStrAVector& filterList = hash->pThis->m_filterFileList;
814 if (status->text_status == git_wc_status_external)
816 apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);
817 return Git_NO_ERROR;
819 if(filterList.size() > 0)
821 // We have a filter active - we're only interested in files which are in
822 // the filter
823 if(!binary_search(filterList.begin(), filterList.end(), path))
825 // This item is not in the filter - don't store it
826 return Git_NO_ERROR;
829 git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);
830 apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);
831 return Git_NO_ERROR;
834 apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,
835 int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),
836 apr_pool_t *pool)
838 apr_hash_index_t *hi;
839 apr_array_header_t *ary;
841 /* allocate an array with only one element to begin with. */
842 ary = apr_array_make (pool, 1, sizeof(sort_item));
844 /* loop over hash table and push all keys into the array */
845 for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))
847 sort_item *item = (sort_item*)apr_array_push (ary);
849 apr_hash_this (hi, &item->key, &item->klen, &item->value);
852 /* now quick sort the array. */
853 qsort (ary->elts, ary->nelts, ary->elt_size,
854 (int (*)(const void *, const void *))comparison_func);
856 return ary;
859 int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)
861 const char *astr, *bstr;
863 astr = (const char*)a->key;
864 bstr = (const char*)b->key;
865 return git_path_compare_paths (astr, bstr);
867 #endif
869 git_error_t* GitStatus::cancel(void *baton)
871 #if 0
872 volatile bool * canceled = (bool *)baton;
873 if (*canceled)
875 CString temp;
876 temp.LoadString(IDS_Git_USERCANCELLED);
877 return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));
879 return Git_NO_ERROR;
880 #endif
881 return 0;
884 #ifdef _MFC_VER
886 // Set-up a filter to restrict the files which will have their status stored by a get-status
887 void GitStatus::SetFilter(const CTGitPathList& fileList)
889 m_filterFileList.clear();
890 for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)
892 // m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));
894 // Sort the list so that we can do binary searches
895 std::sort(m_filterFileList.begin(), m_filterFileList.end());
898 void GitStatus::ClearFilter()
900 m_filterFileList.clear();
903 #endif // _MFC_VER