OSDN Git Service

Experiment with retrieving full log in one git.exe call
[tortoisegit/TortoiseGitJp.git] / src / Git / Git.cpp
1 #include "StdAfx.h"\r
2 #include "Git.h"\r
3 #include "atlconv.h"\r
4 #include "GitRev.h"\r
5 #include "registry.h"\r
6 #include "GitConfig.h"\r
7 \r
8 \r
9 static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen)\r
10 {\r
11         LPCTSTR orgsrc;\r
12 \r
13         while (*src == _T(';'))\r
14                 src++;\r
15 \r
16         orgsrc = src;\r
17 \r
18         if (!--maxlen)\r
19                 goto nullterm;\r
20 \r
21         while (*src && *src != _T(';'))\r
22         {\r
23                 if (*src != _T('"'))\r
24                 {\r
25                         *dst++ = *src++;\r
26                         if (!--maxlen)\r
27                         {\r
28                                 orgsrc = src;\r
29                                 goto nullterm;\r
30                         }\r
31                 }\r
32                 else\r
33                 {\r
34                         src++;\r
35                         while (*src && *src != _T('"'))\r
36                         {\r
37                                 *dst++ = *src++;\r
38                                 if (!--maxlen)\r
39                                 {\r
40                                         orgsrc = src;\r
41                                         goto nullterm;\r
42                                 }\r
43                         }\r
44 \r
45                         if (*src)\r
46                                 src++;\r
47                 }\r
48         }\r
49 \r
50         while (*src == _T(';'))\r
51                 src++;\r
52 \r
53 nullterm:\r
54 \r
55         *dst = 0;\r
56 \r
57         return (orgsrc != src) ? (LPTSTR)src : NULL;\r
58 }\r
59 \r
60 static inline BOOL FileExists(LPCTSTR lpszFileName)\r
61 {\r
62         struct _stat st;\r
63         return _tstat(lpszFileName, &st) == 0;\r
64 }\r
65 \r
66 static BOOL FindGitPath()\r
67 {\r
68         size_t size;\r
69         _tgetenv_s(&size, NULL, 0, _T("PATH"));\r
70 \r
71         if (!size)\r
72         {\r
73                 return FALSE;\r
74         }\r
75 \r
76         TCHAR *env = (TCHAR*)alloca(size * sizeof(TCHAR));\r
77         _tgetenv_s(&size, env, size, _T("PATH"));\r
78 \r
79         TCHAR buf[_MAX_PATH];\r
80 \r
81         // search in all paths defined in PATH\r
82         while ((env = nextpath(env, buf, _MAX_PATH-1)) && *buf)\r
83         {\r
84                 TCHAR *pfin = buf + _tcslen(buf)-1;\r
85 \r
86                 // ensure trailing slash\r
87                 if (*pfin != _T('/') && *pfin != _T('\\'))\r
88                         _tcscpy(++pfin, _T("\\"));\r
89 \r
90                 const int len = _tcslen(buf);\r
91 \r
92                 if ((len + 7) < _MAX_PATH)\r
93                         _tcscpy(pfin+1, _T("git.exe"));\r
94                 else\r
95                         break;\r
96 \r
97                 if ( FileExists(buf) )\r
98                 {\r
99                         // dir found\r
100                         return TRUE;\r
101                 }\r
102         }\r
103 \r
104         return FALSE;\r
105 }\r
106 \r
107 \r
108 #define MAX_DIRBUFFER 1000\r
109 #define CALL_OUTPUT_READ_CHUNK_SIZE 1024\r
110 \r
111 CString CGit::ms_LastMsysGitDir;\r
112 CGit g_Git;\r
113 BOOL g_IsWingitDllload = TRUE;\r
114 \r
115 LPBYTE wgGetRevisionID_safe(const char *pszProjectPath, const char *pszName)\r
116 {\r
117         if(g_IsWingitDllload)\r
118                 return wgGetRevisionID(pszProjectPath,pszName);\r
119         else\r
120                 return NULL;\r
121 }\r
122 \r
123 BOOL wgEnumFiles_safe(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
124 {\r
125         if(g_IsWingitDllload)\r
126                 return wgEnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);\r
127         else\r
128                 return FALSE;\r
129 }\r
130 \r
131 BOOL CGit::IsVista()\r
132 {\r
133 \r
134         if( CRegStdWORD(_T("Software\\TortoiseGit\\CacheType") ) == 0)\r
135         {\r
136                 g_IsWingitDllload=FALSE;\r
137                 return TRUE;\r
138         }\r
139 \r
140         OSVERSIONINFO osvi;\r
141     BOOL bIsWindowsXPorLater;\r
142 \r
143     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));\r
144     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
145 \r
146     GetVersionEx(&osvi);\r
147         \r
148         if(osvi.dwMajorVersion >= 6)\r
149                 return TRUE;\r
150         else\r
151                 return FALSE;\r
152 }\r
153 \r
154 static void InitWinGitDll()\r
155 {\r
156         __try\r
157         {\r
158 \r
159                 if( CGit::IsVista () )\r
160                 {\r
161                         g_IsWingitDllload=FALSE;\r
162                         return;\r
163                 }\r
164                 if ( !wgInit() )\r
165                 {\r
166                                 // TODO\r
167                 }\r
168         }\r
169         __except(1)\r
170         {\r
171                 g_IsWingitDllload=FALSE;\r
172                 return;\r
173         }\r
174 \r
175 }\r
176 CGit::CGit(void)\r
177 {\r
178         GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));\r
179         m_CurrentDir.ReleaseBuffer();\r
180         // make sure git/bin is in PATH before wingit.dll gets (delay) loaded by wgInit()\r
181         if ( !CheckMsysGitDir() )\r
182         {\r
183                 // TODO\r
184         }\r
185         InitWinGitDll();\r
186 }\r
187 \r
188 CGit::~CGit(void)\r
189 {\r
190 }\r
191 \r
192 static char g_Buffer[4096];\r
193 \r
194 int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)\r
195 {\r
196         SECURITY_ATTRIBUTES sa;\r
197         HANDLE hRead, hWrite;\r
198         HANDLE hStdioFile = NULL;\r
199 \r
200         sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
201         sa.lpSecurityDescriptor=NULL;\r
202         sa.bInheritHandle=TRUE;\r
203         if(!CreatePipe(&hRead,&hWrite,&sa,0))\r
204         {\r
205                 return GIT_ERROR_OPEN_PIP;\r
206         }\r
207         \r
208         if(StdioFile)\r
209         {\r
210                 hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
211                         &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  \r
212         }\r
213 \r
214         STARTUPINFO si;\r
215         PROCESS_INFORMATION pi;\r
216         si.cb=sizeof(STARTUPINFO);\r
217         GetStartupInfo(&si);\r
218 \r
219         si.hStdError=hWrite;\r
220         if(StdioFile)\r
221                 si.hStdOutput=hStdioFile;\r
222         else\r
223                 si.hStdOutput=hWrite;\r
224 \r
225         si.wShowWindow=SW_HIDE;\r
226         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
227 \r
228         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
229         {\r
230                 LPVOID lpMsgBuf;\r
231                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
232                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
233                         (LPTSTR)&lpMsgBuf,\r
234                         0,NULL);\r
235                 return GIT_ERROR_CREATE_PROCESS;\r
236         }\r
237         \r
238         CloseHandle(hWrite);\r
239         if(piOut)\r
240                 *piOut=pi;\r
241         if(hReadOut)\r
242                 *hReadOut=hRead;\r
243         \r
244         return 0;\r
245 \r
246 }\r
247 //Must use sperate function to convert ANSI str to union code string\r
248 //Becuase A2W use stack as internal convert buffer. \r
249 void CGit::StringAppend(CString *str,BYTE *p,int code,int length)\r
250 {\r
251      //USES_CONVERSION;\r
252          //str->Append(A2W_CP((LPCSTR)p,code));\r
253         WCHAR * buf;\r
254 \r
255         int len ;\r
256         if(length<0)\r
257                 len= strlen((const char*)p);\r
258         else\r
259                 len=length;\r
260         //if (len==0)\r
261         //      return ;\r
262         //buf = new WCHAR[len*4 + 1];\r
263         buf = str->GetBuffer(len*4+1+str->GetLength())+str->GetLength();\r
264         SecureZeroMemory(buf, (len*4 + 1)*sizeof(WCHAR));\r
265         MultiByteToWideChar(code, 0, (LPCSTR)p, len, buf, len*4);\r
266         str->ReleaseBuffer();\r
267         //str->Append(buf);\r
268         //delete buf;\r
269 }       \r
270 BOOL CGit::IsInitRepos()\r
271 {\r
272         CString cmdout;\r
273         cmdout.Empty();\r
274         if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8))\r
275         {\r
276         //      CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
277                 return TRUE;\r
278         }\r
279         if(cmdout.IsEmpty())\r
280                 return TRUE;\r
281 \r
282         return FALSE;\r
283 }\r
284 int CGit::Run(CGitCall* pcall)\r
285 {\r
286         PROCESS_INFORMATION pi;\r
287         HANDLE hRead;\r
288         if(RunAsync(pcall->GetCmd(),&pi,&hRead))\r
289                 return GIT_ERROR_CREATE_PROCESS;\r
290 \r
291         DWORD readnumber;\r
292         BYTE data[CALL_OUTPUT_READ_CHUNK_SIZE];\r
293         while(ReadFile(hRead,data,CALL_OUTPUT_READ_CHUNK_SIZE,&readnumber,NULL))\r
294         {\r
295                 pcall->OnOutputData(data,readnumber);\r
296         }\r
297 \r
298         \r
299         CloseHandle(pi.hThread);\r
300 \r
301         WaitForSingleObject(pi.hProcess, INFINITE);\r
302         DWORD exitcode =0;\r
303 \r
304         if(!GetExitCodeProcess(pi.hProcess,&exitcode))\r
305         {\r
306                 return GIT_ERROR_GET_EXIT_CODE;\r
307         }\r
308 \r
309         CloseHandle(pi.hProcess);\r
310 \r
311         CloseHandle(hRead);\r
312         return exitcode;\r
313 }\r
314 class CGitCall_ByteVector : public CGitCall\r
315 {\r
316 public:\r
317         CGitCall_ByteVector(CString cmd,BYTE_VECTOR* pvector):CGitCall(cmd),m_pvector(pvector){}\r
318         virtual bool OnOutputData(const BYTE* data, size_t size)\r
319         {\r
320                 size_t oldsize=m_pvector->size();\r
321                 m_pvector->resize(m_pvector->size()+size);\r
322                 memcpy(&*(m_pvector->begin()+oldsize),data,size);\r
323                 return false;\r
324         }\r
325         BYTE_VECTOR* m_pvector;\r
326 \r
327 };\r
328 int CGit::Run(CString cmd,BYTE_VECTOR *vector)\r
329 {\r
330         CGitCall_ByteVector call(cmd,vector);\r
331         return Run(&call);\r
332 }\r
333 int CGit::Run(CString cmd, CString* output,int code)\r
334 {\r
335         BYTE_VECTOR vector;\r
336         int ret;\r
337         ret=Run(cmd,&vector);\r
338 \r
339         vector.push_back(0);\r
340         \r
341         StringAppend(output,&(vector[0]),code);\r
342         return ret;\r
343 }\r
344 \r
345 CString CGit::GetUserName(void)\r
346 {\r
347         CString UserName;\r
348         Run(_T("git.exe config user.name"),&UserName,CP_UTF8);\r
349         return UserName;\r
350 }\r
351 CString CGit::GetUserEmail(void)\r
352 {\r
353         CString UserName;\r
354         Run(_T("git.exe config user.email"),&UserName,CP_UTF8);\r
355         return UserName;\r
356 }\r
357 \r
358 CString CGit::GetCurrentBranch(void)\r
359 {\r
360         CString output;\r
361         //Run(_T("git.exe branch"),&branch);\r
362 \r
363         int ret=g_Git.Run(_T("git.exe branch"),&output,CP_UTF8);\r
364         if(!ret)\r
365         {               \r
366                 int pos=0;\r
367                 CString one;\r
368                 while( pos>=0 )\r
369                 {\r
370                         //i++;\r
371                         one=output.Tokenize(_T("\n"),pos);\r
372                         //list.push_back(one.Right(one.GetLength()-2));\r
373                         if(one[0] == _T('*'))\r
374                                 return one.Right(one.GetLength()-2);\r
375                 }\r
376         }\r
377         return CString("");\r
378 }\r
379 \r
380 int CGit::BuildOutputFormat(CString &format,bool IsFull)\r
381 {\r
382         CString log;\r
383         log.Format(_T("#<%c>%%x00"),LOG_REV_ITEM_BEGIN);\r
384         format += log;\r
385         if(IsFull)\r
386         {\r
387                 log.Format(_T("#<%c>%%an%%x00"),LOG_REV_AUTHOR_NAME);\r
388                 format += log;\r
389                 log.Format(_T("#<%c>%%ae%%x00"),LOG_REV_AUTHOR_EMAIL);\r
390                 format += log;\r
391                 log.Format(_T("#<%c>%%ai%%x00"),LOG_REV_AUTHOR_DATE);\r
392                 format += log;\r
393                 log.Format(_T("#<%c>%%cn%%x00"),LOG_REV_COMMIT_NAME);\r
394                 format += log;\r
395                 log.Format(_T("#<%c>%%ce%%x00"),LOG_REV_COMMIT_EMAIL);\r
396                 format += log;\r
397                 log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE);\r
398                 format += log;\r
399                 log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT);\r
400                 format += log;\r
401                 log.Format(_T("#<%c>%%b%%x00"),LOG_REV_COMMIT_BODY);\r
402                 format += log;\r
403         }\r
404         log.Format(_T("#<%c>%%m%%H%%x00"),LOG_REV_COMMIT_HASH);\r
405         format += log;\r
406         log.Format(_T("#<%c>%%P%%x00"),LOG_REV_COMMIT_PARENT);\r
407         format += log;\r
408 \r
409         if(IsFull)\r
410         {\r
411                 log.Format(_T("#<%c>%%x00"),LOG_REV_COMMIT_FILE);\r
412                 format += log;\r
413         }\r
414         return 0;\r
415 }\r
416 \r
417 int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash,  CTGitPath *path ,int count,int mask)\r
418 {\r
419         CGitCall_ByteVector gitCall(CString(),&logOut);\r
420         return GetLog(&gitCall,hash,path,count,mask);\r
421 }\r
422 \r
423 //int CGit::GetLog(CGitCall* pgitCall, CString &hash,  CTGitPath *path ,int count,int mask)\r
424 int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask)\r
425 {\r
426 \r
427         CString cmd;\r
428         CString log;\r
429         CString num;\r
430         CString since;\r
431 \r
432         CString file;\r
433 \r
434         if(path)\r
435                 file.Format(_T(" -- \"%s\""),path->GetGitPathString());\r
436         \r
437         if(count>0)\r
438                 num.Format(_T("-n%d"),count);\r
439 \r
440         CString param;\r
441 \r
442         if(mask& LOG_INFO_STAT )\r
443                 param += _T(" --numstat ");\r
444         if(mask& LOG_INFO_FILESTATE)\r
445                 param += _T(" --raw ");\r
446 \r
447         if(mask& LOG_INFO_FULLHISTORY)\r
448                 param += _T(" --full-history ");\r
449 \r
450         if(mask& LOG_INFO_BOUNDARY)\r
451                 param += _T(" --left-right --boundary ");\r
452 \r
453         if(mask& CGit::LOG_INFO_ALL_BRANCH)\r
454                 param += _T(" --all ");\r
455 \r
456         if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)\r
457                 param += _T(" -C ");\r
458         \r
459         if(mask& CGit::LOG_INFO_DETECT_RENAME )\r
460                 param += _T(" -M ");\r
461 \r
462         if(mask& CGit::LOG_INFO_FIRST_PARENT )\r
463                 param += _T(" --first-parent ");\r
464         \r
465         if(mask& CGit::LOG_INFO_NO_MERGE )\r
466                 param += _T(" --no-merges ");\r
467 \r
468         if(mask& CGit::LOG_INFO_FOLLOW)\r
469                 param += _T(" --follow ");\r
470 \r
471         param+=hash;\r
472 \r
473         cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""),\r
474                                 num,param);\r
475 \r
476         BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));\r
477 \r
478         cmd += log;\r
479         cmd += CString(_T("\"  "))+hash+file;\r
480 \r
481         pgitCall->SetCmd(cmd);\r
482 \r
483         return Run(pgitCall);\r
484 //      return Run(cmd,&logOut);\r
485 }\r
486 \r
487 #if 0\r
488 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)\r
489 {\r
490         CString cmd;\r
491         CString log;\r
492         int n;\r
493         if(count<0)\r
494                 n=100;\r
495         else\r
496                 n=count;\r
497         cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);\r
498         BuildOutputFormat(log,false);\r
499         cmd += log+_T("\"");\r
500         if (path)\r
501                 cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");\r
502         //cmd += CString(_T("\" HEAD~40..HEAD"));\r
503         return Run(cmd,&logOut);\r
504 }\r
505 #endif\r
506 \r
507 #define BUFSIZE 512\r
508 void GetTempPath(CString &path)\r
509 {\r
510         TCHAR lpPathBuffer[BUFSIZE];\r
511         DWORD dwRetVal;\r
512         DWORD dwBufSize=BUFSIZE;\r
513         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
514                            lpPathBuffer); // buffer for path \r
515     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
516     {\r
517         path=_T("");\r
518     }\r
519         path.Format(_T("%s"),lpPathBuffer);\r
520 }\r
521 CString GetTempFile()\r
522 {\r
523         TCHAR lpPathBuffer[BUFSIZE];\r
524         DWORD dwRetVal;\r
525     DWORD dwBufSize=BUFSIZE;\r
526         TCHAR szTempName[BUFSIZE];  \r
527         UINT uRetVal;\r
528 \r
529         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
530                            lpPathBuffer); // buffer for path \r
531     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
532     {\r
533         return _T("");\r
534     }\r
535          // Create a temporary file. \r
536     uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
537                               TEXT("Patch"),  // temp file name prefix \r
538                               0,            // create unique name \r
539                               szTempName);  // buffer for name \r
540 \r
541 \r
542     if (uRetVal == 0)\r
543     {\r
544         return _T("");\r
545     }\r
546 \r
547         return CString(szTempName);\r
548 \r
549 }\r
550 \r
551 int CGit::RunLogFile(CString cmd,CString &filename)\r
552 {\r
553         STARTUPINFO si;\r
554         PROCESS_INFORMATION pi;\r
555         si.cb=sizeof(STARTUPINFO);\r
556         GetStartupInfo(&si);\r
557 \r
558         SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
559         psa.bInheritHandle=TRUE;   \r
560     \r
561         HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
562                         &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
563 \r
564 \r
565         si.wShowWindow=SW_HIDE;\r
566         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
567         si.hStdOutput   =   houtfile; \r
568         \r
569         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
570         {\r
571                 LPVOID lpMsgBuf;\r
572                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
573                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
574                         (LPTSTR)&lpMsgBuf,\r
575                         0,NULL);\r
576                 return GIT_ERROR_CREATE_PROCESS;\r
577         }\r
578         \r
579         WaitForSingleObject(pi.hProcess,INFINITE);   \r
580         \r
581         CloseHandle(pi.hThread);\r
582         CloseHandle(pi.hProcess);\r
583         CloseHandle(houtfile);\r
584         return GIT_SUCCESS;\r
585 //      return 0;\r
586 }\r
587 \r
588 git_revnum_t CGit::GetHash(CString &friendname)\r
589 {\r
590         // NOTE: could replace this with wgGetRevisionID call\r
591 \r
592         CString cmd;\r
593         CString out;\r
594         cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
595         Run(cmd,&out,CP_UTF8);\r
596         int pos=out.ReverseFind(_T('\n'));\r
597         if(pos>0)\r
598                 return out.Left(pos);\r
599         return out;\r
600 }\r
601 \r
602 int CGit::GetTagList(STRING_VECTOR &list)\r
603 {\r
604         int ret;\r
605         CString cmd,output;\r
606         cmd=_T("git.exe tag -l");\r
607         int i=0;\r
608         ret=g_Git.Run(cmd,&output,CP_UTF8);\r
609         if(!ret)\r
610         {               \r
611                 int pos=0;\r
612                 CString one;\r
613                 while( pos>=0 )\r
614                 {\r
615                         i++;\r
616                         one=output.Tokenize(_T("\n"),pos);\r
617                         list.push_back(one);\r
618                 }\r
619         }\r
620         return ret;\r
621 }\r
622 \r
623 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
624 {\r
625         int ret;\r
626         CString cmd,output;\r
627         cmd=_T("git.exe branch");\r
628 \r
629         if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
630                 cmd+=_T(" -a");\r
631         else if(type==BRANCH_REMOTE)\r
632                 cmd+=_T(" -r");\r
633 \r
634         int i=0;\r
635         ret=g_Git.Run(cmd,&output,CP_UTF8);\r
636         if(!ret)\r
637         {               \r
638                 int pos=0;\r
639                 CString one;\r
640                 while( pos>=0 )\r
641                 {\r
642                         one=output.Tokenize(_T("\n"),pos);\r
643                         list.push_back(one.Right(one.GetLength()-2));\r
644                         if(one[0] == _T('*'))\r
645                                 if(current)\r
646                                         *current=i;\r
647                         i++;\r
648                 }\r
649         }\r
650         return ret;\r
651 }\r
652 \r
653 int CGit::GetRemoteList(STRING_VECTOR &list)\r
654 {\r
655         int ret;\r
656         CString cmd,output;\r
657         cmd=_T("git.exe config  --get-regexp remote.*.url");\r
658         ret=g_Git.Run(cmd,&output,CP_UTF8);\r
659         if(!ret)\r
660         {\r
661                 int pos=0;\r
662                 CString one;\r
663                 while( pos>=0 )\r
664                 {\r
665                         one=output.Tokenize(_T("\n"),pos);\r
666                         int start=one.Find(_T("."),0);\r
667                         if(start>0)\r
668                         {\r
669                                 CString url;\r
670                                 url=one.Right(one.GetLength()-start-1);\r
671                                 one=url;\r
672                                 one=one.Left(one.Find(_T("."),0));\r
673                                 list.push_back(one);\r
674                         }\r
675                 }\r
676         }\r
677         return ret;\r
678 }\r
679 \r
680 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
681 {\r
682         int ret;\r
683         CString cmd,output;\r
684         cmd=_T("git show-ref -d");\r
685         ret=g_Git.Run(cmd,&output,CP_UTF8);\r
686         if(!ret)\r
687         {\r
688                 int pos=0;\r
689                 CString one;\r
690                 while( pos>=0 )\r
691                 {\r
692                         one=output.Tokenize(_T("\n"),pos);\r
693                         int start=one.Find(_T(" "),0);\r
694                         if(start>0)\r
695                         {\r
696                                 CString name;\r
697                                 name=one.Right(one.GetLength()-start-1);\r
698 \r
699                                 CString hash;\r
700                                 hash=one.Left(start);\r
701 \r
702                                 map[hash].push_back(name);\r
703                         }\r
704                 }\r
705         }\r
706         return ret;\r
707 }\r
708 \r
709 BOOL CGit::CheckMsysGitDir()\r
710 {\r
711         static BOOL bInitialized = FALSE;\r
712 \r
713         if (bInitialized)\r
714         {\r
715                 return TRUE;\r
716         }\r
717 \r
718         TCHAR *oldpath,*home;\r
719         size_t size;\r
720 \r
721         // set HOME if not set already\r
722         _tgetenv_s(&size, NULL, 0, _T("HOME"));\r
723         if (!size)\r
724         {\r
725                 _tdupenv_s(&home,&size,_T("USERPROFILE")); \r
726                 _tputenv_s(_T("HOME"),home);\r
727                 free(home);\r
728         }\r
729 \r
730         //setup ssh client\r
731         CRegString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));\r
732         CString ssh=sshclient;\r
733 \r
734         if(!ssh.IsEmpty())\r
735         {\r
736                 _tputenv_s(_T("GIT_SSH"),ssh);\r
737         }else\r
738         {\r
739                 _tputenv_s(_T("GIT_SSH"),_T(""));\r
740         }\r
741 \r
742         // search PATH if git/bin directory is alredy present\r
743         if ( FindGitPath() )\r
744         {\r
745                 bInitialized = TRUE;\r
746                 return TRUE;\r
747         }\r
748 \r
749         // add git/bin path to PATH\r
750 \r
751         CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
752         CString str=msysdir;\r
753         if(str.IsEmpty())\r
754         {\r
755                 CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
756                 str=msysinstalldir;\r
757                 if ( !str.IsEmpty() )\r
758                 {\r
759                         str += (str[str.GetLength()-1] != '\\') ? "\\bin" : "bin";\r
760                         msysdir=str;\r
761                         msysdir.write();\r
762                 }\r
763                 else\r
764                 {\r
765                         return false;\r
766                 }\r
767         }\r
768         //CGit::m_MsysGitPath=str;\r
769 \r
770         //set path\r
771 \r
772         _tdupenv_s(&oldpath,&size,_T("PATH")); \r
773 \r
774         CString path;\r
775         path.Format(_T("%s;%s"),oldpath,str);\r
776 \r
777         _tputenv_s(_T("PATH"),path);\r
778 \r
779         free(oldpath);\r
780 \r
781 \r
782     if( !FindGitPath() )\r
783         {\r
784                 return false;\r
785         }\r
786         else\r
787         {\r
788                 bInitialized = TRUE;\r
789                 return true;\r
790         }\r
791 }\r